diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index d6d7e191..578540dd 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -3,23 +3,25 @@ #include #include -#define CONCISE_EMULATOR_OUTPUT - #include "object_watching.hpp" -bool use_gdb = false; - namespace { - void watch_system_objects(windows_emulator& win_emu) + struct analysis_options { - watch_object(win_emu, *win_emu.current_thread().teb); - watch_object(win_emu, win_emu.process().peb); - watch_object(win_emu, emulator_object{win_emu.emu(), kusd_mmio::address()}); - auto* params_hook = watch_object(win_emu, win_emu.process().process_params); + bool use_gdb{false}; + bool concise_logging{false}; + }; + + void watch_system_objects(windows_emulator& win_emu, const bool cache_logging) + { + watch_object(win_emu, *win_emu.current_thread().teb, cache_logging); + watch_object(win_emu, win_emu.process().peb, cache_logging); + watch_object(win_emu, emulator_object{win_emu.emu(), kusd_mmio::address()}, cache_logging); + auto* params_hook = watch_object(win_emu, win_emu.process().process_params, cache_logging); win_emu.emu().hook_memory_write(win_emu.process().peb.value() + offsetof(PEB, ProcessParameters), 0x8, - [&](const uint64_t address, size_t, const uint64_t value) + [&, cache_logging](const uint64_t address, size_t, const uint64_t value) { const auto target_address = win_emu.process().peb.value() + offsetof( PEB, ProcessParameters); @@ -31,16 +33,16 @@ namespace }; win_emu.emu().delete_hook(params_hook); - params_hook = watch_object(win_emu, obj); + params_hook = watch_object(win_emu, obj, cache_logging); } }); } - void run_emulation(windows_emulator& win_emu) + void run_emulation(windows_emulator& win_emu, const analysis_options& options) { try { - if (use_gdb) + if (options.use_gdb) { const auto* address = "127.0.0.1:28960"; win_emu.logger.print(color::pink, "Waiting for GDB connection on %s...\n", address); @@ -76,44 +78,44 @@ namespace } } - std::vector parse_arguments(char* argv[], const size_t argc) + std::vector parse_arguments(const std::span args) { - std::vector args{}; - args.reserve(argc - 1); + std::vector wide_args{}; + wide_args.reserve(args.size() - 1); - for (size_t i = 1; i < argc; ++i) + for (size_t i = 1; i < args.size(); ++i) { - std::string_view arg(argv[i]); - args.emplace_back(arg.begin(), arg.end()); + const auto& arg = args[i]; + wide_args.emplace_back(arg.begin(), arg.end()); } - return args; + return wide_args; } - void run(char* argv[], const size_t argc) + void run(const analysis_options& options, const std::span args) { - if (argc < 1) + if (args.empty()) { return; } emulator_settings settings{ - .application = argv[0], - .arguments = parse_arguments(argv, argc), -#ifdef CONCISE_EMULATOR_OUTPUT - .silent_until_main = true, -#endif + .application = args[0], + .arguments = parse_arguments(args), + .silent_until_main = options.concise_logging, }; windows_emulator win_emu{std::move(settings)}; (void)&watch_system_objects; - watch_system_objects(win_emu); + watch_system_objects(win_emu, options.concise_logging); win_emu.buffer_stdout = true; //win_emu.verbose_calls = true; const auto& exe = *win_emu.process().executable; + const auto concise_logging = options.concise_logging; + for (const auto& section : exe.sections) { if ((section.region.permissions & memory_permission::exec) != memory_permission::exec) @@ -121,7 +123,7 @@ namespace continue; } - auto read_handler = [&, section](const uint64_t address, size_t, uint64_t) + auto read_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) { const auto rip = win_emu.emu().read_instruction_pointer(); if (win_emu.process().module_manager.find_by_address(rip) != win_emu.process().executable) @@ -129,11 +131,12 @@ namespace return; } -#ifdef CONCISE_EMULATOR_OUTPUT - static uint64_t count{0}; - ++count; - if (count > 100 && count % 10000 != 0) return; -#endif + if (concise_logging) + { + static uint64_t count{0}; + ++count; + if (count > 100 && count % 10000 != 0) return; + } win_emu.logger.print( color::green, @@ -141,7 +144,7 @@ namespace section.name.c_str(), address, rip); }; - const auto write_handler = [&, section](const uint64_t address, size_t, uint64_t) + const auto write_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) { const auto rip = win_emu.emu().read_instruction_pointer(); if (win_emu.process().module_manager.find_by_address(rip) != win_emu.process().executable) @@ -149,11 +152,12 @@ namespace return; } -#ifdef CONCISE_EMULATOR_OUTPUT - static uint64_t count{0}; - ++count; - if (count > 100 && count % 10000 != 0) return; -#endif + if (concise_logging) + { + static uint64_t count{0}; + ++count; + if (count > 100 && count % 10000 != 0) return; + } win_emu.logger.print( color::blue, @@ -165,32 +169,67 @@ namespace win_emu.emu().hook_memory_write(section.region.start, section.region.length, std::move(write_handler)); } - run_emulation(win_emu); + run_emulation(win_emu, options); + } + + std::vector bundle_arguments(const int argc, char** argv) + { + std::vector args{}; + + for (int i = 1; i < argc; ++i) + { + args.push_back(argv[i]); + } + + return args; + } + + analysis_options parse_options(std::vector& args) + { + analysis_options options{}; + + while (!args.empty()) + { + auto arg_it = args.begin(); + const auto& arg = *arg_it; + + if (arg == "-d") + { + options.use_gdb = true; + } + else if (arg == "-c") + { + options.concise_logging = true; + } + else + { + break; + } + + args.erase(arg_it); + } + + return options; } } int main(const int argc, char** argv) { - if (argc <= 1) - { - puts("Application not specified!"); - return 1; - } - - //setvbuf(stdout, nullptr, _IOFBF, 0x10000); - if (argc > 2 && argv[1] == "-d"sv) - { - use_gdb = true; - } - try { + auto args = bundle_arguments(argc, argv); + const auto options = parse_options(args); + + if (args.empty()) + { + throw std::runtime_error("Application not specified!"); + } + do { - const auto offset = use_gdb ? 2 : 1; - run(argv + offset, static_cast(argc - offset)); + run(options, args); } - while (use_gdb); + while (options.use_gdb); return 0; } diff --git a/src/analyzer/object_watching.hpp b/src/analyzer/object_watching.hpp index 9e0db652..4ebb62b8 100644 --- a/src/analyzer/object_watching.hpp +++ b/src/analyzer/object_watching.hpp @@ -2,15 +2,13 @@ #include "reflect_type_info.hpp" -//#define CACHE_OBJECT_ADDRESSES - template -emulator_hook* watch_object(windows_emulator& emu, emulator_object object) +emulator_hook* watch_object(windows_emulator& emu, emulator_object object, const bool cache_logging = false) { const reflect_type_info info{}; return emu.emu().hook_memory_read(object.value(), object.size(), - [i = std::move(info), object, &emu]( + [i = std::move(info), object, &emu, cache_logging]( const uint64_t address, size_t, uint64_t) { const auto rip = emu.emu().read_instruction_pointer(); @@ -22,13 +20,14 @@ emulator_hook* watch_object(windows_emulator& emu, emulator_object object) return; } -#if defined(CACHE_OBJECT_ADDRESSES) || defined(CONCISE_EMULATOR_OUTPUT) - static std::unordered_set logged_addresses{}; - if (is_main_access && !logged_addresses.insert(address).second) + if (cache_logging) { - return; + static std::unordered_set logged_addresses{}; + if (is_main_access && !logged_addresses.insert(address).second) + { + return; + } } -#endif const auto offset = address - object.value(); emu.logger.print(is_main_access ? color::green : color::dark_gray, diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index e806720c..b335ed07 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -100,8 +100,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } else { - const auto* previous_mod = context.module_manager.find_by_address(context.previous_ip); - if (previous_mod == mod) + if (mod->is_within(context.previous_ip)) { const auto rsp = c.emu.read_stack_pointer(); const auto return_address = c.emu.read_memory(rsp); @@ -113,6 +112,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } else { + const auto* previous_mod = context.module_manager.find_by_address(context.previous_ip); win_emu.logger.print(color::blue, "Crafted out-of-line syscall: %s (0x%X) at 0x%llX (%s) via 0x%llX (%s)\n", entry->second.name.c_str(), diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 1a0bd6e0..e2b0edf3 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -805,6 +805,75 @@ void windows_emulator::perform_thread_switch() } } +void windows_emulator::on_instruction_execution(uint64_t address) +{ + auto& process = this->process(); + auto& thread = this->current_thread(); + + ++process.executed_instructions; + const auto thread_insts = ++thread.executed_instructions; + if (thread_insts % MAX_INSTRUCTIONS_PER_TIME_SLICE == 0) + { + this->switch_thread = true; + this->emu().stop(); + } + + process.previous_ip = process.current_ip; + process.current_ip = this->emu().read_instruction_pointer(); + + const auto is_main_exe = process.executable->is_within(address); + const auto is_interesting_call = process.executable->is_within(process.previous_ip) || is_main_exe; + + if (this->silent_until_main_ && is_main_exe) + { + this->silent_until_main_ = false; + this->logger.disable_output(false); + } + + if (!this->verbose && !this->verbose_calls && !is_interesting_call) + { + return; + } + + const auto* binary = this->process().module_manager.find_by_address(address); + + if (binary) + { + const auto export_entry = binary->address_names.find(address); + if (export_entry != binary->address_names.end()) + { + logger.print(is_interesting_call ? color::yellow : color::dark_gray, + "Executing function: %s - %s (0x%llX)\n", + binary->name.c_str(), + export_entry->second.c_str(), address); + } + else if (address == binary->entry_point) + { + logger.print(is_interesting_call ? color::yellow : color::gray, + "Executing entry point: %s (0x%llX)\n", + binary->name.c_str(), + address); + } + } + + if (!this->verbose) + { + return; + } + + auto& emu = this->emu(); + + printf( + "Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX - R8: %16llX - R9: %16llX - RDI: %16llX - RSI: %16llX - %s\n", + address, + emu.reg(x64_register::rax), emu.reg(x64_register::rbx), + emu.reg(x64_register::rcx), + emu.reg(x64_register::rdx), emu.reg(x64_register::r8), + emu.reg(x64_register::r9), + emu.reg(x64_register::rdi), emu.reg(x64_register::rsi), + binary ? binary->name.c_str() : ""); +} + void windows_emulator::setup_hooks() { this->emu().hook_instruction(x64_hookable_instructions::syscall, [&] @@ -886,76 +955,12 @@ void windows_emulator::setup_hooks() return memory_violation_continuation::resume; }); - this->emu().hook_memory_execution(0, std::numeric_limits::max(), - [&](const uint64_t address, const size_t, const uint64_t) - { - auto& process = this->process(); - auto& thread = this->current_thread(); - - ++process.executed_instructions; - const auto thread_insts = ++thread.executed_instructions; - if (thread_insts % MAX_INSTRUCTIONS_PER_TIME_SLICE == 0) - { - this->switch_thread = true; - this->emu().stop(); - } - - process.previous_ip = process.current_ip; - process.current_ip = this->emu().read_instruction_pointer(); - - const auto is_main_exe = process.executable->is_within(address); - const auto is_interesting_call = process.executable->is_within( - process.previous_ip) || is_main_exe; - - if (this->silent_until_main_ && is_main_exe) - { - this->silent_until_main_ = false; - this->logger.disable_output(false); - } - - if (!this->verbose && !this->verbose_calls && !is_interesting_call) - { - return; - } - - const auto* binary = this->process().module_manager.find_by_address(address); - - if (binary) - { - const auto export_entry = binary->address_names.find(address); - if (export_entry != binary->address_names.end()) - { - logger.print(is_interesting_call ? color::yellow : color::dark_gray, - "Executing function: %s - %s (0x%llX)\n", - binary->name.c_str(), - export_entry->second.c_str(), address); - } - else if (address == binary->entry_point) - { - logger.print(is_interesting_call ? color::yellow : color::gray, - "Executing entry point: %s (0x%llX)\n", - binary->name.c_str(), - address); - } - } - - if (!this->verbose) - { - return; - } - - auto& emu = this->emu(); - - printf( - "Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX - R8: %16llX - R9: %16llX - RDI: %16llX - RSI: %16llX - %s\n", - address, - emu.reg(x64_register::rax), emu.reg(x64_register::rbx), - emu.reg(x64_register::rcx), - emu.reg(x64_register::rdx), emu.reg(x64_register::r8), - emu.reg(x64_register::r9), - emu.reg(x64_register::rdi), emu.reg(x64_register::rsi), - binary ? binary->name.c_str() : ""); - }); + this->emu().hook_memory_execution( + 0, std::numeric_limits::max(), + [&](const uint64_t address, const size_t, const uint64_t) + { + this->on_instruction_execution(address); + }); } void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index cef15e47..90c494f7 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -127,4 +127,5 @@ private: void setup_hooks(); void setup_process(const emulator_settings& settings); + void on_instruction_execution(uint64_t address); };