From 934374c4bb6bde7e5c263ca514594fd0f90496b3 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Feb 2025 17:43:09 +0100 Subject: [PATCH] Extract main module cache into module manager --- src/analyzer/main.cpp | 6 +- src/analyzer/object_watching.hpp | 2 +- src/fuzzer/main.cpp | 2 +- src/windows-emulator/emulator_thread.cpp | 2 +- .../module/module_manager.cpp | 20 +++ .../module/module_manager.hpp | 7 + src/windows-emulator/process_context.cpp | 128 +++++++++++++++--- src/windows-emulator/process_context.hpp | 107 ++------------- src/windows-emulator/syscall_dispatcher.cpp | 2 +- src/windows-emulator/syscalls.cpp | 2 +- src/windows-emulator/windows_emulator.cpp | 36 ++--- 11 files changed, 166 insertions(+), 148 deletions(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 5af11022..495aa4c7 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -141,7 +141,7 @@ namespace }; } - const auto& exe = *win_emu.process.executable; + const auto& exe = *win_emu.mod_manager.executable; const auto concise_logging = options.concise_logging; @@ -154,7 +154,7 @@ namespace 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.mod_manager.find_by_address(rip) != win_emu.process.executable) + if (win_emu.mod_manager.find_by_address(rip) != win_emu.mod_manager.executable) { return; } @@ -174,7 +174,7 @@ namespace 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.mod_manager.find_by_address(rip) != win_emu.process.executable) + if (win_emu.mod_manager.find_by_address(rip) != win_emu.mod_manager.executable) { return; } diff --git a/src/analyzer/object_watching.hpp b/src/analyzer/object_watching.hpp index e84685f8..0ee5d3f1 100644 --- a/src/analyzer/object_watching.hpp +++ b/src/analyzer/object_watching.hpp @@ -14,7 +14,7 @@ emulator_hook* watch_object(windows_emulator& emu, const std::setname); + const auto is_main_access = mod == emu.mod_manager.executable || modules.contains(mod->name); if (!emu.verbose_calls && !is_main_access) { diff --git a/src/fuzzer/main.cpp b/src/fuzzer/main.cpp index 464c3fa6..9c10eee1 100644 --- a/src/fuzzer/main.cpp +++ b/src/fuzzer/main.cpp @@ -34,7 +34,7 @@ namespace void forward_emulator(windows_emulator& win_emu) { - const auto target = win_emu.process.executable->find_export("vulnerable"); + const auto target = win_emu.mod_manager.executable->find_export("vulnerable"); win_emu.emu().hook_memory_execution(target, 1, [&](uint64_t, size_t, uint64_t) { win_emu.emu().stop(); }); run_emulation(win_emu); diff --git a/src/windows-emulator/emulator_thread.cpp b/src/windows-emulator/emulator_thread.cpp index 40d43697..8798520e 100644 --- a/src/windows-emulator/emulator_thread.cpp +++ b/src/windows-emulator/emulator_thread.cpp @@ -238,6 +238,6 @@ void emulator_thread::setup_registers(x64_emulator& emu, const process_context& 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, context.ldr_initialize_thunk); } diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 41f285a1..cf6ab2c9 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -60,6 +60,14 @@ module_manager::module_manager(memory_manager& memory, file_system& file_sys) { } +void module_manager::map_main_modules(const windows_path& executable_path, const windows_path& ntdll_path, + const windows_path& win32u_path, const logger& logger) +{ + this->executable = this->map_module(executable_path, logger, true); + this->ntdll = this->map_module(ntdll_path, logger, true); + this->win32u = this->map_module(win32u_path, logger, true); +} + mapped_module* module_manager::map_module(const windows_path& file, const logger& logger, const bool is_static) { return this->map_local_module(this->file_sys_->translate(file), logger, is_static); @@ -104,11 +112,23 @@ mapped_module* module_manager::map_local_module(const std::filesystem::path& fil void module_manager::serialize(utils::buffer_serializer& buffer) const { buffer.write_map(this->modules_); + + buffer.write(this->executable->image_base); + buffer.write(this->ntdll->image_base); + buffer.write(this->win32u->image_base); } void module_manager::deserialize(utils::buffer_deserializer& buffer) { buffer.read_map(this->modules_); + + const auto executable_base = buffer.read(); + const auto ntdll_base = buffer.read(); + const auto win32u_base = buffer.read(); + + this->executable = this->find_by_address(executable_base); + this->ntdll = this->find_by_address(ntdll_base); + this->win32u = this->find_by_address(win32u_base); } bool module_manager::unmap(const uint64_t address, const logger& logger) diff --git a/src/windows-emulator/module/module_manager.hpp b/src/windows-emulator/module/module_manager.hpp index a44d52da..0994a3e0 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -12,6 +12,9 @@ class module_manager using module_map = std::map; module_manager(memory_manager& memory, file_system& file_sys); + void map_main_modules(const windows_path& executable_path, const windows_path& ntdll_path, + const windows_path& win32u_path, const logger& logger); + mapped_module* map_module(const windows_path& file, const logger& logger, bool is_static = false); mapped_module* map_local_module(const std::filesystem::path& file, const logger& logger, bool is_static = false); @@ -46,6 +49,10 @@ class module_manager return modules_; } + mapped_module* executable{}; + mapped_module* ntdll{}; + mapped_module* win32u{}; + private: memory_manager* memory_{}; file_system* file_sys_{}; diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 79181698..7dbe27a6 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -28,8 +28,8 @@ namespace } void process_context::setup(x64_emulator& emu, memory_manager& memory, const application_settings& app_settings, - const emulator_settings& emu_settings, const uint64_t process_image_base, - const apiset::container& apiset_container) + const emulator_settings& emu_settings, const mapped_module& executable, + const mapped_module& ntdll, const apiset::container& apiset_container) { setup_gdt(emu, memory); @@ -92,26 +92,114 @@ void process_context::setup(x64_emulator& emu, memory_manager& memory, const app proc_params.MaximumLength = proc_params.Length; }); - this->peb.access([&](PEB64& peb) { - peb.ImageBaseAddress = process_image_base; - peb.ProcessParameters = this->process_params.ptr(); - peb.ApiSetMap = apiset::clone(emu, allocator, apiset_container).ptr(); + this->peb.access([&](PEB64& p) { + p.ImageBaseAddress = executable.image_base; + p.ProcessParameters = this->process_params.ptr(); + p.ApiSetMap = apiset::clone(emu, allocator, apiset_container).ptr(); - peb.ProcessHeap = nullptr; - peb.ProcessHeaps = nullptr; - peb.HeapSegmentReserve = 0x0000000000100000; // TODO: Read from executable - peb.HeapSegmentCommit = 0x0000000000002000; - peb.HeapDeCommitTotalFreeThreshold = 0x0000000000010000; - peb.HeapDeCommitFreeBlockThreshold = 0x0000000000001000; - peb.NumberOfHeaps = 0x00000000; - peb.MaximumNumberOfHeaps = 0x00000010; + p.ProcessHeap = nullptr; + p.ProcessHeaps = nullptr; + p.HeapSegmentReserve = 0x0000000000100000; // TODO: Read from executable + p.HeapSegmentCommit = 0x0000000000002000; + p.HeapDeCommitTotalFreeThreshold = 0x0000000000010000; + p.HeapDeCommitFreeBlockThreshold = 0x0000000000001000; + p.NumberOfHeaps = 0x00000000; + p.MaximumNumberOfHeaps = 0x00000010; - peb.OSPlatformId = 2; - peb.OSMajorVersion = 0x0000000a; - peb.OSBuildNumber = 0x00006c51; + p.OSPlatformId = 2; + p.OSMajorVersion = 0x0000000a; + p.OSBuildNumber = 0x00006c51; - // peb.AnsiCodePageData = allocator.reserve().value(); - // peb.OemCodePageData = allocator.reserve().value(); - peb.UnicodeCaseTableData = allocator.reserve().value(); + // p.AnsiCodePageData = allocator.reserve().value(); + // p.OemCodePageData = allocator.reserve().value(); + p.UnicodeCaseTableData = allocator.reserve().value(); }); + + this->ntdll_image_base = ntdll.image_base; + this->ldr_initialize_thunk = ntdll.find_export("LdrInitializeThunk"); + this->rtl_user_thread_start = ntdll.find_export("RtlUserThreadStart"); + this->ki_user_exception_dispatcher = ntdll.find_export("KiUserExceptionDispatcher"); + + this->default_register_set = emu.save_registers(); +} + +void process_context::serialize(utils::buffer_serializer& buffer) const +{ + buffer.write(this->executed_instructions); + buffer.write(this->current_ip); + buffer.write(this->previous_ip); + buffer.write_optional(this->exception_rip); + buffer.write_optional(this->exit_status); + buffer.write(this->base_allocator); + buffer.write(this->peb); + buffer.write(this->process_params); + buffer.write(this->kusd); + + buffer.write(this->ntdll_image_base); + buffer.write(this->ldr_initialize_thunk); + buffer.write(this->rtl_user_thread_start); + buffer.write(this->ki_user_exception_dispatcher); + + buffer.write(this->events); + buffer.write(this->files); + buffer.write(this->sections); + buffer.write(this->devices); + buffer.write(this->semaphores); + buffer.write(this->ports); + buffer.write(this->mutants); + buffer.write(this->registry_keys); + buffer.write_map(this->atoms); + + buffer.write_vector(this->default_register_set); + buffer.write(this->spawned_thread_count); + buffer.write(this->threads); + + buffer.write(this->threads.find_handle(this->active_thread).bits); +} + +void process_context::deserialize(utils::buffer_deserializer& buffer) +{ + buffer.read(this->executed_instructions); + buffer.read(this->current_ip); + buffer.read(this->previous_ip); + buffer.read_optional(this->exception_rip); + buffer.read_optional(this->exit_status); + buffer.read(this->base_allocator); + buffer.read(this->peb); + buffer.read(this->process_params); + buffer.read(this->kusd); + + buffer.read(this->ntdll_image_base); + buffer.read(this->ldr_initialize_thunk); + buffer.read(this->rtl_user_thread_start); + buffer.read(this->ki_user_exception_dispatcher); + + buffer.read(this->events); + buffer.read(this->files); + buffer.read(this->sections); + buffer.read(this->devices); + buffer.read(this->semaphores); + buffer.read(this->ports); + buffer.read(this->mutants); + buffer.read(this->registry_keys); + buffer.read_map(this->atoms); + + buffer.read_vector(this->default_register_set); + buffer.read(this->spawned_thread_count); + + for (auto& thread : this->threads | std::views::values) + { + thread.leak_memory(); + } + + buffer.read(this->threads); + + this->active_thread = this->threads.get(buffer.read()); +} + +handle process_context::create_thread(memory_manager& memory, const uint64_t start_address, const uint64_t argument, + const uint64_t stack_size) +{ + emulator_thread t{memory, *this, start_address, argument, stack_size, ++this->spawned_thread_count}; + return this->threads.store(std::move(t)); } diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 005a7e67..339807f6 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -41,9 +41,15 @@ struct process_context } void setup(x64_emulator& emu, memory_manager& memory, const application_settings& app_settings, - const emulator_settings& emu_settings, const uint64_t process_image_base, + const emulator_settings& emu_settings, const mapped_module& executable, const mapped_module& ntdll, const apiset::container& apiset_container); + handle create_thread(memory_manager& memory, const uint64_t start_address, const uint64_t argument, + const uint64_t stack_size); + + void serialize(utils::buffer_serializer& buffer) const; + void deserialize(utils::buffer_deserializer& buffer); + uint64_t executed_instructions{0}; uint64_t current_ip{0}; uint64_t previous_ip{0}; @@ -57,11 +63,7 @@ struct process_context emulator_object process_params; kusd_mmio kusd; - // TODO: Remove this - mapped_module* executable{}; - mapped_module* ntdll{}; - mapped_module* win32u{}; - + uint64_t ntdll_image_base{}; uint64_t ldr_initialize_thunk{}; uint64_t rtl_user_thread_start{}; uint64_t ki_user_exception_dispatcher{}; @@ -81,97 +83,4 @@ struct process_context uint32_t spawned_thread_count{0}; handle_store threads{}; emulator_thread* active_thread{nullptr}; - - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->executed_instructions); - buffer.write(this->current_ip); - buffer.write(this->previous_ip); - buffer.write_optional(this->exception_rip); - buffer.write_optional(this->exit_status); - buffer.write(this->base_allocator); - buffer.write(this->peb); - buffer.write(this->process_params); - buffer.write(this->kusd); - - buffer.write(this->executable->image_base); - buffer.write(this->ntdll->image_base); - buffer.write(this->win32u->image_base); - - buffer.write(this->ldr_initialize_thunk); - buffer.write(this->rtl_user_thread_start); - buffer.write(this->ki_user_exception_dispatcher); - - buffer.write(this->events); - buffer.write(this->files); - buffer.write(this->sections); - buffer.write(this->devices); - buffer.write(this->semaphores); - buffer.write(this->ports); - buffer.write(this->mutants); - buffer.write(this->registry_keys); - buffer.write_map(this->atoms); - - buffer.write_vector(this->default_register_set); - buffer.write(this->spawned_thread_count); - buffer.write(this->threads); - - buffer.write(this->threads.find_handle(this->active_thread).bits); - } - - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->executed_instructions); - buffer.read(this->current_ip); - buffer.read(this->previous_ip); - buffer.read_optional(this->exception_rip); - buffer.read_optional(this->exit_status); - buffer.read(this->base_allocator); - buffer.read(this->peb); - buffer.read(this->process_params); - buffer.read(this->kusd); - - const auto executable_base = buffer.read(); - const auto ntdll_base = buffer.read(); - const auto win32u_base = buffer.read(); - - auto& mod_manager = buffer.read().get(); - - this->executable = mod_manager.find_by_address(executable_base); - this->ntdll = mod_manager.find_by_address(ntdll_base); - this->win32u = mod_manager.find_by_address(win32u_base); - - buffer.read(this->ldr_initialize_thunk); - buffer.read(this->rtl_user_thread_start); - buffer.read(this->ki_user_exception_dispatcher); - - buffer.read(this->events); - buffer.read(this->files); - buffer.read(this->sections); - buffer.read(this->devices); - buffer.read(this->semaphores); - buffer.read(this->ports); - buffer.read(this->mutants); - buffer.read(this->registry_keys); - buffer.read_map(this->atoms); - - buffer.read_vector(this->default_register_set); - buffer.read(this->spawned_thread_count); - - for (auto& thread : this->threads | std::views::values) - { - thread.leak_memory(); - } - - buffer.read(this->threads); - - this->active_thread = this->threads.get(buffer.read()); - } - - handle create_thread(memory_manager& memory, const uint64_t start_address, const uint64_t argument, - const uint64_t stack_size) - { - emulator_thread t{memory, *this, start_address, argument, stack_size, ++this->spawned_thread_count}; - return this->threads.store(std::move(t)); - } }; diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index b64acc27..1f846f66 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -89,7 +89,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } const auto* mod = win_emu.mod_manager.find_by_address(address); - if (mod != context.ntdll && mod != context.win32u) + if (mod != win_emu.mod_manager.ntdll && mod != win_emu.mod_manager.win32u) { win_emu.callbacks.inline_syscall(syscall_id, address, mod ? mod->name.c_str() : "", entry->second.name); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index ab246d8c..088f9fcd 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -1301,7 +1301,7 @@ namespace const emulator_object>> info{c.emu, process_information}; info.access([&](SECTION_IMAGE_INFORMATION>& i) { - const auto& mod = *c.proc.executable; + const auto& mod = *c.win_emu.mod_manager.executable; const emulator_object dos_header_obj{c.emu, mod.image_base}; const auto dos_header = dos_header_obj.read(); diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 8e1a59f5..5f20f4c1 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -217,32 +217,26 @@ windows_emulator::~windows_emulator() = default; void windows_emulator::setup_process(const application_settings& app_settings, const emulator_settings& emu_settings) { - auto& emu = this->emu(); - + const auto& emu = this->emu(); auto& context = this->process; - auto* exe = this->mod_manager.map_module(app_settings.application, this->log, true); + this->mod_manager.map_main_modules(app_settings.application, R"(C:\Windows\System32\ntdll.dll)", + R"(C:\Windows\System32\win32u.dll)", this->log); + + const auto* executable = this->mod_manager.executable; + const auto* ntdll = this->mod_manager.ntdll; + const auto* win32u = this->mod_manager.win32u; const auto apiset_data = apiset::obtain(this->emulation_root); - this->process.setup(this->emu(), this->memory, app_settings, emu_settings, exe->image_base, apiset_data); + this->process.setup(this->emu(), this->memory, app_settings, emu_settings, *executable, *ntdll, apiset_data); - context.executable = exe; - context.ntdll = this->mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log, true); - context.win32u = this->mod_manager.map_module(R"(C:\Windows\System32\win32u.dll)", this->log, true); + const auto ntdll_data = emu.read_memory(ntdll->image_base, ntdll->size_of_image); + const auto win32u_data = emu.read_memory(win32u->image_base, win32u->size_of_image); - const auto ntdll_data = emu.read_memory(context.ntdll->image_base, context.ntdll->size_of_image); - const auto win32u_data = emu.read_memory(context.win32u->image_base, context.win32u->size_of_image); + this->dispatcher.setup(ntdll->exports, ntdll_data, win32u->exports, win32u_data); - this->dispatcher.setup(context.ntdll->exports, ntdll_data, context.win32u->exports, win32u_data); - - context.ldr_initialize_thunk = context.ntdll->find_export("LdrInitializeThunk"); - context.rtl_user_thread_start = context.ntdll->find_export("RtlUserThreadStart"); - context.ki_user_exception_dispatcher = context.ntdll->find_export("KiUserExceptionDispatcher"); - - context.default_register_set = emu.save_registers(); - - const auto main_thread_id = context.create_thread(this->memory, context.executable->entry_point, 0, 0); + const auto main_thread_id = context.create_thread(this->memory, this->mod_manager.executable->entry_point, 0, 0); switch_to_thread(*this, main_thread_id); } @@ -305,9 +299,9 @@ void windows_emulator::on_instruction_execution(const uint64_t address) (previous_binary && this->modules_.contains(previous_binary->name)); }; - const auto is_main_exe = this->process.executable->is_within(address); - const auto is_interesting_call = process.executable->is_within(this->process.previous_ip) // - || is_main_exe // + const auto is_main_exe = this->mod_manager.executable->is_within(address); + const auto is_interesting_call = this->mod_manager.executable->is_within(this->process.previous_ip) // + || is_main_exe // || is_in_interesting_module(); if (this->silent_until_main_ && is_main_exe)