mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Small callback optimization and unification
This commit is contained in:
@@ -136,7 +136,7 @@ namespace
|
|||||||
if (options.silent)
|
if (options.silent)
|
||||||
{
|
{
|
||||||
win_emu.buffer_stdout = false;
|
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);
|
(void)fwrite(data.data(), 1, data.size(), stdout);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,9 @@ namespace test
|
|||||||
{
|
{
|
||||||
std::string output_buffer{};
|
std::string output_buffer{};
|
||||||
|
|
||||||
emulator_callbacks callbacks{
|
emulator_callbacks callbacks{};
|
||||||
.stdout_callback =
|
callbacks.on_stdout = [&output_buffer](const std::string_view data) {
|
||||||
[&output_buffer](const std::string_view data) {
|
output_buffer.append(data); //
|
||||||
output_buffer.append(data); //
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const emulator_settings settings{
|
const emulator_settings settings{
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ class handle_store : public generic_handle_store
|
|||||||
return blocked;
|
return blocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle store(T value)
|
std::pair<handle, T*> store_and_get(T value)
|
||||||
{
|
{
|
||||||
if (this->block_mutation_)
|
if (this->block_mutation_)
|
||||||
{
|
{
|
||||||
@@ -171,9 +171,14 @@ class handle_store : public generic_handle_store
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto index = this->find_free_index();
|
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
|
handle make_handle(const index_type index) const
|
||||||
|
|||||||
@@ -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),
|
: 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 image_base = mod.image_base;
|
||||||
const auto entry = this->modules_.try_emplace(image_base, std::move(mod));
|
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;
|
return &entry.first->second;
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
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);
|
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);
|
unmap_module(*this->memory_, mod->second);
|
||||||
this->modules_.erase(mod);
|
this->modules_.erase(mod);
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,15 @@ class logger;
|
|||||||
class module_manager
|
class module_manager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using module_map = std::map<uint64_t, mapped_module>;
|
struct callbacks
|
||||||
utils::optional_function<void(mapped_module& mod)> on_module_load{};
|
{
|
||||||
utils::optional_function<void(mapped_module& mod)> on_module_unload{};
|
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);
|
using module_map = std::map<uint64_t, mapped_module>;
|
||||||
|
|
||||||
|
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,
|
void map_main_modules(const windows_path& executable_path, const windows_path& ntdll_path,
|
||||||
const windows_path& win32u_path, const logger& logger);
|
const windows_path& win32u_path, const logger& logger);
|
||||||
@@ -61,6 +65,7 @@ class module_manager
|
|||||||
private:
|
private:
|
||||||
memory_manager* memory_{};
|
memory_manager* memory_{};
|
||||||
file_system* file_sys_{};
|
file_system* file_sys_{};
|
||||||
|
callbacks* callbacks_{};
|
||||||
|
|
||||||
module_map modules_{};
|
module_map modules_{};
|
||||||
|
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ handle process_context::create_thread(memory_manager& memory, const uint64_t sta
|
|||||||
const uint64_t stack_size)
|
const uint64_t stack_size)
|
||||||
{
|
{
|
||||||
emulator_thread t{memory, *this, start_address, argument, stack_size, ++this->spawned_thread_count};
|
emulator_thread t{memory, *this, start_address, argument, stack_size, ++this->spawned_thread_count};
|
||||||
auto h = this->threads.store(std::move(t));
|
auto [h, thr] = this->threads.store_and_get(std::move(t));
|
||||||
on_create_thread(h, *this->threads.get(h));
|
this->callbacks_->on_create_thread(h, *thr);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,15 @@ struct application_settings;
|
|||||||
|
|
||||||
struct process_context
|
struct process_context
|
||||||
{
|
{
|
||||||
process_context(x64_emulator& emu, memory_manager& memory)
|
struct callbacks
|
||||||
: base_allocator(emu),
|
{
|
||||||
|
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),
|
peb(emu),
|
||||||
process_params(emu),
|
process_params(emu),
|
||||||
kusd(memory, *this)
|
kusd(memory, *this)
|
||||||
@@ -44,14 +51,14 @@ struct process_context
|
|||||||
const emulator_settings& emu_settings, const mapped_module& executable, const mapped_module& ntdll,
|
const emulator_settings& emu_settings, const mapped_module& executable, const mapped_module& ntdll,
|
||||||
const apiset::container& apiset_container);
|
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,
|
handle create_thread(memory_manager& memory, const uint64_t start_address, const uint64_t argument,
|
||||||
const uint64_t stack_size);
|
const uint64_t stack_size);
|
||||||
|
|
||||||
void serialize(utils::buffer_serializer& buffer) const;
|
void serialize(utils::buffer_serializer& buffer) const;
|
||||||
void deserialize(utils::buffer_deserializer& buffer);
|
void deserialize(utils::buffer_deserializer& buffer);
|
||||||
|
|
||||||
|
callbacks* callbacks_{};
|
||||||
|
|
||||||
uint64_t executed_instructions{0};
|
uint64_t executed_instructions{0};
|
||||||
uint64_t current_ip{0};
|
uint64_t current_ip{0};
|
||||||
uint64_t previous_ip{0};
|
uint64_t previous_ip{0};
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
const auto* mod = win_emu.mod_manager.find_by_address(address);
|
||||||
|
|
||||||
const auto entry = this->handlers_.find(syscall_id);
|
const auto entry = this->handlers_.find(syscall_id);
|
||||||
if (entry == this->handlers_.end())
|
if (entry == this->handlers_.end())
|
||||||
{
|
{
|
||||||
@@ -80,6 +82,13 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
|||||||
return;
|
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)
|
if (!entry->second.handler)
|
||||||
{
|
{
|
||||||
win_emu.log.error("Unimplemented syscall: %s - 0x%X\n", entry->second.name.c_str(), syscall_id);
|
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;
|
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)
|
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",
|
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>");
|
entry->second.name.c_str(), syscall_id, address, mod ? mod->name.c_str() : "<N/A>");
|
||||||
}
|
}
|
||||||
@@ -106,20 +111,16 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
|||||||
uint64_t return_address{};
|
uint64_t return_address{};
|
||||||
c.emu.try_read_memory(rsp, &return_address, sizeof(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,
|
win_emu.log.print(color::dark_gray,
|
||||||
"Executing syscall: %s (0x%X) at 0x%" PRIx64 " via 0x%" PRIx64 " (%s)\n",
|
"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
|
else
|
||||||
{
|
{
|
||||||
const auto* previous_mod = win_emu.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() : "<N/A>",
|
|
||||||
entry->second.name, context.previous_ip,
|
|
||||||
previous_mod ? previous_mod->name.c_str() : "<N/A>");
|
|
||||||
|
|
||||||
win_emu.log.print(color::blue,
|
win_emu.log.print(color::blue,
|
||||||
"Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64
|
"Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64
|
||||||
" (%s)\n",
|
" (%s)\n",
|
||||||
|
|||||||
@@ -2878,7 +2878,7 @@ namespace
|
|||||||
io_status_block.write(block);
|
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"))
|
if (!temp_buffer.ends_with("\n"))
|
||||||
{
|
{
|
||||||
@@ -3613,7 +3613,7 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread->exit_status = exit_status;
|
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)
|
if (thread == c.proc.active_thread)
|
||||||
{
|
{
|
||||||
c.win_emu.yield_thread();
|
c.win_emu.yield_thread();
|
||||||
|
|||||||
@@ -184,8 +184,8 @@ windows_emulator::windows_emulator(const emulator_settings& settings, std::uniqu
|
|||||||
file_sys(emulation_root.empty() ? emulation_root : emulation_root / "filesys"),
|
file_sys(emulation_root.empty() ? emulation_root : emulation_root / "filesys"),
|
||||||
memory(*this->emu_),
|
memory(*this->emu_),
|
||||||
registry(emulation_root.empty() ? settings.registry_directory : emulation_root / "registry"),
|
registry(emulation_root.empty() ? settings.registry_directory : emulation_root / "registry"),
|
||||||
mod_manager(memory, file_sys),
|
mod_manager(memory, file_sys, callbacks),
|
||||||
process(*this->emu_, memory)
|
process(*this->emu_, memory, callbacks)
|
||||||
{
|
{
|
||||||
#ifndef OS_WINDOWS
|
#ifndef OS_WINDOWS
|
||||||
if (this->emulation_root.empty())
|
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();
|
const auto& emu = this->emu();
|
||||||
auto& context = this->process;
|
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)",
|
this->mod_manager.map_main_modules(app_settings.application, R"(C:\Windows\System32\ntdll.dll)",
|
||||||
R"(C:\Windows\System32\win32u.dll)", this->log);
|
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()
|
void windows_emulator::setup_hooks()
|
||||||
{
|
{
|
||||||
this->emu().hook_instruction(x64_hookable_instructions::syscall, [&] {
|
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);
|
this->dispatcher.dispatch(*this);
|
||||||
return instruction_hook_continuation::skip_instruction;
|
return instruction_hook_continuation::skip_instruction;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,23 +10,17 @@
|
|||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include "file_system.hpp"
|
#include "file_system.hpp"
|
||||||
#include "memory_manager.hpp"
|
#include "memory_manager.hpp"
|
||||||
|
#include "module/module_manager.hpp"
|
||||||
|
|
||||||
std::unique_ptr<x64_emulator> create_default_x64_emulator();
|
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<instruction_hook_continuation(uint32_t syscall_id, x64_emulator::pointer_type address,
|
||||||
utils::optional_function<void(uint32_t syscall_id, x64_emulator::pointer_type address, std::string_view mod_name,
|
std::string_view mod_name, std::string_view syscall_name)>
|
||||||
std::string_view syscall_name)>
|
on_syscall{};
|
||||||
inline_syscall{};
|
|
||||||
utils::optional_function<void(uint32_t syscall_id, x64_emulator::pointer_type address, std::string_view mod_name,
|
utils::optional_function<void(std::string_view)> on_stdout{};
|
||||||
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{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct application_settings
|
struct application_settings
|
||||||
@@ -57,6 +51,7 @@ class windows_emulator
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
std::filesystem::path emulation_root{};
|
std::filesystem::path emulation_root{};
|
||||||
|
emulator_callbacks callbacks{};
|
||||||
logger log{};
|
logger log{};
|
||||||
file_system file_sys;
|
file_system file_sys;
|
||||||
memory_manager memory;
|
memory_manager memory;
|
||||||
@@ -64,7 +59,6 @@ class windows_emulator
|
|||||||
module_manager mod_manager;
|
module_manager mod_manager;
|
||||||
process_context process;
|
process_context process;
|
||||||
syscall_dispatcher dispatcher;
|
syscall_dispatcher dispatcher;
|
||||||
emulator_callbacks callbacks{};
|
|
||||||
|
|
||||||
windows_emulator(const emulator_settings& settings = {},
|
windows_emulator(const emulator_settings& settings = {},
|
||||||
std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
|
std::unique_ptr<x64_emulator> emu = create_default_x64_emulator());
|
||||||
@@ -107,11 +101,6 @@ class windows_emulator
|
|||||||
void save_snapshot();
|
void save_snapshot();
|
||||||
void restore_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
|
uint16_t get_host_port(const uint16_t emulator_port) const
|
||||||
{
|
{
|
||||||
const auto entry = this->port_mappings_.find(emulator_port);
|
const auto entry = this->port_mappings_.find(emulator_port);
|
||||||
@@ -170,7 +159,6 @@ class windows_emulator
|
|||||||
bool use_relative_time_{false};
|
bool use_relative_time_{false};
|
||||||
bool silent_until_main_{false};
|
bool silent_until_main_{false};
|
||||||
|
|
||||||
std::vector<instruction_hook_callback> syscall_hooks_{};
|
|
||||||
std::unordered_map<uint16_t, uint16_t> port_mappings_{};
|
std::unordered_map<uint16_t, uint16_t> port_mappings_{};
|
||||||
|
|
||||||
std::set<std::string, std::less<>> modules_{};
|
std::set<std::string, std::less<>> modules_{};
|
||||||
|
|||||||
Reference in New Issue
Block a user