Skip to content

Commit

Permalink
Small callback optimization and unification
Browse files Browse the repository at this point in the history
  • Loading branch information
momo5502 committed Feb 14, 2025
1 parent 6b4e860 commit 012f54a
Show file tree
Hide file tree
Showing 11 changed files with 59 additions and 64 deletions.
2 changes: 1 addition & 1 deletion src/analyzer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/windows-emulator-test/time_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace test
std::string output_buffer{};

emulator_callbacks callbacks{
.stdout_callback =
.on_stdout =
[&output_buffer](const std::string_view data) {
output_buffer.append(data); //
},
Expand Down
11 changes: 8 additions & 3 deletions src/windows-emulator/handles.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,17 +163,22 @@ class handle_store : public generic_handle_store
return blocked;
}

handle store(T value)
std::pair<handle, T*> store_and_get(T value)
{
if (this->block_mutation_)
{
throw std::runtime_error("Mutation of handle store is blocked!");
}

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), &it->second};
}

return make_handle(index);
handle store(T value)
{
return this->store_and_get(std::move(value)).first;
}

handle make_handle(const index_type index) const
Expand Down
9 changes: 5 additions & 4 deletions src/windows-emulator/module/module_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);

Expand Down
11 changes: 8 additions & 3 deletions src/windows-emulator/module/module_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ class logger;
class module_manager
{
public:
struct callbacks
{
utils::optional_function<void(mapped_module& mod)> on_module_load{};
utils::optional_function<void(mapped_module& mod)> on_module_unload{};
};

using module_map = std::map<uint64_t, mapped_module>;
utils::optional_function<void(mapped_module& mod)> on_module_load{};
utils::optional_function<void(mapped_module& mod)> on_module_unload{};

module_manager(memory_manager& memory, file_system& file_sys);
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);
Expand Down Expand Up @@ -61,6 +65,7 @@ class module_manager
private:
memory_manager* memory_{};
file_system* file_sys_{};
callbacks* callbacks_{};

module_map modules_{};

Expand Down
4 changes: 2 additions & 2 deletions src/windows-emulator/process_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
15 changes: 11 additions & 4 deletions src/windows-emulator/process_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void(handle h, emulator_thread& thr)> on_create_thread{};
utils::optional_function<void(handle h, emulator_thread& thr)> 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)
Expand All @@ -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<void(handle h, emulator_thread& thr)> 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};
Expand Down
21 changes: 11 additions & 10 deletions src/windows-emulator/syscall_dispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
{
Expand All @@ -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);
Expand All @@ -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() : "<N/A>",
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() : "<N/A>");
}
Expand All @@ -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() : "<N/A>",
entry->second.name, context.previous_ip,
previous_mod ? previous_mod->name.c_str() : "<N/A>");

win_emu.log.print(color::blue,
"Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64
" (%s)\n",
Expand Down
4 changes: 2 additions & 2 deletions src/windows-emulator/syscalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
{
Expand Down Expand Up @@ -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();
Expand Down
16 changes: 2 additions & 14 deletions src/windows-emulator/windows_emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
});
Expand Down
28 changes: 8 additions & 20 deletions src/windows-emulator/windows_emulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,17 @@
#include "logger.hpp"
#include "file_system.hpp"
#include "memory_manager.hpp"
#include "module/module_manager.hpp"

std::unique_ptr<x64_emulator> create_default_x64_emulator();

struct emulator_callbacks
struct emulator_callbacks : module_manager::callbacks, process_context::callbacks
{
utils::optional_function<void(std::string_view)> stdout_callback{};
utils::optional_function<void(uint32_t syscall_id, x64_emulator::pointer_type address, std::string_view mod_name,
std::string_view syscall_name)>
inline_syscall{};
utils::optional_function<void(uint32_t syscall_id, x64_emulator::pointer_type address, std::string_view mod_name,
std::string_view syscall_name, x64_emulator::pointer_type prev_address,
std::string_view prev_mod_name)>
outofline_syscall{};
utils::optional_function<void(mapped_module& mod)> module_loaded{};
utils::optional_function<void(mapped_module& mod)> module_unloaded{};
utils::optional_function<void(handle h, emulator_thread& thr)> thread_created{};
utils::optional_function<void(handle h, emulator_thread& thr)> thread_terminated{};
utils::optional_function<instruction_hook_continuation(uint32_t syscall_id, x64_emulator::pointer_type address,
std::string_view mod_name, std::string_view syscall_name)>
on_syscall{};

utils::optional_function<void(std::string_view)> on_stdout{};
};

struct application_settings
Expand Down Expand Up @@ -57,14 +51,14 @@ class windows_emulator

public:
std::filesystem::path emulation_root{};
emulator_callbacks callbacks{};
logger log{};
file_system file_sys;
memory_manager memory;
registry_manager registry{};
module_manager mod_manager;
process_context process;
syscall_dispatcher dispatcher;
emulator_callbacks callbacks{};

windows_emulator(const emulator_settings& settings = {},
std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -170,7 +159,6 @@ class windows_emulator
bool use_relative_time_{false};
bool silent_until_main_{false};

std::vector<instruction_hook_callback> syscall_hooks_{};
std::unordered_map<uint16_t, uint16_t> port_mappings_{};

std::set<std::string, std::less<>> modules_{};
Expand Down

0 comments on commit 012f54a

Please sign in to comment.