Merge pull request #16 from GleeBug/my_features

fMy features
This commit is contained in:
mrexodia 2015-04-05 20:39:45 +02:00
commit 3ce2a318ca
17 changed files with 509 additions and 67 deletions

View File

@ -8,17 +8,26 @@ namespace GleeBug
/** /**
\brief DLL information structure. \brief DLL information structure.
*/ */
struct DllInfo class DllInfo
{ {
public:
ULONG_PTR lpBaseOfDll; ULONG_PTR lpBaseOfDll;
DWORD sizeOfImage; DWORD sizeOfImage;
ULONG_PTR entryPoint; ULONG_PTR entryPoint;
/**
\brief Default constructor.
*/
DllInfo(); 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); DllInfo(LPVOID lpBaseOfDll, DWORD sizeOfImage, LPVOID entryPoint);
}; };
typedef std::map<Range, DllInfo, RangeCompare> DllMap;
}; };
#endif //_DEBUGGER_DLL_H #endif //_DEBUGGER_DLL_H

View File

@ -6,6 +6,8 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <map> #include <map>
#include <set>
#include <functional>
#include <windows.h> #include <windows.h>
#include <psapi.h> #include <psapi.h>
@ -21,6 +23,26 @@ namespace GleeBug
return a.second < b.first; 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 #endif //_DEBUGGER_GLOBAL_H

View File

@ -7,12 +7,12 @@ namespace GleeBug
//DLL housekeeping //DLL housekeeping
MODULEINFO modinfo; MODULEINFO modinfo;
memset(&modinfo, 0, sizeof(MODULEINFO)); memset(&modinfo, 0, sizeof(MODULEINFO));
GetModuleInformation(_curProcess->hProcess, GetModuleInformation(_process->hProcess,
(HMODULE)loadDll.lpBaseOfDll, (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);
_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 //call the debug event callback
cbLoadDllEvent(loadDll, dll); cbLoadDllEvent(loadDll, dll);
@ -25,14 +25,14 @@ namespace GleeBug
{ {
//call the debug event callback //call the debug event callback
ULONG_PTR lpBaseOfDll = (ULONG_PTR)unloadDll.lpBaseOfDll; ULONG_PTR lpBaseOfDll = (ULONG_PTR)unloadDll.lpBaseOfDll;
auto dll = _curProcess->dlls.find(Range(lpBaseOfDll, lpBaseOfDll)); auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
if (dll != _curProcess->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, 0));
//DLL housekeeping //DLL housekeeping
if (dll != _curProcess->dlls.end()) if (dll != _process->dlls.end())
_curProcess->dlls.erase(dll); _process->dlls.erase(dll);
} }
}; };

View File

@ -4,9 +4,9 @@ namespace GleeBug
{ {
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) 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; _continueStatus = DBG_CONTINUE;
//call the callback //call the callback
@ -19,6 +19,21 @@ namespace GleeBug
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
{
_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) void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)

View File

@ -6,15 +6,25 @@ namespace GleeBug
{ {
//process housekeeping //process housekeeping
ProcessInfo process(_debugEvent.dwProcessId, ProcessInfo process(_debugEvent.dwProcessId,
createProcess.hProcess,
_debugEvent.dwThreadId); _debugEvent.dwThreadId);
_processes.insert({ process.dwProcessId, process }); _processes.insert({ process.dwProcessId, process });
_process = &_processes.find(process.dwProcessId)->second;
//set the current process and current thread //thread housekeeping (main thread is created implicitly)
_curProcess = &_processes[process.dwProcessId]; ThreadInfo thread(_debugEvent.dwThreadId,
_curProcess->curThread = &_curProcess->threads[process.dwMainThreadId]; 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 //call the debug event callback
cbCreateProcessEvent(createProcess, *_curProcess); cbCreateProcessEvent(createProcess, *_process);
//close the file handle //close the file handle
CloseHandle(createProcess.hFile); CloseHandle(createProcess.hFile);
@ -27,12 +37,12 @@ namespace GleeBug
_breakDebugger = true; _breakDebugger = true;
//call the debug event callback //call the debug event callback
cbExitProcessEvent(exitProcess, *_curProcess); cbExitProcessEvent(exitProcess, *_process);
//process housekeeping //process housekeeping
_processes.erase(_debugEvent.dwProcessId); _processes.erase(_debugEvent.dwProcessId);
//set the current process //set the current process
_curProcess = nullptr; _process = nullptr;
} }
}; };

