mirror of https://github.com/x64dbg/GleeBug
commit
3ce2a318ca
|
|
@ -8,17 +8,26 @@ namespace GleeBug
|
|||
/**
|
||||
\brief DLL information structure.
|
||||
*/
|
||||
struct DllInfo
|
||||
class DllInfo
|
||||
{
|
||||
public:
|
||||
ULONG_PTR lpBaseOfDll;
|
||||
DWORD sizeOfImage;
|
||||
ULONG_PTR entryPoint;
|
||||
|
||||
/**
|
||||
\brief Default constructor.
|
||||
*/
|
||||
DllInfo();
|
||||
|
||||
/**
|
||||
\brief Constructor.
|
||||
\param lpBaseOfDll The base of DLL.
|
||||
\param sizeOfImage Size of the image.
|
||||
\param entryPoint The entry point.
|
||||
*/
|
||||
DllInfo(LPVOID lpBaseOfDll, DWORD sizeOfImage, LPVOID entryPoint);
|
||||
};
|
||||
|
||||
typedef std::map<Range, DllInfo, RangeCompare> DllMap;
|
||||
};
|
||||
|
||||
#endif //_DEBUGGER_DLL_H
|
||||
|
|
@ -6,6 +6,8 @@
|
|||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
|
|
@ -21,6 +23,26 @@ namespace GleeBug
|
|||
return a.second < b.first;
|
||||
}
|
||||
};
|
||||
|
||||
//forward declarations
|
||||
class Debugger;
|
||||
class ProcessInfo;
|
||||
class DllInfo;
|
||||
class ThreadInfo;
|
||||
|
||||
//map typedefs
|
||||
typedef std::map<DWORD, ProcessInfo> ProcessMap;
|
||||
typedef std::map<Range, DllInfo, RangeCompare> DllMap;
|
||||
typedef std::map<DWORD, ThreadInfo> ThreadMap;
|
||||
|
||||
//callback function typedefs
|
||||
typedef std::function<void()> StepCallback;
|
||||
|
||||
//vector typedefs
|
||||
typedef std::vector<StepCallback> StepCallbackVector;
|
||||
|
||||
//macros
|
||||
#define BIND(thisPtr, funcPtr) std::bind(&funcPtr, thisPtr)
|
||||
};
|
||||
|
||||
#endif //_DEBUGGER_GLOBAL_H
|
||||
|
|
@ -7,12 +7,12 @@ namespace GleeBug
|
|||
//DLL housekeeping
|
||||
MODULEINFO modinfo;
|
||||
memset(&modinfo, 0, sizeof(MODULEINFO));
|
||||
GetModuleInformation(_curProcess->hProcess,
|
||||
GetModuleInformation(_process->hProcess,
|
||||
(HMODULE)loadDll.lpBaseOfDll,
|
||||
&modinfo,
|
||||
sizeof(MODULEINFO));
|
||||
DllInfo dll(loadDll.lpBaseOfDll, modinfo.SizeOfImage, modinfo.EntryPoint);
|
||||
_curProcess->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll });
|
||||
_process->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll });
|
||||
|
||||
//call the debug event callback
|
||||
cbLoadDllEvent(loadDll, dll);
|
||||
|
|
@ -25,14 +25,14 @@ namespace GleeBug
|
|||
{
|
||||
//call the debug event callback
|
||||
ULONG_PTR lpBaseOfDll = (ULONG_PTR)unloadDll.lpBaseOfDll;
|
||||
auto dll = _curProcess->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
|
||||
if (dll != _curProcess->dlls.end())
|
||||
auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
|
||||
if (dll != _process->dlls.end())
|
||||
cbUnloadDllEvent(unloadDll, dll->second);
|
||||
else
|
||||
cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, 0));
|
||||
|
||||
//DLL housekeeping
|
||||
if (dll != _curProcess->dlls.end())
|
||||
_curProcess->dlls.erase(dll);
|
||||
if (dll != _process->dlls.end())
|
||||
_process->dlls.erase(dll);
|
||||
}
|
||||
};
|
||||
|
|
@ -4,9 +4,9 @@ namespace GleeBug
|
|||
{
|
||||
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
||||
{
|
||||
if (!_curProcess->systemBreakpoint) //handle system breakpoint
|
||||
if (!_process->systemBreakpoint) //handle system breakpoint
|
||||
{
|
||||
_curProcess->systemBreakpoint = true;
|
||||
_process->systemBreakpoint = true;
|
||||
_continueStatus = DBG_CONTINUE;
|
||||
|
||||
//call the callback
|
||||
|
|
@ -19,6 +19,21 @@ namespace GleeBug
|
|||
|
||||
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
|
||||
{
|
||||
if (_thread->isSingleStepping) //handle single step
|
||||
{
|
||||
_thread->isSingleStepping = false;
|
||||
_continueStatus = DBG_CONTINUE;
|
||||
|
||||
//call the callbacks
|
||||
StepCallbackVector cbStepCopy = _thread->stepCallbacks;
|
||||
_thread->stepCallbacks.clear();
|
||||
for (auto cbStep : cbStepCopy)
|
||||
cbStep();
|
||||
cbStep();
|
||||
}
|
||||
else //handle other single step exceptions
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
||||
|
|
|
|||
|
|
@ -6,15 +6,25 @@ namespace GleeBug
|
|||
{
|
||||
//process housekeeping
|
||||
ProcessInfo process(_debugEvent.dwProcessId,
|
||||
createProcess.hProcess,
|
||||
_debugEvent.dwThreadId);
|
||||
_processes.insert({ process.dwProcessId, process });
|
||||
_process = &_processes.find(process.dwProcessId)->second;
|
||||
|
||||
//set the current process and current thread
|
||||
_curProcess = &_processes[process.dwProcessId];
|
||||
_curProcess->curThread = &_curProcess->threads[process.dwMainThreadId];
|
||||
//thread housekeeping (main thread is created implicitly)
|
||||
ThreadInfo thread(_debugEvent.dwThreadId,
|
||||
createProcess.hThread,
|
||||
createProcess.lpThreadLocalBase,
|
||||
createProcess.lpStartAddress);
|
||||
_process->threads.insert({ thread.dwThreadId, thread });
|
||||
_thread = _process->thread = &_process->threads.find(thread.dwThreadId)->second;
|
||||
|
||||
//read thread context from main thread
|
||||
if (!_thread->RegReadContext())
|
||||
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
||||
|
||||
//call the debug event callback
|
||||
cbCreateProcessEvent(createProcess, *_curProcess);
|
||||
cbCreateProcessEvent(createProcess, *_process);
|
||||
|
||||
//close the file handle
|
||||
CloseHandle(createProcess.hFile);
|
||||
|
|
@ -27,12 +37,12 @@ namespace GleeBug
|
|||
_breakDebugger = true;
|
||||
|
||||
//call the debug event callback
|
||||
cbExitProcessEvent(exitProcess, *_curProcess);
|
||||
cbExitProcessEvent(exitProcess, *_process);
|
||||
|
||||
//process housekeeping
|
||||
_processes.erase(_debugEvent.dwProcessId);
|
||||
|
||||
//set the current process
|
||||
_curProcess = nullptr;
|
||||
_process = nullptr;
|
||||
}
|
||||
};
|
||||
|
|
@ -5,25 +5,27 @@ namespace GleeBug
|
|||
void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread)
|
||||
{
|
||||
//thread housekeeping
|
||||
ThreadInfo thread(_debugEvent.dwThreadId, createThread.lpThreadLocalBase, createThread.lpStartAddress);
|
||||
_curProcess->threads.insert({ thread.dwThreadId, thread });
|
||||
_process->threads.insert({ _debugEvent.dwThreadId,
|
||||
ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) });
|
||||
|
||||
//set the current thread
|
||||
_curProcess->curThread = &_curProcess->threads[thread.dwThreadId];
|
||||
_thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second;
|
||||
if (!_thread->RegReadContext())
|
||||
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
||||
|
||||
//call the debug event callback
|
||||
cbCreateThreadEvent(createThread, *_curProcess->curThread);
|
||||
cbCreateThreadEvent(createThread, *_thread);
|
||||
}
|
||||
|
||||
void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread)
|
||||
{
|
||||
//call the debug event callback
|
||||
cbExitThreadEvent(exitThread, *_curProcess->curThread);
|
||||
cbExitThreadEvent(exitThread, *_thread);
|
||||
|
||||
//thread housekeeping
|
||||
_curProcess->threads.erase(_debugEvent.dwThreadId);
|
||||
_process->threads.erase(_debugEvent.dwThreadId);
|
||||
|
||||
//set the current thread
|
||||
_curProcess->curThread = nullptr;
|
||||
_thread = _process->thread = nullptr;
|
||||
}
|
||||
};
|
||||
|
|
@ -16,19 +16,23 @@ namespace GleeBug
|
|||
_isRunning = false;
|
||||
|
||||
//set default continue status
|
||||
_continueStatus = DBG_CONTINUE;
|
||||
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
||||
|
||||
//set the current process and thread
|
||||
if (_processes.count(_debugEvent.dwProcessId))
|
||||
{
|
||||
_curProcess = &_processes[_debugEvent.dwProcessId];
|
||||
if (_curProcess->threads.count(_debugEvent.dwThreadId))
|
||||
_curProcess->curThread = &_curProcess->threads[_debugEvent.dwThreadId];
|
||||
else
|
||||
_curProcess->curThread = nullptr;
|
||||
_process = &_processes[_debugEvent.dwProcessId];
|
||||
if (_process->threads.count(_debugEvent.dwThreadId))
|
||||
{
|
||||
_thread = _process->thread = &_process->threads[_debugEvent.dwThreadId];
|
||||
if (!_thread->RegReadContext())
|
||||
cbInternalError("ThreadInfo::RegReadContext() failed!");
|
||||
}
|
||||
else
|
||||
_curProcess = nullptr;
|
||||
_thread = _process->thread = nullptr;
|
||||
}
|
||||
else
|
||||
_process = nullptr;
|
||||
|
||||
//dispatch the debug event
|
||||
switch (_debugEvent.dwDebugEventCode)
|
||||
|
|
@ -62,6 +66,13 @@ namespace GleeBug
|
|||
break;
|
||||
}
|
||||
|
||||
//write the register context
|
||||
if (_thread)
|
||||
{
|
||||
if (!_thread->RegWriteContext())
|
||||
cbInternalError("ThreadInfo::RegWriteContext() failed!");
|
||||
}
|
||||
|
||||
//continue the debug event
|
||||
if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus))
|
||||
break;
|
||||
|
|
@ -69,6 +80,6 @@ namespace GleeBug
|
|||
|
||||
//cleanup
|
||||
_processes.clear();
|
||||
_curProcess = nullptr;
|
||||
_process = nullptr;
|
||||
}
|
||||
};
|
||||
|
|
@ -4,23 +4,26 @@ namespace GleeBug
|
|||
{
|
||||
ProcessInfo::ProcessInfo()
|
||||
{
|
||||
this->curThread = nullptr;
|
||||
this->thread = nullptr;
|
||||
this->systemBreakpoint = false;
|
||||
this->hProcess = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
ProcessInfo::ProcessInfo(DWORD dwProcessId, DWORD dwMainThreadId)
|
||||
ProcessInfo::ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId)
|
||||
{
|
||||
this->systemBreakpoint = false;
|
||||
this->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
|
||||
this->dwProcessId = dwProcessId;
|
||||
this->dwMainThreadId = dwMainThreadId;
|
||||
this->threads.clear();
|
||||
}
|
||||
|
||||
ProcessInfo::~ProcessInfo()
|
||||
bool ProcessInfo::MemRead(ULONG_PTR address, const size_t size, void* buffer)
|
||||
{
|
||||
if (this->hProcess != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hProcess);
|
||||
return !!ReadProcessMemory(this->hProcess, (const void*)address, buffer, size, NULL);
|
||||
}
|
||||
|
||||
bool ProcessInfo::MemWrite(ULONG_PTR address, const size_t size, const void* buffer)
|
||||
{
|
||||
return !!WriteProcessMemory(this->hProcess, (void*)address, buffer, size, NULL);
|
||||
}
|
||||
};
|
||||
|
|
@ -10,24 +10,49 @@ namespace GleeBug
|
|||
/**
|
||||
\brief Process information structure.
|
||||
*/
|
||||
struct ProcessInfo
|
||||
class ProcessInfo
|
||||
{
|
||||
public:
|
||||
HANDLE hProcess;
|
||||
DWORD dwProcessId;
|
||||
DWORD dwMainThreadId;
|
||||
|
||||
ThreadInfo* curThread;
|
||||
ThreadInfo* thread;
|
||||
bool systemBreakpoint;
|
||||
|
||||
ThreadMap threads;
|
||||
DllMap dlls;
|
||||
|
||||
/**
|
||||
\brief Default constructor.
|
||||
*/
|
||||
ProcessInfo();
|
||||
ProcessInfo(DWORD dwProcessId, DWORD dwMainThreadId);
|
||||
~ProcessInfo();
|
||||
};
|
||||
|
||||
typedef std::map<DWORD, ProcessInfo> ProcessMap;
|
||||
/**
|
||||
\brief Constructor.
|
||||
\param dwProcessId Identifier for the process.
|
||||
\param dwMainThreadId Identifier for the main thread.
|
||||
*/
|
||||
ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId);
|
||||
|
||||
/**
|
||||
\brief Read memory from the process.
|
||||
\param address The virtual address to read from.
|
||||
\param size The size to read.
|
||||
\param [out] buffer Destination buffer. Cannot be null. May be filled partially on failure.
|
||||
\return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool MemRead(ULONG_PTR address, const size_t size, void* buffer);
|
||||
|
||||
/**
|
||||
\brief Write memory to the process.
|
||||
\param address The virtual address to write to.
|
||||
\param size The size to write.
|
||||
\param [in] buffer Source buffer. Cannot be null.
|
||||
\return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool MemWrite(ULONG_PTR address, const size_t size, const void* buffer);
|
||||
};
|
||||
};
|
||||
|
||||
#endif //_DEBUGGER_PROCESS_H
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
#include "Debugger.Thread.Registers.h"
|
||||
|
||||
namespace GleeBug
|
||||
{
|
||||
RegistersInfo::RegistersInfo()
|
||||
{
|
||||
memset(&this->_context, 0, sizeof(CONTEXT));
|
||||
}
|
||||
|
||||
const CONTEXT* RegistersInfo::GetContext()
|
||||
{
|
||||
#ifdef _WIN64
|
||||
_context.Rax = this->Rax;
|
||||
_context.Rbx = this->Rbx;
|
||||
_context.Rcx = this->Rcx;
|
||||
_context.Rdx = this->Rdx;
|
||||
_context.Rsi = this->Rsi;
|
||||
_context.Rdi = this->Rdi;
|
||||
_context.Rbp = this->Rbp;
|
||||
_context.Rsp = this->Rsp;
|
||||
_context.Rip = this->Rip;
|
||||
_context.R8 = this->R8;
|
||||
_context.R9 = this->R9;
|
||||
_context.R10 = this->R10;
|
||||
_context.R11 = this->R11;
|
||||
_context.R12 = this->R12;
|
||||
_context.R13 = this->R13;
|
||||
_context.R14 = this->R14;
|
||||
_context.R15 = this->R15;
|
||||
_context.EFlags = this->EFlags;
|
||||
#else //x86
|
||||
_context.Eax = this->Eax;
|
||||
_context.Ebx = this->Ebx;
|
||||
_context.Ecx = this->Ecx;
|
||||
_context.Edx = this->Edx;
|
||||
_context.Esi = this->Esi;
|
||||
_context.Edi = this->Edi;
|
||||
_context.Ebp = this->Ebp;
|
||||
_context.Esp = this->Esp;
|
||||
_context.Eip = this->Eip;
|
||||
_context.EFlags = this->EFlags;
|
||||
#endif //_WIN64
|
||||
return &_context;
|
||||
}
|
||||
|
||||
void RegistersInfo::SetContext(const CONTEXT & context)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
this->Rax = context.Rax;
|
||||
this->Rbx = context.Rbx;
|
||||
this->Rcx = context.Rcx;
|
||||
this->Rdx = context.Rdx;
|
||||
this->Rsi = context.Rsi;
|
||||
this->Rdi = context.Rdi;
|
||||
this->Rbp = context.Rbp;
|
||||
this->Rsp = context.Rsp;
|
||||
this->Rip = context.Rip;
|
||||
this->R8 = context.R8;
|
||||
this->R9 = context.R9;
|
||||
this->R10 = context.R10;
|
||||
this->R11 = context.R11;
|
||||
this->R12 = context.R12;
|
||||
this->R13 = context.R13;
|
||||
this->R14 = context.R14;
|
||||
this->R15 = context.R15;
|
||||
this->EFlags = context.EFlags;
|
||||
#else //x86
|
||||
this->Eax = context.Eax;
|
||||
this->Ebx = context.Ebx;
|
||||
this->Ecx = context.Ecx;
|
||||
this->Edx = context.Edx;
|
||||
this->Esi = context.Esi;
|
||||
this->Edi = context.Edi;
|
||||
this->Ebp = context.Ebp;
|
||||
this->Esp = context.Esp;
|
||||
this->Eip = context.Eip;
|
||||
this->EFlags = context.EFlags;
|
||||
#endif //_WIN64
|
||||
this->_context = context;
|
||||
}
|
||||
|
||||
void RegistersInfo::SetTrapFlag(bool set)
|
||||
{
|
||||
if (set)
|
||||
this->EFlags |= TRAP_FLAG;
|
||||
else
|
||||
this->EFlags &= ~TRAP_FLAG;
|
||||
}
|
||||
|
||||
bool RegistersInfo::GetTrapFlag()
|
||||
{
|
||||
return (this->EFlags & TRAP_FLAG) == TRAP_FLAG;
|
||||
}
|
||||
|
||||
void RegistersInfo::SetResumeFlag(bool set)
|
||||
{
|
||||
if (set)
|
||||
this->EFlags |= RESUME_FLAG;
|
||||
else
|
||||
this->EFlags &= ~RESUME_FLAG;
|
||||
}
|
||||
|
||||
bool RegistersInfo::GetResumeFlag()
|
||||
{
|
||||
return (this->EFlags & RESUME_FLAG) == RESUME_FLAG;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#ifndef _DEBUGGER_THREAD_REGISTERS_H
|
||||
#define _DEBUGGER_THREAD_REGISTERS_H
|
||||
|
||||
#include "Debugger.Global.h"
|
||||
|
||||
namespace GleeBug
|
||||
{
|
||||
CONTEXT;
|
||||
/**
|
||||
\brief Thread register context.
|
||||
*/
|
||||
class RegistersInfo
|
||||
{
|
||||
public:
|
||||
#ifdef _WIN64
|
||||
DWORD64 Rax;
|
||||
DWORD64 Rbx;
|
||||
DWORD64 Rcx;
|
||||
DWORD64 Rdx;
|
||||
DWORD64 Rsi;
|
||||
DWORD64 Rdi;
|
||||
DWORD64 Rbp;
|
||||
DWORD64 Rsp;
|
||||
DWORD64 Rip;
|
||||
DWORD64 R8;
|
||||
DWORD64 R9;
|
||||
DWORD64 R10;
|
||||
DWORD64 R11;
|
||||
DWORD64 R12;
|
||||
DWORD64 R13;
|
||||
DWORD64 R14;
|
||||
DWORD64 R15;
|
||||
DWORD EFlags;
|
||||
#else //x86
|
||||
DWORD Eax;
|
||||
DWORD Ebx;
|
||||
DWORD Ecx;
|
||||
DWORD Edx;
|
||||
DWORD Esi;
|
||||
DWORD Edi;
|
||||
DWORD Ebp;
|
||||
DWORD Esp;
|
||||
DWORD Eip;
|
||||
DWORD EFlags;
|
||||
#endif //_WIN64
|
||||
|
||||
/**
|
||||
\brief Default constructor.
|
||||
*/
|
||||
RegistersInfo();
|
||||
|
||||
/**
|
||||
\brief Gets a pointer to the context object.
|
||||
\return This function will never return a nullptr.
|
||||
*/
|
||||
const CONTEXT* GetContext();
|
||||
|
||||
/**
|
||||
\brief Sets the CONTEXT.
|
||||
\param context The context to set.
|
||||
*/
|
||||
void SetContext(const CONTEXT & context);
|
||||
|
||||
/**
|
||||
\brief Sets trap flag.
|
||||
\param set (Optional) true to set, false to unset.
|
||||
*/
|
||||
void SetTrapFlag(bool set = true);
|
||||
|
||||
/**
|
||||
\brief Gets trap flag.
|
||||
\return true if the flag is set, false otherwise.
|
||||
*/
|
||||
bool GetTrapFlag();
|
||||
|
||||
/**
|
||||
\brief Sets resume flag.
|
||||
\param set (Optional) true to set, false to unset.
|
||||
*/
|
||||
void SetResumeFlag(bool set = true);
|
||||
|
||||
/**
|
||||
\brief Gets resume flag.
|
||||
\return true if the flag is set, false otherwise.
|
||||
*/
|
||||
bool GetResumeFlag();
|
||||
|
||||
private:
|
||||
CONTEXT _context;
|
||||
const int TRAP_FLAG = 0x100;
|
||||
const int RESUME_FLAG = 0x10000;
|
||||
};
|
||||
};
|
||||
|
||||
#endif //_DEBUGGER_THREAD_REGISTERS_H
|
||||
|
|
@ -7,17 +7,50 @@ namespace GleeBug
|
|||
this->hThread = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
ThreadInfo::ThreadInfo(DWORD dwThreadId, LPVOID lpThreadLocalBase, LPVOID lpStartAddress)
|
||||
ThreadInfo::ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress)
|
||||
{
|
||||
this->dwThreadId = dwThreadId;
|
||||
this->hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId);
|
||||
this->hThread = hThread;
|
||||
this->lpThreadLocalBase = (ULONG_PTR)lpThreadLocalBase;
|
||||
this->lpStartAddress = (ULONG_PTR)lpStartAddress;
|
||||
}
|
||||
|
||||
ThreadInfo::~ThreadInfo()
|
||||
bool ThreadInfo::RegReadContext()
|
||||
{
|
||||
if (this->hThread != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hThread);
|
||||
SuspendThread(this->hThread);
|
||||
memset(&this->_oldContext, 0, sizeof(CONTEXT));
|
||||
this->_oldContext.ContextFlags = CONTEXT_ALL;
|
||||
bool bReturn = false;
|
||||
if (GetThreadContext(this->hThread, &this->_oldContext))
|
||||
{
|
||||
this->registers.SetContext(this->_oldContext);
|
||||
bReturn = true;
|
||||
}
|
||||
ResumeThread(this->hThread);
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
bool ThreadInfo::RegWriteContext()
|
||||
{
|
||||
//check if something actually changed
|
||||
if (memcmp(&this->_oldContext, this->registers.GetContext(), sizeof(CONTEXT)) == 0)
|
||||
return true;
|
||||
//update the context
|
||||
SuspendThread(this->hThread);
|
||||
bool bReturn = !!SetThreadContext(this->hThread, this->registers.GetContext());
|
||||
ResumeThread(this->hThread);
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
void ThreadInfo::StepInto(StepCallback cbStep)
|
||||
{
|
||||
StepInto();
|
||||
stepCallbacks.push_back(cbStep);
|
||||
}
|
||||
|
||||
void ThreadInfo::StepInto()
|
||||
{
|
||||
registers.SetTrapFlag();
|
||||
isSingleStepping = true;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,26 +1,78 @@
|
|||
#ifndef _DEBUGGER_THREADS_H
|
||||
#define _DEBUGGER_THREADS_H
|
||||
#ifndef _DEBUGGER_THREAD_H
|
||||
#define _DEBUGGER_THREAD_H
|
||||
|
||||
#include "Debugger.Global.h"
|
||||
#include "Debugger.Thread.Registers.h"
|
||||
|
||||
namespace GleeBug
|
||||
{
|
||||
/**
|
||||
\brief Thread information structure.
|
||||
*/
|
||||
struct ThreadInfo
|
||||
class ThreadInfo
|
||||
{
|
||||
public:
|
||||
DWORD dwThreadId;
|
||||
HANDLE hThread;
|
||||
ULONG_PTR lpThreadLocalBase;
|
||||
ULONG_PTR lpStartAddress;
|
||||
|
||||
ThreadInfo();
|
||||
ThreadInfo(DWORD dwThreadId, LPVOID lpThreadLocalBase, LPVOID lpStartAddress);
|
||||
~ThreadInfo();
|
||||
};
|
||||
RegistersInfo registers;
|
||||
StepCallbackVector stepCallbacks;
|
||||
bool isSingleStepping;
|
||||
|
||||
typedef std::map<DWORD, ThreadInfo> ThreadMap;
|
||||
/**
|
||||
\brief Default constructor.
|
||||
*/
|
||||
ThreadInfo();
|
||||
|
||||
/**
|
||||
\brief Constructor.
|
||||
\param dwThreadId Identifier for the thread.
|
||||
\param lpThreadLocalBase The thread local base.
|
||||
\param lpStartAddress The start address.
|
||||
*/
|
||||
ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress);
|
||||
|
||||
/**
|
||||
\brief Read the register context from the thread. This fills the RegistersInfo member.
|
||||
\return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool RegReadContext();
|
||||
|
||||
/**
|
||||
\brief Write the register context to the thread. This does nothing if the RegistersInfo member did not change.
|
||||
\return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool RegWriteContext();
|
||||
|
||||
/**
|
||||
\brief Step into.
|
||||
*/
|
||||
void StepInto();
|
||||
|
||||
/**
|
||||
\brief Step into.
|
||||
\param cbStep StepCallback. Can be written using BIND(this, MyDebugger::cb).
|
||||
*/
|
||||
void StepInto(StepCallback cbStep);
|
||||
|
||||
/**
|
||||
\brief Step into.
|
||||
\tparam T Generic type parameter. Must be a subclass of Debugger.
|
||||
\param debugger This pointer to a subclass of Debugger.
|
||||
\param callback Pointer to the callback. Written like: &MyDebugger::cb
|
||||
*/
|
||||
template <typename T>
|
||||
void StepInto(T* debugger, void(T::*callback)())
|
||||
{
|
||||
static_cast<void>(static_cast<Debugger *>(debugger));
|
||||
StepInto(std::bind(callback, debugger));
|
||||
}
|
||||
|
||||
private:
|
||||
CONTEXT _oldContext;
|
||||
};
|
||||
};
|
||||
|
||||
#endif //_DEBUGGER_THREADS_H
|
||||
|
|
@ -101,6 +101,12 @@ namespace GleeBug
|
|||
virtual void cbRipEvent(const RIP_INFO & rip) {};
|
||||
|
||||
protected: //other callbacks
|
||||
/**
|
||||
\brief Internal error callback. Provide an implementation to use this callback.
|
||||
\param error The error message.
|
||||
*/
|
||||
virtual void cbInternalError(const std::string & error) {};
|
||||
|
||||
/**
|
||||
\brief Unhandled exception callback. Provide an implementation to use this callback.
|
||||
\param exceptionRecord The exception record.
|
||||
|
|
@ -113,6 +119,11 @@ namespace GleeBug
|
|||
*/
|
||||
virtual void cbSystemBreakpoint() {};
|
||||
|
||||
/**
|
||||
\brief Step callback. Provide an implementation to use this callback.
|
||||
*/
|
||||
virtual void cbStep() {};
|
||||
|
||||
protected: //core debug event handlers
|
||||
/**
|
||||
\brief Process creation debug event. Do not override this unless you know what you are doing!
|
||||
|
|
@ -189,8 +200,17 @@ namespace GleeBug
|
|||
bool _breakDebugger;
|
||||
DEBUG_EVENT _debugEvent;
|
||||
ProcessMap _processes;
|
||||
ProcessInfo* _curProcess;
|
||||
bool _isRunning;
|
||||
|
||||
/**
|
||||
\brief The current process (can be null in some cases).
|
||||
*/
|
||||
ProcessInfo* _process;
|
||||
|
||||
/**
|
||||
\brief The current thread (can be null in some cases). Should be a copy of _process->thread.
|
||||
*/
|
||||
ThreadInfo* _thread;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@
|
|||
<ClCompile Include="Debugger.Loop.Thread.cpp" />
|
||||
<ClCompile Include="Debugger.Process.cpp" />
|
||||
<ClCompile Include="Debugger.Thread.cpp" />
|
||||
<ClCompile Include="Debugger.Thread.Registers.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Debugger.Dll.h" />
|
||||
|
|
@ -164,6 +165,7 @@
|
|||
<ClInclude Include="Debugger.h" />
|
||||
<ClInclude Include="Debugger.Thread.h" />
|
||||
<ClInclude Include="Debugger.Global.h" />
|
||||
<ClInclude Include="Debugger.Thread.Registers.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@
|
|||
<ClCompile Include="Debugger.Loop.Rip.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger.Thread.Registers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Debugger.h">
|
||||
|
|
@ -65,5 +68,8 @@
|
|||
<ClInclude Include="Debugger.Global.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger.Thread.Registers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -10,52 +10,82 @@ class MyDebugger : public Debugger
|
|||
protected:
|
||||
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process)
|
||||
{
|
||||
printf("Process %d created with entry 0x%p\n", _debugEvent.dwProcessId, createProcess.lpStartAddress);
|
||||
printf("Process %d created with entry 0x%p\n",
|
||||
_debugEvent.dwProcessId,
|
||||
createProcess.lpStartAddress);
|
||||
};
|
||||
|
||||
virtual void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process)
|
||||
{
|
||||
printf("Process %d terminated with exit code 0x%08X\n", _debugEvent.dwProcessId, exitProcess.dwExitCode);
|
||||
printf("Process %d terminated with exit code 0x%08X\n",
|
||||
_debugEvent.dwProcessId,
|
||||
exitProcess.dwExitCode);
|
||||
}
|
||||
|
||||
virtual void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread)
|
||||
{
|
||||
printf("Thread %d created with entry 0x%p\n", _debugEvent.dwThreadId, createThread.lpStartAddress);
|
||||
printf("Thread %d created with entry 0x%p\n",
|
||||
_debugEvent.dwThreadId,
|
||||
createThread.lpStartAddress);
|
||||
};
|
||||
|
||||
virtual void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread)
|
||||
{
|
||||
printf("Thread %d terminated with exit code 0x%08X\n", _debugEvent.dwThreadId, exitThread.dwExitCode);
|
||||
printf("Thread %d terminated with exit code 0x%08X\n",
|
||||
_debugEvent.dwThreadId,
|
||||
exitThread.dwExitCode);
|
||||
};
|
||||
|
||||
virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll)
|
||||
{
|
||||
printf("DLL loaded at 0x%p\n", loadDll.lpBaseOfDll);
|
||||
printf("DLL loaded at 0x%p\n",
|
||||
loadDll.lpBaseOfDll);
|
||||
};
|
||||
|
||||
virtual void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll)
|
||||
{
|
||||
printf("DLL 0x%p unloaded\n", unloadDll.lpBaseOfDll);
|
||||
printf("DLL 0x%p unloaded\n",
|
||||
unloadDll.lpBaseOfDll);
|
||||
};
|
||||
|
||||
virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
|
||||
{
|
||||
printf("Exception with code 0x%08X\n", exceptionInfo.ExceptionRecord.ExceptionCode);
|
||||
printf("Exception with code 0x%08X at 0x%p\n",
|
||||
exceptionInfo.ExceptionRecord.ExceptionCode,
|
||||
exceptionInfo.ExceptionRecord.ExceptionAddress);
|
||||
};
|
||||
|
||||
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
|
||||
{
|
||||
printf("Debug string at 0x%p with length %d\n", debugString.lpDebugStringData, debugString.nDebugStringLength);
|
||||
printf("Debug string at 0x%p with length %d\n",
|
||||
debugString.lpDebugStringData,
|
||||
debugString.nDebugStringLength);
|
||||
};
|
||||
|
||||
virtual void cbRipEvent(const RIP_INFO & rip)
|
||||
{
|
||||
printf("RIP event type 0x%X, error 0x%X", rip.dwType, rip.dwError);
|
||||
printf("RIP event type 0x%X, error 0x%X",
|
||||
rip.dwType,
|
||||
rip.dwError);
|
||||
};
|
||||
|
||||
void boobs()
|
||||
{
|
||||
printf("(.)Y(.) 0x%p\n",
|
||||
_thread->registers.Rip);
|
||||
}
|
||||
|
||||
virtual void cbSystemBreakpoint()
|
||||
{
|
||||
printf("System breakpoint reached!");
|
||||
printf("System breakpoint reached, CIP: 0x%p\n",
|
||||
_thread->registers.Rip);
|
||||
_thread->StepInto(BIND(this, MyDebugger::boobs));
|
||||
}
|
||||
|
||||
virtual void cbInternalError(const std::string & error)
|
||||
{
|
||||
printf("Internal Error: %s\n",
|
||||
error.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue