Skip to content

Fix existing issues and implement dump analysis class#4

Merged
ShallowFeather merged 7 commits intoShallowFeather:mainfrom
Lompandi:main
Nov 17, 2025
Merged

Fix existing issues and implement dump analysis class#4
ShallowFeather merged 7 commits intoShallowFeather:mainfrom
Lompandi:main

Conversation

@Lompandi
Copy link
Copy Markdown
Contributor

  • Added Debugger.cpp and Debugger.hpp to improve dump information parsing
  • Fixed memory leak issue in PELoader::objectList
  • Implemented temporary hooking utility for easier monitoring of function execution results
  • Removed redundant custom string processing function implementations

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds dump analysis capabilities through a new Debugger class, fixes a memory leak by converting raw pointers to std::shared_ptr for object management, and introduces a temporary hooking utility. However, several critical bugs were introduced during the refactoring.

  • Implemented Debugger.cpp and Debugger.h for enhanced dump file parsing using Windows Debug Engine API
  • Migrated objectList from raw pointers to std::shared_ptr to prevent memory leaks
  • Added HookManager class for temporary code execution monitoring
  • Replaced std::map with std::unordered_map for better performance

Reviewed Changes

Copilot reviewed 11 out of 14 changed files in this pull request and generated 21 comments.

Show a summary per file
File Description
KDemu/Debugger.h Defines new Debugger_t class interface for dump analysis with module enumeration and symbol resolution
KDemu/Debugger.cpp Implements debugger functionality with several critical bugs in error handling, resource cleanup, and cache logic
KDemu/LoadPE.hpp Adds Debugger integration, converts objectList to shared_ptr, changes maps to unordered_map
KDemu/LoadPE.cpp Implements new MapAllDriversFromKdmp using Debugger, updates LoadDmp to return bool, updates object creation to use shared_ptr
KDemu/unicorn.cpp Refactors match function to use memcmp (with incorrect argument order)
KDemu/KDemu.cpp Updates object hook registration to use shared_ptr, adds error handling for LoadDmp
KDemu/Emulate.hpp Adds HookManager class for temporary hooks
KDemu/Emulate.cpp Replaces printf-style formatting implementations with incomplete hook-based logging, breaking functionality
KDemu/KDemu.vcxproj Adds Debugger source files to project
KDemu/KDemu.vcxproj.filters Adds Debugger files to filters
.gitignore Adds Release build directories to ignore list

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1233 to +1252
auto returnAddress = emu->qword(emu->rsp());
g_TmpHooks.add_temporary_hook(uc,
[](uc_engine* uc, uint64_t addr, uint32_t size, const std::vector<uint64_t>& savedArgs) {
auto emu = Emu(uc);

if (j < format.size() && format[j] == L'0' && j + 1 < format.size() && iswdigit(format[j + 1])) {
j++;
while (j < format.size() && iswdigit(format[j])) {
zero_pad = zero_pad * 10 + (format[j] - L'0');
j++;
}
}
auto buffer_ptr = savedArgs.at(0);

if (j + 1 < format.size() && format[j] == L'h' && format[j + 1] == L'u') {
if (arg_idx < guest_args.size()) {
uint16_t val = static_cast<uint16_t>(guest_args[arg_idx++]);
ws << std::setfill(L'0') << std::setw(zero_pad) << val;
}
i = j + 1;
}
else if (format[j] == L'u' && arg_idx < guest_args.size()) {
uint32_t val = static_cast<uint32_t>(guest_args[arg_idx++]);
ws << std::setfill(L'0') << std::setw(zero_pad) << val;
i = j;
}
else if (format[j] == L'X' && arg_idx < guest_args.size()) {
uint32_t val = static_cast<uint32_t>(guest_args[arg_idx++]);
ws << std::uppercase << std::hex << std::setfill(L'0') << std::setw(zero_pad) << val << std::dec;
i = j;
}
else if (format[j] == L'S' && arg_idx < guest_args.size()) {
char tmp[512] = {};
if (emu->try_read(guest_args[arg_idx++], tmp, sizeof(tmp))) {
std::string ansi_tmp(tmp);
std::wstring wide_tmp;
ANSIToUnicode(ansi_tmp, wide_tmp);
ws << wide_tmp.c_str();
}
i = j;
}
else if (format[j] == L's' && arg_idx < guest_args.size()) {
wchar_t tmp[512] = {};
if (emu->try_read(guest_args[arg_idx++], tmp, sizeof(tmp))) {
ws << tmp;
std::wstring result;
for (uint64_t addr = buffer_ptr;; addr += sizeof(wchar_t)) {
wchar_t ch = 0;
if (!emu->try_read(addr, &ch, sizeof(ch))) {
break;
}
i = j;
}
else if ((format[j] == L'd' || format[j] == L'i') && arg_idx < guest_args.size()) {
int64_t val = static_cast<int64_t>(guest_args[arg_idx++]);
ws << std::setfill(L'0') << std::setw(zero_pad) << val;
i = j;
}
else if (format[j] == L'x' && arg_idx < guest_args.size()) {
int64_t val = static_cast<int64_t>(guest_args[arg_idx++]);
ws << std::hex << std::setfill(L'0') << std::setw(zero_pad) << val << std::dec;
i = j;
}
else {
ws << format[i];
result.push_back(ch);
if (ch == L'\0') break;
}
}
else {
ws << format[i];
}
}

std::wstring result = ws.str();
size_t required = result.size() + 1;
if (required > sizeInWords) {
wchar_t zero = L'\0';
emu->write(buffer_ptr, &zero, sizeof(wchar_t));
emu->rax(static_cast<uint64_t>(-1));
RetHook(uc);
restore_threads();
return;
}

Logger::Log(true, ConsoleColor::RED, L"%ls\n", result.c_str());
emu->write(buffer_ptr, result.c_str(), required * sizeof(wchar_t));
emu->rax(static_cast<uint64_t>(result.size()));
RetHook(uc);
restore_threads();
Logger::Log(true, ConsoleColor::RED, L"%ls\n", result.c_str());
}, returnAddress, returnAddress + 1,
{ buffer_ptr, sizeInWords, format_ptr, va_args_ptr });
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _vswprintf_s function implementation is incomplete. The entire printf-style formatting logic has been removed and replaced with a hook that only logs the result buffer after the function returns. However, the actual formatting and writing to the buffer is not performed, which means the emulated code won't work correctly. The function needs to either:

  1. Keep the original formatting implementation, or
  2. Allow the actual implementation to run and just log the result

