massive cleanup + fixed various code problems

This commit is contained in:
Mr. eXoDia 2015-07-15 02:48:11 +02:00
parent 3ce2a318ca
commit 2481e33abd
22 changed files with 928 additions and 914 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ Release/
*.suo *.suo
*.sdf *.sdf
*.opensdf *.opensdf
*.orig

View File

@ -2,14 +2,14 @@
namespace GleeBug namespace GleeBug
{ {
DllInfo::DllInfo() DllInfo::DllInfo()
{ {
} }
DllInfo::DllInfo(LPVOID lpBaseOfDll, DWORD sizeOfImage, LPVOID entryPoint) DllInfo::DllInfo(LPVOID lpBaseOfDll, ULONG_PTR sizeOfImage, LPVOID entryPoint)
{ {
this->lpBaseOfDll = (ULONG_PTR)lpBaseOfDll; this->lpBaseOfDll = reinterpret_cast<ULONG_PTR>(lpBaseOfDll);
this->sizeOfImage = sizeOfImage; this->sizeOfImage = sizeOfImage;
this->entryPoint = (ULONG_PTR)entryPoint; this->entryPoint = reinterpret_cast<ULONG_PTR>(entryPoint);
} }
}; };

View File

@ -5,29 +5,29 @@
namespace GleeBug namespace GleeBug
{ {
/** /**
\brief DLL information structure. \brief DLL information structure.
*/ */
class DllInfo class DllInfo
{ {
public: public:
ULONG_PTR lpBaseOfDll; ULONG_PTR lpBaseOfDll;
DWORD sizeOfImage; ULONG_PTR sizeOfImage;
ULONG_PTR entryPoint; ULONG_PTR entryPoint;
/** /**
\brief Default constructor. \brief Default constructor.
*/ */
DllInfo(); DllInfo();
/** /**
\brief Constructor. \brief Constructor.
\param lpBaseOfDll The base of DLL. \param lpBaseOfDll The base of DLL.
\param sizeOfImage Size of the image. \param sizeOfImage Size of the image.
\param entryPoint The entry point. \param entryPoint The entry point.
*/ */
DllInfo(LPVOID lpBaseOfDll, DWORD sizeOfImage, LPVOID entryPoint); DllInfo(LPVOID lpBaseOfDll, ULONG_PTR sizeOfImage, LPVOID entryPoint);
}; };
}; };
#endif //_DEBUGGER_DLL_H #endif //_DEBUGGER_DLL_H

View File

@ -14,35 +14,35 @@
namespace GleeBug namespace GleeBug
{ {
typedef std::pair<ULONG_PTR, ULONG_PTR> Range; typedef std::pair<ULONG_PTR, ULONG_PTR> Range;
struct RangeCompare struct RangeCompare
{ {
inline bool operator()(const Range & a, const Range & b) const //a before b? inline bool operator()(const Range & a, const Range & b) const //a before b?
{ {
return a.second < b.first; return a.second < b.first;
} }
}; };
//forward declarations //forward declarations
class Debugger; class Debugger;
class ProcessInfo; class ProcessInfo;
class DllInfo; class DllInfo;
class ThreadInfo; class ThreadInfo;
//map typedefs //map typedefs
typedef std::map<DWORD, ProcessInfo> ProcessMap; typedef std::map<DWORD, ProcessInfo> ProcessMap;
typedef std::map<Range, DllInfo, RangeCompare> DllMap; typedef std::map<Range, DllInfo, RangeCompare> DllMap;
typedef std::map<DWORD, ThreadInfo> ThreadMap; typedef std::map<DWORD, ThreadInfo> ThreadMap;
//callback function typedefs
typedef std::function<void()> StepCallback;
//vector typedefs //callback function typedefs
typedef std::vector<StepCallback> StepCallbackVector; typedef std::function<void()> StepCallback;
//macros //vector typedefs
#define BIND(thisPtr, funcPtr) std::bind(&funcPtr, thisPtr) typedef std::vector<StepCallback> StepCallbackVector;
//macros
#define BIND(thisPtr, funcPtr) std::bind(&funcPtr, thisPtr)
}; };
#endif //_DEBUGGER_GLOBAL_H #endif //_DEBUGGER_GLOBAL_H

View File

@ -2,12 +2,12 @@
namespace GleeBug namespace GleeBug
{ {
void Debugger::debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) void Debugger::debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
{ {
//prevent anti-debug trick (debug string events are actually exceptions) //prevent anti-debug trick (debug string events are actually exceptions)
_continueStatus = DBG_EXCEPTION_NOT_HANDLED; _continueStatus = DBG_EXCEPTION_NOT_HANDLED;
//call the debug event callback //call the debug event callback
cbDebugStringEvent(debugString); cbDebugStringEvent(debugString);
} }
}; };

View File

@ -2,37 +2,37 @@
namespace GleeBug namespace GleeBug
{ {
void Debugger::loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll) void Debugger::loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll)
{ {
//DLL housekeeping //DLL housekeeping
MODULEINFO modinfo; MODULEINFO modinfo;
memset(&modinfo, 0, sizeof(MODULEINFO)); memset(&modinfo, 0, sizeof(MODULEINFO));
GetModuleInformation(_process->hProcess, GetModuleInformation(_process->hProcess,
(HMODULE)loadDll.lpBaseOfDll, reinterpret_cast<HMODULE>(loadDll.lpBaseOfDll),
&modinfo, &modinfo,
sizeof(MODULEINFO)); sizeof(MODULEINFO));
DllInfo dll(loadDll.lpBaseOfDll, modinfo.SizeOfImage, modinfo.EntryPoint); DllInfo dll(loadDll.lpBaseOfDll, modinfo.SizeOfImage, modinfo.EntryPoint);
_process->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 //call the debug event callback
cbLoadDllEvent(loadDll, dll); cbLoadDllEvent(loadDll, dll);
//close the file handle //close the file handle
CloseHandle(loadDll.hFile); CloseHandle(loadDll.hFile);
} }
void Debugger::unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll) void Debugger::unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll)
{ {
//call the debug event callback //call the debug event callback
ULONG_PTR lpBaseOfDll = (ULONG_PTR)unloadDll.lpBaseOfDll; ULONG_PTR lpBaseOfDll = reinterpret_cast<ULONG_PTR>(unloadDll.lpBaseOfDll);
auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll)); auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
if (dll != _process->dlls.end()) if (dll != _process->dlls.end())
cbUnloadDllEvent(unloadDll, dll->second); cbUnloadDllEvent(unloadDll, dll->second);
else else
cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, 0)); cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, nullptr));
//DLL housekeeping //DLL housekeeping
if (dll != _process->dlls.end()) if (dll != _process->dlls.end())
_process->dlls.erase(dll); _process->dlls.erase(dll);
} }
}; };

View File

