Support concise debugger output

This commit is contained in:
momo5502
2025-01-03 13:08:28 +01:00
parent 3d70541ef7
commit 010fbb2120
8 changed files with 661 additions and 585 deletions

View File

@@ -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,52 @@ 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};
if (++count > 100) 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};
if (++count > 100) 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);
}

View File

@@ -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

View File

@@ -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{};
};

View File

@@ -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);

View File

@@ -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));
}
}

View File

@@ -800,7 +800,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;
});
@@ -1259,6 +1259,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)

View File

@@ -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",