123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/zucchini/zucchini_tools.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <algorithm>
- #include <memory>
- #include <ostream>
- #include <utility>
- #include "base/bind.h"
- #include "base/check_op.h"
- #include "base/strings/stringprintf.h"
- #include "components/zucchini/disassembler.h"
- #include "components/zucchini/element_detection.h"
- #include "components/zucchini/ensemble_matcher.h"
- #include "components/zucchini/heuristic_ensemble_matcher.h"
- #include "components/zucchini/imposed_ensemble_matcher.h"
- #include "components/zucchini/io_utils.h"
- namespace zucchini {
- status::Code ReadReferences(ConstBufferView image,
- bool do_dump,
- std::ostream& out) {
- std::unique_ptr<Disassembler> disasm = MakeDisassemblerWithoutFallback(image);
- if (!disasm) {
- out << "Input file not recognized as executable." << std::endl;
- return status::kStatusInvalidOldImage;
- }
- std::vector<offset_t> targets;
- for (const auto& group : disasm->MakeReferenceGroups()) {
- targets.clear();
- auto refs = group.GetReader(disasm.get());
- for (auto ref = refs->GetNext(); ref.has_value(); ref = refs->GetNext())
- targets.push_back(ref->target);
- size_t num_locations = targets.size();
- std::sort(targets.begin(), targets.end());
- targets.erase(std::unique(targets.begin(), targets.end()), targets.end());
- size_t num_targets = targets.size();
- out << "Type " << int(group.type_tag().value())
- << ": Pool=" << static_cast<uint32_t>(group.pool_tag().value())
- << ", width=" << group.width() << ", #locations=" << num_locations
- << ", #targets=" << num_targets;
- if (num_targets > 0) {
- double ratio = static_cast<double>(num_locations) / num_targets;
- out << " (ratio=" << base::StringPrintf("%.4f", ratio) << ")";
- }
- out << std::endl;
- if (do_dump) {
- refs = group.GetReader(disasm.get());
- for (auto ref = refs->GetNext(); ref; ref = refs->GetNext()) {
- out << " " << AsHex<8>(ref->location) << " " << AsHex<8>(ref->target)
- << std::endl;
- }
- }
- }
- return status::kStatusSuccess;
- }
- status::Code DetectAll(ConstBufferView image,
- std::ostream& out,
- std::vector<ConstBufferView>* sub_image_list) {
- DCHECK_NE(sub_image_list, nullptr);
- sub_image_list->clear();
- const size_t size = image.size();
- size_t last_out_pos = 0;
- size_t total_bytes_found = 0;
- auto print_range = [&out](size_t pos, size_t size, const std::string& msg) {
- out << "-- " << AsHex<8, size_t>(pos) << " +" << AsHex<8, size_t>(size)
- << ": " << msg << std::endl;
- };
- ElementFinder finder(image,
- base::BindRepeating(DetectElementFromDisassembler));
- for (auto element = finder.GetNext(); element.has_value();
- element = finder.GetNext()) {
- ConstBufferView sub_image = image[element->region()];
- sub_image_list->push_back(sub_image);
- size_t pos = sub_image.begin() - image.begin();
- size_t prog_size = sub_image.size();
- if (last_out_pos < pos)
- print_range(last_out_pos, pos - last_out_pos, "?");
- auto disasm = MakeDisassemblerOfType(sub_image, element->exe_type);
- print_range(pos, prog_size, disasm->GetExeTypeString());
- total_bytes_found += prog_size;
- last_out_pos = pos + prog_size;
- }
- if (last_out_pos < size)
- print_range(last_out_pos, size - last_out_pos, "?");
- out << std::endl;
- // Print summary, using decimal instead of hexadecimal.
- out << "Detected " << total_bytes_found << "/" << size << " bytes => ";
- double percent = total_bytes_found * 100.0 / size;
- out << base::StringPrintf("%.2f", percent) << "%." << std::endl;
- return status::kStatusSuccess;
- }
- status::Code MatchAll(ConstBufferView old_image,
- ConstBufferView new_image,
- std::string imposed_matches,
- std::ostream& out) {
- std::unique_ptr<EnsembleMatcher> matcher;
- if (imposed_matches.empty()) {
- matcher = std::make_unique<HeuristicEnsembleMatcher>(&out);
- } else {
- matcher =
- std::make_unique<ImposedEnsembleMatcher>(std::move(imposed_matches));
- }
- if (!matcher->RunMatch(old_image, new_image)) {
- out << "RunMatch() failed.";
- return status::kStatusFatal;
- }
- out << "Found " << matcher->matches().size() << " nontrivial matches and "
- << matcher->num_identical() << " identical matches." << std::endl
- << "To impose the same matches by command line, use: " << std::endl
- << " -impose=";
- PrefixSep sep(",");
- for (const ElementMatch& match : matcher->matches())
- out << sep << match.ToString();
- out << std::endl;
- return status::kStatusSuccess;
- }
- } // namespace zucchini
|