From a28be3049b459cbedf9c217b146286bfd48179c2 Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Mon, 10 Feb 2025 15:46:38 +0100 Subject: [PATCH] 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); };