xref: /aosp_15_r20/external/zucchini/element_detection.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
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)41 std::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)103 std::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)138 uint16_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)172 std::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)181 ElementFinder::ElementFinder(ConstBufferView image, ElementDetector&& detector)
182     : image_(image), detector_(std::move(detector)) {}
183 
184 ElementFinder::~ElementFinder() = default;
185 
GetNext()186 std::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