@ -2,64 +2,61 @@
namespace GleeBug namespace GleeBug
{ {
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{ {
if (!_process->systemBreakpoint) //handle system breakpoint if (!_process->systemBreakpoint) //handle system breakpoint
{ {
_process->systemBreakpoint = true; _process->systemBreakpoint = true;
_continueStatus = DBG_CONTINUE; _continueStatus = DBG_CONTINUE;
//call the callback //call the callback
cbSystemBreakpoint(); cbSystemBreakpoint();
} }
else //handle other breakpoint exceptions }
{
}
}
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{ {
if (_thread->isSingleStepping) //handle single step if (_thread->isSingleStepping) //handle single step
{ {
_thread->isSingleStepping = false; _thread->isSingleStepping = false;
_continueStatus = DBG_CONTINUE; _continueStatus = DBG_CONTINUE;
//call the callbacks //call the callbacks
StepCallbackVector cbStepCopy = _thread->stepCallbacks; StepCallbackVector cbStepCopy = _thread->stepCallbacks;
_thread->stepCallbacks.clear(); _thread->stepCallbacks.clear();
for (auto cbStep : cbStepCopy) for (auto cbStep : cbStepCopy)
cbStep(); cbStep();
cbStep(); cbStep();
} }
else //handle other single step exceptions else //handle other single step exceptions
{ {
} }
} }
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
{ {
//let the debuggee handle exceptions per default //let the debuggee handle exceptions per default
_continueStatus = DBG_EXCEPTION_NOT_HANDLED; _continueStatus = DBG_EXCEPTION_NOT_HANDLED;
const EXCEPTION_RECORD & exceptionRecord = exceptionInfo.ExceptionRecord; const EXCEPTION_RECORD & exceptionRecord = exceptionInfo.ExceptionRecord;
const bool firstChance = exceptionInfo.dwFirstChance == 1; const bool firstChance = exceptionInfo.dwFirstChance == 1;
//dispatch the exception //dispatch the exception
switch (exceptionInfo.ExceptionRecord.ExceptionCode) switch (exceptionInfo.ExceptionRecord.ExceptionCode)
{ {
case STATUS_BREAKPOINT: case STATUS_BREAKPOINT:
exceptionBreakpoint(exceptionRecord, firstChance); exceptionBreakpoint(exceptionRecord, firstChance);
break; break;
case STATUS_SINGLE_STEP: case STATUS_SINGLE_STEP:
exceptionSingleStep(exceptionRecord, firstChance); exceptionSingleStep(exceptionRecord, firstChance);
break; break;
} }
//call the unhandled exception callback //call the unhandled exception callback
if (_continueStatus == DBG_EXCEPTION_NOT_HANDLED) if (_continueStatus == DBG_EXCEPTION_NOT_HANDLED)
cbUnhandledException(exceptionRecord, firstChance); cbUnhandledException(exceptionRecord, firstChance);
//call the debug event callback //call the debug event callback
cbExceptionEvent(exceptionInfo); cbExceptionEvent(exceptionInfo);
} }
}; };

View File

@ -2,47 +2,47 @@
namespace GleeBug namespace GleeBug
{ {
void Debugger::createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess) void Debugger::createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess)
{ {
//process housekeeping //process housekeeping
ProcessInfo process(_debugEvent.dwProcessId, ProcessInfo process(_debugEvent.dwProcessId,
createProcess.hProcess, createProcess.hProcess,
_debugEvent.dwThreadId); _debugEvent.dwThreadId);
_processes.insert({ process.dwProcessId, process }); _processes.insert({ process.dwProcessId, process });
_process = &_processes.find(process.dwProcessId)->second; _process = &_processes.find(process.dwProcessId)->second;
//thread housekeeping (main thread is created implicitly) //thread housekeeping (main thread is created implicitly)
ThreadInfo thread(_debugEvent.dwThreadId, ThreadInfo thread(_debugEvent.dwThreadId,
createProcess.hThread, createProcess.hThread,
createProcess.lpThreadLocalBase, createProcess.lpThreadLocalBase,
createProcess.lpStartAddress); createProcess.lpStartAddress);
_process->threads.insert({ thread.dwThreadId, thread }); _process->threads.insert({ thread.dwThreadId, thread });
_thread = _process->thread = &_process->threads.find(thread.dwThreadId)->second; _thread = _process->thread = &_process->threads.find(thread.dwThreadId)->second;
//read thread context from main thread //read thread context from main thread
if (!_thread->RegReadContext()) if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!"); cbInternalError("ThreadInfo::RegReadContext() failed!");
//call the debug event callback //call the debug event callback
cbCreateProcessEvent(createProcess, *_process); cbCreateProcessEvent(createProcess, *_process);
//close the file handle //close the file handle
CloseHandle(createProcess.hFile); CloseHandle(createProcess.hFile);
} }
void Debugger::exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess) void Debugger::exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess)
{ {
//check if the terminated process is the main debuggee //check if the terminated process is the main debuggee
if (_debugEvent.dwProcessId == _mainProcess.dwProcessId) if (_debugEvent.dwProcessId == _mainProcess.dwProcessId)
_breakDebugger = true; _breakDebugger = true;
//call the debug event callback //call the debug event callback
cbExitProcessEvent(exitProcess, *_process); cbExitProcessEvent(exitProcess, *_process);
//process housekeeping //process housekeeping
_processes.erase(_debugEvent.dwProcessId); _processes.erase(_debugEvent.dwProcessId);
//set the current process //set the current process
_process = nullptr; _process = nullptr;
} }
}; };

View File

@ -2,12 +2,12 @@
namespace GleeBug namespace GleeBug
{ {
void Debugger::ripEvent(const RIP_INFO & rip) void Debugger::ripEvent(const RIP_INFO & rip)
{ {
//prevent anti-debug trick (RIP events are actually exceptions) //prevent anti-debug trick (RIP events are actually exceptions)
_continueStatus = DBG_EXCEPTION_NOT_HANDLED; _continueStatus = DBG_EXCEPTION_NOT_HANDLED;
//call the debug event callback //call the debug event callback
cbRipEvent(rip); cbRipEvent(rip);
} }
}; };

View File

@ -2,30 +2,30 @@
namespace GleeBug namespace GleeBug
{ {
void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread) void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread)
{ {
//thread housekeeping //thread housekeeping
_process->threads.insert({ _debugEvent.dwThreadId, _process->threads.insert({ _debugEvent.dwThreadId,
ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) }); ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) });
//set the current thread //set the current thread
_thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second; _thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second;
if (!_thread->RegReadContext()) if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!"); cbInternalError("ThreadInfo::RegReadContext() failed!");
//call the debug event callback //call the debug event callback
cbCreateThreadEvent(createThread, *_thread); cbCreateThreadEvent(createThread, *_thread);
} }
void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread) void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread)
{ {
//call the debug event callback //call the debug event callback
cbExitThreadEvent(exitThread, *_thread); cbExitThreadEvent(exitThread, *_thread);
//thread housekeeping //thread housekeeping
_process->threads.erase(_debugEvent.dwThreadId); _process->threads.erase(_debugEvent.dwThreadId);
//set the current thread //set the current thread
_thread = _process->thread = nullptr; _thread = _process->thread = nullptr;
} }
}; };

View File

