diff --git a/page/src/components/settings-menu.tsx b/page/src/components/settings-menu.tsx index a92d08b3..fbc61839 100644 --- a/page/src/components/settings-menu.tsx +++ b/page/src/components/settings-menu.tsx @@ -172,6 +172,21 @@ export class SettingsMenu extends React.Component { /> +
+ { + this.setState({ instructionSummary: checked }); + }} + /> + +
+
{ switches.push("-i"); switches.push(f); diff --git a/src/analyzer/analysis.cpp b/src/analyzer/analysis.cpp index c872ea2a..29067a22 100644 --- a/src/analyzer/analysis.cpp +++ b/src/analyzer/analysis.cpp @@ -277,6 +277,25 @@ namespace return cs_insn_group(disasm.get_handle(), instructions.data(), CS_GRP_RET); } + void record_instruction(analysis_context& c, const uint64_t address) + { + std::array instruction_bytes{}; + const auto result = c.win_emu->emu().try_read_memory(address, instruction_bytes.data(), instruction_bytes.size()); + if (!result) + { + return; + } + + disassembler disasm{}; + const auto instructions = disasm.disassemble(instruction_bytes, 1); + if (instructions.empty()) + { + return; + } + + ++c.instructions[instructions[0].mnemonic]; + } + void handle_instruction(analysis_context& c, const uint64_t address) { auto& win_emu = *c.win_emu; @@ -312,18 +331,25 @@ namespace return win_emu.mod_manager.find_by_address(previous_ip); // }); + const auto is_current_binary_interesting = utils::make_lazy([&] { + return is_main_exe || (binary && c.settings->modules.contains(binary->name)); // + }); + const auto is_in_interesting_module = [&] { if (c.settings->modules.empty()) { return false; } - return (binary && c.settings->modules.contains(binary->name)) || - (previous_binary && c.settings->modules.contains(previous_binary->name)); + return is_current_binary_interesting || (previous_binary && c.settings->modules.contains(previous_binary->name)); }; + if (c.settings->instruction_summary && (is_current_binary_interesting || !binary)) + { + record_instruction(c, address); + } + const auto is_interesting_call = is_previous_main_exe // - || is_main_exe // || !previous_binary // || is_in_interesting_module(); diff --git a/src/analyzer/analysis.hpp b/src/analyzer/analysis.hpp index 08438603..b24e5355 100644 --- a/src/analyzer/analysis.hpp +++ b/src/analyzer/analysis.hpp @@ -15,6 +15,7 @@ struct analysis_settings bool verbose_logging{false}; bool silent{false}; bool buffer_stdout{false}; + bool instruction_summary{false}; string_set modules{}; string_set ignored_functions{}; @@ -39,6 +40,7 @@ struct analysis_context std::string output{}; bool has_reached_main{false}; + std::map instructions{}; std::vector accessed_imports{}; }; diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index f5a74ef8..81ae5e04 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -221,8 +221,33 @@ namespace } } + void print_instruction_summary(const analysis_context& c) + { + std::map> instruction_counts{}; + + for (const auto& [mnemonic, count] : c.instructions) + { + instruction_counts[count].push_back(mnemonic); + } + + c.win_emu->log.print(color::white, "Instruction summary:\n"); + + for (const auto& [count, mnemonics] : instruction_counts) + { + for (const auto& mnemonic : mnemonics) + { + c.win_emu->log.print(color::white, "%s: %" PRIx64 "\n", mnemonic.c_str(), count); + } + } + } + void do_post_emulation_work(const analysis_context& c) { + if (c.settings->instruction_summary) + { + print_instruction_summary(c); + } + if (c.settings->buffer_stdout) { c.win_emu->log.info("%.*s%s", static_cast(c.output.size()), c.output.data(), c.output.ends_with("\n") ? "" : "\n"); @@ -647,6 +672,10 @@ namespace { options.tenet_trace = true; } + else if (arg == "-is" || arg == "--instruction-summary") + { + options.instruction_summary = true; + } else if (arg == "-m" || arg == "--module") { if (args.size() < 2)