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