From 01b1d422d9c1b87e047633e011b0d4c2b30f9b93 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 8 Sep 2024 16:08:31 +0200 Subject: [PATCH] Implement more efficient export logging Unicorn hooks are expensive. It seems to iterate all hooks every time an instruction is executed. Therefore more hooks -> slower execution. Instead, we'll have one hook. Within that hook we'll check if the address is within a mapped binary. If so, we then check if it is and export and log when true. That's far more efficient than checking all hooks every time. --- src/windows_emulator/main.cpp | 56 ++++++++++++++++++------ src/windows_emulator/module_mapper.cpp | 47 +++++++------------- src/windows_emulator/module_mapper.hpp | 2 +- src/windows_emulator/process_context.hpp | 9 +++- src/windows_emulator/syscalls.cpp | 12 ++--- 5 files changed, 73 insertions(+), 53 deletions(-) diff --git a/src/windows_emulator/main.cpp b/src/windows_emulator/main.cpp index 437228f3..cd554640 100644 --- a/src/windows_emulator/main.cpp +++ b/src/windows_emulator/main.cpp @@ -783,21 +783,21 @@ namespace auto context = setup_context(*emu); - context.executable = *map_file(*emu, R"(C:\Users\mauri\Desktop\ConsoleApplication6.exe)"); + context.executable = map_file(context, *emu, R"(C:\Users\mauri\Desktop\boiii.exe)"); context.peb.access([&](PEB& peb) { - peb.ImageBaseAddress = reinterpret_cast(context.executable.image_base); + peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); }); - context.ntdll = *map_file(*emu, R"(C:\Windows\System32\ntdll.dll)"); + context.ntdll = map_file(context, *emu, R"(C:\Windows\System32\ntdll.dll)"); - const auto ldr_initialize_thunk = find_exported_function(context.ntdll.exports, "LdrInitializeThunk"); - const auto rtl_user_thread_start = find_exported_function(context.ntdll.exports, "RtlUserThreadStart"); + const auto ldr_initialize_thunk = find_exported_function(context.ntdll->exports, "LdrInitializeThunk"); + const auto rtl_user_thread_start = find_exported_function(context.ntdll->exports, "RtlUserThreadStart"); const auto ki_user_exception_dispatcher = find_exported_function( - context.ntdll.exports, "KiUserExceptionDispatcher"); + context.ntdll->exports, "KiUserExceptionDispatcher"); - syscall_dispatcher dispatcher{context.ntdll.exports}; + syscall_dispatcher dispatcher{context.ntdll->exports}; emu->hook_instruction(x64_hookable_instructions::syscall, [&] { @@ -843,14 +843,42 @@ namespace }); /* - watch_object(*emu, context.teb); - watch_object(*emu, context.peb); - watch_object(*emu, context.process_params); - watch_object(*emu, context.kusd); - */ + watch_object(*emu, context.teb); + watch_object(*emu, context.peb); + watch_object(*emu, context.process_params); + watch_object(*emu, context.kusd); + */ + emu->hook_memory_execution(0, std::numeric_limits::max(), [&](const uint64_t address, const size_t) { ++context.executed_instructions; + + const mapped_binary* binary{nullptr}; + for (const auto& entry : context.mapped_binaries) + { + const auto& mod = entry.second; + if (is_within_start_and_length(address, mod->image_base, mod->size_of_image)) + { + binary = mod.get(); + break; + } + + if (address < mod->image_base) + { + break; + } + } + + if (binary) + { + const auto export_entry = binary->export_remap.find(address); + if (export_entry != binary->export_remap.end()) + { + printf("Executing function: %s - %s (%llX)\n", binary->name.c_str(), export_entry->second.c_str(), + address); + } + } + if (!context.verbose) { return; @@ -872,7 +900,7 @@ namespace context_frame::save(*emu, ctx); ctx.Rip = rtl_user_thread_start; - ctx.Rcx = context.executable.entry_point; + ctx.Rcx = context.executable->entry_point; const auto ctx_obj = allocate_object_on_stack(*emu); ctx_obj.write(ctx); @@ -880,7 +908,7 @@ namespace unalign_stack(*emu); emu->reg(x64_register::rcx, ctx_obj.value()); - emu->reg(x64_register::rdx, context.ntdll.image_base); + emu->reg(x64_register::rdx, context.ntdll->image_base); emu->reg(x64_register::rip, ldr_initialize_thunk); try diff --git a/src/windows_emulator/module_mapper.cpp b/src/windows_emulator/module_mapper.cpp index 14c06a48..3f71e9e5 100644 --- a/src/windows_emulator/module_mapper.cpp +++ b/src/windows_emulator/module_mapper.cpp @@ -38,6 +38,11 @@ namespace binary.exports.push_back(std::move(symbol)); } + + for (const auto& symbol : binary.exports) + { + binary.export_remap.try_emplace(symbol.address, symbol.name); + } } void apply_relocations(x64_emulator& emu, const mapped_binary& binary, @@ -148,32 +153,12 @@ namespace } } - void hook_exports(emulator& emu, const mapped_binary& binary, const std::filesystem::path& file) - { - const auto filename = file.filename().string(); - - std::unordered_map export_remap{}; - for (const auto& symbol : binary.exports) - { - export_remap.try_emplace(symbol.address, symbol.name); - } - - for (const auto& exp : export_remap) - { - auto name = exp.second; - emu.hook_memory_execution(exp.first, 0, - [n = std::move(name), filename](const uint64_t address, const size_t) - { - printf("Executing function: %s - %s (%llX)\n", filename.c_str(), n.c_str(), - address); - }); - } - } - mapped_binary map_module(x64_emulator& emu, const std::vector& module_data, - const std::string& name) + std::filesystem::path file) { mapped_binary binary{}; + binary.path = std::move(file); + binary.name = binary.path.filename().string(); // TODO: Range checks auto* ptr = module_data.data(); @@ -196,10 +181,9 @@ namespace } } - binary.entry_point = binary.image_base + optional_header.AddressOfEntryPoint; - printf("Mapping %s at %llX\n", name.c_str(), binary.image_base); + printf("Mapping %s at %llX\n", binary.path.generic_string().c_str(), binary.image_base); emu.write_memory(binary.image_base, ptr, optional_header.SizeOfHeaders); @@ -217,17 +201,20 @@ namespace } } -std::optional map_file(x64_emulator& emu, const std::filesystem::path& file) +mapped_binary* map_file(process_context& context, x64_emulator& emu, std::filesystem::path file) { const auto data = load_file(file); if (data.empty()) { - return {}; + return nullptr; } - auto binary = map_module(emu, data, file.generic_string()); + auto binary = map_module(emu, data, std::move(file)); + auto binary_ptr = std::make_unique(std::move(binary)); + auto* res = binary_ptr.get(); - hook_exports(emu, binary, file); + const auto image_base = binary_ptr->image_base; + context.mapped_binaries[image_base] = std::move(binary_ptr); - return binary; + return res; } diff --git a/src/windows_emulator/module_mapper.hpp b/src/windows_emulator/module_mapper.hpp index 447ee4a2..ba844120 100644 --- a/src/windows_emulator/module_mapper.hpp +++ b/src/windows_emulator/module_mapper.hpp @@ -3,4 +3,4 @@ #include "process_context.hpp" #include -std::optional map_file(x64_emulator& emu, const std::filesystem::path& file); \ No newline at end of file +mapped_binary* map_file(process_context& context, x64_emulator& emu, std::filesystem::path file); diff --git a/src/windows_emulator/process_context.hpp b/src/windows_emulator/process_context.hpp index e48025d4..c42c4f9d 100644 --- a/src/windows_emulator/process_context.hpp +++ b/src/windows_emulator/process_context.hpp @@ -14,10 +14,13 @@ using exported_symbols = std::vector; struct mapped_binary { + std::filesystem::path path{}; + std::string name{}; uint64_t image_base{}; uint64_t size_of_image{}; uint64_t entry_point{}; exported_symbols exports{}; + std::unordered_map export_remap{}; }; struct event @@ -51,8 +54,10 @@ struct process_context emulator_object process_params{}; emulator_object kusd{}; - mapped_binary executable{}; - mapped_binary ntdll{}; + std::map> mapped_binaries{}; + + mapped_binary* executable{}; + mapped_binary* ntdll{}; handle_store events{}; handle_store files{}; diff --git a/src/windows_emulator/syscalls.cpp b/src/windows_emulator/syscalls.cpp index 2c90a4d2..54156f1a 100644 --- a/src/windows_emulator/syscalls.cpp +++ b/src/windows_emulator/syscalls.cpp @@ -298,7 +298,7 @@ namespace { if (fs_information_class != FileFsDeviceInformation) { - printf("Unsupported process info class: %X\n", fs_information_class); + printf("Unsupported fs info class: %X\n", fs_information_class); c.emu.stop(); return STATUS_NOT_SUPPORTED; } @@ -396,8 +396,8 @@ namespace return STATUS_INVALID_HANDLE; } - const auto binary = map_file(c.emu, section_entry->name); - if (!binary.has_value()) + const auto binary = map_file(c.proc, c.emu, section_entry->name); + if (!binary) { return STATUS_FILE_INVALID; } @@ -491,7 +491,7 @@ namespace return STATUS_BUFFER_OVERFLOW; } - if (!is_within_start_and_length(base_address, c.proc.ntdll.image_base, c.proc.ntdll.size_of_image)) + if (!is_within_start_and_length(base_address, c.proc.ntdll->image_base, c.proc.ntdll->size_of_image)) { puts("Bad image request"); c.emu.stop(); @@ -502,8 +502,8 @@ namespace info.access([&](MEMORY_IMAGE_INFORMATION& image_info) { - image_info.ImageBase = reinterpret_cast(c.proc.ntdll.image_base); - image_info.SizeOfImage = c.proc.ntdll.size_of_image; + image_info.ImageBase = reinterpret_cast(c.proc.ntdll->image_base); + image_info.SizeOfImage = c.proc.ntdll->size_of_image; }); return STATUS_SUCCESS;