even more code separation

This commit is contained in:
Mr. eXoDia 2015-03-28 15:21:54 +01:00
parent 30036a9fb6
commit b92b32b146
13 changed files with 258 additions and 113 deletions

View File

@ -0,0 +1,13 @@
#include "Debugger.h"
namespace GleeBug
{
void Debugger::debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
{
//prevent anti-debug trick (debug string events are actually exceptions)
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
//call the debug event callback
cbDebugStringEvent(debugString);
}
};

View File

@ -0,0 +1,38 @@
#include "Debugger.h"
namespace GleeBug
{
void Debugger::loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll)
{
//DLL housekeeping
MODULEINFO modinfo;
memset(&modinfo, 0, sizeof(MODULEINFO));
GetModuleInformation(_curProcess->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 });
//call the debug event callback
cbLoadDllEvent(loadDll, dll);
//close the file handle
CloseHandle(loadDll.hFile);
}
void Debugger::unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll)
{
//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())
cbUnloadDllEvent(unloadDll, dll->second);
else
cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, 0));
//DLL housekeeping
if (dll != _curProcess->dlls.end())
_curProcess->dlls.erase(dll);
}
};

View File

@ -0,0 +1,50 @@
#include "Debugger.h"
namespace GleeBug
{
void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{
if (!_curProcess->systemBreakpoint) //handle system breakpoint
{
_curProcess->systemBreakpoint = true;
_continueStatus = DBG_CONTINUE;
//call the callback
cbSystemBreakpoint();
}
else //handle other breakpoint exceptions
{
}
}
void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance)
{
}
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
{
//let the debuggee handle exceptions per default
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
const EXCEPTION_RECORD & exceptionRecord = exceptionInfo.ExceptionRecord;
const bool firstChance = exceptionInfo.dwFirstChance == 1;
//dispatch the exception
switch (exceptionInfo.ExceptionRecord.ExceptionCode)
{
case STATUS_BREAKPOINT:
exceptionBreakpoint(exceptionRecord, firstChance);
break;
case STATUS_SINGLE_STEP:
exceptionSingleStep(exceptionRecord, firstChance);
break;
}
//call the unhandled exception callback
if (_continueStatus == DBG_EXCEPTION_NOT_HANDLED)
cbUnhandledException(exceptionRecord, firstChance);
//call the debug event callback
cbExceptionEvent(exceptionInfo);
}
};

View File

@ -0,0 +1,38 @@
#include "Debugger.h"
namespace GleeBug
{
void Debugger::createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess)
{
//process housekeeping
ProcessInfo process(_debugEvent.dwProcessId,
_debugEvent.dwThreadId);
_processes.insert({ process.dwProcessId, process });
//set the current process and current thread
_curProcess = &_processes[process.dwProcessId];
_curProcess->curThread = &_curProcess->threads[process.dwMainThreadId];
//call the debug event callback
cbCreateProcessEvent(createProcess, *_curProcess);
//close the file handle
CloseHandle(createProcess.hFile);
}
void Debugger::exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess)
{
//check if the terminated process is the main debuggee
if (_debugEvent.dwProcessId == _mainProcess.dwProcessId)
_breakDebugger = true;
//call the debug event callback
cbExitProcessEvent(exitProcess, *_curProcess);
//process housekeeping
_processes.erase(_debugEvent.dwProcessId);
//set the current process
_curProcess = nullptr;
}
};

View File

@ -0,0 +1,13 @@
#include "Debugger.h"
namespace GleeBug
{
void Debugger::ripEvent(const RIP_INFO & rip)
{
//prevent anti-debug trick (RIP events are actually exceptions)
_continueStatus = DBG_EXCEPTION_NOT_HANDLED;
//call the debug event callback
cbRipEvent(rip);
}
};

View File

@ -0,0 +1,29 @@
#include "Debugger.h"
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 });
//set the current thread
_curProcess->curThread = &_curProcess->threads[thread.dwThreadId];
//call the debug event callback
cbCreateThreadEvent(createThread, *_curProcess->curThread);
}
void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread)
{
//call the debug event callback
cbExitThreadEvent(exitThread, *_curProcess->curThread);
//thread housekeeping
_curProcess->threads.erase(_debugEvent.dwThreadId);
//set the current thread
_curProcess->curThread = nullptr;
}
};

View File

