141 lines
4.8 KiB
C++
141 lines
4.8 KiB
C++
// 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
|