@ -2,84 +2,84 @@
namespace GleeBug namespace GleeBug
{ {
void Debugger::Start() void Debugger::Start()
{ {
//initialize loop variables //initialize loop variables
_breakDebugger = false; _breakDebugger = false;
while (!_breakDebugger) while (!_breakDebugger)
{ {
//wait for a debug event //wait for a debug event
_isRunning = true; _isRunning = true;
if (!WaitForDebugEvent(&_debugEvent, INFINITE)) if (!WaitForDebugEvent(&_debugEvent, INFINITE))
break; break;
_isRunning = false; _isRunning = false;
//set default continue status //set default continue status
_continueStatus = DBG_EXCEPTION_NOT_HANDLED; _continueStatus = DBG_EXCEPTION_NOT_HANDLED;
//set the current process and thread //set the current process and thread
if (_processes.count(_debugEvent.dwProcessId)) if (_processes.count(_debugEvent.dwProcessId))
{ {
_process = &_processes[_debugEvent.dwProcessId]; _process = &_processes[_debugEvent.dwProcessId];
if (_process->threads.count(_debugEvent.dwThreadId)) if (_process->threads.count(_debugEvent.dwThreadId))
{ {
_thread = _process->thread = &_process->threads[_debugEvent.dwThreadId]; _thread = _process->thread = &_process->threads[_debugEvent.dwThreadId];
if (!_thread->RegReadContext()) if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!"); cbInternalError("ThreadInfo::RegReadContext() failed!");
} }
else else
_thread = _process->thread = nullptr; _thread = _process->thread = nullptr;
} }
else else
_process = nullptr; _process = nullptr;
//dispatch the debug event //dispatch the debug event
switch (_debugEvent.dwDebugEventCode) switch (_debugEvent.dwDebugEventCode)
{ {
case CREATE_PROCESS_DEBUG_EVENT: case CREATE_PROCESS_DEBUG_EVENT:
createProcessEvent(_debugEvent.u.CreateProcessInfo); createProcessEvent(_debugEvent.u.CreateProcessInfo);
break; break;
case EXIT_PROCESS_DEBUG_EVENT: case EXIT_PROCESS_DEBUG_EVENT:
exitProcessEvent(_debugEvent.u.ExitProcess); exitProcessEvent(_debugEvent.u.ExitProcess);
break; break;
case CREATE_THREAD_DEBUG_EVENT: case CREATE_THREAD_DEBUG_EVENT:
createThreadEvent(_debugEvent.u.CreateThread); createThreadEvent(_debugEvent.u.CreateThread);
break; break;
case EXIT_THREAD_DEBUG_EVENT: case EXIT_THREAD_DEBUG_EVENT:
exitThreadEvent(_debugEvent.u.ExitThread); exitThreadEvent(_debugEvent.u.ExitThread);
break; break;
case LOAD_DLL_DEBUG_EVENT: case LOAD_DLL_DEBUG_EVENT:
loadDllEvent(_debugEvent.u.LoadDll); loadDllEvent(_debugEvent.u.LoadDll);
break; break;
case UNLOAD_DLL_DEBUG_EVENT: case UNLOAD_DLL_DEBUG_EVENT:
unloadDllEvent(_debugEvent.u.UnloadDll); unloadDllEvent(_debugEvent.u.UnloadDll);
break; break;
case EXCEPTION_DEBUG_EVENT: case EXCEPTION_DEBUG_EVENT:
exceptionEvent(_debugEvent.u.Exception); exceptionEvent(_debugEvent.u.Exception);
break; break;
case OUTPUT_DEBUG_STRING_EVENT: case OUTPUT_DEBUG_STRING_EVENT:
debugStringEvent(_debugEvent.u.DebugString); debugStringEvent(_debugEvent.u.DebugString);
break; break;
case RIP_EVENT: case RIP_EVENT:
ripEvent(_debugEvent.u.RipInfo); ripEvent(_debugEvent.u.RipInfo);
break; break;
} }
//write the register context //write the register context
if (_thread) if (_thread)
{ {
if (!_thread->RegWriteContext()) if (!_thread->RegWriteContext())
cbInternalError("ThreadInfo::RegWriteContext() failed!"); cbInternalError("ThreadInfo::RegWriteContext() failed!");
} }
//continue the debug event //continue the debug event
if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus)) if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus))
break; break;
} }
//cleanup //cleanup
_processes.clear(); _processes.clear();
_process = nullptr; _process = nullptr;
} }
}; };

View File

@ -2,28 +2,28 @@
namespace GleeBug namespace GleeBug
{ {
ProcessInfo::ProcessInfo() ProcessInfo::ProcessInfo()
{ {
this->thread = nullptr; this->thread = nullptr;
this->systemBreakpoint = false; this->systemBreakpoint = false;
this->hProcess = INVALID_HANDLE_VALUE; this->hProcess = INVALID_HANDLE_VALUE;
} }
ProcessInfo::ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId) ProcessInfo::ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId)
{ {
this->systemBreakpoint = false; this->systemBreakpoint = false;
this->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); this->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
this->dwProcessId = dwProcessId; this->dwProcessId = dwProcessId;
this->dwMainThreadId = dwMainThreadId; this->dwMainThreadId = dwMainThreadId;
} }
bool ProcessInfo::MemRead(ULONG_PTR address, const size_t size, void* buffer) bool ProcessInfo::MemRead(ULONG_PTR address, const size_t size, void* buffer)
{ {
return !!ReadProcessMemory(this->hProcess, (const void*)address, buffer, size, NULL); return !!ReadProcessMemory(this->hProcess, reinterpret_cast<const void*>(address), buffer, size, nullptr);
} }
bool ProcessInfo::MemWrite(ULONG_PTR address, const size_t size, const void* buffer) bool ProcessInfo::MemWrite(ULONG_PTR address, const size_t size, const void* buffer)
{ {
return !!WriteProcessMemory(this->hProcess, (void*)address, buffer, size, NULL); return !!WriteProcessMemory(this->hProcess, reinterpret_cast<void*>(address), buffer, size, nullptr);
} }
}; };

View File

@ -7,52 +7,52 @@
namespace GleeBug namespace GleeBug
{ {
/** /**
\brief Process information structure. \brief Process information structure.
*/ */
class ProcessInfo class ProcessInfo
{ {
public: public:
HANDLE hProcess; HANDLE hProcess;
DWORD dwProcessId; DWORD dwProcessId;
DWORD dwMainThreadId; DWORD dwMainThreadId;
ThreadInfo* thread; ThreadInfo* thread;
bool systemBreakpoint; bool systemBreakpoint;
ThreadMap threads; ThreadMap threads;
DllMap dlls; DllMap dlls;
/** /**
\brief Default constructor. \brief Default constructor.
*/ */
ProcessInfo(); ProcessInfo();
/** /**
\brief Constructor. \brief Constructor.
\param dwProcessId Identifier for the process. \param dwProcessId Identifier for the process.
\param dwMainThreadId Identifier for the main thread. \param dwMainThreadId Identifier for the main thread.
*/ */
ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId); ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId);
/** /**
\brief Read memory from the process. \brief Read memory from the process.
\param address The virtual address to read from. \param address The virtual address to read from.
\param size The size to read. \param size The size to read.
\param [out] buffer Destination buffer. Cannot be null. May be filled partially on failure. \param [out] buffer Destination buffer. Cannot be null. May be filled partially on failure.
\return true if it succeeds, false if it fails. \return true if it succeeds, false if it fails.
*/ */
bool MemRead(ULONG_PTR address, const size_t size, void* buffer); bool MemRead(ULONG_PTR address, const size_t size, void* buffer);
/** /**
\brief Write memory to the process. \brief Write memory to the process.
\param address The virtual address to write to. \param address The virtual address to write to.
\param size The size to write. \param size The size to write.
\param [in] buffer Source buffer. Cannot be null. \param [in] buffer Source buffer. Cannot be null.
\return true if it succeeds, false if it fails. \return true if it succeeds, false if it fails.
*/ */
bool MemWrite(ULONG_PTR address, const size_t size, const void* buffer); bool MemWrite(ULONG_PTR address, const size_t size, const void* buffer);
}; };
}; };
#endif //_DEBUGGER_PROCESS_H #endif //_DEBUGGER_PROCESS_H