View File

@ -5,25 +5,27 @@ namespace GleeBug
void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread) void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread)
{ {
//thread housekeeping //thread housekeeping
ThreadInfo thread(_debugEvent.dwThreadId, createThread.lpThreadLocalBase, createThread.lpStartAddress); _process->threads.insert({ _debugEvent.dwThreadId,
_curProcess->threads.insert({ thread.dwThreadId, thread }); ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) });
//set the current thread //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 //call the debug event callback
cbCreateThreadEvent(createThread, *_curProcess->curThread); 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, *_curProcess->curThread); cbExitThreadEvent(exitThread, *_thread);
//thread housekeeping //thread housekeeping
_curProcess->threads.erase(_debugEvent.dwThreadId); _process->threads.erase(_debugEvent.dwThreadId);
//set the current thread //set the current thread
_curProcess->curThread = nullptr; _thread = _process->thread = nullptr;
} }
}; };

View File

@ -16,19 +16,23 @@ namespace GleeBug
_isRunning = false; _isRunning = false;
//set default continue status //set default continue status
_continueStatus = DBG_CONTINUE; _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))
{ {
_curProcess = &_processes[_debugEvent.dwProcessId]; _process = &_processes[_debugEvent.dwProcessId];
if (_curProcess->threads.count(_debugEvent.dwThreadId)) if (_process->threads.count(_debugEvent.dwThreadId))
_curProcess->curThread = &_curProcess->threads[_debugEvent.dwThreadId]; {
else _thread = _process->thread = &_process->threads[_debugEvent.dwThreadId];
_curProcess->curThread = nullptr; if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!");
} }
else else
_curProcess = nullptr; _thread = _process->thread = nullptr;
}
else
_process = nullptr;
//dispatch the debug event //dispatch the debug event
switch (_debugEvent.dwDebugEventCode) switch (_debugEvent.dwDebugEventCode)
@ -62,6 +66,13 @@ namespace GleeBug
break; break;
} }
//write the register context
if (_thread)
{
if (!_thread->RegWriteContext())
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;
@ -69,6 +80,6 @@ namespace GleeBug
//cleanup //cleanup
_processes.clear(); _processes.clear();
_curProcess = nullptr; _process = nullptr;
} }
}; };

View File

@ -4,23 +4,26 @@ namespace GleeBug
{ {
ProcessInfo::ProcessInfo() ProcessInfo::ProcessInfo()
{ {
this->curThread = nullptr; this->thread = nullptr;
this->systemBreakpoint = false; this->systemBreakpoint = false;
this->hProcess = INVALID_HANDLE_VALUE; this->hProcess = INVALID_HANDLE_VALUE;
} }
ProcessInfo::ProcessInfo(DWORD dwProcessId, 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;
this->threads.clear();
} }
ProcessInfo::~ProcessInfo() bool ProcessInfo::MemRead(ULONG_PTR address, const size_t size, void* buffer)
{ {
if (this->hProcess != INVALID_HANDLE_VALUE) return !!ReadProcessMemory(this->hProcess, (const void*)address, buffer, size, NULL);
CloseHandle(hProcess); }
bool ProcessInfo::MemWrite(ULONG_PTR address, const size_t size, const void* buffer)
{
return !!WriteProcessMemory(this->hProcess, (void*)address, buffer, size, NULL);
} }
}; };

View File

@ -10,24 +10,49 @@ namespace GleeBug
/** /**
\brief Process information structure. \brief Process information structure.
*/ */
struct ProcessInfo class ProcessInfo
{ {
public:
HANDLE hProcess; HANDLE hProcess;
DWORD dwProcessId; DWORD dwProcessId;
DWORD dwMainThreadId; DWORD dwMainThreadId;
ThreadInfo* curThread; ThreadInfo* thread;
bool systemBreakpoint; bool systemBreakpoint;
ThreadMap threads; ThreadMap threads;
DllMap dlls; DllMap dlls;
/**
\brief Default constructor.
*/
ProcessInfo(); 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 #endif //_DEBUGGER_PROCESS_H

View File

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

View File

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

View File

@ -7,17 +7,50 @@ namespace GleeBug
this->hThread = INVALID_HANDLE_VALUE; 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->dwThreadId = dwThreadId;
this->hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId); this->hThread = hThread;
this->lpThreadLocalBase = (ULONG_PTR)lpThreadLocalBase; this->lpThreadLocalBase = (ULONG_PTR)lpThreadLocalBase;
this->lpStartAddress = (ULONG_PTR)lpStartAddress; this->lpStartAddress = (ULONG_PTR)lpStartAddress;
} }
ThreadInfo::~ThreadInfo() bool ThreadInfo::RegReadContext()
{ {
if (this->hThread != INVALID_HANDLE_VALUE) SuspendThread(this->hThread);
CloseHandle(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;
} }
}; };

