diff --git a/src/windows-emulator/event_manager.cpp b/src/windows-emulator/event_manager.cpp index e20376ce..805d3ff4 100644 --- a/src/windows-emulator/event_manager.cpp +++ b/src/windows-emulator/event_manager.cpp @@ -1,2 +1,45 @@ #include "std_include.hpp" #include "event_manager.hpp" +#include "windows_emulator.hpp" + +void syscall_event::print(generic_logger& log) const +{ + auto& win = *this->win_emu; + auto& emu = win.emu(); + + const auto address = emu.read_instruction_pointer(); + const auto* mod = win.mod_manager.find_by_address(address); + + if (mod != win.mod_manager.ntdll && mod != win.mod_manager.win32u) + { + log.print(color::blue, "Executing inline syscall: %.*s (0x%X) at 0x%" PRIx64 " (%s)\n", + static_cast(this->data.name.size()), this->data.name.data(), this->data.id, address, + mod ? mod->name.c_str() : ""); + } + else + { + if (mod->is_within(win_emu->process.previous_ip)) + { + const auto rsp = emu.read_stack_pointer(); + + uint64_t return_address{}; + emu.try_read_memory(rsp, &return_address, sizeof(return_address)); + + const auto* caller_mod_name = win.mod_manager.find_name(return_address); + + log.print(color::dark_gray, "Executing syscall: %.*s (0x%X) at 0x%" PRIx64 " via 0x%" PRIx64 " (%s)\n", + static_cast(this->data.name.size()), this->data.name.data(), this->data.id, address, + return_address, caller_mod_name); + } + else + { + const auto* previous_mod = win.mod_manager.find_by_address(win.process.previous_ip); + + log.print(color::blue, + "Crafted out-of-line syscall: %.*s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64 " (%s)\n", + static_cast(this->data.name.size()), this->data.name.data(), this->data.id, address, + mod ? mod->name.c_str() : "", win.process.previous_ip, + previous_mod ? previous_mod->name.c_str() : ""); + } + } +} diff --git a/src/windows-emulator/event_manager.hpp b/src/windows-emulator/event_manager.hpp index 26a2c98b..91987688 100644 --- a/src/windows-emulator/event_manager.hpp +++ b/src/windows-emulator/event_manager.hpp @@ -2,82 +2,98 @@ #include "logger.hpp" struct mapped_module; -struct windows_emulator; +class windows_emulator; -enum class event_type +enum class emulation_event_type { syscall, function_call, }; -struct event : utils::object +struct emulation_event : utils::object { - event() = default; + emulation_event() = default; - event(event&&) = delete; - event& operator=(event&&) = delete; - event(const event&) = delete; - event& operator=(const event&) = delete; + emulation_event(emulation_event&&) = delete; + emulation_event& operator=(emulation_event&&) = delete; + emulation_event(const emulation_event&) = delete; + emulation_event& operator=(const emulation_event&) = delete; - virtual event_type get_type() const = 0; + virtual emulation_event_type get_type() const = 0; - virtual void print(const generic_logger& log) const + virtual void print(generic_logger& log) const { (void)log; } }; -template -struct typed_event : event +template +struct typed_event : emulation_event { - using event::event; + using emulation_event::emulation_event; - event_type get_type() const override + emulation_event_type get_type() const override { return Type; } }; -template -class rich_event : typed_event +struct empty_data +{ +}; + +template +class rich_event : public typed_event { public: - rich_event(windows_emulator& win_emu, Data data) + rich_event(windows_emulator& win_emu, Input input = {}, Output output = {}) : win_emu(&win_emu), - data(std::move(data)) + in(std::move(input)) { } - const Data& get_data() const + const Input& get_input() const { - return this->data; + return this->in; + } + + Output& get_output() + { + return this->out; + } + + const Output& get_output() const + { + return this->out; } protected: windows_emulator* win_emu{}; - Data data{}; + Input in{}; + Output out{}; }; -struct syscall_data +struct syscall_input { uint32_t id{}; std::string_view name{}; }; -struct syscall_event : rich_event +struct syscall_output { - struct extended_info - { - uint64_t address{}; - mapped_module* origin{}; - }; + bool skip{false}; +}; - extended_info get_extended_info() const; +struct syscall_event : rich_event +{ + using rich_event::rich_event; + + void print(generic_logger& log) const override; }; struct event_manager : utils::object { - virtual void handle(const event& e); + virtual void handle(emulation_event& e); }; class printing_event_manager : public event_manager @@ -88,7 +104,7 @@ class printing_event_manager : public event_manager { } - void handle(const event& e) override + void handle(emulation_event& e) override { e.print(*this->logger_); } diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index 9495f630..b5e6232b 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -87,9 +87,14 @@ 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) + syscall_event e(c.win_emu, { + .id = syscall_id, + .name = entry->second.name, + }); + + c.win_emu.manager().handle(e); + + if (e.get_output().skip) { return; } @@ -102,38 +107,6 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu) return; } - if (mod != win_emu.mod_manager.ntdll && mod != win_emu.mod_manager.win32u) - { - 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() : ""); - } - else - { - if (mod->is_within(context.previous_ip)) - { - const auto rsp = c.emu.read_stack_pointer(); - - uint64_t return_address{}; - c.emu.try_read_memory(rsp, &return_address, sizeof(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, caller_mod_name); - } - else - { - const auto* previous_mod = win_emu.mod_manager.find_by_address(context.previous_ip); - - win_emu.log.print(color::blue, - "Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64 - " (%s)\n", - entry->second.name.c_str(), syscall_id, address, mod ? mod->name.c_str() : "", - context.previous_ip, previous_mod ? previous_mod->name.c_str() : ""); - } - } - entry->second.handler(c); } catch (std::exception& e) diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index a1fae00e..cd2a7ed8 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -5,6 +5,7 @@ #include +#include "event_manager.hpp" #include "syscall_dispatcher.hpp" #include "process_context.hpp" #include "logger.hpp" @@ -15,10 +16,6 @@ struct emulator_callbacks : module_manager::callbacks, process_context::callbacks { - utils::optional_function - on_syscall{}; - utils::optional_function on_stdout{}; }; @@ -58,6 +55,7 @@ class windows_emulator std::unique_ptr emu_{}; std::unique_ptr clock_{}; std::unique_ptr socket_factory_{}; + std::unique_ptr event_manager_{}; public: std::filesystem::path emulation_root{}; @@ -93,6 +91,16 @@ class windows_emulator return *this->emu_; } + event_manager& manager() + { + return *this->event_manager_; + } + + event_manager& manager() const + { + return *this->event_manager_; + } + utils::clock& clock() { return *this->clock_;