View File

@ -2,106 +2,106 @@
namespace GleeBug namespace GleeBug
{ {
RegistersInfo::RegistersInfo() RegistersInfo::RegistersInfo()
{ {
memset(&this->_context, 0, sizeof(CONTEXT)); memset(&this->_context, 0, sizeof(CONTEXT));
} }
const CONTEXT* RegistersInfo::GetContext() const CONTEXT* RegistersInfo::GetContext()
{ {
#ifdef _WIN64 #ifdef _WIN64
_context.Rax = this->Rax; _context.Rax = this->Rax;
_context.Rbx = this->Rbx; _context.Rbx = this->Rbx;
_context.Rcx = this->Rcx; _context.Rcx = this->Rcx;
_context.Rdx = this->Rdx; _context.Rdx = this->Rdx;
_context.Rsi = this->Rsi; _context.Rsi = this->Rsi;
_context.Rdi = this->Rdi; _context.Rdi = this->Rdi;
_context.Rbp = this->Rbp; _context.Rbp = this->Rbp;
_context.Rsp = this->Rsp; _context.Rsp = this->Rsp;
_context.Rip = this->Rip; _context.Rip = this->Rip;
_context.R8 = this->R8; _context.R8 = this->R8;
_context.R9 = this->R9; _context.R9 = this->R9;
_context.R10 = this->R10; _context.R10 = this->R10;
_context.R11 = this->R11; _context.R11 = this->R11;
_context.R12 = this->R12; _context.R12 = this->R12;
_context.R13 = this->R13; _context.R13 = this->R13;
_context.R14 = this->R14; _context.R14 = this->R14;
_context.R15 = this->R15; _context.R15 = this->R15;
_context.EFlags = this->EFlags; _context.EFlags = this->EFlags;
#else //x86 #else //x86
_context.Eax = this->Eax; _context.Eax = this->Eax;
_context.Ebx = this->Ebx; _context.Ebx = this->Ebx;
_context.Ecx = this->Ecx; _context.Ecx = this->Ecx;
_context.Edx = this->Edx; _context.Edx = this->Edx;
_context.Esi = this->Esi; _context.Esi = this->Esi;
_context.Edi = this->Edi; _context.Edi = this->Edi;
_context.Ebp = this->Ebp; _context.Ebp = this->Ebp;
_context.Esp = this->Esp; _context.Esp = this->Esp;
_context.Eip = this->Eip; _context.Eip = this->Eip;
_context.EFlags = this->EFlags; _context.EFlags = this->EFlags;
#endif //_WIN64 #endif //_WIN64
return &_context; return &_context;
} }
void RegistersInfo::SetContext(const CONTEXT & context) void RegistersInfo::SetContext(const CONTEXT & context)
{ {
#ifdef _WIN64 #ifdef _WIN64
this->Rax = context.Rax; this->Rax = context.Rax;
this->Rbx = context.Rbx; this->Rbx = context.Rbx;
this->Rcx = context.Rcx; this->Rcx = context.Rcx;
this->Rdx = context.Rdx; this->Rdx = context.Rdx;
this->Rsi = context.Rsi; this->Rsi = context.Rsi;
this->Rdi = context.Rdi; this->Rdi = context.Rdi;
this->Rbp = context.Rbp; this->Rbp = context.Rbp;
this->Rsp = context.Rsp; this->Rsp = context.Rsp;
this->Rip = context.Rip; this->Rip = context.Rip;
this->R8 = context.R8; this->R8 = context.R8;
this->R9 = context.R9; this->R9 = context.R9;
this->R10 = context.R10; this->R10 = context.R10;
this->R11 = context.R11; this->R11 = context.R11;
this->R12 = context.R12; this->R12 = context.R12;
this->R13 = context.R13; this->R13 = context.R13;
this->R14 = context.R14; this->R14 = context.R14;
this->R15 = context.R15; this->R15 = context.R15;
this->EFlags = context.EFlags; this->EFlags = context.EFlags;
#else //x86 #else //x86
this->Eax = context.Eax; this->Eax = context.Eax;
this->Ebx = context.Ebx; this->Ebx = context.Ebx;
this->Ecx = context.Ecx; this->Ecx = context.Ecx;
this->Edx = context.Edx; this->Edx = context.Edx;
this->Esi = context.Esi; this->Esi = context.Esi;
this->Edi = context.Edi; this->Edi = context.Edi;
this->Ebp = context.Ebp; this->Ebp = context.Ebp;
this->Esp = context.Esp; this->Esp = context.Esp;
this->Eip = context.Eip; this->Eip = context.Eip;
this->EFlags = context.EFlags; this->EFlags = context.EFlags;
#endif //_WIN64 #endif //_WIN64
this->_context = context; this->_context = context;
} }
void RegistersInfo::SetTrapFlag(bool set) void RegistersInfo::SetTrapFlag(bool set)
{ {
if (set) if (set)
this->EFlags |= TRAP_FLAG; this->EFlags |= TRAP_FLAG;
else else
this->EFlags &= ~TRAP_FLAG; this->EFlags &= ~TRAP_FLAG;
} }
bool RegistersInfo::GetTrapFlag() bool RegistersInfo::GetTrapFlag()
{ {
return (this->EFlags & TRAP_FLAG) == TRAP_FLAG; return (this->EFlags & TRAP_FLAG) == TRAP_FLAG;
} }
void RegistersInfo::SetResumeFlag(bool set) void RegistersInfo::SetResumeFlag(bool set)
{ {
if (set) if (set)
this->EFlags |= RESUME_FLAG; this->EFlags |= RESUME_FLAG;
else else
this->EFlags &= ~RESUME_FLAG; this->EFlags &= ~RESUME_FLAG;
} }
bool RegistersInfo::GetResumeFlag() bool RegistersInfo::GetResumeFlag()
{ {
return (this->EFlags & RESUME_FLAG) == RESUME_FLAG; return (this->EFlags & RESUME_FLAG) == RESUME_FLAG;
} }
}; };

View File