@ -2,122 +2,21 @@
namespace GleeBug namespace GleeBug
{ {
void Debugger::createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess)
{
//process housekeeping
ProcessInfo process(_debugEvent.dwProcessId,
_debugEvent.dwThreadId);
_processes.insert({ process.dwProcessId, process });
//set the current process and current thread
_curProcess = &_processes[process.dwProcessId];
_curProcess->curThread = &_curProcess->threads[process.dwMainThreadId];
//call the callback
cbCreateProcessEvent(createProcess, *_curProcess);
//close the file handle
CloseHandle(createProcess.hFile);
}
void Debugger::exitProcessEvent(const EXIT_PROCESS_DEBUG_INFO & exitProcess)
{
//check if the terminated process is the main debuggee
if (_debugEvent.dwProcessId == _mainProcess.dwProcessId)
_breakDebugger = true;
//call the callback
cbExitProcessEvent(exitProcess, *_curProcess);
//process housekeeping
_processes.erase(_debugEvent.dwProcessId);
//set the current process
_curProcess = nullptr;
}
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 });
//set the current thread
_curProcess->curThread = &_curProcess->threads[thread.dwThreadId];
//call the callback
cbCreateThreadEvent(createThread, *_curProcess->curThread);
}
void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread)
{
//call the callback
cbExitThreadEvent(exitThread, *_curProcess->curThread);
//thread housekeeping
_curProcess->threads.erase(_debugEvent.dwThreadId);
//set the current thread
_curProcess->curThread = nullptr;
}
void Debugger::loadDllEvent(const LOAD_DLL_DEBUG_INFO & loadDll)
{
//DLL housekeeping
MODULEINFO modinfo;
memset(&modinfo, 0, sizeof(MODULEINFO));
GetModuleInformation(_curProcess->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 });
//call the callback
cbLoadDllEvent(loadDll, dll);
//close the file handle
CloseHandle(loadDll.hFile);
}
void Debugger::unloadDllEvent(const UNLOAD_DLL_DEBUG_INFO & unloadDll)
{
//call the callback
ULONG_PTR lpBaseOfDll = (ULONG_PTR)unloadDll.lpBaseOfDll;
auto dll = _curProcess->dlls.find(Range(lpBaseOfDll, lpBaseOfDll));
if (dll != _curProcess->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);
}
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)
{
cbExceptionEvent(exceptionInfo);
}
void Debugger::debugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
{
cbDebugStringEvent(debugString);
}
void Debugger::ripEvent(const RIP_INFO & rip)
{
cbRipEvent(rip);
}
void Debugger::Start() void Debugger::Start()
{ {
_continueStatus = DBG_EXCEPTION_NOT_HANDLED; //initialize loop variables
_breakDebugger = false; _breakDebugger = false;
while (!_breakDebugger) while (!_breakDebugger)
{ {
//wait for a debug event
_isRunning = true;
if (!WaitForDebugEvent(&_debugEvent, INFINITE)) if (!WaitForDebugEvent(&_debugEvent, INFINITE))
break; break;
_isRunning = false;
//set default continue status
_continueStatus = DBG_CONTINUE;
//set the current process and thread //set the current process and thread
if (_processes.count(_debugEvent.dwProcessId)) if (_processes.count(_debugEvent.dwProcessId))
@ -131,6 +30,7 @@ namespace GleeBug
else else
_curProcess = nullptr; _curProcess = nullptr;
//dispatch the debug event
switch (_debugEvent.dwDebugEventCode) switch (_debugEvent.dwDebugEventCode)
{ {
case CREATE_PROCESS_DEBUG_EVENT: case CREATE_PROCESS_DEBUG_EVENT:
@ -162,10 +62,12 @@ namespace GleeBug
break; break;
} }
//continue the debug event
if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus)) if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus))
break; break;
} }
//cleanup
_processes.clear(); _processes.clear();
_curProcess = nullptr; _curProcess = nullptr;
} }

View File

