mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-19 19:53:56 +00:00
Merge development progress (#41)
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
#include <windows_emulator.hpp>
|
||||
#include <debugging/win_x64_gdb_stub_handler.hpp>
|
||||
|
||||
//#define CONCISE_EMULATOR_OUTPUT
|
||||
|
||||
#include "object_watching.hpp"
|
||||
|
||||
bool use_gdb = false;
|
||||
@@ -98,6 +100,9 @@ namespace
|
||||
emulator_settings settings{
|
||||
.application = argv[0],
|
||||
.arguments = parse_arguments(argv, argc),
|
||||
#ifdef CONCISE_EMULATOR_OUTPUT
|
||||
.silent_until_main = true,
|
||||
#endif
|
||||
};
|
||||
|
||||
windows_emulator win_emu{std::move(settings)};
|
||||
@@ -109,18 +114,54 @@ namespace
|
||||
|
||||
const auto& exe = *win_emu.process().executable;
|
||||
|
||||
const auto text_start = exe.image_base + 0x1000;
|
||||
const auto text_end = exe.image_base + 0x52000;
|
||||
constexpr auto scan_size = 0x100;
|
||||
|
||||
win_emu.emu().hook_memory_read(text_start, scan_size, [&](const uint64_t address, size_t, uint64_t)
|
||||
for (const auto& section : exe.sections)
|
||||
{
|
||||
const auto rip = win_emu.emu().read_instruction_pointer();
|
||||
if (rip >= text_start && rip < text_end)
|
||||
if ((section.region.permissions & memory_permission::exec) != memory_permission::exec)
|
||||
{
|
||||
win_emu.logger.print(color::green, "Reading from executable .text: 0x%llX at 0x%llX\n", address, rip);
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
||||
auto read_handler = [&, section](const uint64_t address, size_t, uint64_t)
|
||||
{
|
||||
const auto rip = win_emu.emu().read_instruction_pointer();
|
||||
if (rip >= section.region.start && rip < section.region.start + section.
|
||||
region.length)
|
||||
{
|
||||
#ifdef CONCISE_EMULATOR_OUTPUT
|
||||
static uint64_t count{0};
|
||||
++count;
|
||||
if (count > 100 && count % 10000 != 0) return;
|
||||
#endif
|
||||
|
||||
win_emu.logger.print(
|
||||
color::green,
|
||||
"Reading from executable section %s: 0x%llX at 0x%llX\n",
|
||||
section.name.c_str(), address, rip);
|
||||
}
|
||||
};
|
||||
|
||||
const auto write_handler = [&, section](const uint64_t address, size_t, uint64_t)
|
||||
{
|
||||
const auto rip = win_emu.emu().read_instruction_pointer();
|
||||
if (rip >= section.region.start && rip < section.region.start + section.
|
||||
region.length)
|
||||
{
|
||||
#ifdef CONCISE_EMULATOR_OUTPUT
|
||||
static uint64_t count{0};
|
||||
++count;
|
||||
if (count > 100 && count % 10000 != 0) return;
|
||||
#endif
|
||||
|
||||
win_emu.logger.print(
|
||||
color::cyan,
|
||||
"Writing to executable section %s: 0x%llX at 0x%llX\n",
|
||||
section.name.c_str(), address, rip);
|
||||
}
|
||||
};
|
||||
|
||||
win_emu.emu().hook_memory_read(section.region.start, section.region.length, std::move(read_handler));
|
||||
win_emu.emu().hook_memory_write(section.region.start, section.region.length, std::move(write_handler));
|
||||
}
|
||||
|
||||
run_emulation(win_emu);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ emulator_hook* watch_object(windows_emulator& emu, emulator_object<T> object)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CACHE_OBJECT_ADDRESSES
|
||||
#if defined(CACHE_OBJECT_ADDRESSES) || defined(CONCISE_EMULATOR_OUTPUT)
|
||||
static std::unordered_set<uint64_t> logged_addresses{};
|
||||
if (is_main_access && !logged_addresses.insert(address).second)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
#include "memory_permission.hpp"
|
||||
|
||||
struct basic_memory_region
|
||||
{
|
||||
uint64_t start{};
|
||||
size_t length{};
|
||||
memory_permission pemissions{};
|
||||
};
|
||||
|
||||
struct memory_region : basic_memory_region
|
||||
{
|
||||
bool committed{};
|
||||
};
|
||||
#pragma once
|
||||
#include "memory_permission.hpp"
|
||||
|
||||
struct basic_memory_region
|
||||
{
|
||||
uint64_t start{};
|
||||
size_t length{};
|
||||
memory_permission permissions{};
|
||||
};
|
||||
|
||||
struct memory_region : basic_memory_region
|
||||
{
|
||||
bool committed{};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <memory_region.hpp>
|
||||
|
||||
struct exported_symbol
|
||||
{
|
||||
@@ -11,6 +12,12 @@ struct exported_symbol
|
||||
using exported_symbols = std::vector<exported_symbol>;
|
||||
using address_name_mapping = std::map<uint64_t, std::string>;
|
||||
|
||||
struct mapped_section
|
||||
{
|
||||
std::string name{};
|
||||
basic_memory_region region{};
|
||||
};
|
||||
|
||||
struct mapped_module
|
||||
{
|
||||
std::string name{};
|
||||
@@ -23,6 +30,8 @@ struct mapped_module
|
||||
exported_symbols exports{};
|
||||
address_name_mapping address_names{};
|
||||
|
||||
std::vector<mapped_section> sections{};
|
||||
|
||||
bool is_within(const uint64_t address) const
|
||||
{
|
||||
return address >= this->image_base && address < (this->image_base + this->size_of_image);
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace
|
||||
return nt_headers_offset + (first_section_absolute - absolute_base);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> read_mapped_memory(emulator& emu, const mapped_module& binary)
|
||||
std::vector<uint8_t> read_mapped_memory(const emulator& emu, const mapped_module& binary)
|
||||
{
|
||||
std::vector<uint8_t> memory{};
|
||||
memory.resize(binary.size_of_image);
|
||||
@@ -132,7 +132,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void map_sections(emulator& emu, const mapped_module& binary,
|
||||
void map_sections(emulator& emu, mapped_module& binary,
|
||||
const utils::safe_buffer_accessor<const uint8_t> buffer,
|
||||
const IMAGE_NT_HEADERS& nt_headers, const uint64_t nt_headers_offset)
|
||||
{
|
||||
@@ -171,6 +171,18 @@ namespace
|
||||
const auto size_of_section = page_align_up(std::max(section.SizeOfRawData, section.Misc.VirtualSize));
|
||||
|
||||
emu.protect_memory(target_ptr, size_of_section, permissions, nullptr);
|
||||
|
||||
mapped_section section_info{};
|
||||
section_info.region.start = target_ptr;
|
||||
section_info.region.length = size_of_section;
|
||||
section_info.region.permissions = permissions;
|
||||
|
||||
for (size_t j = 0; j < sizeof(section.Name) && section.Name[j]; ++j)
|
||||
{
|
||||
section_info.name.push_back(static_cast<char>(section.Name[j]));
|
||||
}
|
||||
|
||||
binary.sections.push_back(std::move(section_info));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +202,7 @@ namespace
|
||||
auto& optional_header = nt_headers.OptionalHeader;
|
||||
|
||||
binary.image_base = optional_header.ImageBase;
|
||||
binary.size_of_image = optional_header.SizeOfImage; // TODO: Sanitize
|
||||
binary.size_of_image = page_align_up(optional_header.SizeOfImage); // TODO: Sanitize
|
||||
|
||||
if (!emu.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::read))
|
||||
{
|
||||
|
||||
@@ -104,7 +104,7 @@ void syscall_dispatcher::dispatch(windows_emulator& win_emu)
|
||||
const auto return_address = c.emu.read_memory<uint64_t>(rsp);
|
||||
const auto* mod_name = context.module_manager.find_name(return_address);
|
||||
|
||||
win_emu.logger.print(color::dark_gray, "Executing syscall: %s (0x%X) at 0x%llX via %llX (%s)\n",
|
||||
win_emu.logger.print(color::dark_gray, "Executing syscall: %s (0x%X) at 0x%llX via 0x%llX (%s)\n",
|
||||
entry->second.name.c_str(),
|
||||
syscall_id, address, return_address, mod_name);
|
||||
}
|
||||
|
||||
@@ -309,6 +309,12 @@ namespace
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (info_class == ThreadHideFromDebugger)
|
||||
{
|
||||
c.win_emu.logger.print(color::pink, "--> Hiding thread %X from debugger!\n", thread->id);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (info_class == ThreadNameInformation)
|
||||
{
|
||||
if (thread_information_length != sizeof(THREAD_NAME_INFORMATION))
|
||||
@@ -354,7 +360,7 @@ namespace
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Unsupported thread info class: %X\n", info_class);
|
||||
printf("Unsupported thread set info class: %X\n", info_class);
|
||||
c.emu.stop();
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
@@ -800,7 +806,7 @@ namespace
|
||||
: (region_info.is_reserved
|
||||
? MEM_RESERVE
|
||||
: MEM_FREE);
|
||||
image_info.Protect = map_emulator_to_nt_protection(region_info.pemissions);
|
||||
image_info.Protect = map_emulator_to_nt_protection(region_info.permissions);
|
||||
image_info.Type = MEM_PRIVATE;
|
||||
});
|
||||
|
||||
@@ -1235,7 +1241,7 @@ namespace
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (info_class == ProcessDefaultHardErrorMode)
|
||||
if (info_class == ProcessDefaultHardErrorMode || info_class == ProcessWx86Information)
|
||||
{
|
||||
if (return_length)
|
||||
{
|
||||
@@ -1259,6 +1265,24 @@ namespace
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (info_class == ProcessTimes)
|
||||
{
|
||||
if (return_length)
|
||||
{
|
||||
return_length.write(sizeof(KERNEL_USER_TIMES));
|
||||
}
|
||||
|
||||
if (process_information_length != sizeof(KERNEL_USER_TIMES))
|
||||
{
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
const emulator_object<KERNEL_USER_TIMES> info{c.emu, process_information};
|
||||
info.write(KERNEL_USER_TIMES{});
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (info_class == ProcessBasicInformation)
|
||||
{
|
||||
if (return_length)
|
||||
@@ -1323,9 +1347,13 @@ namespace
|
||||
const uint32_t thread_information_length,
|
||||
const emulator_object<uint32_t> return_length)
|
||||
{
|
||||
if (thread_handle != CURRENT_THREAD)
|
||||
const auto* thread = thread_handle == CURRENT_THREAD
|
||||
? c.proc.active_thread
|
||||
: c.proc.threads.get(thread_handle);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (info_class == ThreadBasicInformation)
|
||||
@@ -1343,8 +1371,8 @@ namespace
|
||||
const emulator_object<THREAD_BASIC_INFORMATION> info{c.emu, thread_information};
|
||||
info.access([&](THREAD_BASIC_INFORMATION& i)
|
||||
{
|
||||
i.TebBaseAddress = c.win_emu.current_thread().teb->ptr();
|
||||
i.ClientId = c.win_emu.current_thread().teb->read().ClientId;
|
||||
i.TebBaseAddress = thread->teb->ptr();
|
||||
i.ClientId = thread->teb->read().ClientId;
|
||||
});
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
@@ -1368,7 +1396,25 @@ namespace
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Unsupported thread info class: %X\n", info_class);
|
||||
if (info_class == ThreadQuerySetWin32StartAddress)
|
||||
{
|
||||
if (return_length)
|
||||
{
|
||||
return_length.write(sizeof(ULONG_PTR));
|
||||
}
|
||||
|
||||
if (thread_information_length != sizeof(ULONG_PTR))
|
||||
{
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
const emulator_object<ULONG_PTR> info{c.emu, thread_information};
|
||||
info.write(thread->start_address);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
printf("Unsupported thread query info class: %X\n", info_class);
|
||||
c.emu.stop();
|
||||
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
@@ -2203,6 +2249,11 @@ namespace
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtUserSystemParametersInfo()
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
TOKEN_TYPE get_token_type(const handle token_handle)
|
||||
{
|
||||
return token_handle == DUMMY_IMPERSONATION_TOKEN //
|
||||
@@ -3340,6 +3391,39 @@ namespace
|
||||
processor_number.write(number);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtGetContextThread(const syscall_context& c, handle thread_handle,
|
||||
const emulator_object<CONTEXT> thread_context)
|
||||
{
|
||||
const auto* thread = thread_handle == CURRENT_THREAD
|
||||
? c.proc.active_thread
|
||||
: c.proc.threads.get(thread_handle);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
c.proc.active_thread->save(c.emu);
|
||||
const auto _ = utils::finally([&]
|
||||
{
|
||||
c.proc.active_thread->restore(c.emu);
|
||||
});
|
||||
|
||||
thread->restore(c.emu);
|
||||
|
||||
thread_context.access([&](CONTEXT& context)
|
||||
{
|
||||
if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
c.win_emu.logger.print(color::pink, "--> Reading debug registers!\n");
|
||||
}
|
||||
|
||||
context_frame::save(c.emu, context);
|
||||
});
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& handler_mapping)
|
||||
@@ -3449,6 +3533,8 @@ void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& ha
|
||||
add_handler(NtSetInformationKey);
|
||||
add_handler(NtUserGetKeyboardLayout);
|
||||
add_handler(NtQueryDirectoryFileEx);
|
||||
add_handler(NtUserSystemParametersInfo);
|
||||
add_handler(NtGetContextThread);
|
||||
|
||||
#undef add_handler
|
||||
}
|
||||
|
||||
@@ -875,8 +875,15 @@ void windows_emulator::setup_hooks()
|
||||
process.previous_ip = process.current_ip;
|
||||
process.current_ip = this->emu().read_instruction_pointer();
|
||||
|
||||
const auto is_main_exe = process.executable->is_within(address);
|
||||
const auto is_interesting_call = process.executable->is_within(
|
||||
process.previous_ip) || process.executable->is_within(address);
|
||||
process.previous_ip) || is_main_exe;
|
||||
|
||||
if (this->silent_until_main_ && is_main_exe)
|
||||
{
|
||||
this->silent_until_main_ = false;
|
||||
this->logger.disable_output(false);
|
||||
}
|
||||
|
||||
if (!this->verbose && !this->verbose_calls && !is_interesting_call)
|
||||
{
|
||||
@@ -887,15 +894,6 @@ void windows_emulator::setup_hooks()
|
||||
|
||||
if (binary)
|
||||
{
|
||||
const auto is_entry_point = address == binary->entry_point;
|
||||
|
||||
if (this->silent_until_main_ && is_entry_point && binary == this->process_
|
||||
.executable)
|
||||
{
|
||||
this->silent_until_main_ = false;
|
||||
this->logger.disable_output(false);
|
||||
}
|
||||
|
||||
const auto export_entry = binary->address_names.find(address);
|
||||
if (export_entry != binary->address_names.end())
|
||||
{
|
||||
@@ -904,7 +902,7 @@ void windows_emulator::setup_hooks()
|
||||
binary->name.c_str(),
|
||||
export_entry->second.c_str(), address);
|
||||
}
|
||||
else if (is_entry_point)
|
||||
else if (address == binary->entry_point)
|
||||
{
|
||||
logger.print(is_interesting_call ? color::yellow : color::gray,
|
||||
"Executing entry point: %s (0x%llX)\n",
|
||||
|
||||
Reference in New Issue
Block a user