@ -5,91 +5,91 @@
namespace GleeBug namespace GleeBug
{ {
CONTEXT; CONTEXT;
/** /**
\brief Thread register context. \brief Thread register context.
*/ */
class RegistersInfo class RegistersInfo
{ {
public: public:
#ifdef _WIN64 #ifdef _WIN64
DWORD64 Rax; DWORD64 Rax;
DWORD64 Rbx; DWORD64 Rbx;
DWORD64 Rcx; DWORD64 Rcx;
DWORD64 Rdx; DWORD64 Rdx;
DWORD64 Rsi; DWORD64 Rsi;
DWORD64 Rdi; DWORD64 Rdi;
DWORD64 Rbp; DWORD64 Rbp;
DWORD64 Rsp; DWORD64 Rsp;
DWORD64 Rip; DWORD64 Rip;
DWORD64 R8; DWORD64 R8;
DWORD64 R9; DWORD64 R9;
DWORD64 R10; DWORD64 R10;
DWORD64 R11; DWORD64 R11;
DWORD64 R12; DWORD64 R12;
DWORD64 R13; DWORD64 R13;
DWORD64 R14; DWORD64 R14;
DWORD64 R15; DWORD64 R15;
DWORD EFlags; DWORD EFlags;
#else //x86 #else //x86
DWORD Eax; DWORD Eax;
DWORD Ebx; DWORD Ebx;
DWORD Ecx; DWORD Ecx;
DWORD Edx; DWORD Edx;
DWORD Esi; DWORD Esi;
DWORD Edi; DWORD Edi;
DWORD Ebp; DWORD Ebp;
DWORD Esp; DWORD Esp;
DWORD Eip; DWORD Eip;
DWORD EFlags; DWORD EFlags;
#endif //_WIN64 #endif //_WIN64
/** /**
\brief Default constructor. \brief Default constructor.
*/ */
RegistersInfo(); RegistersInfo();
/** /**
\brief Gets a pointer to the context object. \brief Gets a pointer to the context object.
\return This function will never return a nullptr. \return This function will never return a nullptr.
*/ */
const CONTEXT* GetContext(); const CONTEXT* GetContext();
/** /**
\brief Sets the CONTEXT. \brief Sets the CONTEXT.
\param context The context to set. \param context The context to set.
*/ */
void SetContext(const CONTEXT & context); void SetContext(const CONTEXT & context);
/** /**
\brief Sets trap flag. \brief Sets trap flag.
\param set (Optional) true to set, false to unset. \param set (Optional) true to set, false to unset.
*/ */
void SetTrapFlag(bool set = true); void SetTrapFlag(bool set = true);
/** /**
\brief Gets trap flag. \brief Gets trap flag.
\return true if the flag is set, false otherwise. \return true if the flag is set, false otherwise.
*/ */
bool GetTrapFlag(); bool GetTrapFlag();
/** /**
\brief Sets resume flag. \brief Sets resume flag.
\param set (Optional) true to set, false to unset. \param set (Optional) true to set, false to unset.
*/ */
void SetResumeFlag(bool set = true); void SetResumeFlag(bool set = true);
/** /**
\brief Gets resume flag. \brief Gets resume flag.
\return true if the flag is set, false otherwise. \return true if the flag is set, false otherwise.
*/ */
bool GetResumeFlag(); bool GetResumeFlag();
private: private:
CONTEXT _context; CONTEXT _context;
const int TRAP_FLAG = 0x100; const int TRAP_FLAG = 0x100;
const int RESUME_FLAG = 0x10000; const int RESUME_FLAG = 0x10000;
}; };
}; };
#endif //_DEBUGGER_THREAD_REGISTERS_H #endif //_DEBUGGER_THREAD_REGISTERS_H

View File

@ -2,55 +2,55 @@
namespace GleeBug namespace GleeBug
{ {
ThreadInfo::ThreadInfo() ThreadInfo::ThreadInfo()
{ {
this->hThread = INVALID_HANDLE_VALUE; this->hThread = INVALID_HANDLE_VALUE;
} }
ThreadInfo::ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress) ThreadInfo::ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress)
{ {
this->dwThreadId = dwThreadId; this->dwThreadId = dwThreadId;
this->hThread = hThread; this->hThread = hThread;
this->lpThreadLocalBase = (ULONG_PTR)lpThreadLocalBase; this->lpThreadLocalBase = reinterpret_cast<ULONG_PTR>(lpThreadLocalBase);
this->lpStartAddress = (ULONG_PTR)lpStartAddress; this->lpStartAddress = reinterpret_cast<ULONG_PTR>(lpStartAddress);
} }
bool ThreadInfo::RegReadContext() bool ThreadInfo::RegReadContext()
{ {
SuspendThread(this->hThread); SuspendThread(this->hThread);
memset(&this->_oldContext, 0, sizeof(CONTEXT)); memset(&this->_oldContext, 0, sizeof(CONTEXT));
this->_oldContext.ContextFlags = CONTEXT_ALL; this->_oldContext.ContextFlags = CONTEXT_ALL;
bool bReturn = false; bool bReturn = false;
if (GetThreadContext(this->hThread, &this->_oldContext)) if (GetThreadContext(this->hThread, &this->_oldContext))
{ {
this->registers.SetContext(this->_oldContext); this->registers.SetContext(this->_oldContext);
bReturn = true; bReturn = true;
} }
ResumeThread(this->hThread); ResumeThread(this->hThread);
return bReturn; return bReturn;
} }
bool ThreadInfo::RegWriteContext() bool ThreadInfo::RegWriteContext()
{ {
//check if something actually changed //check if something actually changed
if (memcmp(&this->_oldContext, this->registers.GetContext(), sizeof(CONTEXT)) == 0) if (memcmp(&this->_oldContext, this->registers.GetContext(), sizeof(CONTEXT)) == 0)
return true; return true;
//update the context //update the context
SuspendThread(this->hThread); SuspendThread(this->hThread);
bool bReturn = !!SetThreadContext(this->hThread, this->registers.GetContext()); bool bReturn = !!SetThreadContext(this->hThread, this->registers.GetContext());
ResumeThread(this->hThread); ResumeThread(this->hThread);
return bReturn; return bReturn;
} }
void ThreadInfo::StepInto(StepCallback cbStep) void ThreadInfo::StepInto(const StepCallback & cbStep)
{ {
StepInto(); StepInto();
stepCallbacks.push_back(cbStep); stepCallbacks.push_back(cbStep);
} }
void ThreadInfo::StepInto() void ThreadInfo::StepInto()
{ {
registers.SetTrapFlag(); registers.SetTrapFlag();
isSingleStepping = true; isSingleStepping = true;
} }
}; };

View File

