xref: /aosp_15_r20/external/zucchini/zucchini_tools.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/zucchini_tools.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include <stddef.h>
8*a03ca8b9SKrzysztof Kosiński #include <stdint.h>
9*a03ca8b9SKrzysztof Kosiński 
10*a03ca8b9SKrzysztof Kosiński #include <algorithm>
11*a03ca8b9SKrzysztof Kosiński #include <memory>
12*a03ca8b9SKrzysztof Kosiński #include <ostream>
13*a03ca8b9SKrzysztof Kosiński #include <utility>
14*a03ca8b9SKrzysztof Kosiński 
15*a03ca8b9SKrzysztof Kosiński #include "base/bind.h"
16*a03ca8b9SKrzysztof Kosiński #include "base/check_op.h"
17*a03ca8b9SKrzysztof Kosiński #include "base/strings/stringprintf.h"
18*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/disassembler.h"
19*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/element_detection.h"
20*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/ensemble_matcher.h"
21*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/heuristic_ensemble_matcher.h"
22*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/imposed_ensemble_matcher.h"
23*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/io_utils.h"
24*a03ca8b9SKrzysztof Kosiński 
25*a03ca8b9SKrzysztof Kosiński namespace zucchini {
26*a03ca8b9SKrzysztof Kosiński 
ReadReferences(ConstBufferView image,bool do_dump,std::ostream & out)27*a03ca8b9SKrzysztof Kosiński status::Code ReadReferences(ConstBufferView image,
28*a03ca8b9SKrzysztof Kosiński                             bool do_dump,
29*a03ca8b9SKrzysztof Kosiński                             std::ostream& out) {
30*a03ca8b9SKrzysztof Kosiński   std::unique_ptr<Disassembler> disasm = MakeDisassemblerWithoutFallback(image);
31*a03ca8b9SKrzysztof Kosiński   if (!disasm) {
32*a03ca8b9SKrzysztof Kosiński     out << "Input file not recognized as executable." << std::endl;
33*a03ca8b9SKrzysztof Kosiński     return status::kStatusInvalidOldImage;
34*a03ca8b9SKrzysztof Kosiński   }
35*a03ca8b9SKrzysztof Kosiński 
36*a03ca8b9SKrzysztof Kosiński   std::vector<offset_t> targets;
37*a03ca8b9SKrzysztof Kosiński   for (const auto& group : disasm->MakeReferenceGroups()) {
38*a03ca8b9SKrzysztof Kosiński     targets.clear();
39*a03ca8b9SKrzysztof Kosiński     auto refs = group.GetReader(disasm.get());
40*a03ca8b9SKrzysztof Kosiński     for (auto ref = refs->GetNext(); ref.has_value(); ref = refs->GetNext())
41*a03ca8b9SKrzysztof Kosiński       targets.push_back(ref->target);
42*a03ca8b9SKrzysztof Kosiński 
43*a03ca8b9SKrzysztof Kosiński     size_t num_locations = targets.size();
44*a03ca8b9SKrzysztof Kosiński     std::sort(targets.begin(), targets.end());
45*a03ca8b9SKrzysztof Kosiński     targets.erase(std::unique(targets.begin(), targets.end()), targets.end());
46*a03ca8b9SKrzysztof Kosiński     size_t num_targets = targets.size();
47*a03ca8b9SKrzysztof Kosiński 
48*a03ca8b9SKrzysztof Kosiński     out << "Type " << int(group.type_tag().value())
49*a03ca8b9SKrzysztof Kosiński         << ": Pool=" << static_cast<uint32_t>(group.pool_tag().value())
50*a03ca8b9SKrzysztof Kosiński         << ", width=" << group.width() << ", #locations=" << num_locations
51*a03ca8b9SKrzysztof Kosiński         << ", #targets=" << num_targets;
52*a03ca8b9SKrzysztof Kosiński     if (num_targets > 0) {
53*a03ca8b9SKrzysztof Kosiński       double ratio = static_cast<double>(num_locations) / num_targets;
54*a03ca8b9SKrzysztof Kosiński       out << " (ratio=" << base::StringPrintf("%.4f", ratio) << ")";
55*a03ca8b9SKrzysztof Kosiński     }
56*a03ca8b9SKrzysztof Kosiński     out << std::endl;
57*a03ca8b9SKrzysztof Kosiński 
58*a03ca8b9SKrzysztof Kosiński     if (do_dump) {
59*a03ca8b9SKrzysztof Kosiński       refs = group.GetReader(disasm.get());
60*a03ca8b9SKrzysztof Kosiński 
61*a03ca8b9SKrzysztof Kosiński       for (auto ref = refs->GetNext(); ref; ref = refs->GetNext()) {
62*a03ca8b9SKrzysztof Kosiński         out << "  " << AsHex<8>(ref->location) << " " << AsHex<8>(ref->target)
63*a03ca8b9SKrzysztof Kosiński             << std::endl;
64*a03ca8b9SKrzysztof Kosiński       }
65*a03ca8b9SKrzysztof Kosiński     }
66*a03ca8b9SKrzysztof Kosiński   }
67*a03ca8b9SKrzysztof Kosiński 
68*a03ca8b9SKrzysztof Kosiński   return status::kStatusSuccess;
69*a03ca8b9SKrzysztof Kosiński }
70*a03ca8b9SKrzysztof Kosiński 
DetectAll(ConstBufferView image,std::ostream & out,std::vector<ConstBufferView> * sub_image_list)71*a03ca8b9SKrzysztof Kosiński status::Code DetectAll(ConstBufferView image,
72*a03ca8b9SKrzysztof Kosiński                        std::ostream& out,
73*a03ca8b9SKrzysztof Kosiński                        std::vector<ConstBufferView>* sub_image_list) {
74*a03ca8b9SKrzysztof Kosiński   DCHECK_NE(sub_image_list, nullptr);
75*a03ca8b9SKrzysztof Kosiński   sub_image_list->clear();
76*a03ca8b9SKrzysztof Kosiński 
77*a03ca8b9SKrzysztof Kosiński   const size_t size = image.size();
78*a03ca8b9SKrzysztof Kosiński   size_t last_out_pos = 0;
79*a03ca8b9SKrzysztof Kosiński   size_t total_bytes_found = 0;
80*a03ca8b9SKrzysztof Kosiński 
81*a03ca8b9SKrzysztof Kosiński   auto print_range = [&out](size_t pos, size_t size, const std::string& msg) {
82*a03ca8b9SKrzysztof Kosiński     out << "-- " << AsHex<8, size_t>(pos) << " +" << AsHex<8, size_t>(size)
83*a03ca8b9SKrzysztof Kosiński         << ": " << msg << std::endl;
84*a03ca8b9SKrzysztof Kosiński   };
85*a03ca8b9SKrzysztof Kosiński 
86*a03ca8b9SKrzysztof Kosiński   ElementFinder finder(image,
87*a03ca8b9SKrzysztof Kosiński                        base::BindRepeating(DetectElementFromDisassembler));
88*a03ca8b9SKrzysztof Kosiński   for (auto element = finder.GetNext(); element.has_value();
89*a03ca8b9SKrzysztof Kosiński        element = finder.GetNext()) {
90*a03ca8b9SKrzysztof Kosiński     ConstBufferView sub_image = image[element->region()];
91*a03ca8b9SKrzysztof Kosiński     sub_image_list->push_back(sub_image);
92*a03ca8b9SKrzysztof Kosiński     size_t pos = sub_image.begin() - image.begin();
93*a03ca8b9SKrzysztof Kosiński     size_t prog_size = sub_image.size();
94*a03ca8b9SKrzysztof Kosiński     if (last_out_pos < pos)
95*a03ca8b9SKrzysztof Kosiński       print_range(last_out_pos, pos - last_out_pos, "?");
96*a03ca8b9SKrzysztof Kosiński     auto disasm = MakeDisassemblerOfType(sub_image, element->exe_type);
97*a03ca8b9SKrzysztof Kosiński     print_range(pos, prog_size, disasm->GetExeTypeString());
98*a03ca8b9SKrzysztof Kosiński     total_bytes_found += prog_size;
99*a03ca8b9SKrzysztof Kosiński     last_out_pos = pos + prog_size;
100*a03ca8b9SKrzysztof Kosiński   }
101*a03ca8b9SKrzysztof Kosiński   if (last_out_pos < size)
102*a03ca8b9SKrzysztof Kosiński     print_range(last_out_pos, size - last_out_pos, "?");
103*a03ca8b9SKrzysztof Kosiński   out << std::endl;
104*a03ca8b9SKrzysztof Kosiński 
105*a03ca8b9SKrzysztof Kosiński   // Print summary, using decimal instead of hexadecimal.
106*a03ca8b9SKrzysztof Kosiński   out << "Detected " << total_bytes_found << "/" << size << " bytes => ";
107*a03ca8b9SKrzysztof Kosiński   double percent = total_bytes_found * 100.0 / size;
108*a03ca8b9SKrzysztof Kosiński   out << base::StringPrintf("%.2f", percent) << "%." << std::endl;
109*a03ca8b9SKrzysztof Kosiński 
110*a03ca8b9SKrzysztof Kosiński   return status::kStatusSuccess;
111*a03ca8b9SKrzysztof Kosiński }
112*a03ca8b9SKrzysztof Kosiński 
MatchAll(ConstBufferView old_image,ConstBufferView new_image,std::string imposed_matches,std::ostream & out)113*a03ca8b9SKrzysztof Kosiński status::Code MatchAll(ConstBufferView old_image,
114*a03ca8b9SKrzysztof Kosiński                       ConstBufferView new_image,
115*a03ca8b9SKrzysztof Kosiński                       std::string imposed_matches,
116*a03ca8b9SKrzysztof Kosiński                       std::ostream& out) {
117*a03ca8b9SKrzysztof Kosiński   std::unique_ptr<EnsembleMatcher> matcher;
118*a03ca8b9SKrzysztof Kosiński   if (imposed_matches.empty()) {
119*a03ca8b9SKrzysztof Kosiński     matcher = std::make_unique<HeuristicEnsembleMatcher>(&out);
120*a03ca8b9SKrzysztof Kosiński   } else {
121*a03ca8b9SKrzysztof Kosiński     matcher =
122*a03ca8b9SKrzysztof Kosiński         std::make_unique<ImposedEnsembleMatcher>(std::move(imposed_matches));
123*a03ca8b9SKrzysztof Kosiński   }
124*a03ca8b9SKrzysztof Kosiński   if (!matcher->RunMatch(old_image, new_image)) {
125*a03ca8b9SKrzysztof Kosiński     out << "RunMatch() failed.";
126*a03ca8b9SKrzysztof Kosiński     return status::kStatusFatal;
127*a03ca8b9SKrzysztof Kosiński   }
128*a03ca8b9SKrzysztof Kosiński   out << "Found " << matcher->matches().size() << " nontrivial matches and "
129*a03ca8b9SKrzysztof Kosiński       << matcher->num_identical() << " identical matches." << std::endl
130*a03ca8b9SKrzysztof Kosiński       << "To impose the same matches by command line, use: " << std::endl
131*a03ca8b9SKrzysztof Kosiński       << "  -impose=";
132*a03ca8b9SKrzysztof Kosiński   PrefixSep sep(",");
133*a03ca8b9SKrzysztof Kosiński   for (const ElementMatch& match : matcher->matches())
134*a03ca8b9SKrzysztof Kosiński     out << sep << match.ToString();
135*a03ca8b9SKrzysztof Kosiński   out << std::endl;
136*a03ca8b9SKrzysztof Kosiński 
137*a03ca8b9SKrzysztof Kosiński   return status::kStatusSuccess;
138*a03ca8b9SKrzysztof Kosiński }
139*a03ca8b9SKrzysztof Kosiński 
140*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
141