Currently, neither the return value nor the formatted output is set properly.

Copilot uses AI. Check for mistakes.
Comment on lines +1337 to +1355
auto returnAddress = emu->qword(emu->rsp());
g_TmpHooks.add_temporary_hook(uc,
[](uc_engine* uc, uint64_t addr, uint32_t size, const std::vector<uint64_t>& savedArgs) {
auto emu = Emu(uc);
auto buffer_ptr = savedArgs.at(0);

std::wstring result;
for (uint64_t addr = buffer_ptr;; addr += sizeof(wchar_t)) {
wchar_t ch = 0;
if (!emu->try_read(addr, &ch, sizeof(ch))) {
break;
}
i = j + 1;
}
else if (format[j] == L'u' && arg_idx < guest_args.size()) {
uint32_t val = static_cast<uint32_t>(guest_args[arg_idx++]);
ws << std::setfill(L'0') << std::setw(zero_pad) << val;
i = j;
}
else if (format[j] == L'X' && arg_idx < guest_args.size()) {
uint32_t val = static_cast<uint32_t>(guest_args[arg_idx++]);
ws << std::uppercase << std::hex << std::setfill(L'0') << std::setw(zero_pad) << val << std::dec;
i = j;
}
else if (format[j] == L'S' && arg_idx < guest_args.size()) {
char tmp[512] = {};
auto tmpData = emu_vsnw->read(guest_args[arg_idx++], sizeof(tmp));
memcpy(tmp, tmpData.data(), tmpData.size());
ws << tmp;
i = j;
result.push_back(ch);
if (ch == L'\0') break;
}
else if (format[j] == L's' && arg_idx < guest_args.size()) {
wchar_t tmp[512] = {};
auto tmpData = emu_vsnw->read(guest_args[arg_idx++], sizeof(tmp));
memcpy(tmp, tmpData.data(), tmpData.size());
ws << tmp;
i = j;
}
else if ((format[j] == L'd' || format[j] == L'i') && arg_idx < guest_args.size()) {
int64_t val = static_cast<int64_t>(guest_args[arg_idx++]);
ws << std::setfill(L'0') << std::setw(zero_pad) << val;
i = j;
}
else if (format[j] == L'x' && arg_idx < guest_args.size()) {
int64_t val = static_cast<int64_t>(guest_args[arg_idx++]);
ws << std::hex << std::setfill(L'0') << std::setw(zero_pad) << val << std::dec;
i = j;
}
else {
ws << format[i];
}
}
else {
ws << format[i];
}
}
std::wstring result = ws.str();
std::string results;
UnicodeToANSI(result, results);
if (strcmp(results.c_str(), "\n") != 0) {
std::string s = results + " \n";
Logger::Log(true, ConsoleColor::RED, "_vsnwprintf\n");
Logger::Log(true, ConsoleColor::RED, s.c_str());
}