@ -6,73 +6,73 @@
namespace GleeBug namespace GleeBug
{ {
/** /**
\brief Thread information structure. \brief Thread information structure.
*/ */
class ThreadInfo class ThreadInfo
{ {
public: public:
DWORD dwThreadId; DWORD dwThreadId;
HANDLE hThread; HANDLE hThread;
ULONG_PTR lpThreadLocalBase; ULONG_PTR lpThreadLocalBase;
ULONG_PTR lpStartAddress; ULONG_PTR lpStartAddress;
RegistersInfo registers; RegistersInfo registers;
StepCallbackVector stepCallbacks; StepCallbackVector stepCallbacks;
bool isSingleStepping; bool isSingleStepping;
/** /**
\brief Default constructor. \brief Default constructor.
*/ */
ThreadInfo(); ThreadInfo();
/** /**
\brief Constructor. \brief Constructor.
\param dwThreadId Identifier for the thread. \param dwThreadId Identifier for the thread.
\param lpThreadLocalBase The thread local base. \param lpThreadLocalBase The thread local base.
\param lpStartAddress The start address. \param lpStartAddress The start address.
*/ */
ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress); ThreadInfo(DWORD dwThreadId, HANDLE hThread, LPVOID lpThreadLocalBase, LPVOID lpStartAddress);
/** /**
\brief Read the register context from the thread. This fills the RegistersInfo member. \brief Read the register context from the thread. This fills the RegistersInfo member.
\return true if it succeeds, false if it fails. \return true if it succeeds, false if it fails.
*/ */
bool RegReadContext(); bool RegReadContext();
/** /**
\brief Write the register context to the thread. This does nothing if the RegistersInfo member did not change. \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. \return true if it succeeds, false if it fails.
*/ */
bool RegWriteContext(); bool RegWriteContext();
/** /**
\brief Step into. \brief Step into.
*/ */
void StepInto(); void StepInto();
/** /**
\brief Step into. \brief Step into.
\param cbStep StepCallback. Can be written using BIND(this, MyDebugger::cb). \param cbStep StepCallback. Can be written using BIND(this, MyDebugger::cb).
*/ */
void StepInto(StepCallback cbStep); void StepInto(const StepCallback & cbStep);
/** /**
\brief Step into. \brief Step into.
\tparam T Generic type parameter. Must be a subclass of Debugger. \tparam T Generic type parameter. Must be a subclass of Debugger.
\param debugger This pointer to a subclass of Debugger. \param debugger This pointer to a subclass of Debugger.
\param callback Pointer to the callback. Written like: &MyDebugger::cb \param callback Pointer to the callback. Written like: &MyDebugger::cb
*/ */
template <typename T> template <typename T>
void StepInto(T* debugger, void(T::*callback)()) void StepInto(T* debugger, void(T::*callback)())
{ {
static_cast<void>(static_cast<Debugger *>(debugger)); static_cast<void>(static_cast<Debugger *>(debugger));
StepInto(std::bind(callback, debugger)); StepInto(std::bind(callback, debugger));
} }
private: private:
CONTEXT _oldContext; CONTEXT _oldContext;
}; };
}; };
#endif //_DEBUGGER_THREADS_H #endif //_DEBUGGER_THREADS_H

View File

@ -2,51 +2,62 @@
namespace GleeBug namespace GleeBug
{ {
Debugger::Debugger() Debugger::Debugger()
{ {
_processes.clear(); _processes.clear();
} }
bool Debugger::Init(const wchar_t* szFilePath, Debugger::~Debugger()
const wchar_t* szCommandLine, {
const wchar_t* szCurrentDirectory) }
{
STARTUPINFOW si;
memset(&si, 0, sizeof(si));
const wchar_t* szFileNameCreateProcess;
wchar_t* szCommandLineCreateProcess;
if (szCommandLine == NULL || !wcslen(szCommandLine))
{
szCommandLineCreateProcess = 0;
szFileNameCreateProcess = szFilePath;
}
else
{
wchar_t szCreateWithCmdLine[1024];
swprintf_s(szCreateWithCmdLine, L"\"%s\" %s", szFilePath, szCommandLine);
szCommandLineCreateProcess = szCreateWithCmdLine;
szFileNameCreateProcess = 0;
}
return !!CreateProcessW(szFileNameCreateProcess, bool Debugger::Init(const wchar_t* szFilePath,
szCommandLineCreateProcess, const wchar_t* szCommandLine,
NULL, const wchar_t* szCurrentDirectory)
NULL, {
FALSE, STARTUPINFOW si;
DEBUG_PROCESS | CREATE_NEW_CONSOLE, memset(&si, 0, sizeof(si));
NULL, const wchar_t* szFileNameCreateProcess;
szCurrentDirectory, wchar_t* szCommandLineCreateProcess = nullptr;
&si, wchar_t* szCreateWithCmdLine = nullptr;
&_mainProcess); if (szCommandLine == nullptr || !wcslen(szCommandLine))
} {
szCommandLineCreateProcess = nullptr;
szFileNameCreateProcess = szFilePath;
}
else
{
auto size = 1 + wcslen(szFilePath) + 2 + wcslen(szCommandLine) + 1;
szCreateWithCmdLine = new wchar_t[size];
swprintf_s(szCreateWithCmdLine, size, L"\"%s\" %s", szFilePath, szCommandLine);
szCommandLineCreateProcess = szCreateWithCmdLine;
szFileNameCreateProcess = nullptr;
}
bool Debugger::Stop() bool result = !!CreateProcessW(szFileNameCreateProcess,
{ szCommandLineCreateProcess,
return !!TerminateProcess(_mainProcess.hProcess, 0); nullptr,
} nullptr,
FALSE,
DEBUG_PROCESS | CREATE_NEW_CONSOLE,
nullptr,
szCurrentDirectory,
&si,
&_mainProcess);
bool Debugger::Detach() if (szCreateWithCmdLine)
{ delete[] szCreateWithCmdLine;
return !!DebugActiveProcessStop(_mainProcess.dwProcessId);
} return result;
}
bool Debugger::Stop()
{
return !!TerminateProcess(_mainProcess.hProcess, 0);
}
bool Debugger::Detach()
{
return !!DebugActiveProcessStop(_mainProcess.dwProcessId);
}
}; };

View File

