Skip to content

Commit

Permalink
Implement more efficient export logging
Browse files Browse the repository at this point in the history
Unicorn hooks are expensive. It seems to iterate all hooks every
time an instruction is executed. Therefore more hooks -> slower execution.

Instead, we'll have one hook. Within that hook we'll check if the address
is within a mapped binary. If so, we then check if it is and export and
log when true. That's far more efficient than checking all hooks every time.
  • Loading branch information
momo5502 committed Sep 8, 2024
1 parent 9c5b65b commit 01b1d42
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 53 deletions.
56 changes: 42 additions & 14 deletions src/windows_emulator/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,21 +783,21 @@ namespace

auto context = setup_context(*emu);

context.executable = *map_file(*emu, R"(C:\Users\mauri\Desktop\ConsoleApplication6.exe)");
context.executable = map_file(context, *emu, R"(C:\Users\mauri\Desktop\boiii.exe)");

context.peb.access([&](PEB& peb)
{
peb.ImageBaseAddress = reinterpret_cast<void*>(context.executable.image_base);
peb.ImageBaseAddress = reinterpret_cast<void*>(context.executable->image_base);
});

context.ntdll = *map_file(*emu, R"(C:\Windows\System32\ntdll.dll)");
context.ntdll = map_file(context, *emu, R"(C:\Windows\System32\ntdll.dll)");

const auto ldr_initialize_thunk = find_exported_function(context.ntdll.exports, "LdrInitializeThunk");
const auto rtl_user_thread_start = find_exported_function(context.ntdll.exports, "RtlUserThreadStart");
const auto ldr_initialize_thunk = find_exported_function(context.ntdll->exports, "LdrInitializeThunk");
const auto rtl_user_thread_start = find_exported_function(context.ntdll->exports, "RtlUserThreadStart");
const auto ki_user_exception_dispatcher = find_exported_function(
context.ntdll.exports, "KiUserExceptionDispatcher");
context.ntdll->exports, "KiUserExceptionDispatcher");

syscall_dispatcher dispatcher{context.ntdll.exports};
syscall_dispatcher dispatcher{context.ntdll->exports};

emu->hook_instruction(x64_hookable_instructions::syscall, [&]
{
Expand Down Expand Up @@ -843,14 +843,42 @@ namespace
});

/*
watch_object(*emu, context.teb);
watch_object(*emu, context.peb);
watch_object(*emu, context.process_params);
watch_object(*emu, context.kusd);
*/
watch_object(*emu, context.teb);
watch_object(*emu, context.peb);
watch_object(*emu, context.process_params);
watch_object(*emu, context.kusd);
*/

emu->hook_memory_execution(0, std::numeric_limits<size_t>::max(), [&](const uint64_t address, const size_t)
{
++context.executed_instructions;

const mapped_binary* binary{nullptr};
for (const auto& entry : context.mapped_binaries)
{
const auto& mod = entry.second;
if (is_within_start_and_length(address, mod->image_base, mod->size_of_image))
{
binary = mod.get();
break;
}

if (address < mod->image_base)
{
break;
}
}

if (binary)
{
const auto export_entry = binary->export_remap.find(address);
if (export_entry != binary->export_remap.end())
{
printf("Executing function: %s - %s (%llX)\n", binary->name.c_str(), export_entry->second.c_str(),
address);
}
}

if (!context.verbose)
{
return;
Expand All @@ -872,15 +900,15 @@ namespace
context_frame::save(*emu, ctx);

ctx.Rip = rtl_user_thread_start;
ctx.Rcx = context.executable.entry_point;
ctx.Rcx = context.executable->entry_point;

const auto ctx_obj = allocate_object_on_stack<CONTEXT>(*emu);
ctx_obj.write(ctx);

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, ldr_initialize_thunk);

try
Expand Down
47 changes: 17 additions & 30 deletions src/windows_emulator/module_mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ namespace

binary.exports.push_back(std::move(symbol));
}

for (const auto& symbol : binary.exports)
{
binary.export_remap.try_emplace(symbol.address, symbol.name);
}
}

void apply_relocations(x64_emulator& emu, const mapped_binary& binary,
Expand Down Expand Up @@ -148,32 +153,12 @@ namespace
}
}

void hook_exports(emulator& emu, const mapped_binary& binary, const std::filesystem::path& file)
{
const auto filename = file.filename().string();

std::unordered_map<uint64_t, std::string> export_remap{};
for (const auto& symbol : binary.exports)
{
export_remap.try_emplace(symbol.address, symbol.name);
}

for (const auto& exp : export_remap)
{
auto name = exp.second;
emu.hook_memory_execution(exp.first, 0,
[n = std::move(name), filename](const uint64_t address, const size_t)
{
printf("Executing function: %s - %s (%llX)\n", filename.c_str(), n.c_str(),
address);
});
}
}

mapped_binary map_module(x64_emulator& emu, const std::vector<uint8_t>& module_data,
const std::string& name)
std::filesystem::path file)
{
mapped_binary binary{};
binary.path = std::move(file);
binary.name = binary.path.filename().string();

// TODO: Range checks
auto* ptr = module_data.data();
Expand All @@ -196,10 +181,9 @@ namespace
}
}


binary.entry_point = binary.image_base + optional_header.AddressOfEntryPoint;

printf("Mapping %s at %llX\n", name.c_str(), binary.image_base);
printf("Mapping %s at %llX\n", binary.path.generic_string().c_str(), binary.image_base);

emu.write_memory(binary.image_base, ptr, optional_header.SizeOfHeaders);

Expand All @@ -217,17 +201,20 @@ namespace
}
}

std::optional<mapped_binary> map_file(x64_emulator& emu, const std::filesystem::path& file)
mapped_binary* map_file(process_context& context, x64_emulator& emu, std::filesystem::path file)
{
const auto data = load_file(file);
if (data.empty())
{
return {};
return nullptr;
}

auto binary = map_module(emu, data, file.generic_string());
auto binary = map_module(emu, data, std::move(file));
auto binary_ptr = std::make_unique<mapped_binary>(std::move(binary));
auto* res = binary_ptr.get();

hook_exports(emu, binary, file);
const auto image_base = binary_ptr->image_base;
context.mapped_binaries[image_base] = std::move(binary_ptr);

return binary;
return res;
}
2 changes: 1 addition & 1 deletion src/windows_emulator/module_mapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
#include "process_context.hpp"
#include <x64_emulator.hpp>

std::optional<mapped_binary> map_file(x64_emulator& emu, const std::filesystem::path& file);
mapped_binary* map_file(process_context& context, x64_emulator& emu, std::filesystem::path file);
9 changes: 7 additions & 2 deletions src/windows_emulator/process_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ using exported_symbols = std::vector<exported_symbol>;

struct mapped_binary
{
std::filesystem::path path{};
std::string name{};
uint64_t image_base{};
uint64_t size_of_image{};
uint64_t entry_point{};
exported_symbols exports{};
std::unordered_map<uint64_t, std::string> export_remap{};
};

struct event
Expand Down Expand Up @@ -51,8 +54,10 @@ struct process_context
emulator_object<RTL_USER_PROCESS_PARAMETERS> process_params{};
emulator_object<KUSER_SHARED_DATA> kusd{};

mapped_binary executable{};
mapped_binary ntdll{};
std::map<uint64_t, std::unique_ptr<mapped_binary>> mapped_binaries{};

mapped_binary* executable{};
mapped_binary* ntdll{};

handle_store<handle_types::event, event> events{};
handle_store<handle_types::file, file> files{};
Expand Down
12 changes: 6 additions & 6 deletions src/windows_emulator/syscalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ namespace
{
if (fs_information_class != FileFsDeviceInformation)
{
printf("Unsupported process info class: %X\n", fs_information_class);
printf("Unsupported fs info class: %X\n", fs_information_class);
c.emu.stop();
return STATUS_NOT_SUPPORTED;
}
Expand Down Expand Up @@ -396,8 +396,8 @@ namespace
return STATUS_INVALID_HANDLE;
}

const auto binary = map_file(c.emu, section_entry->name);
if (!binary.has_value())
const auto binary = map_file(c.proc, c.emu, section_entry->name);
if (!binary)
{
return STATUS_FILE_INVALID;
}
Expand Down Expand Up @@ -491,7 +491,7 @@ namespace
return STATUS_BUFFER_OVERFLOW;
}

if (!is_within_start_and_length(base_address, c.proc.ntdll.image_base, c.proc.ntdll.size_of_image))
if (!is_within_start_and_length(base_address, c.proc.ntdll->image_base, c.proc.ntdll->size_of_image))
{
puts("Bad image request");
c.emu.stop();
Expand All @@ -502,8 +502,8 @@ namespace

info.access([&](MEMORY_IMAGE_INFORMATION& image_info)
{
image_info.ImageBase = reinterpret_cast<void*>(c.proc.ntdll.image_base);
image_info.SizeOfImage = c.proc.ntdll.size_of_image;
image_info.ImageBase = reinterpret_cast<void*>(c.proc.ntdll->image_base);
image_info.SizeOfImage = c.proc.ntdll->size_of_image;
});

return STATUS_SUCCESS;
Expand Down

0 comments on commit 01b1d42

Please sign in to comment.