@ -5,11 +5,13 @@ namespace GleeBug
ProcessInfo::ProcessInfo() ProcessInfo::ProcessInfo()
{ {
this->curThread = nullptr; this->curThread = nullptr;
this->systemBreakpoint = false;
this->hProcess = INVALID_HANDLE_VALUE; this->hProcess = INVALID_HANDLE_VALUE;
} }
ProcessInfo::ProcessInfo(DWORD dwProcessId, DWORD dwMainThreadId) ProcessInfo::ProcessInfo(DWORD dwProcessId, DWORD dwMainThreadId)
{ {
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;

View File

@ -16,8 +16,10 @@ namespace GleeBug
DWORD dwProcessId; DWORD dwProcessId;
DWORD dwMainThreadId; DWORD dwMainThreadId;
ThreadMap threads;
ThreadInfo* curThread; ThreadInfo* curThread;
bool systemBreakpoint;
ThreadMap threads;
DllMap dlls; DllMap dlls;
ProcessInfo(); ProcessInfo();

View File

@ -45,7 +45,7 @@ namespace GleeBug
*/ */
void Start(); void Start();
protected: //callbacks protected: //debug event callbacks
/** /**
\brief Process creation debug event callback. Provide an implementation to use this callback. \brief Process creation debug event callback. Provide an implementation to use this callback.
\param createProcess Information about the process created. \param createProcess Information about the process created.
@ -100,7 +100,20 @@ namespace GleeBug
*/ */
virtual void cbRipEvent(const RIP_INFO & rip) {}; virtual void cbRipEvent(const RIP_INFO & rip) {};
protected: //core functionality protected: //other callbacks
/**
\brief Unhandled exception callback. Provide an implementation to use this callback.
\param exceptionRecord The exception record.
\param firstChance True if the exception is a first chance exception, false otherwise.
*/
virtual void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) {};
/**
\brief System breakpoint callback. Provide an implementation to use this callback.
*/
virtual void cbSystemBreakpoint() {};
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!
\param createProcess Information about the process created. \param createProcess Information about the process created.
@ -155,6 +168,21 @@ namespace GleeBug
*/ */
virtual void ripEvent(const RIP_INFO & rip); virtual void ripEvent(const RIP_INFO & rip);
protected: //core exception handlers
/**
\brief Breakpoint exception handler. Do not override this unless you know what you are doing!
\param exceptionRecord The exception record.
\param firstChance True if the exception is a first chance exception, false otherwise.
*/
virtual void exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance);
/**
\brief Single step exception handler. Do not override this unless you know what you are doing!
\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);
protected: //variables protected: //variables
PROCESS_INFORMATION _mainProcess; PROCESS_INFORMATION _mainProcess;
DWORD _continueStatus; DWORD _continueStatus;
@ -162,6 +190,7 @@ namespace GleeBug
DEBUG_EVENT _debugEvent; DEBUG_EVENT _debugEvent;
ProcessMap _processes; ProcessMap _processes;
ProcessInfo* _curProcess; ProcessInfo* _curProcess;
bool _isRunning;
}; };
}; };

View File

@ -149,6 +149,12 @@
<ClCompile Include="Debugger.cpp" /> <ClCompile Include="Debugger.cpp" />
<ClCompile Include="Debugger.Dll.cpp" /> <ClCompile Include="Debugger.Dll.cpp" />
<ClCompile Include="Debugger.Loop.cpp" /> <ClCompile Include="Debugger.Loop.cpp" />
<ClCompile Include="Debugger.Loop.DebugString.cpp" />
<ClCompile Include="Debugger.Loop.Dll.cpp" />
<ClCompile Include="Debugger.Loop.Exception.cpp" />
<ClCompile Include="Debugger.Loop.Process.cpp" />
<ClCompile Include="Debugger.Loop.Rip.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" />
</ItemGroup> </ItemGroup>

View File

@ -30,6 +30,24 @@
<ClCompile Include="Debugger.Dll.cpp"> <ClCompile Include="Debugger.Dll.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Debugger.Loop.Dll.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Debugger.Loop.Exception.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Debugger.Loop.Process.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Debugger.Loop.Thread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Debugger.Loop.DebugString.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Debugger.Loop.Rip.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Debugger.h"> <ClInclude Include="Debugger.h">

View File

@ -40,7 +40,7 @@ protected:
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); printf("Exception with code 0x%08X\n", exceptionInfo.ExceptionRecord.ExceptionCode);
}; };
virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) virtual void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString)
@ -52,6 +52,11 @@ protected:
{ {
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);
}; };
virtual void cbSystemBreakpoint()
{
printf("System breakpoint reached!");
}
}; };
#endif //_MYDEBUGGER_H #endif //_MYDEBUGGER_H