@ -6,212 +6,217 @@
namespace GleeBug namespace GleeBug
{ {
/** /**
\brief A debugger class. \brief A debugger class.
*/ */
class Debugger class Debugger
{ {
public: //public functionality public: //public functionality
/** /**
\brief Constructs the Debugger instance. \brief Constructs the Debugger instance.
*/ */
Debugger(); Debugger();
/** /**
\brief Start the debuggee. \brief Destructs the Debugger instance.
\param szFilePath Full pathname of the file to debug. */
\param szCommandLine The command line to pass to the debuggee. virtual ~Debugger();
\param szCurrentDirectory Pathname of the current directory.
\return true if the debuggee was started correctly, false otherwise.
*/
bool Init(const wchar_t* szFilePath,
const wchar_t* szCommandLine,
const wchar_t* szCurrentDirectory);
/** /**
\brief Stops the debuggee (terminate the process) \brief Start the debuggee.
\return true if the debuggee was stopped correctly, false otherwise. \param szFilePath Full pathname of the file to debug.
*/ \param szCommandLine The command line to pass to the debuggee.
bool Stop(); \param szCurrentDirectory Pathname of the current directory.
\return true if the debuggee was started correctly, false otherwise.
*/
bool Init(const wchar_t* szFilePath,
const wchar_t* szCommandLine,
const wchar_t* szCurrentDirectory);
/** /**
\brief Detaches the debuggee. \brief Stops the debuggee (terminate the process)
\return true if the debuggee was detached correctly, false otherwise. \return true if the debuggee was stopped correctly, false otherwise.
*/ */
bool Detach(); bool Stop();
/** /**
\brief Run the debug loop (does not return until the debuggee is detached or terminated). \brief Detaches the debuggee.
*/ \return true if the debuggee was detached correctly, false otherwise.
void Start(); */
bool Detach();
protected: //debug event callbacks /**
/** \brief Run the debug loop (does not return until the debuggee is detached or terminated).
\brief Process creation debug event callback. Provide an implementation to use this callback. */
\param createProcess Information about the process created. void Start();
*/
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) {};
/** protected: //debug event callbacks
\brief Process termination debug event callback. Provide an implementation to use this callback. /**
\param exitProcess Information about the process terminated. \brief Process creation debug event callback. Provide an implementation to use this callback.
*/ \param createProcess Information about the process created.
virtual void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) {}; */
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) {};
/** /**
\brief Thread creation debug event callback. Provide an implementation to use this callback. \brief Process termination debug event callback. Provide an implementation to use this callback.
\param createThread Information about the thread created. \param exitProcess Information about the process terminated.
*/ */
virtual void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread) {}; virtual void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) {};
/** /**
\brief Thread termination debug event callback. Provide an implementation to use this callback. \brief Thread creation debug event callback. Provide an implementation to use this callback.
\param exitThread Information about the thread terminated. \param createThread Information about the thread created.
*/ */
virtual void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread) {}; virtual void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread) {};
/** /**
\brief DLL load debug event callback. Provide an implementation to use this callback. \brief Thread termination debug event callback. Provide an implementation to use this callback.
\param loadDll Information about the DLL loaded. \param exitThread Information about the thread terminated.
*/ */
virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) {}; virtual void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread) {};
/** /**
\brief DLL unload debug event callback. Provide an implementation to use this callback. \brief DLL load debug event callback. Provide an implementation to use this callback.
\param unloadDll Information about the DLL unloaded. \param loadDll Information about the DLL loaded.
*/ */
virtual void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll) {}; virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) {};
/** /**
\brief Exception debug event callback. Provide an implementation to use this callback. \brief DLL unload debug event callback. Provide an implementation to use this callback.
\param exceptionInfo Information about the exception. \param unloadDll Information about the DLL unloaded.
*/ */
virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) {}; virtual void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll) {};
/** /**
\brief Debug string debug event callback. Provide an implementation to use this callback. \brief Exception debug event callback. Provide an implementation to use this callback.
\param debugString Information about the debug string. \param exceptionInfo Information about the exception.
*/ */
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) {}; virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) {};
/** /**
\brief RIP debug event callback. Provide an implementation to use this callback. \brief Debug string debug event callback. Provide an implementation to use this callback.
\param rip Information about the RIP event. \param debugString Information about the debug string.
*/ */
virtual void cbRipEvent(const RIP_INFO & rip) {}; virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) {};
protected: //other callbacks /**
/** \brief RIP debug event callback. Provide an implementation to use this callback.
\brief Internal error callback. Provide an implementation to use this callback. \param rip Information about the RIP event.
\param error The error message. */
*/ virtual void cbRipEvent(const RIP_INFO & rip) {};
virtual void cbInternalError(const std::string & error) {};
/** protected: //other callbacks
\brief Unhandled exception callback. Provide an implementation to use this callback. /**
\param exceptionRecord The exception record. \brief Internal error callback. Provide an implementation to use this callback.
\param firstChance True if the exception is a first chance exception, false otherwise. \param error The error message.
*/ */
virtual void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) {}; virtual void cbInternalError(const std::string & error) {};
/** /**
\brief System breakpoint callback. Provide an implementation to use this callback. \brief Unhandled exception callback. Provide an implementation to use this callback.
*/ \param exceptionRecord The exception record.
virtual void cbSystemBreakpoint() {}; \param firstChance True if the exception is a first chance exception, false otherwise.
*/
virtual void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) {};
/** /**
\brief Step callback. Provide an implementation to use this callback. \brief System breakpoint callback. Provide an implementation to use this callback.
*/ */
virtual void cbStep() {}; virtual void cbSystemBreakpoint() {};
protected: //core debug event handlers /**
/** \brief Step callback. Provide an implementation to use this callback.
\brief Process creation debug event. Do not override this unless you know what you are doing! */
\param createProcess Information about the process created. virtual void cbStep() {};
*/
virtual void createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess);
/** protected: //core debug event handlers
\brief Process termination debug event. Do not override this unless you know what you are doing! /**
\param exitProcess Information about the process terminated. \brief Process creation debug event. Do not override this unless you know what you are doing!
*/ \param createProcess Information about the process created.
virtual void exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess); */
virtual void createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess);
/** /**
\brief Thread creation debug event. Do not override this unless you know what you are doing! \brief Process termination debug event. Do not override this unless you know what you are doing!
\param createThread Information about the thread created. \param exitProcess Information about the process terminated.
*/ */
virtual void createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread); virtual void exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess);
/** /**
\brief Thread termination debug event. Do not override this unless you know what you are doing! \brief Thread creation debug event. Do not override this unless you know what you are doing!
\param exitThread Information about the thread terminated. \param createThread Information about the thread created.
*/ */
virtual void exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread); virtual void createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread);
/** /**
\brief DLL load debug event. Do not override this unless you know what you are doing! \brief Thread termination debug event. Do not override this unless you know what you are doing!
\param loadDll Information about the DLL loaded. \param exitThread Information about the thread terminated.
*/ */
virtual void loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll); virtual void exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread);
/** /**
\brief DLL unload debug event. Do not override this unless you know what you are doing! \brief DLL load debug event. Do not override this unless you know what you are doing!
\param unloadDll Information about the DLL unloaded. \param loadDll Information about the DLL loaded.
*/ */
virtual void unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll); virtual void loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll);
/** /**
\brief Exception debug event. Do not override this unless you know what you are doing! \brief DLL unload debug event. Do not override this unless you know what you are doing!
\param exceptionInfo Information about the exception. \param unloadDll Information about the DLL unloaded.
*/ */
virtual void exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo); virtual void unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll);
/** /**
\brief Debug string debug event. Do not override this unless you know what you are doing! \brief Exception debug event. Do not override this unless you know what you are doing!
\param debugString Information about the debug string. \param exceptionInfo Information about the exception.
*/ */
virtual void debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString); virtual void exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo);
/** /**
\brief RIP debug event. Do not override this unless you know what you are doing! \brief Debug string debug event. Do not override this unless you know what you are doing!
\param rip Information about the RIP event. \param debugString Information about the debug string.
*/ */
virtual void ripEvent(const RIP_INFO & rip); virtual void debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString);
protected: //core exception handlers /**
/** \brief RIP debug event. Do not override this unless you know what you are doing!
\brief Breakpoint exception handler. Do not override this unless you know what you are doing! \param rip Information about the RIP event.
\param exceptionRecord The exception record. */
\param firstChance True if the exception is a first chance exception, false otherwise. virtual void ripEvent(const RIP_INFO & rip);
*/
virtual void exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
/** protected: //core exception handlers
\brief Single step exception handler. Do not override this unless you know what you are doing! /**
\param exceptionRecord The exception record. \brief Breakpoint exception handler. Do not override this unless you know what you are doing!
\param firstChance True if the exception is a first chance exception, false otherwise. \param exceptionRecord The exception record.
*/ \param firstChance True if the exception is a first chance exception, false otherwise.
virtual void exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance); */
virtual void exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
protected: //variables /**
PROCESS_INFORMATION _mainProcess; \brief Single step exception handler. Do not override this unless you know what you are doing!
DWORD _continueStatus; \param exceptionRecord The exception record.
bool _breakDebugger; \param firstChance True if the exception is a first chance exception, false otherwise.
DEBUG_EVENT _debugEvent; */
ProcessMap _processes; virtual void exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
bool _isRunning;
/** protected: //variables
\brief The current process (can be null in some cases). PROCESS_INFORMATION _mainProcess;
*/ DWORD _continueStatus;
ProcessInfo* _process; bool _breakDebugger;
DEBUG_EVENT _debugEvent;
ProcessMap _processes;
bool _isRunning;
/** /**
\brief The current thread (can be null in some cases). Should be a copy of _process->thread. \brief The current process (can be null in some cases).
*/ */
ThreadInfo* _thread; ProcessInfo* _process;
};
/**
\brief The current thread (can be null in some cases). Should be a copy of _process->thread.
*/
ThreadInfo* _thread;
};
}; };
#endif //_DEBUGGER_H #endif //_DEBUGGER_H

