working single step with callbacks

This commit is contained in:
Mr. eXoDia 2015-04-05 05:11:51 +02:00
parent 25b4dd40de
commit 1a072a78c5
12 changed files with 100 additions and 40 deletions

View File

@ -36,8 +36,13 @@ namespace GleeBug
typedef std::map<DWORD, ThreadInfo> ThreadMap; typedef std::map<DWORD, ThreadInfo> ThreadMap;
//callback function typedefs //callback function typedefs
typedef std::function<void(const Debugger &)> StepCallback; 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

@ -9,22 +9,22 @@ namespace GleeBug
createProcess.hProcess, createProcess.hProcess,
_debugEvent.dwThreadId); _debugEvent.dwThreadId);
_processes.insert({ process.dwProcessId, process }); _processes.insert({ process.dwProcessId, process });
_curProcess = &_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);
_curProcess->threads.insert({ thread.dwThreadId, thread }); _process->threads.insert({ thread.dwThreadId, thread });
_curProcess->curThread = &_curProcess->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 (!_curProcess->curThread->RegReadContext()) if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!"); 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);
@ -37,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,27 +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
_curProcess->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
_curProcess->curThread = &_curProcess->threads.find(_debugEvent.dwThreadId)->second; _thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second;
if (!_curProcess->curThread->RegReadContext()) if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!"); 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

@ -21,18 +21,18 @@ namespace GleeBug
//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]; _thread = _process->thread = &_process->threads[_debugEvent.dwThreadId];
if (!_curProcess->curThread->RegReadContext()) if (!_thread->RegReadContext())
cbInternalError("ThreadInfo::RegReadContext() failed!"); cbInternalError("ThreadInfo::RegReadContext() failed!");
} }
else else
_curProcess->curThread = nullptr; _thread = _process->thread = nullptr;
} }
else else
_curProcess = nullptr; _process = nullptr;
//dispatch the debug event //dispatch the debug event
switch (_debugEvent.dwDebugEventCode) switch (_debugEvent.dwDebugEventCode)
@ -67,9 +67,9 @@ namespace GleeBug
} }
//write the register context //write the register context
if (_curProcess && _curProcess->curThread) if (_thread)
{ {
if (!_curProcess->curThread->RegWriteContext()) if (!_thread->RegWriteContext())
cbInternalError("ThreadInfo::RegWriteContext() failed!"); cbInternalError("ThreadInfo::RegWriteContext() failed!");
} }
@ -80,6 +80,6 @@ namespace GleeBug
//cleanup //cleanup
_processes.clear(); _processes.clear();
_curProcess = nullptr; _process = nullptr;
} }
}; };

View File

@ -4,7 +4,7 @@ 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;
} }

View File

@ -17,7 +17,7 @@ namespace GleeBug
DWORD dwProcessId; DWORD dwProcessId;
DWORD dwMainThreadId; DWORD dwMainThreadId;
ThreadInfo* curThread; ThreadInfo* thread;
bool systemBreakpoint; bool systemBreakpoint;
ThreadMap threads; ThreadMap threads;

View File

@ -41,4 +41,16 @@ namespace GleeBug
ResumeThread(this->hThread); ResumeThread(this->hThread);
return bReturn; return bReturn;
} }
void ThreadInfo::StepInto(StepCallback cbStep)
{
StepInto();
stepCallbacks.push_back(cbStep);
}
void ThreadInfo::StepInto()
{
registers.SetTrapFlag();
isSingleStepping = true;
}
}; };

View File

@ -16,7 +16,10 @@ namespace GleeBug
HANDLE hThread; HANDLE hThread;
ULONG_PTR lpThreadLocalBase; ULONG_PTR lpThreadLocalBase;
ULONG_PTR lpStartAddress; ULONG_PTR lpStartAddress;
RegistersInfo registers; RegistersInfo registers;
StepCallbackVector stepCallbacks;
bool isSingleStepping;
/** /**
\brief Default constructor. \brief Default constructor.
@ -43,6 +46,10 @@ namespace GleeBug
*/ */
bool RegWriteContext(); bool RegWriteContext();
void StepInto(StepCallback cbStep);
void StepInto();
private: private:
CONTEXT _oldContext; CONTEXT _oldContext;
}; };

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.
@ -114,10 +120,9 @@ namespace GleeBug
virtual void cbSystemBreakpoint() {}; virtual void cbSystemBreakpoint() {};
/** /**
\brief Internal error callback. Provide an implementation to use this callback. \brief Step callback. Provide an implementation to use this callback.
\param error The error message.
*/ */
virtual void cbInternalError(const std::string & error) {}; virtual void cbStep() {};
protected: //core debug event handlers protected: //core debug event handlers
/** /**
@ -195,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

@ -69,10 +69,17 @@ protected:
rip.dwError); rip.dwError);
}; };
void boobs()
{
printf("(.)Y(.) 0x%p\n",
_thread->registers.Rip);
}
virtual void cbSystemBreakpoint() virtual void cbSystemBreakpoint()
{ {
printf("System breakpoint reached, CIP: 0x%p\n", printf("System breakpoint reached, CIP: 0x%p\n",
_curProcess->curThread->registers.Rip); _thread->registers.Rip);
_thread->StepInto(BIND(this, MyDebugger::boobs));
} }
virtual void cbInternalError(const std::string & error) virtual void cbInternalError(const std::string & error)