View File

@ -1,26 +1,78 @@
#ifndef _DEBUGGER_THREADS_H #ifndef _DEBUGGER_THREAD_H
#define _DEBUGGER_THREADS_H #define _DEBUGGER_THREAD_H
#include "Debugger.Global.h" #include "Debugger.Global.h"
#include "Debugger.Thread.Registers.h"
namespace GleeBug namespace GleeBug
{ {
/** /**
\brief Thread information structure. \brief Thread information structure.
*/ */
struct ThreadInfo class ThreadInfo
{ {
public:
DWORD dwThreadId; DWORD dwThreadId;
HANDLE hThread; HANDLE hThread;
ULONG_PTR lpThreadLocalBase; ULONG_PTR lpThreadLocalBase;
ULONG_PTR lpStartAddress; ULONG_PTR lpStartAddress;
ThreadInfo(); RegistersInfo registers;
ThreadInfo(DWORD dwThreadId, LPVOID lpThreadLocalBase, LPVOID lpStartAddress); StepCallbackVector stepCallbacks;
~ThreadInfo(); 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 #endif //_DEBUGGER_THREADS_H

View File

@ -101,6 +101,12 @@ namespace GleeBug
virtual void cbRipEvent(const RIP_INFO & rip) {}; virtual void cbRipEvent(const RIP_INFO & rip) {};
protected: //other callbacks 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. \brief Unhandled exception callback. Provide an implementation to use this callback.
\param exceptionRecord The exception record. \param exceptionRecord The exception record.
@ -113,6 +119,11 @@ namespace GleeBug
*/ */
virtual void cbSystemBreakpoint() {}; virtual void cbSystemBreakpoint() {};
/**
\brief Step callback. Provide an implementation to use this callback.
*/
virtual void cbStep() {};
protected: //core debug event handlers protected: //core debug event handlers
/** /**
\brief Process creation debug event. Do not override this unless you know what you are doing! \brief Process creation debug event. Do not override this unless you know what you are doing!
@ -189,8 +200,17 @@ namespace GleeBug
bool _breakDebugger; bool _breakDebugger;
DEBUG_EVENT _debugEvent; DEBUG_EVENT _debugEvent;
ProcessMap _processes; ProcessMap _processes;
ProcessInfo* _curProcess;
bool _isRunning; 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;
}; };
}; };

View File

@ -157,6 +157,7 @@
<ClCompile Include="Debugger.Loop.Thread.cpp" /> <ClCompile Include="Debugger.Loop.Thread.cpp" />
<ClCompile Include="Debugger.Process.cpp" /> <ClCompile Include="Debugger.Process.cpp" />
<ClCompile Include="Debugger.Thread.cpp" /> <ClCompile Include="Debugger.Thread.cpp" />
<ClCompile Include="Debugger.Thread.Registers.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Debugger.Dll.h" /> <ClInclude Include="Debugger.Dll.h" />
@ -164,6 +165,7 @@
<ClInclude Include="Debugger.h" /> <ClInclude Include="Debugger.h" />
<ClInclude Include="Debugger.Thread.h" /> <ClInclude Include="Debugger.Thread.h" />
<ClInclude Include="Debugger.Global.h" /> <ClInclude Include="Debugger.Global.h" />
<ClInclude Include="Debugger.Thread.Registers.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View File

@ -48,6 +48,9 @@
<ClCompile Include="Debugger.Loop.Rip.cpp"> <ClCompile Include="Debugger.Loop.Rip.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Debugger.Thread.Registers.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Debugger.h"> <ClInclude Include="Debugger.h">
@ -65,5 +68,8 @@
<ClInclude Include="Debugger.Global.h"> <ClInclude Include="Debugger.Global.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Debugger.Thread.Registers.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -10,52 +10,82 @@ class MyDebugger : public Debugger
protected: protected:
virtual void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const ProcessInfo & process) 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) 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) 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) 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) 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) 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) 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) 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) 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() 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());
} }
}; };