zucchini_tools.cc 4.8 KB

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