From a5bae30e00748b86c3d6db452b6df4772c8a3ec1 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 10 Feb 2025 14:28:42 +0100 Subject: [PATCH 1/9] Rename context_frame to cpu_context --- .../{context_frame.cpp => cpu_context.cpp} | 4 ++-- .../{context_frame.hpp => cpu_context.hpp} | 2 +- src/windows-emulator/emulator_thread.cpp | 4 ++-- src/windows-emulator/exception_dispatch.cpp | 4 ++-- src/windows-emulator/syscalls.cpp | 8 ++++---- src/windows-emulator/windows_emulator.cpp | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) rename src/windows-emulator/{context_frame.cpp => cpu_context.cpp} (99%) rename src/windows-emulator/{context_frame.hpp => cpu_context.hpp} (87%) diff --git a/src/windows-emulator/context_frame.cpp b/src/windows-emulator/cpu_context.cpp similarity index 99% rename from src/windows-emulator/context_frame.cpp rename to src/windows-emulator/cpu_context.cpp index e7adf26b..5167bc46 100644 --- a/src/windows-emulator/context_frame.cpp +++ b/src/windows-emulator/cpu_context.cpp @@ -1,7 +1,7 @@ #include "std_include.hpp" -#include "context_frame.hpp" +#include "cpu_context.hpp" -namespace context_frame +namespace cpu_context { void restore(x64_emulator& emu, const CONTEXT64& context) { diff --git a/src/windows-emulator/context_frame.hpp b/src/windows-emulator/cpu_context.hpp similarity index 87% rename from src/windows-emulator/context_frame.hpp rename to src/windows-emulator/cpu_context.hpp index 8f7e5bcd..c702e002 100644 --- a/src/windows-emulator/context_frame.hpp +++ b/src/windows-emulator/cpu_context.hpp @@ -1,7 +1,7 @@ #pragma once #include "x64_emulator.hpp" -namespace context_frame +namespace cpu_context { void save(x64_emulator& emu, CONTEXT64& context); void restore(x64_emulator& emu, const CONTEXT64& context); diff --git a/src/windows-emulator/emulator_thread.cpp b/src/windows-emulator/emulator_thread.cpp index 0ba0fde2..40d43697 100644 --- a/src/windows-emulator/emulator_thread.cpp +++ b/src/windows-emulator/emulator_thread.cpp @@ -1,6 +1,6 @@ #include "emulator_thread.hpp" -#include "context_frame.hpp" +#include "cpu_context.hpp" #include "process_context.hpp" namespace @@ -226,7 +226,7 @@ void emulator_thread::setup_registers(x64_emulator& emu, const process_context& ctx.ContextFlags = CONTEXT64_ALL; unalign_stack(emu); - context_frame::save(emu, ctx); + cpu_context::save(emu, ctx); ctx.Rip = context.rtl_user_thread_start; ctx.Rcx = this->start_address; diff --git a/src/windows-emulator/exception_dispatch.cpp b/src/windows-emulator/exception_dispatch.cpp index d5ff06b8..1db01ee6 100644 --- a/src/windows-emulator/exception_dispatch.cpp +++ b/src/windows-emulator/exception_dispatch.cpp @@ -1,6 +1,6 @@ #include "exception_dispatch.hpp" #include "process_context.hpp" -#include "context_frame.hpp" +#include "cpu_context.hpp" #include @@ -146,7 +146,7 @@ void dispatch_exception(x64_emulator& emu, const process_context& proc, const DW { CONTEXT64 ctx{}; ctx.ContextFlags = CONTEXT64_ALL; - context_frame::save(emu, ctx); + cpu_context::save(emu, ctx); exception_record record{}; memset(&record, 0, sizeof(record)); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 4695e0d8..86af4125 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -1,6 +1,6 @@ #include "std_include.hpp" #include "syscall_dispatcher.hpp" -#include "context_frame.hpp" +#include "cpu_context.hpp" #include "emulator_utils.hpp" #include "syscall_utils.hpp" @@ -2775,7 +2775,7 @@ namespace c.write_status = false; const auto context = thread_context.read(); - context_frame::restore(c.emu, context); + cpu_context::restore(c.emu, context); return STATUS_SUCCESS; } @@ -3800,7 +3800,7 @@ namespace c.win_emu.log.print(color::pink, "--> Reading debug registers!\n"); } - context_frame::save(c.emu, context); + cpu_context::save(c.emu, context); }); return STATUS_SUCCESS; @@ -3832,7 +3832,7 @@ namespace }); const auto context = thread_context.read(); - context_frame::restore(c.emu, context); + cpu_context::restore(c.emu, context); if ((context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) == CONTEXT_DEBUG_REGISTERS_64) { diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 358ef143..ac51ff9e 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -2,7 +2,7 @@ #include "windows_emulator.hpp" #include "address_utils.hpp" -#include "context_frame.hpp" +#include "cpu_context.hpp" #include From a28be3049b459cbedf9c217b146286bfd48179c2 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 10 Feb 2025 15:46:38 +0100 Subject: [PATCH 2/9] Separate application and emulator settings --- src/analyzer/main.cpp | 9 ++- src/fuzzer/main.cpp | 2 +- .../emulation_test_utils.hpp | 41 +++++++--- .../serialization_test.cpp | 18 +++-- src/windows-emulator-test/time_test.cpp | 8 +- src/windows-emulator/windows_emulator.cpp | 81 +++++++++++-------- src/windows-emulator/windows_emulator.hpp | 16 ++-- 7 files changed, 115 insertions(+), 60 deletions(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 21c1b3c0..97fe3162 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -113,18 +113,21 @@ namespace return false; } - const emulator_settings settings{ + application_settings app_settings{ .application = args[0], + .arguments = parse_arguments(args), + }; + + const emulator_settings settings{ .registry_directory = options.registry_path, .emulation_root = options.emulation_root, - .arguments = parse_arguments(args), .verbose_calls = options.verbose_logging, .disable_logging = options.silent, .silent_until_main = options.concise_logging, .modules = options.modules, }; - windows_emulator win_emu{settings}; + windows_emulator win_emu{std::move(app_settings), settings}; (void)&watch_system_objects; watch_system_objects(win_emu, options.modules, options.concise_logging); diff --git a/src/fuzzer/main.cpp b/src/fuzzer/main.cpp index 439d815d..e2769fef 100644 --- a/src/fuzzer/main.cpp +++ b/src/fuzzer/main.cpp @@ -137,7 +137,7 @@ namespace void run(const std::string_view application) { - emulator_settings settings{ + application_settings settings{ .application = application, }; diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index 1b280a25..a5e1673d 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -38,7 +38,30 @@ namespace test return env; } - inline windows_emulator create_sample_emulator(emulator_settings settings, const bool reproducible = false, + struct sample_configuration + { + bool reproducible{false}; + bool print_time{false}; + }; + + inline application_settings get_sample_app_settings(const sample_configuration& config) + { + application_settings settings{.application = "C:\\test-sample.exe"}; + + if (config.print_time) + { + settings.arguments.emplace_back(u"-time"); + } + + if (config.reproducible) + { + settings.arguments.emplace_back(u"-reproducible"); + } + + return settings; + } + + inline windows_emulator create_sample_emulator(emulator_settings settings, const sample_configuration& config = {}, emulator_callbacks callbacks = {}) { const auto is_verbose = enable_verbose_logging(); @@ -49,29 +72,27 @@ namespace test // settings.verbose_calls = true; } - if (reproducible) - { - settings.arguments = {u"-reproducible"}; - } - - settings.application = "c:/test-sample.exe"; settings.emulation_root = get_emulator_root(); settings.port_mappings[28970] = static_cast(getpid()); settings.path_mappings["C:\\a.txt"] = std::filesystem::temp_directory_path() / ("emulator-test-file-" + std::to_string(getpid()) + ".txt"); - return windows_emulator{std::move(settings), std::move(callbacks)}; + return windows_emulator{ + get_sample_app_settings(config), + settings, + std::move(callbacks), + }; } - inline windows_emulator create_sample_emulator(const bool reproducible = false) + inline windows_emulator create_sample_emulator(const sample_configuration& config = {}) { emulator_settings settings{ .disable_logging = true, .use_relative_time = true, }; - return create_sample_emulator(std::move(settings), reproducible); + return create_sample_emulator(std::move(settings), config); } inline void bisect_emulation(windows_emulator& emu) diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp index 990e48f8..8ac40a42 100644 --- a/src/windows-emulator-test/serialization_test.cpp +++ b/src/windows-emulator-test/serialization_test.cpp @@ -2,9 +2,17 @@ namespace test { + namespace + { + auto create_reproducible_sample_emulator() + { + return create_sample_emulator({.reproducible = true}); + } + } + TEST(SerializationTest, ResettingEmulatorWorks) { - auto emu = create_sample_emulator(true); + auto emu = create_reproducible_sample_emulator(); utils::buffer_serializer start_state{}; emu.serialize(start_state); @@ -31,7 +39,7 @@ namespace test TEST(SerializationTest, SerializedDataIsReproducible) { - auto emu1 = create_sample_emulator(true); + auto emu1 = create_reproducible_sample_emulator(); emu1.start(); ASSERT_TERMINATED_SUCCESSFULLY(emu1); @@ -55,7 +63,7 @@ namespace test TEST(SerializationTest, EmulationIsReproducible) { - auto emu1 = create_sample_emulator(true); + auto emu1 = create_reproducible_sample_emulator(); emu1.start(); ASSERT_TERMINATED_SUCCESSFULLY(emu1); @@ -63,7 +71,7 @@ namespace test utils::buffer_serializer serializer1{}; emu1.serialize(serializer1); - auto emu2 = create_sample_emulator(true); + auto emu2 = create_reproducible_sample_emulator(); emu2.start(); ASSERT_TERMINATED_SUCCESSFULLY(emu2); @@ -76,7 +84,7 @@ namespace test TEST(SerializationTest, DeserializedEmulatorBehavesLikeSource) { - auto emu = create_sample_emulator(true); + auto emu = create_reproducible_sample_emulator(); emu.start({}, 100); utils::buffer_serializer serializer{}; diff --git a/src/windows-emulator-test/time_test.cpp b/src/windows-emulator-test/time_test.cpp index bb4b1e01..54e7b897 100644 --- a/src/windows-emulator-test/time_test.cpp +++ b/src/windows-emulator-test/time_test.cpp @@ -7,16 +7,18 @@ namespace test std::string output_buffer{}; emulator_callbacks callbacks{ - .stdout_callback = [&output_buffer](const std::string_view data) { output_buffer.append(data); }, + .stdout_callback = + [&output_buffer](const std::string_view data) { + output_buffer.append(data); // + }, }; const emulator_settings settings{ - .arguments = {u"-time"}, .disable_logging = true, .use_relative_time = false, }; - auto emu = create_sample_emulator(settings, false, callbacks); + auto emu = create_sample_emulator(settings, {.print_time = true}, std::move(callbacks)); emu.start(); constexpr auto prefix = "Time: "sv; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index ac51ff9e..1966a211 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -18,6 +18,38 @@ constexpr auto MAX_INSTRUCTIONS_PER_TIME_SLICE = 100000; namespace { + void adjust_working_directory(application_settings& app_settings) + { + if (!app_settings.working_directory.empty()) + { + // Do nothing + } +#ifdef OS_WINDOWS + else if (app_settings.application.is_relative()) + { + app_settings.working_directory = std::filesystem::current_path(); + } +#endif + else + { + app_settings.working_directory = app_settings.application.parent(); + } + } + + void adjust_application(application_settings& app_settings) + { + if (app_settings.application.is_relative()) + { + app_settings.application = app_settings.working_directory / app_settings.application; + } + } + + void fixup_application_settings(application_settings& app_settings) + { + adjust_working_directory(app_settings); + adjust_application(app_settings); + } + uint64_t copy_string(x64_emulator& emu, emulator_allocator& allocator, const void* base_ptr, const uint64_t offset, const size_t length) { @@ -177,8 +209,8 @@ namespace emu.reg(x64_register::ss, 0x2B); } - void setup_context(windows_emulator& win_emu, const emulator_settings& settings, const windows_path& application, - const windows_path& working_dir) + void setup_context(windows_emulator& win_emu, const application_settings& app_settings, + const emulator_settings& emu_settings) { auto& emu = win_emu.emu(); auto& context = win_emu.process(); @@ -186,11 +218,12 @@ namespace setup_gdt(emu, memory); + // TODO: Move that out context.registry = - registry_manager(win_emu.get_emulation_root().empty() ? settings.registry_directory + registry_manager(win_emu.get_emulation_root().empty() ? emu_settings.registry_directory : win_emu.get_emulation_root() / "registry"); - context.kusd.setup(settings.use_relative_time); + context.kusd.setup(emu_settings.use_relative_time); context.base_allocator = create_allocator(memory, PEB_SEGMENT_SIZE); auto& allocator = context.base_allocator; @@ -228,18 +261,19 @@ namespace allocator.copy_string(u"SystemRoot=C:\\WINDOWS"); allocator.copy_string(u""); - const auto application_str = application.u16string(); + const auto application_str = app_settings.application.u16string(); std::u16string command_line = u"\"" + application_str + u"\""; - for (const auto& arg : settings.arguments) + for (const auto& arg : app_settings.arguments) { command_line.push_back(u' '); command_line.append(arg); } allocator.make_unicode_string(proc_params.CommandLine, command_line); - allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, working_dir.u16string() + u"\\", 1024); + allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, + app_settings.working_directory.u16string() + u"\\", 1024); allocator.make_unicode_string(proc_params.ImagePathName, application_str); const auto total_length = allocator.get_next_address() - context.process_params.value(); @@ -403,26 +437,11 @@ std::unique_ptr create_default_x64_emulator() return unicorn::create_x64_emulator(); } -windows_emulator::windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks, - std::unique_ptr emu) +windows_emulator::windows_emulator(application_settings app_settings, const emulator_settings& settings, + emulator_callbacks callbacks, std::unique_ptr emu) : windows_emulator(settings.emulation_root, std::move(emu)) { - windows_path working_dir{}; - - if (!settings.working_directory.empty()) - { - working_dir = settings.working_directory; - } -#ifdef OS_WINDOWS - else if (settings.application.is_relative()) - { - working_dir = std::filesystem::current_path(); - } -#endif - else - { - working_dir = settings.application.parent(); - } + fixup_application_settings(app_settings); for (const auto& mapping : settings.path_mappings) { @@ -441,7 +460,7 @@ windows_emulator::windows_emulator(const emulator_settings& settings, emulator_c this->callbacks_ = std::move(callbacks); this->modules_ = settings.modules; - this->setup_process(settings, working_dir); + this->setup_process(app_settings, settings); } windows_emulator::windows_emulator(const std::filesystem::path& emulation_root, std::unique_ptr emu) @@ -463,20 +482,16 @@ windows_emulator::windows_emulator(const std::filesystem::path& emulation_root, windows_emulator::~windows_emulator() = default; -void windows_emulator::setup_process(const emulator_settings& settings, const windows_path& working_directory) +void windows_emulator::setup_process(const application_settings& app_settings, const emulator_settings& emu_settings) { auto& emu = this->emu(); auto& context = this->process(); context.mod_manager = module_manager(this->memory(), this->file_sys()); // TODO: Cleanup module manager - const auto application = settings.application.is_absolute() // - ? settings.application - : (working_directory / settings.application); + setup_context(*this, app_settings, emu_settings); - setup_context(*this, settings, application, working_directory); - - context.executable = context.mod_manager.map_module(application, this->log, true); + context.executable = context.mod_manager.map_module(app_settings.application, this->log, true); context.peb.access([&](PEB64& peb) { peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); // diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index e54f8f3b..1ef43195 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -25,18 +25,23 @@ struct emulator_callbacks outofline_syscall{}; }; -// TODO: Split up into application and emulator settings -struct emulator_settings +struct application_settings { windows_path application{}; windows_path working_directory{}; + std::vector arguments{}; +}; + +struct emulator_settings +{ std::filesystem::path registry_directory{"./registry"}; std::filesystem::path emulation_root{}; - std::vector arguments{}; + bool verbose_calls{false}; bool disable_logging{false}; bool silent_until_main{false}; bool use_relative_time{false}; + std::unordered_map port_mappings{}; std::unordered_map path_mappings{}; std::set> modules{}; @@ -55,7 +60,8 @@ class windows_emulator public: windows_emulator(const std::filesystem::path& emulation_root, std::unique_ptr emu = create_default_x64_emulator()); - windows_emulator(const emulator_settings& settings, emulator_callbacks callbacks = {}, + windows_emulator(application_settings app_settings, const emulator_settings& settings = {}, + emulator_callbacks callbacks = {}, std::unique_ptr emu = create_default_x64_emulator()); windows_emulator(windows_emulator&&) = delete; @@ -227,6 +233,6 @@ class windows_emulator // std::optional process_snapshot_{}; void setup_hooks(); - void setup_process(const emulator_settings& settings, const windows_path& working_directory); + void setup_process(const application_settings& app_settings, const emulator_settings& emu_settings); void on_instruction_execution(uint64_t address); }; From adf632c64ea3a9138baeb348147254c166451a28 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Feb 2025 16:14:37 +0100 Subject: [PATCH 3/9] Remove getters --- src/analyzer/main.cpp | 18 +-- src/analyzer/object_watching.hpp | 4 +- src/fuzzer/main.cpp | 8 +- src/windows-emulator-test/emulation_test.cpp | 8 +- .../emulation_test_utils.hpp | 22 ++-- src/windows-emulator/devices/afd_endpoint.cpp | 4 +- src/windows-emulator/syscall_dispatcher.cpp | 12 +- src/windows-emulator/syscalls.cpp | 47 ++++--- src/windows-emulator/windows_emulator.cpp | 122 +++++++++--------- src/windows-emulator/windows_emulator.hpp | 77 ++--------- .../win_x64_gdb_stub_handler.hpp | 4 +- 11 files changed, 136 insertions(+), 190 deletions(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 97fe3162..37063aaf 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -27,17 +27,17 @@ namespace #ifdef OS_WINDOWS watch_object(win_emu, modules, *win_emu.current_thread().teb, cache_logging); - watch_object(win_emu, modules, win_emu.process().peb, cache_logging); + watch_object(win_emu, modules, win_emu.process.peb, cache_logging); watch_object(win_emu, modules, emulator_object{win_emu.emu(), kusd_mmio::address()}, cache_logging); - auto* params_hook = watch_object(win_emu, modules, win_emu.process().process_params, cache_logging); + auto* params_hook = watch_object(win_emu, modules, win_emu.process.process_params, cache_logging); win_emu.emu().hook_memory_write( - win_emu.process().peb.value() + offsetof(PEB64, ProcessParameters), 0x8, + win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters), 0x8, [&win_emu, cache_logging, params_hook, modules](const uint64_t address, size_t, const uint64_t value) mutable { - const auto target_address = win_emu.process().peb.value() + offsetof(PEB64, ProcessParameters); + const auto target_address = win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters); if (address == target_address) { @@ -80,7 +80,7 @@ namespace throw; } - const auto exit_status = win_emu.process().exit_status; + const auto exit_status = win_emu.process.exit_status; if (!exit_status.has_value()) { win_emu.log.print(color::red, "Emulation terminated without status!\n"); @@ -136,12 +136,12 @@ namespace if (options.silent) { win_emu.buffer_stdout = false; - win_emu.callbacks().stdout_callback = [](const std::string_view data) { + win_emu.callbacks.stdout_callback = [](const std::string_view data) { (void)fwrite(data.data(), 1, data.size(), stdout); }; } - const auto& exe = *win_emu.process().executable; + const auto& exe = *win_emu.process.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.process().mod_manager.find_by_address(rip) != win_emu.process().executable) + if (win_emu.process.mod_manager.find_by_address(rip) != win_emu.process.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.process().mod_manager.find_by_address(rip) != win_emu.process().executable) + if (win_emu.process.mod_manager.find_by_address(rip) != win_emu.process.executable) { return; } diff --git a/src/analyzer/object_watching.hpp b/src/analyzer/object_watching.hpp index 57bef027..a7dc3e61 100644 --- a/src/analyzer/object_watching.hpp +++ b/src/analyzer/object_watching.hpp @@ -13,8 +13,8 @@ emulator_hook* watch_object(windows_emulator& emu, const std::setname); + const auto* mod = emu.process.mod_manager.find_by_address(rip); + const auto is_main_access = mod == emu.process.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 e2769fef..a76980c0 100644 --- a/src/fuzzer/main.cpp +++ b/src/fuzzer/main.cpp @@ -16,7 +16,7 @@ namespace win_emu.log.disable_output(true); win_emu.start(); - if (win_emu.process().exception_rip.has_value()) + if (win_emu.process.exception_rip.has_value()) { throw std::runtime_error("Exception!"); } @@ -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.process.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); @@ -83,8 +83,8 @@ namespace restore_emulator(); - const auto memory = emu.memory().allocate_memory( - page_align_up(std::max(data.size(), static_cast(1))), memory_permission::read_write); + const auto memory = emu.memory.allocate_memory(page_align_up(std::max(data.size(), static_cast(1))), + memory_permission::read_write); emu.emu().write_memory(memory, data.data(), data.size()); emu.emu().reg(x64_register::rcx, memory); diff --git a/src/windows-emulator-test/emulation_test.cpp b/src/windows-emulator-test/emulation_test.cpp index 9c6acd57..3a8eec32 100644 --- a/src/windows-emulator-test/emulation_test.cpp +++ b/src/windows-emulator-test/emulation_test.cpp @@ -17,7 +17,7 @@ namespace test auto emu = create_sample_emulator(); emu.start({}, count); - ASSERT_EQ(emu.process().executed_instructions, count); + ASSERT_EQ(emu.process.executed_instructions, count); } TEST(EmulationTest, CountedEmulationIsAccurate) @@ -27,7 +27,7 @@ namespace test ASSERT_TERMINATED_SUCCESSFULLY(emu); - const auto executedInstructions = emu.process().executed_instructions; + const auto executedInstructions = emu.process.executed_instructions; auto new_emu = create_sample_emulator(); @@ -36,12 +36,12 @@ namespace test new_emu.start({}, instructionsToExecute); - ASSERT_EQ(new_emu.process().executed_instructions, instructionsToExecute); + ASSERT_EQ(new_emu.process.executed_instructions, instructionsToExecute); ASSERT_NOT_TERMINATED(new_emu); new_emu.start({}, offset); ASSERT_TERMINATED_SUCCESSFULLY(new_emu); - ASSERT_EQ(new_emu.process().executed_instructions, executedInstructions); + ASSERT_EQ(new_emu.process.executed_instructions, executedInstructions); } } diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index a5e1673d..c65eeba7 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -4,17 +4,17 @@ #include #include -#define ASSERT_NOT_TERMINATED(win_emu) \ - do \ - { \ - ASSERT_FALSE((win_emu).process().exit_status.has_value()); \ +#define ASSERT_NOT_TERMINATED(win_emu) \ + do \ + { \ + ASSERT_FALSE((win_emu).process.exit_status.has_value()); \ } while (false) -#define ASSERT_TERMINATED_WITH_STATUS(win_emu, status) \ - do \ - { \ - ASSERT_TRUE((win_emu).process().exit_status.has_value()); \ - ASSERT_EQ(*(win_emu).process().exit_status, status); \ +#define ASSERT_TERMINATED_WITH_STATUS(win_emu, status) \ + do \ + { \ + ASSERT_TRUE((win_emu).process.exit_status.has_value()); \ + ASSERT_EQ(*(win_emu).process.exit_status, status); \ } while (false) #define ASSERT_TERMINATED_SUCCESSFULLY(win_emu) ASSERT_TERMINATED_WITH_STATUS(win_emu, STATUS_SUCCESS) @@ -101,7 +101,7 @@ namespace test emu.serialize(start_state); emu.start(); - const auto limit = emu.process().executed_instructions; + const auto limit = emu.process.executed_instructions; const auto reset_emulator = [&] { utils::buffer_deserializer deserializer{start_state.get_buffer()}; @@ -152,6 +152,6 @@ namespace test const auto rip = emu.emu().read_instruction_pointer(); printf("Diff detected after 0x%" PRIx64 " instructions at 0x%" PRIx64 " (%s)\n", lower_bound, rip, - emu.process().mod_manager.find_name(rip)); + emu.process.mod_manager.find_name(rip)); } } diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index 46b83939..e3d38399 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -465,7 +465,7 @@ namespace write_io_status(this->delayed_ioctl_->io_status_block, STATUS_TIMEOUT); } - auto* e = win_emu.process().events.get(this->delayed_ioctl_->event); + auto* e = win_emu.process.events.get(this->delayed_ioctl_->event); if (e) { e->signaled = true; @@ -547,7 +547,7 @@ namespace static std::vector resolve_endpoints(windows_emulator& win_emu, const std::span handles) { - auto& proc = win_emu.process(); + auto& proc = win_emu.process; std::vector endpoints{}; endpoints.reserve(handles.size()); diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index 810268ce..f0c0343a 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -62,7 +62,7 @@ void syscall_dispatcher::add_handlers() void syscall_dispatcher::dispatch(windows_emulator& win_emu) { auto& emu = win_emu.emu(); - auto& context = win_emu.process(); + auto& context = win_emu.process; const auto address = emu.read_instruction_pointer(); const auto syscall_id = emu.reg(x64_register::eax); @@ -91,8 +91,8 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) const auto* mod = context.mod_manager.find_by_address(address); if (mod != context.ntdll && mod != context.win32u) { - win_emu.callbacks().inline_syscall(syscall_id, address, mod ? mod->name.c_str() : "", - entry->second.name); + win_emu.callbacks.inline_syscall(syscall_id, address, mod ? mod->name.c_str() : "", + entry->second.name); win_emu.log.print(color::blue, "Executing inline syscall: %s (0x%X) at 0x%" PRIx64 " (%s)\n", entry->second.name.c_str(), syscall_id, address, mod ? mod->name.c_str() : ""); @@ -116,9 +116,9 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) { const auto* previous_mod = context.mod_manager.find_by_address(context.previous_ip); - win_emu.callbacks().outofline_syscall(syscall_id, address, mod ? mod->name.c_str() : "", - entry->second.name, context.previous_ip, - previous_mod ? previous_mod->name.c_str() : ""); + win_emu.callbacks.outofline_syscall(syscall_id, address, mod ? mod->name.c_str() : "", + entry->second.name, context.previous_ip, + previous_mod ? previous_mod->name.c_str() : ""); win_emu.log.print(color::blue, "Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64 diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 86af4125..5fdf1aca 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -704,8 +704,8 @@ namespace { constexpr auto shared_section_size = 0x10000; - const auto address = c.win_emu.memory().find_free_allocation_base(shared_section_size); - c.win_emu.memory().allocate_memory(address, shared_section_size, memory_permission::read_write); + const auto address = c.win_emu.memory.find_free_allocation_base(shared_section_size); + c.win_emu.memory.allocate_memory(address, shared_section_size, memory_permission::read_write); const std::u16string_view windows_dir = c.proc.kusd.get().NtSystemRoot.arr; const auto windows_dir_size = windows_dir.size() * 2; @@ -789,7 +789,7 @@ namespace } const auto protection = map_nt_to_emulator_protection(section_entry->section_page_protection); - const auto address = c.win_emu.memory().allocate_memory(size, protection); + const auto address = c.win_emu.memory.allocate_memory(size, protection); if (!file_data.empty()) { @@ -850,7 +850,7 @@ namespace const emulator_object info{c.emu, memory_information}; info.access([&](EMU_MEMORY_BASIC_INFORMATION64& image_info) { - const auto region_info = c.win_emu.memory().get_region_info(base_address); + const auto region_info = c.win_emu.memory.get_region_info(base_address); assert(!region_info.is_committed || region_info.is_reserved); @@ -910,7 +910,7 @@ namespace return STATUS_BUFFER_OVERFLOW; } - const auto region_info = c.win_emu.memory().get_region_info(base_address); + const auto region_info = c.win_emu.memory.get_region_info(base_address); if (!region_info.is_reserved) { return STATUS_INVALID_ADDRESS; @@ -1655,7 +1655,7 @@ namespace if (!f->enumeration_state || query_flags & SL_RESTART_SCAN) { f->enumeration_state.emplace(file_enumeration_state{}); - f->enumeration_state->files = scan_directory(c.win_emu.file_sys().translate(f->name)); + f->enumeration_state->files = scan_directory(c.win_emu.file_sys.translate(f->name)); } auto& enum_state = *f->enumeration_state; @@ -2015,8 +2015,7 @@ namespace try { - c.win_emu.memory().protect_memory(aligned_start, aligned_length, requested_protection, - &old_protection_value); + c.win_emu.memory.protect_memory(aligned_start, aligned_length, requested_protection, &old_protection_value); } catch (...) { @@ -2118,7 +2117,7 @@ namespace auto potential_base = base_address.read(); if (!potential_base) { - potential_base = c.win_emu.memory().find_free_allocation_base(allocation_bytes); + potential_base = c.win_emu.memory.find_free_allocation_base(allocation_bytes); } if (!potential_base) @@ -2138,7 +2137,7 @@ namespace throw std::runtime_error("Unsupported allocation type!"); } - if (commit && !reserve && c.win_emu.memory().commit_memory(potential_base, allocation_bytes, protection)) + if (commit && !reserve && c.win_emu.memory.commit_memory(potential_base, allocation_bytes, protection)) { c.win_emu.log.print(color::dark_gray, "--> Committed 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base, potential_base + allocation_bytes); @@ -2149,7 +2148,7 @@ namespace c.win_emu.log.print(color::dark_gray, "--> Allocated 0x%" PRIx64 " - 0x%" PRIx64 "\n", potential_base, potential_base + allocation_bytes); - return c.win_emu.memory().allocate_memory(potential_base, allocation_bytes, protection, !commit) + return c.win_emu.memory.allocate_memory(potential_base, allocation_bytes, protection, !commit) ? STATUS_SUCCESS : STATUS_MEMORY_NOT_ALLOCATED; } @@ -2177,14 +2176,14 @@ namespace if (free_type & MEM_RELEASE) { - return c.win_emu.memory().release_memory(allocation_base, allocation_size) ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; + return c.win_emu.memory.release_memory(allocation_base, allocation_size) ? STATUS_SUCCESS + : STATUS_MEMORY_NOT_ALLOCATED; } if (free_type & MEM_DECOMMIT) { - return c.win_emu.memory().decommit_memory(allocation_base, allocation_size) ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; + return c.win_emu.memory.decommit_memory(allocation_base, allocation_size) ? STATUS_SUCCESS + : STATUS_MEMORY_NOT_ALLOCATED; } throw std::runtime_error("Bad free type"); @@ -2261,7 +2260,7 @@ namespace } client_shared_memory.access([&](PORT_VIEW64& view) { - p.view_base = c.win_emu.memory().allocate_memory(view.ViewSize, memory_permission::read_write); + p.view_base = c.win_emu.memory.allocate_memory(view.ViewSize, memory_permission::read_write); view.ViewBase = p.view_base; view.ViewRemoteBase = view.ViewBase; }); @@ -2746,14 +2745,14 @@ namespace const emulator_object /*default_casing_table_size*/) { const auto locale_file = - utils::io::read_file(c.win_emu.file_sys().translate(R"(C:\Windows\System32\locale.nls)")); + utils::io::read_file(c.win_emu.file_sys.translate(R"(C:\Windows\System32\locale.nls)")); if (locale_file.empty()) { return STATUS_FILE_INVALID; } const auto size = page_align_up(locale_file.size()); - const auto base = c.win_emu.memory().allocate_memory(size, memory_permission::read); + const auto base = c.win_emu.memory.allocate_memory(size, memory_permission::read); c.emu.write_memory(base, locale_file.data(), locale_file.size()); base_address.write(base); @@ -2879,7 +2878,7 @@ namespace io_status_block.write(block); } - c.win_emu.callbacks().stdout_callback(temp_buffer); + c.win_emu.callbacks.stdout_callback(temp_buffer); if (!temp_buffer.ends_with("\n")) { @@ -3048,14 +3047,14 @@ namespace if (create_disposition & FILE_CREATE) { std::error_code ec{}; - create_directory(c.win_emu.file_sys().translate(f.name), ec); + create_directory(c.win_emu.file_sys.translate(f.name), ec); if (ec) { return STATUS_ACCESS_DENIED; } } - else if (!std::filesystem::is_directory(c.win_emu.file_sys().translate(f.name))) + else if (!std::filesystem::is_directory(c.win_emu.file_sys.translate(f.name))) { return STATUS_OBJECT_NAME_NOT_FOUND; } @@ -3078,7 +3077,7 @@ namespace FILE* file{}; - const auto error = open_unicode(&file, c.win_emu.file_sys().translate(path), mode); + const auto error = open_unicode(&file, c.win_emu.file_sys.translate(path), mode); if (!file) { @@ -3123,7 +3122,7 @@ namespace c.win_emu.log.print(color::dark_gray, "--> Querying file attributes: %s\n", u16_to_u8(filename).c_str()); - const auto local_filename = c.win_emu.file_sys().translate(filename).string(); + const auto local_filename = c.win_emu.file_sys.translate(filename).string(); struct _stat64 file_stat{}; if (_stat64(local_filename.c_str(), &file_stat) != 0) @@ -3446,7 +3445,7 @@ namespace return STATUS_NOT_SUPPORTED; } - const auto h = c.proc.create_thread(c.win_emu.memory(), start_routine, argument, stack_size); + const auto h = c.proc.create_thread(c.win_emu.memory, start_routine, argument, stack_size); thread_handle.write(h); if (!attribute_list) diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 1966a211..3666fa32 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -213,15 +213,14 @@ namespace const emulator_settings& emu_settings) { auto& emu = win_emu.emu(); - auto& context = win_emu.process(); - auto& memory = win_emu.memory(); + auto& context = win_emu.process; + auto& memory = win_emu.memory; setup_gdt(emu, memory); // TODO: Move that out - context.registry = - registry_manager(win_emu.get_emulation_root().empty() ? emu_settings.registry_directory - : win_emu.get_emulation_root() / "registry"); + context.registry = registry_manager(win_emu.emulation_root.empty() ? emu_settings.registry_directory + : win_emu.emulation_root / "registry"); context.kusd.setup(emu_settings.use_relative_time); @@ -285,7 +284,7 @@ namespace apiset_location apiset_loc = apiset_location::file; - if (win_emu.get_emulation_root().empty()) + if (win_emu.emulation_root.empty()) { #ifdef OS_WINDOWS apiset_loc = apiset_location::host; @@ -297,7 +296,7 @@ namespace context.peb.access([&](PEB64& peb) { peb.ImageBaseAddress = nullptr; peb.ProcessParameters = context.process_params.ptr(); - peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc, win_emu.get_emulation_root()).ptr(); + peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc, win_emu.emulation_root).ptr(); peb.ProcessHeap = nullptr; peb.ProcessHeaps = nullptr; @@ -320,7 +319,7 @@ namespace void perform_context_switch_work(windows_emulator& win_emu) { - auto& devices = win_emu.process().devices; + auto& devices = win_emu.process.devices; // Crappy mechanism to prevent mutation while iterating. const auto was_blocked = devices.block_mutation(true); @@ -353,7 +352,7 @@ namespace } auto& emu = win_emu.emu(); - auto& context = win_emu.process(); + auto& context = win_emu.process; const auto is_ready = thread.is_thread_ready(context); @@ -385,7 +384,7 @@ namespace bool switch_to_thread(windows_emulator& win_emu, const handle thread_handle) { - auto* thread = win_emu.process().threads.get(thread_handle); + auto* thread = win_emu.process.threads.get(thread_handle); if (!thread) { throw std::runtime_error("Bad thread handle"); @@ -398,7 +397,7 @@ namespace { perform_context_switch_work(win_emu); - auto& context = win_emu.process(); + auto& context = win_emu.process; bool next_thread = false; @@ -445,7 +444,7 @@ windows_emulator::windows_emulator(application_settings app_settings, const emul for (const auto& mapping : settings.path_mappings) { - this->file_sys().map(mapping.first, mapping.second); + this->file_sys.map(mapping.first, mapping.second); } for (const auto& mapping : settings.port_mappings) @@ -457,21 +456,22 @@ windows_emulator::windows_emulator(application_settings app_settings, const emul this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging; this->use_relative_time_ = settings.use_relative_time; this->log.disable_output(settings.disable_logging || this->silent_until_main_); - this->callbacks_ = std::move(callbacks); + this->callbacks = std::move(callbacks); this->modules_ = settings.modules; this->setup_process(app_settings, settings); } -windows_emulator::windows_emulator(const std::filesystem::path& emulation_root, std::unique_ptr emu) - : emulation_root_{emulation_root.empty() ? emulation_root : absolute(emulation_root)}, - file_sys_(emulation_root_.empty() ? emulation_root_ : emulation_root_ / "filesys"), - emu_(std::move(emu)), - memory_manager_(*this->emu_), - process_(*emu_, memory_manager_, file_sys_) +windows_emulator::windows_emulator(const std::filesystem::path& emulation_root_directory, + std::unique_ptr emu) + : emu_(std::move(emu)), + emulation_root{emulation_root_directory.empty() ? emulation_root_directory : absolute(emulation_root_directory)}, + file_sys(emulation_root.empty() ? emulation_root : emulation_root / "filesys"), + memory(*this->emu_), + process(*this->emu_, memory, file_sys) { #ifndef OS_WINDOWS - if (this->get_emulation_root().empty()) + if (this->emulation_root.empty()) { throw std::runtime_error("Emulation root directory can not be empty!"); } @@ -486,8 +486,8 @@ void windows_emulator::setup_process(const application_settings& app_settings, c { auto& emu = this->emu(); - auto& context = this->process(); - context.mod_manager = module_manager(this->memory(), this->file_sys()); // TODO: Cleanup module manager + auto& context = this->process; + context.mod_manager = module_manager(this->memory, this->file_sys); // TODO: Cleanup module manager setup_context(*this, app_settings, emu_settings); @@ -503,7 +503,7 @@ void windows_emulator::setup_process(const application_settings& app_settings, c 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(context.ntdll->exports, ntdll_data, context.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"); @@ -511,7 +511,7 @@ void windows_emulator::setup_process(const application_settings& app_settings, c 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, context.executable->entry_point, 0, 0); switch_to_thread(*this, main_thread_id); } @@ -533,7 +533,7 @@ void windows_emulator::perform_thread_switch() bool windows_emulator::activate_thread(const uint32_t id) { - const auto thread = get_thread_by_id(this->process(), id); + const auto thread = get_thread_by_id(this->process, id); if (!thread) { return false; @@ -544,25 +544,24 @@ bool windows_emulator::activate_thread(const uint32_t id) void windows_emulator::on_instruction_execution(const uint64_t address) { - auto& process = this->process(); auto& thread = this->current_thread(); - ++process.executed_instructions; + ++this->process.executed_instructions; const auto thread_insts = ++thread.executed_instructions; if (thread_insts % MAX_INSTRUCTIONS_PER_TIME_SLICE == 0) { this->yield_thread(); } - process.previous_ip = process.current_ip; - process.current_ip = this->emu().read_instruction_pointer(); + this->process.previous_ip = this->process.current_ip; + this->process.current_ip = this->emu().read_instruction_pointer(); const auto binary = utils::make_lazy([&] { - return this->process().mod_manager.find_by_address(address); // + return this->process.mod_manager.find_by_address(address); // }); const auto previous_binary = utils::make_lazy([&] { - return this->process().mod_manager.find_by_address(process.previous_ip); // + return this->process.mod_manager.find_by_address(this->process.previous_ip); // }); const auto is_in_interesting_module = [&] { @@ -575,9 +574,9 @@ void windows_emulator::on_instruction_execution(const uint64_t address) (previous_binary && this->modules_.contains(previous_binary->name)); }; - 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 // + 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 // || is_in_interesting_module(); if (this->silent_until_main_ && is_main_exe) @@ -601,7 +600,7 @@ void windows_emulator::on_instruction_execution(const uint64_t address) uint64_t return_address{}; this->emu().try_read_memory(rsp, &return_address, sizeof(return_address)); - const auto* mod_name = this->process().mod_manager.find_name(return_address); + const auto* mod_name = this->process.mod_manager.find_name(return_address); log.print(is_interesting_call ? color::yellow : color::dark_gray, "Executing function: %s - %s (0x%" PRIx64 ") via (0x%" PRIx64 ") %s\n", binary->name.c_str(), @@ -621,6 +620,7 @@ void windows_emulator::on_instruction_execution(const uint64_t address) auto& emu = this->emu(); + // TODO: Remove or cleanup log.print(color::gray, "Inst: %16" PRIx64 " - RAX: %16" PRIx64 " - RBX: %16" PRIx64 " - RCX: %16" PRIx64 " - RDX: %16" PRIx64 " - R8: %16" PRIx64 " - R9: %16" PRIx64 " - RDI: %16" PRIx64 " - RSI: %16" PRIx64 " - %s\n", @@ -640,12 +640,12 @@ void windows_emulator::setup_hooks() } } - this->dispatcher_.dispatch(*this); + this->dispatcher.dispatch(*this); return instruction_hook_continuation::skip_instruction; }); this->emu().hook_instruction(x64_hookable_instructions::rdtsc, [&] { - const auto instructions = this->process().executed_instructions; + const auto instructions = this->process.executed_instructions; this->emu().reg(x64_register::rax, instructions & 0xFFFFFFFF); this->emu().reg(x64_register::rdx, (instructions >> 32) & 0xFFFFFFFF); return instruction_hook_continuation::skip_instruction; @@ -665,14 +665,14 @@ void windows_emulator::setup_hooks() switch (interrupt) { case 0: - dispatch_integer_division_by_zero(this->emu(), this->process()); + dispatch_integer_division_by_zero(this->emu(), this->process); return; case 1: this->log.print(color::pink, "Singlestep: 0x%" PRIx64 "\n", rip); - dispatch_single_step(this->emu(), this->process()); + dispatch_single_step(this->emu(), this->process); return; case 6: - dispatch_illegal_instruction_violation(this->emu(), this->process()); + dispatch_illegal_instruction_violation(this->emu(), this->process); return; default: break; @@ -682,7 +682,7 @@ void windows_emulator::setup_hooks() if (this->fuzzing || true) // TODO: Fix { - this->process().exception_rip = rip; + this->process.exception_rip = rip; this->emu().stop(); } }); @@ -691,7 +691,7 @@ void windows_emulator::setup_hooks() const memory_violation_type type) { const auto permission = get_permission_string(operation); const auto ip = this->emu().read_instruction_pointer(); - const char* name = this->process().mod_manager.find_name(ip); + const char* name = this->process.mod_manager.find_name(ip); if (type == memory_violation_type::protection) { @@ -706,12 +706,12 @@ void windows_emulator::setup_hooks() if (this->fuzzing) { - this->process().exception_rip = ip; + this->process.exception_rip = ip; this->emu().stop(); return memory_violation_continuation::stop; } - dispatch_access_violation(this->emu(), this->process(), address, operation); + dispatch_access_violation(this->emu(), this->process, address, operation); return memory_violation_continuation::resume; }); @@ -726,14 +726,14 @@ void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) const auto use_timeout = timeout != std::chrono::nanoseconds{}; const auto start_time = std::chrono::high_resolution_clock::now(); - const auto start_instructions = this->process().executed_instructions; + const auto start_instructions = this->process.executed_instructions; const auto target_time = start_time + timeout; const auto target_instructions = start_instructions + count; while (true) { - if (this->switch_thread_ || !this->current_thread().is_thread_ready(this->process())) + if (this->switch_thread_ || !this->current_thread().is_thread_ready(this->process)) { this->perform_thread_switch(); } @@ -759,7 +759,7 @@ void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) if (use_count) { - const auto current_instructions = this->process().executed_instructions; + const auto current_instructions = this->process.executed_instructions; if (current_instructions >= target_instructions) { @@ -776,15 +776,15 @@ void windows_emulator::serialize(utils::buffer_serializer& buffer) const buffer.write(this->switch_thread_); buffer.write(this->use_relative_time_); this->emu().serialize_state(buffer, false); - this->memory().serialize_memory_state(buffer, false); - this->process_.serialize(buffer); - this->dispatcher_.serialize(buffer); + this->memory.serialize_memory_state(buffer, false); + this->process.serialize(buffer); + this->dispatcher.serialize(buffer); } void windows_emulator::deserialize(utils::buffer_deserializer& buffer) { buffer.register_factory([this] { - return memory_manager_wrapper{this->memory()}; // + return memory_manager_wrapper{this->memory}; // }); buffer.register_factory([this] { @@ -798,25 +798,25 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) buffer.read(this->switch_thread_); buffer.read(this->use_relative_time_); - this->memory().unmap_all_memory(); + this->memory.unmap_all_memory(); this->emu().deserialize_state(buffer, false); - this->memory().deserialize_memory_state(buffer, false); - this->process_.deserialize(buffer); - this->dispatcher_.deserialize(buffer); + this->memory.deserialize_memory_state(buffer, false); + this->process.deserialize(buffer); + this->dispatcher.deserialize(buffer); } void windows_emulator::save_snapshot() { utils::buffer_serializer serializer{}; this->emu().serialize_state(serializer, true); - this->memory().serialize_memory_state(serializer, true); - this->process_.serialize(serializer); + this->memory.serialize_memory_state(serializer, true); + this->process.serialize(serializer); this->process_snapshot_ = serializer.move_buffer(); // TODO: Make process copyable - // this->process_snapshot_ = this->process(); + // this->process_snapshot_ = this->process; } void windows_emulator::restore_snapshot() @@ -829,7 +829,7 @@ void windows_emulator::restore_snapshot() utils::buffer_deserializer deserializer{this->process_snapshot_}; this->emu().deserialize_state(deserializer, true); - this->memory().deserialize_memory_state(deserializer, true); - this->process_.deserialize(deserializer); - // this->process_ = *this->process_snapshot_; + this->memory.deserialize_memory_state(deserializer, true); + this->process.deserialize(deserializer); + // this->process = *this->process_snapshot_; } diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 1ef43195..3f6b3653 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -57,7 +57,17 @@ enum class apiset_location : uint8_t class windows_emulator { + std::unique_ptr emu_{}; + public: + std::filesystem::path emulation_root{}; + emulator_callbacks callbacks{}; + logger log{}; + file_system file_sys; + memory_manager memory; + process_context process; + syscall_dispatcher dispatcher; + windows_emulator(const std::filesystem::path& emulation_root, std::unique_ptr emu = create_default_x64_emulator()); windows_emulator(application_settings app_settings, const emulator_settings& settings = {}, @@ -81,34 +91,14 @@ class windows_emulator return *this->emu_; } - process_context& process() - { - return this->process_; - } - - const process_context& process() const - { - return this->process_; - } - - syscall_dispatcher& dispatcher() - { - return this->dispatcher_; - } - - const syscall_dispatcher& dispatcher() const - { - return this->dispatcher_; - } - emulator_thread& current_thread() const { - if (!this->process_.active_thread) + if (!this->process.active_thread) { throw std::runtime_error("No active thread!"); } - return *this->process_.active_thread; + return *this->process.active_thread; } void start(std::chrono::nanoseconds timeout = {}, size_t count = 0); @@ -163,7 +153,6 @@ class windows_emulator } } - logger log{}; bool verbose{false}; bool verbose_calls{false}; bool buffer_stdout{false}; @@ -178,57 +167,15 @@ class windows_emulator return this->use_relative_time_; } - emulator_callbacks& callbacks() - { - return this->callbacks_; - } - - file_system& file_sys() - { - return this->file_sys_; - } - - const file_system& file_sys() const - { - return this->file_sys_; - } - - memory_manager& memory() - { - return this->memory_manager_; - } - - const memory_manager& memory() const - { - return this->memory_manager_; - } - - const std::filesystem::path& get_emulation_root() - { - return this->emulation_root_; - } - private: - std::filesystem::path emulation_root_{}; - file_system file_sys_; - - emulator_callbacks callbacks_{}; - bool switch_thread_{false}; bool use_relative_time_{false}; bool silent_until_main_{false}; - std::unique_ptr emu_{}; std::vector syscall_hooks_{}; std::unordered_map port_mappings_{}; - memory_manager memory_manager_; - std::set> modules_{}; - - process_context process_; - syscall_dispatcher dispatcher_; - std::vector process_snapshot_{}; // std::optional process_snapshot_{}; diff --git a/src/windows-gdb-stub/win_x64_gdb_stub_handler.hpp b/src/windows-gdb-stub/win_x64_gdb_stub_handler.hpp index e3855b6c..a9d00147 100644 --- a/src/windows-gdb-stub/win_x64_gdb_stub_handler.hpp +++ b/src/windows-gdb-stub/win_x64_gdb_stub_handler.hpp @@ -47,7 +47,7 @@ class win_x64_gdb_stub_handler : public x64_gdb_stub_handler std::vector get_thread_ids() override { - const auto& threads = this->win_emu_->process().threads; + const auto& threads = this->win_emu_->process.threads; std::vector ids{}; ids.reserve(threads.size()); @@ -70,7 +70,7 @@ class win_x64_gdb_stub_handler : public x64_gdb_stub_handler std::optional get_exit_code() override { - const auto status = this->win_emu_->process().exit_status; + const auto status = this->win_emu_->process.exit_status; if (!status) { return std::nullopt; From 7ae36a6452da5caae74fd127a600915bdfbb45b1 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Feb 2025 16:37:33 +0100 Subject: [PATCH 4/9] Move registry manager into windows emulator --- src/analyzer/main.cpp | 2 +- src/fuzzer/main.cpp | 2 +- .../serialization_test.cpp | 4 +- src/windows-emulator/process_context.hpp | 4 -- .../registry/registry_manager.cpp | 19 ++------ .../registry/registry_manager.hpp | 3 -- src/windows-emulator/syscalls.cpp | 4 +- src/windows-emulator/windows_emulator.cpp | 44 +++++++++---------- src/windows-emulator/windows_emulator.hpp | 5 ++- 9 files changed, 32 insertions(+), 55 deletions(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 37063aaf..dbdb9cf0 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -119,8 +119,8 @@ namespace }; const emulator_settings settings{ - .registry_directory = options.registry_path, .emulation_root = options.emulation_root, + .registry_directory = options.registry_path, .verbose_calls = options.verbose_logging, .disable_logging = options.silent, .silent_until_main = options.concise_logging, diff --git a/src/fuzzer/main.cpp b/src/fuzzer/main.cpp index a76980c0..464c3fa6 100644 --- a/src/fuzzer/main.cpp +++ b/src/fuzzer/main.cpp @@ -42,7 +42,7 @@ namespace struct fuzzer_executer : fuzzer::executer { - windows_emulator emu{"./"}; // TODO: Fix root directory + windows_emulator emu{{.emulation_root = "./"}}; // TODO: Fix root directory std::span emulator_data{}; std::unordered_set visited_blocks{}; const std::function* handler{nullptr}; diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp index 8ac40a42..97060080 100644 --- a/src/windows-emulator-test/serialization_test.cpp +++ b/src/windows-emulator-test/serialization_test.cpp @@ -49,7 +49,7 @@ namespace test utils::buffer_deserializer deserializer{serializer1.get_buffer()}; - windows_emulator new_emu{get_emulator_root()}; + windows_emulator new_emu{{.emulation_root = get_emulator_root()}}; new_emu.deserialize(deserializer); utils::buffer_serializer serializer2{}; @@ -92,7 +92,7 @@ namespace test utils::buffer_deserializer deserializer{serializer.get_buffer()}; - windows_emulator new_emu{get_emulator_root()}; + windows_emulator new_emu{{.emulation_root = get_emulator_root()}}; new_emu.log.disable_output(true); new_emu.deserialize(deserializer); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index dec59678..39dd1bd7 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -36,8 +36,6 @@ struct process_context { } - registry_manager registry{}; - uint64_t executed_instructions{0}; uint64_t current_ip{0}; uint64_t previous_ip{0}; @@ -79,7 +77,6 @@ struct process_context void serialize(utils::buffer_serializer& buffer) const { - buffer.write(this->registry); buffer.write(this->executed_instructions); buffer.write(this->current_ip); buffer.write(this->previous_ip); @@ -118,7 +115,6 @@ struct process_context void deserialize(utils::buffer_deserializer& buffer) { - buffer.read(this->registry); buffer.read(this->executed_instructions); buffer.read(this->current_ip); buffer.read(this->previous_ip); diff --git a/src/windows-emulator/registry/registry_manager.cpp b/src/windows-emulator/registry/registry_manager.cpp index 2b9fb544..7f64b1d1 100644 --- a/src/windows-emulator/registry/registry_manager.cpp +++ b/src/windows-emulator/registry/registry_manager.cpp @@ -60,30 +60,17 @@ void registry_manager::setup() this->add_path_mapping(machine / "system" / "CurrentControlSet", machine / "system" / "ControlSet001"); } -void registry_manager::serialize(utils::buffer_serializer& buffer) const -{ - buffer.write(this->hive_path_); -} - -void registry_manager::deserialize(utils::buffer_deserializer& buffer) -{ - buffer.read(this->hive_path_); - this->setup(); -} - utils::path_key registry_manager::normalize_path(const utils::path_key& path) const { - const utils::path_key canonical_path = path; - for (const auto& mapping : this->path_mapping_) { - if (is_subpath(mapping.first.get(), canonical_path.get())) + if (is_subpath(mapping.first.get(), path.get())) { - return mapping.second.get() / canonical_path.get().lexically_relative(mapping.first.get()); + return mapping.second.get() / path.get().lexically_relative(mapping.first.get()); } } - return canonical_path.get(); + return path; } void registry_manager::add_path_mapping(const utils::path_key& key, const utils::path_key& value) diff --git a/src/windows-emulator/registry/registry_manager.hpp b/src/windows-emulator/registry/registry_manager.hpp index c5160d76..c041d2f2 100644 --- a/src/windows-emulator/registry/registry_manager.hpp +++ b/src/windows-emulator/registry/registry_manager.hpp @@ -46,9 +46,6 @@ class registry_manager registry_manager(const registry_manager&) = delete; registry_manager& operator=(const registry_manager&) = delete; - void serialize(utils::buffer_serializer& buffer) const; - void deserialize(utils::buffer_deserializer& buffer); - std::optional get_key(const utils::path_key& key); std::optional get_value(const registry_key& key, std::string name); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 5fdf1aca..ddd59d1b 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -84,7 +84,7 @@ namespace c.win_emu.log.print(color::dark_gray, "--> Registry key: %s\n", u16_to_u8(key).c_str()); - auto entry = c.proc.registry.get_key({key}); + auto entry = c.win_emu.registry.get_key({key}); if (!entry.has_value()) { return STATUS_OBJECT_NAME_NOT_FOUND; @@ -187,7 +187,7 @@ namespace const auto query_name = read_unicode_string(c.emu, value_name); - const auto value = c.proc.registry.get_value(*key, u16_to_u8(query_name)); + const auto value = c.win_emu.registry.get_value(*key, u16_to_u8(query_name)); if (!value) { return STATUS_OBJECT_NAME_NOT_FOUND; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 3666fa32..940b83a1 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -218,10 +218,6 @@ namespace setup_gdt(emu, memory); - // TODO: Move that out - context.registry = registry_manager(win_emu.emulation_root.empty() ? emu_settings.registry_directory - : win_emu.emulation_root / "registry"); - context.kusd.setup(emu_settings.use_relative_time); context.base_allocator = create_allocator(memory, PEB_SEGMENT_SIZE); @@ -438,9 +434,28 @@ std::unique_ptr create_default_x64_emulator() windows_emulator::windows_emulator(application_settings app_settings, const emulator_settings& settings, emulator_callbacks callbacks, std::unique_ptr emu) - : windows_emulator(settings.emulation_root, std::move(emu)) + : windows_emulator(settings, std::move(emu)) { + this->callbacks = std::move(callbacks); + fixup_application_settings(app_settings); + this->setup_process(app_settings, settings); +} + +windows_emulator::windows_emulator(const emulator_settings& settings, std::unique_ptr emu) + : emu_(std::move(emu)), + emulation_root{settings.emulation_root.empty() ? settings.emulation_root : absolute(settings.emulation_root)}, + file_sys(emulation_root.empty() ? emulation_root : emulation_root / "filesys"), + memory(*this->emu_), + registry(emulation_root.empty() ? settings.registry_directory : emulation_root / "registry"), + process(*this->emu_, memory, file_sys) +{ +#ifndef OS_WINDOWS + if (this->emulation_root.empty()) + { + throw std::runtime_error("Emulation root directory can not be empty!"); + } +#endif for (const auto& mapping : settings.path_mappings) { @@ -456,27 +471,8 @@ windows_emulator::windows_emulator(application_settings app_settings, const emul this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging; this->use_relative_time_ = settings.use_relative_time; this->log.disable_output(settings.disable_logging || this->silent_until_main_); - this->callbacks = std::move(callbacks); this->modules_ = settings.modules; - this->setup_process(app_settings, settings); -} - -windows_emulator::windows_emulator(const std::filesystem::path& emulation_root_directory, - std::unique_ptr emu) - : emu_(std::move(emu)), - emulation_root{emulation_root_directory.empty() ? emulation_root_directory : absolute(emulation_root_directory)}, - file_sys(emulation_root.empty() ? emulation_root : emulation_root / "filesys"), - memory(*this->emu_), - process(*this->emu_, memory, file_sys) -{ -#ifndef OS_WINDOWS - if (this->emulation_root.empty()) - { - throw std::runtime_error("Emulation root directory can not be empty!"); - } -#endif - this->setup_hooks(); } diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 3f6b3653..1009c7ee 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -34,8 +34,8 @@ struct application_settings struct emulator_settings { - std::filesystem::path registry_directory{"./registry"}; std::filesystem::path emulation_root{}; + std::filesystem::path registry_directory{"./registry"}; bool verbose_calls{false}; bool disable_logging{false}; @@ -65,10 +65,11 @@ class windows_emulator logger log{}; file_system file_sys; memory_manager memory; + registry_manager registry{}; process_context process; syscall_dispatcher dispatcher; - windows_emulator(const std::filesystem::path& emulation_root, + windows_emulator(const emulator_settings& settings = {}, std::unique_ptr emu = create_default_x64_emulator()); windows_emulator(application_settings app_settings, const emulator_settings& settings = {}, emulator_callbacks callbacks = {}, From 349ef9688a24fe8dba9677722a58706bc998a0ba Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Feb 2025 16:48:15 +0100 Subject: [PATCH 5/9] Move module manager into windows emulator --- src/analyzer/main.cpp | 4 +-- src/analyzer/object_watching.hpp | 2 +- .../emulation_test_utils.hpp | 2 +- src/windows-emulator/emulator_utils.hpp | 2 ++ src/windows-emulator/process_context.hpp | 18 +++++----- src/windows-emulator/syscall_dispatcher.cpp | 6 ++-- src/windows-emulator/syscalls.cpp | 8 ++--- src/windows-emulator/windows_emulator.cpp | 36 ++++++++++++------- src/windows-emulator/windows_emulator.hpp | 1 + 9 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index dbdb9cf0..5af11022 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -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.process.mod_manager.find_by_address(rip) != win_emu.process.executable) + if (win_emu.mod_manager.find_by_address(rip) != win_emu.process.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.process.mod_manager.find_by_address(rip) != win_emu.process.executable) + if (win_emu.mod_manager.find_by_address(rip) != win_emu.process.executable) { return; } diff --git a/src/analyzer/object_watching.hpp b/src/analyzer/object_watching.hpp index a7dc3e61..e84685f8 100644 --- a/src/analyzer/object_watching.hpp +++ b/src/analyzer/object_watching.hpp @@ -13,7 +13,7 @@ emulator_hook* watch_object(windows_emulator& emu, const std::setname); if (!emu.verbose_calls && !is_main_access) diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index c65eeba7..be6e10fb 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -152,6 +152,6 @@ namespace test const auto rip = emu.emu().read_instruction_pointer(); printf("Diff detected after 0x%" PRIx64 " instructions at 0x%" PRIx64 " (%s)\n", lower_bound, rip, - emu.process.mod_manager.find_name(rip)); + emu.mod_manager.find_name(rip)); } } diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index b9b0b21f..dfe5e5c6 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -40,10 +40,12 @@ class object_wrapper }; class windows_emulator; +class module_manager; struct process_context; using x64_emulator_wrapper = object_wrapper; using memory_manager_wrapper = object_wrapper; +using module_manager_wrapper = object_wrapper; using process_context_wrapper = object_wrapper; using windows_emulator_wrapper = object_wrapper; diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 39dd1bd7..4c47c2f4 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -27,12 +27,11 @@ struct process_context { - process_context(x64_emulator& emu, memory_manager& memory, file_system& file_sys) + process_context(x64_emulator& emu, memory_manager& memory) : base_allocator(emu), peb(emu), process_params(emu), - kusd(memory, *this), - mod_manager(memory, file_sys) + kusd(memory, *this) { } @@ -49,8 +48,7 @@ struct process_context emulator_object process_params; kusd_mmio kusd; - module_manager mod_manager; - + // TODO: Remove this mapped_module* executable{}; mapped_module* ntdll{}; mapped_module* win32u{}; @@ -86,7 +84,6 @@ struct process_context buffer.write(this->peb); buffer.write(this->process_params); buffer.write(this->kusd); - buffer.write(this->mod_manager); buffer.write(this->executable->image_base); buffer.write(this->ntdll->image_base); @@ -124,15 +121,16 @@ struct process_context buffer.read(this->peb); buffer.read(this->process_params); buffer.read(this->kusd); - buffer.read(this->mod_manager); const auto executable_base = buffer.read(); const auto ntdll_base = buffer.read(); const auto win32u_base = buffer.read(); - this->executable = this->mod_manager.find_by_address(executable_base); - this->ntdll = this->mod_manager.find_by_address(ntdll_base); - this->win32u = this->mod_manager.find_by_address(win32u_base); + 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); diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index f0c0343a..b64acc27 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -88,7 +88,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) return; } - const auto* mod = context.mod_manager.find_by_address(address); + const auto* mod = win_emu.mod_manager.find_by_address(address); if (mod != context.ntdll && mod != context.win32u) { win_emu.callbacks.inline_syscall(syscall_id, address, mod ? mod->name.c_str() : "", @@ -106,7 +106,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) uint64_t return_address{}; c.emu.try_read_memory(rsp, &return_address, sizeof(return_address)); - const auto* mod_name = context.mod_manager.find_name(return_address); + const auto* mod_name = win_emu.mod_manager.find_name(return_address); win_emu.log.print(color::dark_gray, "Executing syscall: %s (0x%X) at 0x%" PRIx64 " via 0x%" PRIx64 " (%s)\n", @@ -114,7 +114,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) } else { - const auto* previous_mod = context.mod_manager.find_by_address(context.previous_ip); + const auto* previous_mod = win_emu.mod_manager.find_by_address(context.previous_ip); win_emu.callbacks.outofline_syscall(syscall_id, address, mod ? mod->name.c_str() : "", entry->second.name, context.previous_ip, diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index ddd59d1b..ab246d8c 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -756,7 +756,7 @@ namespace if (section_entry->is_image()) { - const auto binary = c.proc.mod_manager.map_module(section_entry->file_name, c.win_emu.log); + const auto binary = c.win_emu.mod_manager.map_module(section_entry->file_name, c.win_emu.log); if (!binary) { return STATUS_FILE_INVALID; @@ -880,7 +880,7 @@ namespace return STATUS_BUFFER_OVERFLOW; } - const auto mod = c.proc.mod_manager.find_by_address(base_address); + const auto mod = c.win_emu.mod_manager.find_by_address(base_address); if (!mod) { c.win_emu.log.error("Bad address for memory image request: 0x%" PRIx64 "\n", base_address); @@ -3408,7 +3408,7 @@ namespace return STATUS_NOT_SUPPORTED; } - const auto* mod = c.proc.mod_manager.find_by_address(base_address); + const auto* mod = c.win_emu.mod_manager.find_by_address(base_address); if (!mod) { c.win_emu.log.error("Unmapping non-module section not supported!\n"); @@ -3416,7 +3416,7 @@ namespace return STATUS_NOT_SUPPORTED; } - if (c.proc.mod_manager.unmap(base_address, c.win_emu.log)) + if (c.win_emu.mod_manager.unmap(base_address, c.win_emu.log)) { return STATUS_SUCCESS; } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 940b83a1..ae06004b 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -448,7 +448,8 @@ windows_emulator::windows_emulator(const emulator_settings& settings, std::uniqu file_sys(emulation_root.empty() ? emulation_root : emulation_root / "filesys"), memory(*this->emu_), registry(emulation_root.empty() ? settings.registry_directory : emulation_root / "registry"), - process(*this->emu_, memory, file_sys) + mod_manager(memory, file_sys), + process(*this->emu_, memory) { #ifndef OS_WINDOWS if (this->emulation_root.empty()) @@ -483,18 +484,17 @@ void windows_emulator::setup_process(const application_settings& app_settings, c auto& emu = this->emu(); auto& context = this->process; - context.mod_manager = module_manager(this->memory, this->file_sys); // TODO: Cleanup module manager setup_context(*this, app_settings, emu_settings); - context.executable = context.mod_manager.map_module(app_settings.application, this->log, true); + context.executable = this->mod_manager.map_module(app_settings.application, this->log, true); context.peb.access([&](PEB64& peb) { peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); // }); - context.ntdll = context.mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log, true); - context.win32u = context.mod_manager.map_module(R"(C:\Windows\System32\win32u.dll)", this->log, true); + 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(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); @@ -553,11 +553,11 @@ void windows_emulator::on_instruction_execution(const uint64_t address) this->process.current_ip = this->emu().read_instruction_pointer(); const auto binary = utils::make_lazy([&] { - return this->process.mod_manager.find_by_address(address); // + return this->mod_manager.find_by_address(address); // }); const auto previous_binary = utils::make_lazy([&] { - return this->process.mod_manager.find_by_address(this->process.previous_ip); // + return this->mod_manager.find_by_address(this->process.previous_ip); // }); const auto is_in_interesting_module = [&] { @@ -596,7 +596,7 @@ void windows_emulator::on_instruction_execution(const uint64_t address) uint64_t return_address{}; this->emu().try_read_memory(rsp, &return_address, sizeof(return_address)); - const auto* mod_name = this->process.mod_manager.find_name(return_address); + const auto* mod_name = this->mod_manager.find_name(return_address); log.print(is_interesting_call ? color::yellow : color::dark_gray, "Executing function: %s - %s (0x%" PRIx64 ") via (0x%" PRIx64 ") %s\n", binary->name.c_str(), @@ -687,7 +687,7 @@ void windows_emulator::setup_hooks() const memory_violation_type type) { const auto permission = get_permission_string(operation); const auto ip = this->emu().read_instruction_pointer(); - const char* name = this->process.mod_manager.find_name(ip); + const char* name = this->mod_manager.find_name(ip); if (type == memory_violation_type::protection) { @@ -773,6 +773,7 @@ void windows_emulator::serialize(utils::buffer_serializer& buffer) const buffer.write(this->use_relative_time_); this->emu().serialize_state(buffer, false); this->memory.serialize_memory_state(buffer, false); + this->mod_manager.serialize(buffer); this->process.serialize(buffer); this->dispatcher.serialize(buffer); } @@ -783,6 +784,10 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) return memory_manager_wrapper{this->memory}; // }); + buffer.register_factory([this] { + return module_manager_wrapper{this->mod_manager}; // + }); + buffer.register_factory([this] { return x64_emulator_wrapper{this->emu()}; // }); @@ -798,26 +803,30 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) this->emu().deserialize_state(buffer, false); this->memory.deserialize_memory_state(buffer, false); + this->mod_manager.deserialize(buffer); this->process.deserialize(buffer); this->dispatcher.deserialize(buffer); } void windows_emulator::save_snapshot() { - utils::buffer_serializer serializer{}; + throw std::runtime_error("Not supported"); + /*utils::buffer_serializer serializer{}; this->emu().serialize_state(serializer, true); this->memory.serialize_memory_state(serializer, true); + this->mod_manager.serialize(serializer); this->process.serialize(serializer); this->process_snapshot_ = serializer.move_buffer(); // TODO: Make process copyable - // this->process_snapshot_ = this->process; + // this->process_snapshot_ = this->process;*/ } void windows_emulator::restore_snapshot() { - if (this->process_snapshot_.empty()) + throw std::runtime_error("Not supported"); + /*if (this->process_snapshot_.empty()) { assert(false); return; @@ -826,6 +835,7 @@ void windows_emulator::restore_snapshot() utils::buffer_deserializer deserializer{this->process_snapshot_}; this->emu().deserialize_state(deserializer, true); this->memory.deserialize_memory_state(deserializer, true); + this->mod_manager.deserialize(deserializer); this->process.deserialize(deserializer); - // this->process = *this->process_snapshot_; + // this->process = *this->process_snapshot_;*/ } diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 1009c7ee..8e663858 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -66,6 +66,7 @@ class windows_emulator file_system file_sys; memory_manager memory; registry_manager registry{}; + module_manager mod_manager; process_context process; syscall_dispatcher dispatcher; From 2815a74a188d71c738d9290f2754c7cebce362be Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Feb 2025 16:58:57 +0100 Subject: [PATCH 6/9] Setup PEB image base --- src/common/platform/kernel_mapped.hpp | 2 +- src/windows-emulator/windows_emulator.cpp | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/common/platform/kernel_mapped.hpp b/src/common/platform/kernel_mapped.hpp index 5d7dcb85..9a18cb21 100644 --- a/src/common/platform/kernel_mapped.hpp +++ b/src/common/platform/kernel_mapped.hpp @@ -250,7 +250,7 @@ typedef struct _PEB64 EmulatorTraits::HANDLE Mutant; - std::uint64_t* ImageBaseAddress; + std::uint64_t ImageBaseAddress; PPEB_LDR_DATA64 Ldr; PRTL_USER_PROCESS_PARAMETERS64 ProcessParameters; std::uint64_t* SubSystemData; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index ae06004b..3ed9bd45 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -210,7 +210,7 @@ namespace } void setup_context(windows_emulator& win_emu, const application_settings& app_settings, - const emulator_settings& emu_settings) + const emulator_settings& emu_settings, const uint64_t process_image_base) { auto& emu = win_emu.emu(); auto& context = win_emu.process; @@ -290,7 +290,7 @@ namespace } context.peb.access([&](PEB64& peb) { - peb.ImageBaseAddress = nullptr; + peb.ImageBaseAddress = process_image_base; peb.ProcessParameters = context.process_params.ptr(); peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc, win_emu.emulation_root).ptr(); @@ -485,14 +485,11 @@ void windows_emulator::setup_process(const application_settings& app_settings, c auto& context = this->process; - setup_context(*this, app_settings, emu_settings); + auto* exe = this->mod_manager.map_module(app_settings.application, this->log, true); - context.executable = this->mod_manager.map_module(app_settings.application, this->log, true); - - context.peb.access([&](PEB64& peb) { - peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); // - }); + setup_context(*this, app_settings, emu_settings, exe->image_base); + 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); From 04ca0981a10bab3735d4ca2d747d7e9dc322750f Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Feb 2025 17:21:34 +0100 Subject: [PATCH 7/9] Extract API set data --- src/windows-emulator/apiset/apiset.cpp | 171 ++++++++++++++++++ src/windows-emulator/apiset/apiset.hpp | 37 ++++ .../{apiset.hpp => apiset/default_apiset.hpp} | 0 src/windows-emulator/windows_emulator.cpp | 161 +---------------- src/windows-emulator/windows_emulator.hpp | 8 - 5 files changed, 215 insertions(+), 162 deletions(-) create mode 100644 src/windows-emulator/apiset/apiset.cpp create mode 100644 src/windows-emulator/apiset/apiset.hpp rename src/windows-emulator/{apiset.hpp => apiset/default_apiset.hpp} (100%) diff --git a/src/windows-emulator/apiset/apiset.cpp b/src/windows-emulator/apiset/apiset.cpp new file mode 100644 index 00000000..2031acae --- /dev/null +++ b/src/windows-emulator/apiset/apiset.cpp @@ -0,0 +1,171 @@ +#include "apiset.hpp" +#include "default_apiset.hpp" + +#include "../emulator_utils.hpp" + +#include + +#include +#include + +namespace apiset +{ + namespace + { + uint64_t copy_string(x64_emulator& emu, emulator_allocator& allocator, const void* base_ptr, + const uint64_t offset, const size_t length) + { + if (!length) + { + return 0; + } + + const auto length_to_allocate = length + 2; + const auto str_obj = allocator.reserve(length_to_allocate); + emu.write_memory(str_obj, static_cast(base_ptr) + offset, length); + + return str_obj; + } + + ULONG copy_string_as_relative(x64_emulator& emu, emulator_allocator& allocator, const uint64_t result_base, + const void* base_ptr, const uint64_t offset, const size_t length) + { + const auto address = copy_string(emu, allocator, base_ptr, offset, length); + if (!address) + { + return 0; + } + + assert(address > result_base); + return static_cast(address - result_base); + } + + std::vector decompress_apiset(const std::vector& apiset) + { + auto buffer = utils::compression::zlib::decompress(apiset); + if (buffer.empty()) + throw std::runtime_error("Failed to decompress API-SET"); + return buffer; + } + + std::vector obtain_data(const location location, const std::filesystem::path& root) + { + switch (location) + { +#ifdef OS_WINDOWS + case location::host: { + const auto apiSetMap = + reinterpret_cast(NtCurrentTeb64()->ProcessEnvironmentBlock->ApiSetMap); + const auto* dataPtr = reinterpret_cast(apiSetMap); + return {dataPtr, dataPtr + apiSetMap->Size}; + } +#else + case location::host: + throw std::runtime_error("The APISET host location is not supported on this platform"); +#endif + case location::file: { + const auto apiset = utils::io::read_file(root / "api-set.bin"); + if (apiset.empty()) + throw std::runtime_error("Failed to read file api-set.bin"); + return decompress_apiset(apiset); + } + case location::default_windows_10: { + const std::vector apiset{apiset_w10, apiset_w10 + sizeof(apiset_w10)}; + return decompress_apiset(apiset); + } + case location::default_windows_11: { + const std::vector apiset{apiset_w11, apiset_w11 + sizeof(apiset_w11)}; + return decompress_apiset(apiset); + } + default: + throw std::runtime_error("Bad API set location"); + } + } + } + + container obtain(const location location, const std::filesystem::path& root) + { + return {.data = obtain_data(location, root)}; + } + + container obtain(const std::filesystem::path& root) + { + auto apiset_loc = location::file; + + if (root.empty()) + { +#ifdef OS_WINDOWS + apiset_loc = location::host; +#else + apiset_loc = location::default_windows_11; +#endif + } + + return obtain(apiset_loc, root); + } + + emulator_object clone(x64_emulator& emu, emulator_allocator& allocator, + const container& container) + { + return clone(emu, allocator, container.get()); + } + + emulator_object clone(x64_emulator& emu, emulator_allocator& allocator, + const API_SET_NAMESPACE& orig_api_set_map) + { + const auto api_set_map_obj = allocator.reserve(); + const auto ns_entries_obj = allocator.reserve(orig_api_set_map.Count); + const auto hash_entries_obj = allocator.reserve(orig_api_set_map.Count); + + api_set_map_obj.access([&](API_SET_NAMESPACE& api_set) { + api_set = orig_api_set_map; + api_set.EntryOffset = static_cast(ns_entries_obj.value() - api_set_map_obj.value()); + api_set.HashOffset = static_cast(hash_entries_obj.value() - api_set_map_obj.value()); + }); + + const auto orig_ns_entries = + offset_pointer(&orig_api_set_map, orig_api_set_map.EntryOffset); + const auto orig_hash_entries = + offset_pointer(&orig_api_set_map, orig_api_set_map.HashOffset); + + for (ULONG i = 0; i < orig_api_set_map.Count; ++i) + { + auto ns_entry = orig_ns_entries[i]; + const auto hash_entry = orig_hash_entries[i]; + + ns_entry.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map, + ns_entry.NameOffset, ns_entry.NameLength); + + if (!ns_entry.ValueCount) + { + continue; + } + + const auto values_obj = allocator.reserve(ns_entry.ValueCount); + const auto orig_values = offset_pointer(&orig_api_set_map, ns_entry.ValueOffset); + + ns_entry.ValueOffset = static_cast(values_obj.value() - api_set_map_obj.value()); + + for (ULONG j = 0; j < ns_entry.ValueCount; ++j) + { + auto value = orig_values[j]; + + value.ValueOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map, + value.ValueOffset, value.ValueLength); + + if (value.NameLength) + { + value.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), + &orig_api_set_map, value.NameOffset, value.NameLength); + } + + values_obj.write(value, j); + } + + ns_entries_obj.write(ns_entry, i); + hash_entries_obj.write(hash_entry, i); + } + + return api_set_map_obj; + } +} diff --git a/src/windows-emulator/apiset/apiset.hpp b/src/windows-emulator/apiset/apiset.hpp new file mode 100644 index 00000000..d0097da1 --- /dev/null +++ b/src/windows-emulator/apiset/apiset.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +#include "../emulator_utils.hpp" + +namespace apiset +{ + enum class location : uint8_t + { + host, + file, + default_windows_10, + default_windows_11 + }; + + struct container + { + std::vector data{}; + + const API_SET_NAMESPACE& get() const + { + return *reinterpret_cast(data.data()); + } + }; + + container obtain(location location, const std::filesystem::path& root); + container obtain(const std::filesystem::path& root); + + emulator_object clone(x64_emulator& emu, emulator_allocator& allocator, + const API_SET_NAMESPACE& orig_api_set_map); + + emulator_object clone(x64_emulator& emu, emulator_allocator& allocator, + const container& container); +} diff --git a/src/windows-emulator/apiset.hpp b/src/windows-emulator/apiset/default_apiset.hpp similarity index 100% rename from src/windows-emulator/apiset.hpp rename to src/windows-emulator/apiset/default_apiset.hpp diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 3ed9bd45..64c63cca 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -1,7 +1,6 @@ #include "std_include.hpp" #include "windows_emulator.hpp" -#include "address_utils.hpp" #include "cpu_context.hpp" #include @@ -11,8 +10,8 @@ #include #include -#include "apiset.hpp" #include "exception_dispatch.hpp" +#include "apiset/apiset.hpp" constexpr auto MAX_INSTRUCTIONS_PER_TIME_SLICE = 100000; @@ -50,144 +49,6 @@ namespace adjust_application(app_settings); } - uint64_t copy_string(x64_emulator& emu, emulator_allocator& allocator, const void* base_ptr, const uint64_t offset, - const size_t length) - { - if (!length) - { - return 0; - } - - const auto length_to_allocate = length + 2; - const auto str_obj = allocator.reserve(length_to_allocate); - emu.write_memory(str_obj, static_cast(base_ptr) + offset, length); - - return str_obj; - } - - ULONG copy_string_as_relative(x64_emulator& emu, emulator_allocator& allocator, const uint64_t result_base, - const void* base_ptr, const uint64_t offset, const size_t length) - { - const auto address = copy_string(emu, allocator, base_ptr, offset, length); - if (!address) - { - return 0; - } - - assert(address > result_base); - return static_cast(address - result_base); - } - - emulator_object clone_api_set_map(x64_emulator& emu, emulator_allocator& allocator, - const API_SET_NAMESPACE& orig_api_set_map) - { - const auto api_set_map_obj = allocator.reserve(); - const auto ns_entries_obj = allocator.reserve(orig_api_set_map.Count); - const auto hash_entries_obj = allocator.reserve(orig_api_set_map.Count); - - api_set_map_obj.access([&](API_SET_NAMESPACE& api_set) { - api_set = orig_api_set_map; - api_set.EntryOffset = static_cast(ns_entries_obj.value() - api_set_map_obj.value()); - api_set.HashOffset = static_cast(hash_entries_obj.value() - api_set_map_obj.value()); - }); - - const auto orig_ns_entries = - offset_pointer(&orig_api_set_map, orig_api_set_map.EntryOffset); - const auto orig_hash_entries = - offset_pointer(&orig_api_set_map, orig_api_set_map.HashOffset); - - for (ULONG i = 0; i < orig_api_set_map.Count; ++i) - { - auto ns_entry = orig_ns_entries[i]; - const auto hash_entry = orig_hash_entries[i]; - - ns_entry.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map, - ns_entry.NameOffset, ns_entry.NameLength); - - if (!ns_entry.ValueCount) - { - continue; - } - - const auto values_obj = allocator.reserve(ns_entry.ValueCount); - const auto orig_values = offset_pointer(&orig_api_set_map, ns_entry.ValueOffset); - - ns_entry.ValueOffset = static_cast(values_obj.value() - api_set_map_obj.value()); - - for (ULONG j = 0; j < ns_entry.ValueCount; ++j) - { - auto value = orig_values[j]; - - value.ValueOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map, - value.ValueOffset, value.ValueLength); - - if (value.NameLength) - { - value.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), - &orig_api_set_map, value.NameOffset, value.NameLength); - } - - values_obj.write(value, j); - } - - ns_entries_obj.write(ns_entry, i); - hash_entries_obj.write(hash_entry, i); - } - - return api_set_map_obj; - } - - std::vector decompress_apiset(const std::vector& apiset) - { - auto buffer = utils::compression::zlib::decompress(apiset); - if (buffer.empty()) - throw std::runtime_error("Failed to decompress API-SET"); - return buffer; - } - - std::vector obtain_api_set(const apiset_location location, const std::filesystem::path& root) - { - switch (location) - { -#ifdef OS_WINDOWS - case apiset_location::host: { - const auto apiSetMap = - reinterpret_cast(NtCurrentTeb64()->ProcessEnvironmentBlock->ApiSetMap); - const auto* dataPtr = reinterpret_cast(apiSetMap); - std::vector buffer(dataPtr, dataPtr + apiSetMap->Size); - return buffer; - } -#else - case apiset_location::host: - throw std::runtime_error("The APISET host location is not supported on this platform"); -#endif - case apiset_location::file: { - const auto apiset = utils::io::read_file(root / "api-set.bin"); - if (apiset.empty()) - throw std::runtime_error("Failed to read file api-set.bin"); - return decompress_apiset(apiset); - } - case apiset_location::default_windows_10: { - const std::vector apiset{apiset_w10, apiset_w10 + sizeof(apiset_w10)}; - return decompress_apiset(apiset); - } - case apiset_location::default_windows_11: { - const std::vector apiset{apiset_w11, apiset_w11 + sizeof(apiset_w11)}; - return decompress_apiset(apiset); - } - default: - throw std::runtime_error("Bad API set location"); - } - } - - emulator_object build_api_set_map(x64_emulator& emu, emulator_allocator& allocator, - const apiset_location location = apiset_location::host, - const std::filesystem::path& root = {}) - { - return clone_api_set_map(emu, allocator, - reinterpret_cast(*obtain_api_set(location, root).data())); - } - emulator_allocator create_allocator(memory_manager& memory, const size_t size) { const auto base = memory.find_free_allocation_base(size); @@ -210,7 +71,8 @@ namespace } void setup_context(windows_emulator& win_emu, const application_settings& app_settings, - const emulator_settings& emu_settings, const uint64_t process_image_base) + const emulator_settings& emu_settings, const uint64_t process_image_base, + const apiset::container& apiset_container) { auto& emu = win_emu.emu(); auto& context = win_emu.process; @@ -278,21 +140,10 @@ namespace proc_params.MaximumLength = proc_params.Length; }); - apiset_location apiset_loc = apiset_location::file; - - if (win_emu.emulation_root.empty()) - { -#ifdef OS_WINDOWS - apiset_loc = apiset_location::host; -#else - apiset_loc = apiset_location::default_windows_11; -#endif - } - context.peb.access([&](PEB64& peb) { peb.ImageBaseAddress = process_image_base; peb.ProcessParameters = context.process_params.ptr(); - peb.ApiSetMap = build_api_set_map(emu, allocator, apiset_loc, win_emu.emulation_root).ptr(); + peb.ApiSetMap = apiset::clone(emu, allocator, apiset_container).ptr(); peb.ProcessHeap = nullptr; peb.ProcessHeaps = nullptr; @@ -487,7 +338,9 @@ void windows_emulator::setup_process(const application_settings& app_settings, c auto* exe = this->mod_manager.map_module(app_settings.application, this->log, true); - setup_context(*this, app_settings, emu_settings, exe->image_base); + const auto apiset_data = apiset::obtain(this->emulation_root); + + setup_context(*this, app_settings, emu_settings, exe->image_base, apiset_data); context.executable = exe; context.ntdll = this->mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log, true); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 8e663858..6665dc55 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -47,14 +47,6 @@ struct emulator_settings std::set> modules{}; }; -enum class apiset_location : uint8_t -{ - host, - file, - default_windows_10, - default_windows_11 -}; - class windows_emulator { std::unique_ptr emu_{}; From c1aa260f8ff2c5e48fd1c5547c1572d3c734b196 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Feb 2025 17:28:00 +0100 Subject: [PATCH 8/9] Cleanup process context --- src/windows-emulator/process_context.cpp | 117 ++++++++++++++++++++++ src/windows-emulator/process_context.hpp | 9 ++ src/windows-emulator/windows_emulator.cpp | 117 +--------------------- 3 files changed, 127 insertions(+), 116 deletions(-) create mode 100644 src/windows-emulator/process_context.cpp diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp new file mode 100644 index 00000000..79181698 --- /dev/null +++ b/src/windows-emulator/process_context.cpp @@ -0,0 +1,117 @@ +#include "process_context.hpp" + +#include "emulator_utils.hpp" +#include "windows_emulator.hpp" + +namespace +{ + emulator_allocator create_allocator(memory_manager& memory, const size_t size) + { + const auto base = memory.find_free_allocation_base(size); + memory.allocate_memory(base, size, memory_permission::read_write); + + return emulator_allocator{memory, base, size}; + } + + void setup_gdt(x64_emulator& emu, memory_manager& memory) + { + constexpr uint64_t gdtr[4] = {0, GDT_ADDR, GDT_LIMIT, 0}; + emu.write_register(x64_register::gdtr, &gdtr, sizeof(gdtr)); + memory.allocate_memory(GDT_ADDR, GDT_LIMIT, memory_permission::read); + + emu.write_memory(GDT_ADDR + 6 * (sizeof(uint64_t)), 0xEFFE000000FFFF); + emu.reg(x64_register::cs, 0x33); + + emu.write_memory(GDT_ADDR + 5 * (sizeof(uint64_t)), 0xEFF6000000FFFF); + emu.reg(x64_register::ss, 0x2B); + } +} + +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) +{ + setup_gdt(emu, memory); + + this->kusd.setup(emu_settings.use_relative_time); + + this->base_allocator = create_allocator(memory, PEB_SEGMENT_SIZE); + auto& allocator = this->base_allocator; + + this->peb = allocator.reserve(); + + /* Values of the following fields must be + * allocated relative to the process_params themselves + * and included in the length: + * + * CurrentDirectory + * DllPath + * ImagePathName + * CommandLine + * WindowTitle + * DesktopInfo + * ShellInfo + * RuntimeData + * RedirectionDllName + */ + + this->process_params = allocator.reserve(); + + this->process_params.access([&](RTL_USER_PROCESS_PARAMETERS64& proc_params) { + proc_params.Flags = 0x6001; //| 0x80000000; // Prevent CsrClientConnectToServer + + proc_params.ConsoleHandle = CONSOLE_HANDLE.h; + proc_params.StandardOutput = STDOUT_HANDLE.h; + proc_params.StandardInput = STDIN_HANDLE.h; + proc_params.StandardError = proc_params.StandardOutput; + + proc_params.Environment = reinterpret_cast(allocator.copy_string(u"=::=::\\")); + allocator.copy_string(u"EMULATOR=1"); + allocator.copy_string(u"COMPUTERNAME=momo"); + allocator.copy_string(u"SystemRoot=C:\\WINDOWS"); + allocator.copy_string(u""); + + const auto application_str = app_settings.application.u16string(); + + std::u16string command_line = u"\"" + application_str + u"\""; + + for (const auto& arg : app_settings.arguments) + { + command_line.push_back(u' '); + command_line.append(arg); + } + + allocator.make_unicode_string(proc_params.CommandLine, command_line); + allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, + app_settings.working_directory.u16string() + u"\\", 1024); + allocator.make_unicode_string(proc_params.ImagePathName, application_str); + + const auto total_length = allocator.get_next_address() - this->process_params.value(); + + proc_params.Length = static_cast(std::max(static_cast(sizeof(proc_params)), total_length)); + 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(); + + 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; + + peb.OSPlatformId = 2; + peb.OSMajorVersion = 0x0000000a; + peb.OSBuildNumber = 0x00006c51; + + // peb.AnsiCodePageData = allocator.reserve().value(); + // peb.OemCodePageData = allocator.reserve().value(); + peb.UnicodeCaseTableData = allocator.reserve().value(); + }); +} diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 4c47c2f4..005a7e67 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -14,6 +14,8 @@ #include "windows_objects.hpp" #include "emulator_thread.hpp" +#include "apiset/apiset.hpp" + #define PEB_SEGMENT_SIZE (20 << 20) // 20 MB #define GS_SEGMENT_SIZE (1 << 20) // 1 MB @@ -25,6 +27,9 @@ #define GDT_LIMIT 0x1000 #define GDT_ENTRY_SIZE 0x8 +struct emulator_settings; +struct application_settings; + struct process_context { process_context(x64_emulator& emu, memory_manager& memory) @@ -35,6 +40,10 @@ 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 apiset::container& apiset_container); + uint64_t executed_instructions{0}; uint64_t current_ip{0}; uint64_t previous_ip{0}; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 64c63cca..8e1a59f5 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -49,121 +49,6 @@ namespace adjust_application(app_settings); } - emulator_allocator create_allocator(memory_manager& memory, const size_t size) - { - const auto base = memory.find_free_allocation_base(size); - memory.allocate_memory(base, size, memory_permission::read_write); - - return emulator_allocator{memory, base, size}; - } - - void setup_gdt(x64_emulator& emu, memory_manager& memory) - { - constexpr uint64_t gdtr[4] = {0, GDT_ADDR, GDT_LIMIT, 0}; - emu.write_register(x64_register::gdtr, &gdtr, sizeof(gdtr)); - memory.allocate_memory(GDT_ADDR, GDT_LIMIT, memory_permission::read); - - emu.write_memory(GDT_ADDR + 6 * (sizeof(uint64_t)), 0xEFFE000000FFFF); - emu.reg(x64_register::cs, 0x33); - - emu.write_memory(GDT_ADDR + 5 * (sizeof(uint64_t)), 0xEFF6000000FFFF); - emu.reg(x64_register::ss, 0x2B); - } - - void setup_context(windows_emulator& win_emu, const application_settings& app_settings, - const emulator_settings& emu_settings, const uint64_t process_image_base, - const apiset::container& apiset_container) - { - auto& emu = win_emu.emu(); - auto& context = win_emu.process; - auto& memory = win_emu.memory; - - setup_gdt(emu, memory); - - context.kusd.setup(emu_settings.use_relative_time); - - context.base_allocator = create_allocator(memory, PEB_SEGMENT_SIZE); - auto& allocator = context.base_allocator; - - context.peb = allocator.reserve(); - - /* Values of the following fields must be - * allocated relative to the process_params themselves - * and included in the length: - * - * CurrentDirectory - * DllPath - * ImagePathName - * CommandLine - * WindowTitle - * DesktopInfo - * ShellInfo - * RuntimeData - * RedirectionDllName - */ - - context.process_params = allocator.reserve(); - - context.process_params.access([&](RTL_USER_PROCESS_PARAMETERS64& proc_params) { - proc_params.Flags = 0x6001; //| 0x80000000; // Prevent CsrClientConnectToServer - - proc_params.ConsoleHandle = CONSOLE_HANDLE.h; - proc_params.StandardOutput = STDOUT_HANDLE.h; - proc_params.StandardInput = STDIN_HANDLE.h; - proc_params.StandardError = proc_params.StandardOutput; - - proc_params.Environment = reinterpret_cast(allocator.copy_string(u"=::=::\\")); - allocator.copy_string(u"EMULATOR=1"); - allocator.copy_string(u"COMPUTERNAME=momo"); - allocator.copy_string(u"SystemRoot=C:\\WINDOWS"); - allocator.copy_string(u""); - - const auto application_str = app_settings.application.u16string(); - - std::u16string command_line = u"\"" + application_str + u"\""; - - for (const auto& arg : app_settings.arguments) - { - command_line.push_back(u' '); - command_line.append(arg); - } - - allocator.make_unicode_string(proc_params.CommandLine, command_line); - allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, - app_settings.working_directory.u16string() + u"\\", 1024); - allocator.make_unicode_string(proc_params.ImagePathName, application_str); - - const auto total_length = allocator.get_next_address() - context.process_params.value(); - - proc_params.Length = - static_cast(std::max(static_cast(sizeof(proc_params)), total_length)); - proc_params.MaximumLength = proc_params.Length; - }); - - context.peb.access([&](PEB64& peb) { - peb.ImageBaseAddress = process_image_base; - peb.ProcessParameters = context.process_params.ptr(); - peb.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; - - peb.OSPlatformId = 2; - peb.OSMajorVersion = 0x0000000a; - peb.OSBuildNumber = 0x00006c51; - - // peb.AnsiCodePageData = allocator.reserve().value(); - // peb.OemCodePageData = allocator.reserve().value(); - peb.UnicodeCaseTableData = allocator.reserve().value(); - }); - } - void perform_context_switch_work(windows_emulator& win_emu) { auto& devices = win_emu.process.devices; @@ -340,7 +225,7 @@ void windows_emulator::setup_process(const application_settings& app_settings, c const auto apiset_data = apiset::obtain(this->emulation_root); - setup_context(*this, app_settings, emu_settings, exe->image_base, apiset_data); + this->process.setup(this->emu(), this->memory, app_settings, emu_settings, exe->image_base, apiset_data); context.executable = exe; context.ntdll = this->mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log, true); From 934374c4bb6bde7e5c263ca514594fd0f90496b3 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 10 Feb 2025 17:43:09 +0100 Subject: [PATCH 9/9] 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)