mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Extract main module cache into module manager
This commit is contained in:
@@ -141,7 +141,7 @@ namespace
|
||||
};
|
||||
}
|
||||
|
||||
const auto& exe = *win_emu.process.executable;
|
||||
const auto& exe = *win_emu.mod_manager.executable;
|
||||
|
||||
const auto concise_logging = options.concise_logging;
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace
|
||||
|
||||
auto read_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) {
|
||||
const auto rip = win_emu.emu().read_instruction_pointer();
|
||||
if (win_emu.mod_manager.find_by_address(rip) != win_emu.process.executable)
|
||||
if (win_emu.mod_manager.find_by_address(rip) != win_emu.mod_manager.executable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -174,7 +174,7 @@ namespace
|
||||
|
||||
const auto write_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) {
|
||||
const auto rip = win_emu.emu().read_instruction_pointer();
|
||||
if (win_emu.mod_manager.find_by_address(rip) != win_emu.process.executable)
|
||||
if (win_emu.mod_manager.find_by_address(rip) != win_emu.mod_manager.executable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ emulator_hook* watch_object(windows_emulator& emu, const std::set<std::string, s
|
||||
[i = std::move(info), object, &emu, cache_logging, modules](const uint64_t address, size_t, uint64_t) {
|
||||
const auto rip = emu.emu().read_instruction_pointer();
|
||||
const auto* mod = emu.mod_manager.find_by_address(rip);
|
||||
const auto is_main_access = mod == emu.process.executable || modules.contains(mod->name);
|
||||
const auto is_main_access = mod == emu.mod_manager.executable || modules.contains(mod->name);
|
||||
|
||||
if (!emu.verbose_calls && !is_main_access)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace
|
||||
|
||||
void forward_emulator(windows_emulator& win_emu)
|
||||
{
|
||||
const auto target = win_emu.process.executable->find_export("vulnerable");
|
||||
const auto target = win_emu.mod_manager.executable->find_export("vulnerable");
|
||||
win_emu.emu().hook_memory_execution(target, 1, [&](uint64_t, size_t, uint64_t) { win_emu.emu().stop(); });
|
||||
|
||||
run_emulation(win_emu);
|
||||
|
||||
@@ -238,6 +238,6 @@ void emulator_thread::setup_registers(x64_emulator& emu, const process_context&
|
||||
unalign_stack(emu);
|
||||
|
||||
emu.reg(x64_register::rcx, ctx_obj.value());
|
||||
emu.reg(x64_register::rdx, context.ntdll->image_base);
|
||||
emu.reg(x64_register::rdx, context.ntdll_image_base);
|
||||
emu.reg(x64_register::rip, context.ldr_initialize_thunk);
|
||||
}
|
||||
|
||||
@@ -60,6 +60,14 @@ module_manager::module_manager(memory_manager& memory, file_system& file_sys)
|
||||
{
|
||||
}
|
||||
|
||||
void module_manager::map_main_modules(const windows_path& executable_path, const windows_path& ntdll_path,
|
||||
const windows_path& win32u_path, const logger& logger)
|
||||
{
|
||||
this->executable = this->map_module(executable_path, logger, true);
|
||||
this->ntdll = this->map_module(ntdll_path, logger, true);
|
||||
this->win32u = this->map_module(win32u_path, logger, true);
|
||||
}
|
||||
|
||||
mapped_module* module_manager::map_module(const windows_path& file, const logger& logger, const bool is_static)
|
||||
{
|
||||
return this->map_local_module(this->file_sys_->translate(file), logger, is_static);
|
||||
@@ -104,11 +112,23 @@ mapped_module* module_manager::map_local_module(const std::filesystem::path& fil
|
||||
void module_manager::serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write_map(this->modules_);
|
||||
|
||||
buffer.write(this->executable->image_base);
|
||||
buffer.write(this->ntdll->image_base);
|
||||
buffer.write(this->win32u->image_base);
|
||||
}
|
||||
|
||||
void module_manager::deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read_map(this->modules_);
|
||||
|
||||
const auto executable_base = buffer.read<uint64_t>();
|
||||
const auto ntdll_base = buffer.read<uint64_t>();
|
||||
const auto win32u_base = buffer.read<uint64_t>();
|
||||
|
||||
this->executable = this->find_by_address(executable_base);
|
||||
this->ntdll = this->find_by_address(ntdll_base);
|
||||
this->win32u = this->find_by_address(win32u_base);
|
||||
}
|
||||
|
||||
bool module_manager::unmap(const uint64_t address, const logger& logger)
|
||||
|
||||
@@ -12,6 +12,9 @@ class module_manager
|
||||
using module_map = std::map<uint64_t, mapped_module>;
|
||||
module_manager(memory_manager& memory, file_system& file_sys);
|
||||
|
||||
void map_main_modules(const windows_path& executable_path, const windows_path& ntdll_path,
|
||||
const windows_path& win32u_path, const logger& logger);
|
||||
|
||||
mapped_module* map_module(const windows_path& file, const logger& logger, bool is_static = false);
|
||||
mapped_module* map_local_module(const std::filesystem::path& file, const logger& logger, bool is_static = false);
|
||||
|
||||
@@ -46,6 +49,10 @@ class module_manager
|
||||
return modules_;
|
||||
}
|
||||
|
||||
mapped_module* executable{};
|
||||
mapped_module* ntdll{};
|
||||
mapped_module* win32u{};
|
||||
|
||||
private:
|
||||
memory_manager* memory_{};
|
||||
file_system* file_sys_{};
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace
|
||||
}
|
||||
|
||||
void process_context::setup(x64_emulator& emu, memory_manager& memory, const application_settings& app_settings,
|
||||
const emulator_settings& emu_settings, const uint64_t process_image_base,
|
||||
const apiset::container& apiset_container)
|
||||
const emulator_settings& emu_settings, const mapped_module& executable,
|
||||
const mapped_module& ntdll, const apiset::container& apiset_container)
|
||||
{
|
||||
setup_gdt(emu, memory);
|
||||
|
||||
@@ -92,26 +92,114 @@ void process_context::setup(x64_emulator& emu, memory_manager& memory, const app
|
||||
proc_params.MaximumLength = proc_params.Length;
|
||||
});
|
||||
|
||||
this->peb.access([&](PEB64& peb) {
|
||||
peb.ImageBaseAddress = process_image_base;
|
||||
peb.ProcessParameters = this->process_params.ptr();
|
||||
peb.ApiSetMap = apiset::clone(emu, allocator, apiset_container).ptr();
|
||||
this->peb.access([&](PEB64& p) {
|
||||
p.ImageBaseAddress = executable.image_base;
|
||||
p.ProcessParameters = this->process_params.ptr();
|
||||
p.ApiSetMap = apiset::clone(emu, allocator, apiset_container).ptr();
|
||||
|
||||
peb.ProcessHeap = nullptr;
|
||||
peb.ProcessHeaps = nullptr;
|
||||
peb.HeapSegmentReserve = 0x0000000000100000; // TODO: Read from executable
|
||||
peb.HeapSegmentCommit = 0x0000000000002000;
|
||||
peb.HeapDeCommitTotalFreeThreshold = 0x0000000000010000;
|
||||
peb.HeapDeCommitFreeBlockThreshold = 0x0000000000001000;
|
||||
peb.NumberOfHeaps = 0x00000000;
|
||||
peb.MaximumNumberOfHeaps = 0x00000010;
|
||||
p.ProcessHeap = nullptr;
|
||||
p.ProcessHeaps = nullptr;
|
||||
p.HeapSegmentReserve = 0x0000000000100000; // TODO: Read from executable
|
||||
p.HeapSegmentCommit = 0x0000000000002000;
|
||||
p.HeapDeCommitTotalFreeThreshold = 0x0000000000010000;
|
||||
p.HeapDeCommitFreeBlockThreshold = 0x0000000000001000;
|
||||
p.NumberOfHeaps = 0x00000000;
|
||||
p.MaximumNumberOfHeaps = 0x00000010;
|
||||
|
||||
peb.OSPlatformId = 2;
|
||||
peb.OSMajorVersion = 0x0000000a;
|
||||
peb.OSBuildNumber = 0x00006c51;
|
||||
p.OSPlatformId = 2;
|
||||
p.OSMajorVersion = 0x0000000a;
|
||||
p.OSBuildNumber = 0x00006c51;
|
||||
|
||||
// peb.AnsiCodePageData = allocator.reserve<CPTABLEINFO>().value();
|
||||
// peb.OemCodePageData = allocator.reserve<CPTABLEINFO>().value();
|
||||
peb.UnicodeCaseTableData = allocator.reserve<NLSTABLEINFO>().value();
|
||||
// p.AnsiCodePageData = allocator.reserve<CPTABLEINFO>().value();
|
||||
// p.OemCodePageData = allocator.reserve<CPTABLEINFO>().value();
|
||||
p.UnicodeCaseTableData = allocator.reserve<NLSTABLEINFO>().value();
|
||||
});
|
||||
|
||||
this->ntdll_image_base = ntdll.image_base;
|
||||
this->ldr_initialize_thunk = ntdll.find_export("LdrInitializeThunk");
|
||||
this->rtl_user_thread_start = ntdll.find_export("RtlUserThreadStart");
|
||||
this->ki_user_exception_dispatcher = ntdll.find_export("KiUserExceptionDispatcher");
|
||||
|
||||
this->default_register_set = emu.save_registers();
|
||||
}
|
||||
|
||||
void process_context::serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->executed_instructions);
|
||||
buffer.write(this->current_ip);
|
||||
buffer.write(this->previous_ip);
|
||||
buffer.write_optional(this->exception_rip);
|
||||
buffer.write_optional(this->exit_status);
|
||||
buffer.write(this->base_allocator);
|
||||
buffer.write(this->peb);
|
||||
buffer.write(this->process_params);
|
||||
buffer.write(this->kusd);
|
||||
|
||||
buffer.write(this->ntdll_image_base);
|
||||
buffer.write(this->ldr_initialize_thunk);
|
||||
buffer.write(this->rtl_user_thread_start);
|
||||
buffer.write(this->ki_user_exception_dispatcher);
|
||||
|
||||
buffer.write(this->events);
|
||||
buffer.write(this->files);
|
||||
buffer.write(this->sections);
|
||||
buffer.write(this->devices);
|
||||
buffer.write(this->semaphores);
|
||||
buffer.write(this->ports);
|
||||
buffer.write(this->mutants);
|
||||
buffer.write(this->registry_keys);
|
||||
buffer.write_map(this->atoms);
|
||||
|
||||
buffer.write_vector(this->default_register_set);
|
||||
buffer.write(this->spawned_thread_count);
|
||||
buffer.write(this->threads);
|
||||
|
||||
buffer.write(this->threads.find_handle(this->active_thread).bits);
|
||||
}
|
||||
|
||||
void process_context::deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read(this->executed_instructions);
|
||||
buffer.read(this->current_ip);
|
||||
buffer.read(this->previous_ip);
|
||||
buffer.read_optional(this->exception_rip);
|
||||
buffer.read_optional(this->exit_status);
|
||||
buffer.read(this->base_allocator);
|
||||
buffer.read(this->peb);
|
||||
buffer.read(this->process_params);
|
||||
buffer.read(this->kusd);
|
||||
|
||||
buffer.read(this->ntdll_image_base);
|
||||
buffer.read(this->ldr_initialize_thunk);
|
||||
buffer.read(this->rtl_user_thread_start);
|
||||
buffer.read(this->ki_user_exception_dispatcher);
|
||||
|
||||
buffer.read(this->events);
|
||||
buffer.read(this->files);
|
||||
buffer.read(this->sections);
|
||||
buffer.read(this->devices);
|
||||
buffer.read(this->semaphores);
|
||||
buffer.read(this->ports);
|
||||
buffer.read(this->mutants);
|
||||
buffer.read(this->registry_keys);
|
||||
buffer.read_map(this->atoms);
|
||||
|
||||
buffer.read_vector(this->default_register_set);
|
||||
buffer.read(this->spawned_thread_count);
|
||||
|
||||
for (auto& thread : this->threads | std::views::values)
|
||||
{
|
||||
thread.leak_memory();
|
||||
}
|
||||
|
||||
buffer.read(this->threads);
|
||||
|
||||
this->active_thread = this->threads.get(buffer.read<uint64_t>());
|
||||
}
|
||||
|
||||
handle process_context::create_thread(memory_manager& memory, const uint64_t start_address, const uint64_t argument,
|
||||
const uint64_t stack_size)
|
||||
{
|
||||
emulator_thread t{memory, *this, start_address, argument, stack_size, ++this->spawned_thread_count};
|
||||
return this->threads.store(std::move(t));
|
||||
}
|
||||
|
||||
@@ -41,9 +41,15 @@ struct process_context
|
||||
}
|
||||
|
||||
void setup(x64_emulator& emu, memory_manager& memory, const application_settings& app_settings,
|
||||
const emulator_settings& emu_settings, const uint64_t process_image_base,
|
||||
const emulator_settings& emu_settings, const mapped_module& executable, const mapped_module& ntdll,
|
||||
const apiset::container& apiset_container);
|
||||
|
||||
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);
|
||||
|
||||
uint64_t executed_instructions{0};
|
||||
uint64_t current_ip{0};
|
||||
uint64_t previous_ip{0};
|
||||
@@ -57,11 +63,7 @@ struct process_context
|
||||
emulator_object<RTL_USER_PROCESS_PARAMETERS64> process_params;
|
||||
kusd_mmio kusd;
|
||||
|
||||
// TODO: Remove this
|
||||
mapped_module* executable{};
|
||||
mapped_module* ntdll{};
|
||||
mapped_module* win32u{};
|
||||
|
||||
uint64_t ntdll_image_base{};
|
||||
uint64_t ldr_initialize_thunk{};
|
||||
uint64_t rtl_user_thread_start{};
|
||||
uint64_t ki_user_exception_dispatcher{};
|
||||
@@ -81,97 +83,4 @@ struct process_context
|
||||
uint32_t spawned_thread_count{0};
|
||||
handle_store<handle_types::thread, emulator_thread> threads{};
|
||||
emulator_thread* active_thread{nullptr};
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->executed_instructions);
|
||||
buffer.write(this->current_ip);
|
||||
buffer.write(this->previous_ip);
|
||||
buffer.write_optional(this->exception_rip);
|
||||
buffer.write_optional(this->exit_status);
|
||||
buffer.write(this->base_allocator);
|
||||
buffer.write(this->peb);
|
||||
buffer.write(this->process_params);
|
||||
buffer.write(this->kusd);
|
||||
|
||||
buffer.write(this->executable->image_base);
|
||||
buffer.write(this->ntdll->image_base);
|
||||
buffer.write(this->win32u->image_base);
|
||||
|
||||
buffer.write(this->ldr_initialize_thunk);
|
||||
buffer.write(this->rtl_user_thread_start);
|
||||
buffer.write(this->ki_user_exception_dispatcher);
|
||||
|
||||
buffer.write(this->events);
|
||||
buffer.write(this->files);
|
||||
buffer.write(this->sections);
|
||||
buffer.write(this->devices);
|
||||
buffer.write(this->semaphores);
|
||||
buffer.write(this->ports);
|
||||
buffer.write(this->mutants);
|
||||
buffer.write(this->registry_keys);
|
||||
buffer.write_map(this->atoms);
|
||||
|
||||
buffer.write_vector(this->default_register_set);
|
||||
buffer.write(this->spawned_thread_count);
|
||||
buffer.write(this->threads);
|
||||
|
||||
buffer.write(this->threads.find_handle(this->active_thread).bits);
|
||||
}
|
||||
|
||||
void deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read(this->executed_instructions);
|
||||
buffer.read(this->current_ip);
|
||||
buffer.read(this->previous_ip);
|
||||
buffer.read_optional(this->exception_rip);
|
||||
buffer.read_optional(this->exit_status);
|
||||
buffer.read(this->base_allocator);
|
||||
buffer.read(this->peb);
|
||||
buffer.read(this->process_params);
|
||||
buffer.read(this->kusd);
|
||||
|
||||
const auto executable_base = buffer.read<uint64_t>();
|
||||
const auto ntdll_base = buffer.read<uint64_t>();
|
||||
const auto win32u_base = buffer.read<uint64_t>();
|
||||
|
||||
auto& mod_manager = buffer.read<module_manager_wrapper>().get();
|
||||
|
||||
this->executable = mod_manager.find_by_address(executable_base);
|
||||
this->ntdll = mod_manager.find_by_address(ntdll_base);
|
||||
this->win32u = mod_manager.find_by_address(win32u_base);
|
||||
|
||||
buffer.read(this->ldr_initialize_thunk);
|
||||
buffer.read(this->rtl_user_thread_start);
|
||||
buffer.read(this->ki_user_exception_dispatcher);
|
||||
|
||||
buffer.read(this->events);
|
||||
buffer.read(this->files);
|
||||
buffer.read(this->sections);
|
||||
buffer.read(this->devices);
|
||||
buffer.read(this->semaphores);
|
||||
buffer.read(this->ports);
|
||||
buffer.read(this->mutants);
|
||||
buffer.read(this->registry_keys);
|
||||
buffer.read_map(this->atoms);
|
||||
|
||||
buffer.read_vector(this->default_register_set);
|
||||
buffer.read(this->spawned_thread_count);
|
||||
|
||||
for (auto& thread : this->threads | std::views::values)
|
||||
{
|
||||
thread.leak_memory();
|
||||
}
|
||||
|
||||
buffer.read(this->threads);
|
||||
|
||||
this->active_thread = this->threads.get(buffer.read<uint64_t>());
|
||||
}
|
||||
|
||||
handle create_thread(memory_manager& memory, const uint64_t start_address, const uint64_t argument,
|
||||
const uint64_t stack_size)
|
||||
{
|
||||
emulator_thread t{memory, *this, start_address, argument, stack_size, ++this->spawned_thread_count};
|
||||
return this->threads.store(std::move(t));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,7 +89,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
||||
}
|
||||
|
||||
const auto* mod = win_emu.mod_manager.find_by_address(address);
|
||||
if (mod != context.ntdll && mod != context.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);
|
||||
|
||||
@@ -1301,7 +1301,7 @@ namespace
|
||||
|
||||
const emulator_object<SECTION_IMAGE_INFORMATION<EmulatorTraits<Emu64>>> info{c.emu, process_information};
|
||||
info.access([&](SECTION_IMAGE_INFORMATION<EmulatorTraits<Emu64>>& i) {
|
||||
const auto& mod = *c.proc.executable;
|
||||
const auto& mod = *c.win_emu.mod_manager.executable;
|
||||
|
||||
const emulator_object<PEDosHeader_t> dos_header_obj{c.emu, mod.image_base};
|
||||
const auto dos_header = dos_header_obj.read();
|
||||
|
||||
@@ -217,32 +217,26 @@ windows_emulator::~windows_emulator() = default;
|
||||
|
||||
void windows_emulator::setup_process(const application_settings& app_settings, const emulator_settings& emu_settings)
|
||||
{
|
||||
auto& emu = this->emu();
|
||||
|
||||
const auto& emu = this->emu();
|
||||
auto& context = this->process;
|
||||
|
||||
auto* exe = this->mod_manager.map_module(app_settings.application, this->log, true);
|
||||
this->mod_manager.map_main_modules(app_settings.application, R"(C:\Windows\System32\ntdll.dll)",
|
||||
R"(C:\Windows\System32\win32u.dll)", this->log);
|
||||
|
||||
const auto* executable = this->mod_manager.executable;
|
||||
const auto* ntdll = this->mod_manager.ntdll;
|
||||
const auto* win32u = this->mod_manager.win32u;
|
||||
|
||||
const auto apiset_data = apiset::obtain(this->emulation_root);
|
||||
|
||||
this->process.setup(this->emu(), this->memory, app_settings, emu_settings, exe->image_base, apiset_data);
|
||||
this->process.setup(this->emu(), this->memory, app_settings, emu_settings, *executable, *ntdll, apiset_data);
|
||||
|
||||
context.executable = exe;
|
||||
context.ntdll = this->mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log, true);
|
||||
context.win32u = this->mod_manager.map_module(R"(C:\Windows\System32\win32u.dll)", this->log, true);
|
||||
const auto ntdll_data = emu.read_memory(ntdll->image_base, ntdll->size_of_image);
|
||||
const auto win32u_data = emu.read_memory(win32u->image_base, win32u->size_of_image);
|
||||
|
||||
const auto ntdll_data = emu.read_memory(context.ntdll->image_base, context.ntdll->size_of_image);
|
||||
const auto win32u_data = emu.read_memory(context.win32u->image_base, context.win32u->size_of_image);
|
||||
this->dispatcher.setup(ntdll->exports, ntdll_data, win32u->exports, win32u_data);
|
||||
|
||||
this->dispatcher.setup(context.ntdll->exports, ntdll_data, context.win32u->exports, win32u_data);
|
||||
|
||||
context.ldr_initialize_thunk = context.ntdll->find_export("LdrInitializeThunk");
|
||||
context.rtl_user_thread_start = context.ntdll->find_export("RtlUserThreadStart");
|
||||
context.ki_user_exception_dispatcher = context.ntdll->find_export("KiUserExceptionDispatcher");
|
||||
|
||||
context.default_register_set = emu.save_registers();
|
||||
|
||||
const auto main_thread_id = context.create_thread(this->memory, context.executable->entry_point, 0, 0);
|
||||
const auto main_thread_id = context.create_thread(this->memory, this->mod_manager.executable->entry_point, 0, 0);
|
||||
switch_to_thread(*this, main_thread_id);
|
||||
}
|
||||
|
||||
@@ -305,8 +299,8 @@ void windows_emulator::on_instruction_execution(const uint64_t address)
|
||||
(previous_binary && this->modules_.contains(previous_binary->name));
|
||||
};
|
||||
|
||||
const auto is_main_exe = this->process.executable->is_within(address);
|
||||
const auto is_interesting_call = process.executable->is_within(this->process.previous_ip) //
|
||||
const auto is_main_exe = this->mod_manager.executable->is_within(address);
|
||||
const auto is_interesting_call = this->mod_manager.executable->is_within(this->process.previous_ip) //
|
||||
|| is_main_exe //
|
||||
|| is_in_interesting_module();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user