View File

@ -9,10 +9,6 @@
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter> </Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Debugger.cpp"> <ClCompile Include="Debugger.cpp">

View File

@ -8,85 +8,89 @@ using namespace GleeBug;
class MyDebugger : public Debugger class MyDebugger : public Debugger
{ {
protected: protected:
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) override
{ {
printf("Process %d created with entry 0x%p\n", printf("Process %d created with entry 0x%p\n",
_debugEvent.dwProcessId, _debugEvent.dwProcessId,
createProcess.lpStartAddress); createProcess.lpStartAddress);
}; }
virtual void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) void cbExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess, const ProcessInfo & process) override
{ {
printf("Process %d terminated with exit code 0x%08X\n", printf("Process %u terminated with exit code 0x%08X\n",
_debugEvent.dwProcessId, _debugEvent.dwProcessId,
exitProcess.dwExitCode); exitProcess.dwExitCode);
} }
virtual void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread) void cbCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread, const ThreadInfo & thread) override
{ {
printf("Thread %d created with entry 0x%p\n", printf("Thread %u created with entry 0x%p\n",
_debugEvent.dwThreadId, _debugEvent.dwThreadId,
createThread.lpStartAddress); createThread.lpStartAddress);
}; }
virtual void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread) void cbExitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread, const ThreadInfo & thread) override
{ {
printf("Thread %d terminated with exit code 0x%08X\n", printf("Thread %u terminated with exit code 0x%08X\n",
_debugEvent.dwThreadId, _debugEvent.dwThreadId,
exitThread.dwExitCode); exitThread.dwExitCode);
}; }
virtual void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) void cbLoadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll, const DllInfo & dll) override
{ {
printf("DLL loaded at 0x%p\n", printf("DLL loaded at 0x%p\n",
loadDll.lpBaseOfDll); loadDll.lpBaseOfDll);
}; }
virtual void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll) void cbUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll, const DllInfo & dll) override
{ {
printf("DLL 0x%p unloaded\n", printf("DLL 0x%p unloaded\n",
unloadDll.lpBaseOfDll); unloadDll.lpBaseOfDll);
}; }
virtual void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) void cbExceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) override
{ {
printf("Exception with code 0x%08X at 0x%p\n", printf("Exception with code 0x%08X at 0x%p\n",
exceptionInfo.ExceptionRecord.ExceptionCode, exceptionInfo.ExceptionRecord.ExceptionCode,
exceptionInfo.ExceptionRecord.ExceptionAddress); exceptionInfo.ExceptionRecord.ExceptionAddress);
}; }
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) override
{ {
printf("Debug string at 0x%p with length %d\n", printf("Debug string at 0x%p with length %d\n",
debugString.lpDebugStringData, debugString.lpDebugStringData,
debugString.nDebugStringLength); debugString.nDebugStringLength);
}; }
virtual void cbRipEvent(const RIP_INFO & rip) void cbRipEvent(const RIP_INFO & rip) override
{ {
printf("RIP event type 0x%X, error 0x%X", printf("RIP event type 0x%X, error 0x%X",
rip.dwType, rip.dwType,
rip.dwError); rip.dwError);
}; }
void boobs() void boobs()
{ {
printf("(.)Y(.) 0x%p\n", printf("(.)Y(.) 0x%p\n",
_thread->registers.Rip); #ifdef _WIN64
} _thread->registers.Rip);
#else //x32
_thread->registers.Eip);
#endif //_WIN64
}
virtual void cbSystemBreakpoint() void cbSystemBreakpoint() override
{ {
printf("System breakpoint reached, CIP: 0x%p\n", printf("System breakpoint reached, CIP: 0x%p\n",
_thread->registers.Rip); _thread->registers.Rip);
_thread->StepInto(BIND(this, MyDebugger::boobs)); _thread->StepInto(BIND(this, MyDebugger::boobs));
} }
virtual void cbInternalError(const std::string & error) void cbInternalError(const std::string & error) override
{ {
printf("Internal Error: %s\n", printf("Internal Error: %s\n",
error.c_str()); error.c_str());
} }
}; };
#endif //_MYDEBUGGER_H #endif //_MYDEBUGGER_H

View File

@ -4,23 +4,23 @@
int main() int main()
{ {
#ifdef _WIN64 #ifdef _WIN64
wchar_t szFilePath[256] = L"c:\\test64.exe"; wchar_t szFilePath[256] = L"c:\\test64.exe";
#else //x86 #else //x86
wchar_t szFilePath[256] = L"c:\\test32.exe"; wchar_t szFilePath[256] = L"c:\\test32.exe";
#endif //_WIN64 #endif //_WIN64
wchar_t szCommandLine[256] = L""; wchar_t szCommandLine[256] = L"";
wchar_t szCurrentDir[256] = L"c:\\"; wchar_t szCurrentDir[256] = L"c:\\";
MyDebugger dbg; MyDebugger dbg;
if (dbg.Init(szFilePath, szCommandLine, szCurrentDir)) if (dbg.Init(szFilePath, szCommandLine, szCurrentDir))
{ {
puts("Debugger::Init success!"); puts("Debugger::Init success!");
dbg.Start(); dbg.Start();
puts("Debugger::Start finished!"); puts("Debugger::Start finished!");
} }
else else
{ {
puts("Debugger::Init failed!"); puts("Debugger::Init failed!");
} }
system("pause"); system("pause");
return 0; return 0;
} }