size_t write_len = sizeInWords;
emu_vsnw->write(buffer_ptr, result.c_str(), result.size());

int ret = ws.str().size();
emu_vsnw->rax(static_cast<uint64_t>(ret));


RetHook(uc);
for (auto& ti : loader->Threads) {
SetEvent(ti->Event);
loader->errorevent = nullptr;
}
Logger::Log(true, ConsoleColor::RED, L"%ls\n", result.c_str());
}, returnAddress, returnAddress + 1,
{ buffer_ptr, sizeInWords, format_ptr, va_args_ptr });
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _vsnwprintf function implementation is incomplete. The entire printf-style formatting logic has been removed and replaced with a hook that only logs the result buffer after the function returns. However, the actual formatting and writing to the buffer is not performed, which means the emulated code won't work correctly. The function needs to either keep the original formatting implementation or allow the actual implementation to run.

Copilot uses AI. Check for mistakes.

if (Symbols_) {
Symbols_->Release();
}
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The destructor is missing a null check and Release call for DataSpaces_. All other COM interface pointers (Client_, Control_, Registers_, Symbols_) are properly released in the destructor, but DataSpaces_ is missing. Add:

if (DataSpaces_) {
    DataSpaces_->Release();
}
Suggested change
}
}
if (DataSpaces_) {
DataSpaces_->Release();
}

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +60
IDebugClient4* Client_;
IDebugControl4* Control_;
IDebugRegisters2* Registers_;
IDebugDataSpaces4* DataSpaces_;
IDebugSymbols3* Symbols_;
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The COM interface pointers (Client_, Control_, Registers_, DataSpaces_, Symbols_) are not initialized to nullptr in the constructor. With Debugger_t() = default, these raw pointers will have undefined values. The destructor checks if (Client_) etc., which will be unreliable if these pointers aren't initialized. Either:

  1. Initialize them in-class: IDebugClient4* Client_ = nullptr; etc., or
  2. Provide an explicit constructor that initializes them to nullptr
Suggested change
IDebugClient4* Client_;
IDebugControl4* Control_;
IDebugRegisters2* Registers_;
IDebugDataSpaces4* DataSpaces_;
IDebugSymbols3* Symbols_;
IDebugClient4* Client_ = nullptr;
IDebugControl4* Control_ = nullptr;
IDebugRegisters2* Registers_ = nullptr;
IDebugDataSpaces4* DataSpaces_ = nullptr;
IDebugSymbols3* Symbols_ = nullptr;

