diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 495aa4c7..c6c001c9 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -136,7 +136,7 @@ namespace if (options.silent) { win_emu.buffer_stdout = false; - win_emu.callbacks.stdout_callback = [](const std::string_view data) { + win_emu.callbacks.on_stdout = [](const std::string_view data) { (void)fwrite(data.data(), 1, data.size(), stdout); }; } diff --git a/src/windows-emulator-test/time_test.cpp b/src/windows-emulator-test/time_test.cpp index 54e7b897..d82b2520 100644 --- a/src/windows-emulator-test/time_test.cpp +++ b/src/windows-emulator-test/time_test.cpp @@ -6,11 +6,9 @@ namespace test { std::string output_buffer{}; - emulator_callbacks callbacks{ - .stdout_callback = - [&output_buffer](const std::string_view data) { - output_buffer.append(data); // - }, + emulator_callbacks callbacks{}; + callbacks.on_stdout = [&output_buffer](const std::string_view data) { + output_buffer.append(data); // }; const emulator_settings settings{ diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index de78b99b..0270b093 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -163,7 +163,7 @@ class handle_store : public generic_handle_store return blocked; } - handle store(T value) + std::pair store_and_get(T value) { if (this->block_mutation_) { @@ -171,9 +171,14 @@ class handle_store : public generic_handle_store } auto index = this->find_free_index(); - this->store_.emplace(index, std::move(value)); + const auto it = this->store_.emplace(index, std::move(value)).first; - return make_handle(index); + return {make_handle(index), &it->second}; + } + + handle store(T value) + { + return this->store_and_get(std::move(value)).first; } handle make_handle(const index_type index) const diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index f2ae5791..a90a5678 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -54,9 +54,10 @@ namespace utils } } -module_manager::module_manager(memory_manager& memory, file_system& file_sys) +module_manager::module_manager(memory_manager& memory, file_system& file_sys, callbacks& cb) : memory_(&memory), - file_sys_(&file_sys) + file_sys_(&file_sys), + callbacks_(&cb) { } @@ -95,7 +96,7 @@ mapped_module* module_manager::map_local_module(const std::filesystem::path& fil const auto image_base = mod.image_base; const auto entry = this->modules_.try_emplace(image_base, std::move(mod)); - this->on_module_load(entry.first->second); + this->callbacks_->on_module_load(entry.first->second); return &entry.first->second; } catch (const std::exception& e) @@ -147,7 +148,7 @@ bool module_manager::unmap(const uint64_t address, const logger& logger) logger.log("Unmapping %s (0x%" PRIx64 ")\n", mod->second.path.generic_string().c_str(), mod->second.image_base); - this->on_module_unload(mod->second); + this->callbacks_->on_module_unload(mod->second); unmap_module(*this->memory_, mod->second); this->modules_.erase(mod); diff --git a/src/windows-emulator/module/module_manager.hpp b/src/windows-emulator/module/module_manager.hpp index 6f729f89..f0d18a05 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -10,11 +10,15 @@ class logger; class module_manager { public: - using module_map = std::map; - utils::optional_function on_module_load{}; - utils::optional_function on_module_unload{}; + struct callbacks + { + utils::optional_function on_module_load{}; + utils::optional_function on_module_unload{}; + }; - module_manager(memory_manager& memory, file_system& file_sys); + using module_map = std::map; + + module_manager(memory_manager& memory, file_system& file_sys, callbacks& cb); void map_main_modules(const windows_path& executable_path, const windows_path& ntdll_path, const windows_path& win32u_path, const logger& logger); @@ -61,6 +65,7 @@ class module_manager private: memory_manager* memory_{}; file_system* file_sys_{}; + callbacks* callbacks_{}; module_map modules_{}; diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 0a15cb49..67bdec3c 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -201,7 +201,7 @@ handle process_context::create_thread(memory_manager& memory, const uint64_t sta const uint64_t stack_size) { emulator_thread t{memory, *this, start_address, argument, stack_size, ++this->spawned_thread_count}; - auto h = this->threads.store(std::move(t)); - on_create_thread(h, *this->threads.get(h)); + auto [h, thr] = this->threads.store_and_get(std::move(t)); + this->callbacks_->on_create_thread(h, *thr); return h; } diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index e03b3465..ba7c2f47 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -32,8 +32,15 @@ struct application_settings; struct process_context { - process_context(x64_emulator& emu, memory_manager& memory) - : base_allocator(emu), + struct callbacks + { + utils::optional_function on_create_thread{}; + utils::optional_function on_thread_terminated{}; + }; + + process_context(x64_emulator& emu, memory_manager& memory, callbacks& cb) + : callbacks_(&cb), + base_allocator(emu), peb(emu), process_params(emu), kusd(memory, *this) @@ -44,14 +51,14 @@ struct process_context const emulator_settings& emu_settings, const mapped_module& executable, const mapped_module& ntdll, const apiset::container& apiset_container); - utils::optional_function on_create_thread{}; - 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); + callbacks* callbacks_{}; + uint64_t executed_instructions{0}; uint64_t current_ip{0}; uint64_t previous_ip{0}; diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index 1f846f66..6b7c3c15 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -71,6 +71,8 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) try { + const auto* mod = win_emu.mod_manager.find_by_address(address); + const auto entry = this->handlers_.find(syscall_id); if (entry == this->handlers_.end()) { @@ -80,6 +82,13 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) return; } + const std::string_view mod_name = mod ? mod->name : std::string_view{}; + const auto res = win_emu.callbacks.on_syscall(syscall_id, address, mod_name, entry->second.name); + if (res == instruction_hook_continuation::skip_instruction) + { + return; + } + if (!entry->second.handler) { win_emu.log.error("Unimplemented syscall: %s - 0x%X\n", entry->second.name.c_str(), syscall_id); @@ -88,12 +97,8 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) return; } - const auto* mod = win_emu.mod_manager.find_by_address(address); 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); - 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() : ""); } @@ -106,20 +111,16 @@ 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 = win_emu.mod_manager.find_name(return_address); + const auto* caller_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", - entry->second.name.c_str(), syscall_id, address, return_address, mod_name); + entry->second.name.c_str(), syscall_id, address, return_address, caller_mod_name); } else { 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, - 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 " (%s)\n", diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 872f6ccb..3c2ece3a 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -2878,7 +2878,7 @@ namespace io_status_block.write(block); } - c.win_emu.callbacks.stdout_callback(temp_buffer); + c.win_emu.callbacks.on_stdout(temp_buffer); if (!temp_buffer.ends_with("\n")) { @@ -3613,7 +3613,7 @@ namespace } thread->exit_status = exit_status; - c.win_emu.callbacks.thread_terminated(thread_handle, *thread); + c.win_emu.callbacks.on_thread_terminated(thread_handle, *thread); if (thread == c.proc.active_thread) { c.win_emu.yield_thread(); diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index abd92afc..708cc8bf 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -184,8 +184,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"), - mod_manager(memory, file_sys), - process(*this->emu_, memory) + mod_manager(memory, file_sys, callbacks), + process(*this->emu_, memory, callbacks) { #ifndef OS_WINDOWS if (this->emulation_root.empty()) @@ -220,10 +220,6 @@ void windows_emulator::setup_process(const application_settings& app_settings, c const auto& emu = this->emu(); auto& context = this->process; - mod_manager.on_module_load = std::move(callbacks.module_loaded); - mod_manager.on_module_unload = std::move(callbacks.module_unloaded); - context.on_create_thread = std::move(callbacks.thread_created); - this->mod_manager.map_main_modules(app_settings.application, R"(C:\Windows\System32\ntdll.dll)", R"(C:\Windows\System32\win32u.dll)", this->log); @@ -361,14 +357,6 @@ void windows_emulator::on_instruction_execution(const uint64_t address) void windows_emulator::setup_hooks() { this->emu().hook_instruction(x64_hookable_instructions::syscall, [&] { - for (const auto& hook : this->syscall_hooks_) - { - if (hook() == instruction_hook_continuation::skip_instruction) - { - return instruction_hook_continuation::skip_instruction; - } - } - this->dispatcher.dispatch(*this); return instruction_hook_continuation::skip_instruction; }); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index b6d6ef95..b8b7b700 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -10,23 +10,17 @@ #include "logger.hpp" #include "file_system.hpp" #include "memory_manager.hpp" +#include "module/module_manager.hpp" std::unique_ptr create_default_x64_emulator(); -struct emulator_callbacks +struct emulator_callbacks : module_manager::callbacks, process_context::callbacks { - utils::optional_function stdout_callback{}; - utils::optional_function - inline_syscall{}; - utils::optional_function - outofline_syscall{}; - utils::optional_function module_loaded{}; - utils::optional_function module_unloaded{}; - utils::optional_function thread_created{}; - utils::optional_function thread_terminated{}; + utils::optional_function + on_syscall{}; + + utils::optional_function on_stdout{}; }; struct application_settings @@ -57,6 +51,7 @@ class windows_emulator public: std::filesystem::path emulation_root{}; + emulator_callbacks callbacks{}; logger log{}; file_system file_sys; memory_manager memory; @@ -64,7 +59,6 @@ class windows_emulator module_manager mod_manager; process_context process; syscall_dispatcher dispatcher; - emulator_callbacks callbacks{}; windows_emulator(const emulator_settings& settings = {}, std::unique_ptr emu = create_default_x64_emulator()); @@ -107,11 +101,6 @@ class windows_emulator void save_snapshot(); void restore_snapshot(); - void add_syscall_hook(instruction_hook_callback callback) - { - this->syscall_hooks_.push_back(std::move(callback)); - } - uint16_t get_host_port(const uint16_t emulator_port) const { const auto entry = this->port_mappings_.find(emulator_port); @@ -170,7 +159,6 @@ class windows_emulator bool use_relative_time_{false}; bool silent_until_main_{false}; - std::vector syscall_hooks_{}; std::unordered_map port_mappings_{}; std::set> modules_{};