1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "components/zucchini/element_detection.h" 6 7 #include <utility> 8 9 #include "components/zucchini/buildflags.h" 10 #include "components/zucchini/disassembler.h" 11 #include "components/zucchini/disassembler_no_op.h" 12 #include "components/zucchini/version_info.h" 13 14 #if BUILDFLAG(ENABLE_DEX) 15 #include "components/zucchini/disassembler_dex.h" 16 #endif // BUILDFLAG(ENABLE_DEX) 17 18 #if BUILDFLAG(ENABLE_ELF) 19 #include "components/zucchini/disassembler_elf.h" 20 #endif // BUILDFLAG(ENABLE_ELF) 21 22 #if BUILDFLAG(ENABLE_WIN) 23 #include "components/zucchini/disassembler_win32.h" 24 #endif // BUILDFLAG(ENABLE_WIN) 25 26 #if BUILDFLAG(ENABLE_ZTF) 27 #include "components/zucchini/disassembler_ztf.h" 28 #endif // BUILDFLAG(ENABLE_ZTF) 29 30 namespace zucchini { 31 32 namespace { 33 34 // Impose a minimal program size to eliminate pathological cases. 35 enum : size_t { kMinProgramSize = 16 }; 36 37 } // namespace 38 39 /******** Utility Functions ********/ 40 MakeDisassemblerWithoutFallback(ConstBufferView image)41std::unique_ptr<Disassembler> MakeDisassemblerWithoutFallback( 42 ConstBufferView image) { 43 #if BUILDFLAG(ENABLE_WIN) 44 if (DisassemblerWin32X86::QuickDetect(image)) { 45 auto disasm = Disassembler::Make<DisassemblerWin32X86>(image); 46 if (disasm && disasm->size() >= kMinProgramSize) 47 return disasm; 48 } 49 50 if (DisassemblerWin32X64::QuickDetect(image)) { 51 auto disasm = Disassembler::Make<DisassemblerWin32X64>(image); 52 if (disasm && disasm->size() >= kMinProgramSize) 53 return disasm; 54 } 55 #endif // BUILDFLAG(ENABLE_WIN) 56 57 #if BUILDFLAG(ENABLE_ELF) 58 if (DisassemblerElfX86::QuickDetect(image)) { 59 auto disasm = Disassembler::Make<DisassemblerElfX86>(image); 60 if (disasm && disasm->size() >= kMinProgramSize) 61 return disasm; 62 } 63 64 if (DisassemblerElfX64::QuickDetect(image)) { 65 auto disasm = Disassembler::Make<DisassemblerElfX64>(image); 66 if (disasm && disasm->size() >= kMinProgramSize) 67 return disasm; 68 } 69 70 if (DisassemblerElfAArch32::QuickDetect(image)) { 71 auto disasm = Disassembler::Make<DisassemblerElfAArch32>(image); 72 if (disasm && disasm->size() >= kMinProgramSize) 73 return disasm; 74 } 75 76 if (DisassemblerElfAArch64::QuickDetect(image)) { 77 auto disasm = Disassembler::Make<DisassemblerElfAArch64>(image); 78 if (disasm && disasm->size() >= kMinProgramSize) 79 return disasm; 80 } 81 #endif // BUILDFLAG(ENABLE_ELF) 82 83 #if BUILDFLAG(ENABLE_DEX) 84 if (DisassemblerDex::QuickDetect(image)) { 85 auto disasm = Disassembler::Make<DisassemblerDex>(image); 86 if (disasm && disasm->size() >= kMinProgramSize) 87 return disasm; 88 } 89 #endif // BUILDFLAG(ENABLE_DEX) 90 91 #if BUILDFLAG(ENABLE_ZTF) 92 if (DisassemblerZtf::QuickDetect(image)) { 93 // This disallows very short examples like "ZTxtxtZ\n" in ensemble patching. 94 auto disasm = Disassembler::Make<DisassemblerZtf>(image); 95 if (disasm && disasm->size() >= kMinProgramSize) 96 return disasm; 97 } 98 #endif // BUILDFLAG(ENABLE_ZTF) 99 100 return nullptr; 101 } 102 MakeDisassemblerOfType(ConstBufferView image,ExecutableType exe_type)103std::unique_ptr<Disassembler> MakeDisassemblerOfType(ConstBufferView image, 104 ExecutableType exe_type) { 105 switch (exe_type) { 106 #if BUILDFLAG(ENABLE_WIN) 107 case kExeTypeWin32X86: 108 return Disassembler::Make<DisassemblerWin32X86>(image); 109 case kExeTypeWin32X64: 110 return Disassembler::Make<DisassemblerWin32X64>(image); 111 #endif // BUILDFLAG(ENABLE_WIN) 112 #if BUILDFLAG(ENABLE_ELF) 113 case kExeTypeElfX86: 114 return Disassembler::Make<DisassemblerElfX86>(image); 115 case kExeTypeElfX64: 116 return Disassembler::Make<DisassemblerElfX64>(image); 117 case kExeTypeElfAArch32: 118 return Disassembler::Make<DisassemblerElfAArch32>(image); 119 case kExeTypeElfAArch64: 120 return Disassembler::Make<DisassemblerElfAArch64>(image); 121 #endif // BUILDFLAG(ENABLE_ELF) 122 #if BUILDFLAG(ENABLE_DEX) 123 case kExeTypeDex: 124 return Disassembler::Make<DisassemblerDex>(image); 125 #endif // BUILDFLAG(ENABLE_DEX) 126 #if BUILDFLAG(ENABLE_ZTF) 127 case kExeTypeZtf: 128 return Disassembler::Make<DisassemblerZtf>(image); 129 #endif // BUILDFLAG(ENABLE_ZTF) 130 case kExeTypeNoOp: 131 return Disassembler::Make<DisassemblerNoOp>(image); 132 default: 133 // If an architecture is disabled then null is handled gracefully. 134 return nullptr; 135 } 136 } 137 DisassemblerVersionOfType(ExecutableType exe_type)138uint16_t DisassemblerVersionOfType(ExecutableType exe_type) { 139 switch (exe_type) { 140 #if BUILDFLAG(ENABLE_WIN) 141 case kExeTypeWin32X86: 142 return DisassemblerWin32X86::kVersion; 143 case kExeTypeWin32X64: 144 return DisassemblerWin32X64::kVersion; 145 #endif // BUILDFLAG(ENABLE_WIN) 146 #if BUILDFLAG(ENABLE_ELF) 147 case kExeTypeElfX86: 148 return DisassemblerElfX86::kVersion; 149 case kExeTypeElfX64: 150 return DisassemblerElfX64::kVersion; 151 case kExeTypeElfAArch32: 152 return DisassemblerElfAArch32::kVersion; 153 case kExeTypeElfAArch64: 154 return DisassemblerElfAArch64::kVersion; 155 #endif // BUILDFLAG(ENABLE_ELF) 156 #if BUILDFLAG(ENABLE_DEX) 157 case kExeTypeDex: 158 return DisassemblerDex::kVersion; 159 #endif // BUILDFLAG(ENABLE_DEX) 160 #if BUILDFLAG(ENABLE_ZTF) 161 case kExeTypeZtf: 162 return DisassemblerZtf::kVersion; 163 #endif // BUILDFLAG(ENABLE_ZTF) 164 case kExeTypeNoOp: 165 return DisassemblerNoOp::kVersion; 166 default: 167 // If an architecture is disabled then null is handled gracefully. 168 return kInvalidVersion; 169 } 170 } 171 DetectElementFromDisassembler(ConstBufferView image)172std::optional<Element> DetectElementFromDisassembler(ConstBufferView image) { 173 std::unique_ptr<Disassembler> disasm = MakeDisassemblerWithoutFallback(image); 174 if (disasm) 175 return Element({0, disasm->size()}, disasm->GetExeType()); 176 return std::nullopt; 177 } 178 179 /******** ProgramScanner ********/ 180 ElementFinder(ConstBufferView image,ElementDetector && detector)181ElementFinder::ElementFinder(ConstBufferView image, ElementDetector&& detector) 182 : image_(image), detector_(std::move(detector)) {} 183 184 ElementFinder::~ElementFinder() = default; 185 GetNext()186std::optional<Element> ElementFinder::GetNext() { 187 for (; pos_ < image_.size(); ++pos_) { 188 ConstBufferView test_image = 189 ConstBufferView::FromRange(image_.begin() + pos_, image_.end()); 190 std::optional<Element> element = detector_.Run(test_image); 191 if (element) { 192 element->offset += pos_; 193 pos_ = element->EndOffset(); 194 return element; 195 } 196 } 197 return std::nullopt; 198 } 199 200 } // namespace zucchini 201