Copilot uses AI. Check for mistakes.
for (auto object : loader->objectList) {
uc_hook_add(ti->tuc, &t, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, (void*)Unicorn::hook_access_object, (void*)object, object->address, object->address + object->size);
// MOD_TEST
//uc_hook_add(ti->tuc, &t, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, (void*)Unicorn::hook_access_object, (void*)object, object->address, object->address + object->size);
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Commented-out code (lines 2791-2792) should be removed. The original implementation using raw pointer casting is preserved in comments, but this adds clutter and should be handled through version control.

Suggested change
//uc_hook_add(ti->tuc, &t, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, (void*)Unicorn::hook_access_object, (void*)object, object->address, object->address + object->size);

Copilot uses AI. Check for mistakes.

std::uint64_t Debugger_t::Evaluate64(const char* Expr) const {
DEBUG_VALUE Value;
Control_->Evaluate(Expr, DEBUG_VALUE_INT64, &Value, NULL);
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value of Control_->Evaluate() is not checked. If the evaluation fails, Value.I64 will contain uninitialized data. Add error handling:

HRESULT hr = Control_->Evaluate(Expr, DEBUG_VALUE_INT64, &Value, NULL);
if (FAILED(hr)) {
    return 0ull;
}
return Value.I64;
Suggested change
Control_->Evaluate(Expr, DEBUG_VALUE_INT64, &Value, NULL);
HRESULT hr = Control_->Evaluate(Expr, DEBUG_VALUE_INT64, &Value, NULL);
if (FAILED(hr)) {
return 0ull;
}

Copilot uses AI. Check for mistakes.
Comment on lines +510 to +511
/*Object* cr3Obj = new Object("CR3", cr3, 0x1000);
this->objectList.emplace_back(cr3Obj);*/
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Commented-out code blocks (lines 454-457 and 510-511) should be removed. The original implementation using raw pointers is preserved in comments, but this should be handled through version control instead of inline comments.

Suggested change
/*Object* cr3Obj = new Object("CR3", cr3, 0x1000);
this->objectList.emplace_back(cr3Obj);*/

Copilot uses AI. Check for mistakes.
for (auto object : peLoader.objectList) {
Emu(uc)->hook_add(&t, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, (void*)Unicorn::hook_access_object, (void*)object, object->address, object->address + object->size);
// MOD_TEST
// Emu(uc)->hook_add(&t, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, (void*)Unicorn::hook_access_object, (void*)object, object->address, object->address + object->size);
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Commented-out code (lines 112-113) should be removed. The original implementation using raw pointer casting is preserved in comments, but this adds clutter and should be handled through version control.

Suggested change
// Emu(uc)->hook_add(&t, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, (void*)Unicorn::hook_access_object, (void*)object, object->address, object->address + object->size);

Copilot uses AI. Check for mistakes.
Comment on lines +858 to +859
// else
// Logger::Log(true, ConsoleColor::RED, "Page error : %llx\n", pe->Base + i * 0x1000);
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented-out error logging (lines 858-859) should be removed or uncommented with a proper justification. If page errors should no longer be logged, remove the code entirely. If this is temporary debugging code, it should be removed before merging.

Suggested change
// else
// Logger::Log(true, ConsoleColor::RED, "Page error : %llx\n", pe->Base + i * 0x1000);

Copilot uses AI. Check for mistakes.
const std::vector<std::string_view> Dlls = { "dbghelp.dll", "symsrv.dll",
"dbgeng.dll", "dbgcore.dll" };
const fs::path DefaultDbgDllLocation(
R"(c:\program Files (x86)\windows kits\10\debuggers\x64)");
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path string has inconsistent capitalization. "program Files" should be "Program Files" to match the standard Windows directory naming convention. While Windows paths are case-insensitive, using the correct casing improves code clarity and consistency.

Suggested change
R"(c:\program Files (x86)\windows kits\10\debuggers\x64)");
R"(c:\Program Files (x86)\windows kits\10\debuggers\x64)");

Copilot uses AI. Check for mistakes.
@ShallowFeather ShallowFeather merged commit d6c6f59 into ShallowFeather:main Nov 17, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants