From 1a072a78c5ba25822b521387a77610f031e65240 Mon Sep 17 00:00:00 2001 From: "Mr. eXoDia" Date: Sun, 5 Apr 2015 05:11:51 +0200 Subject: [PATCH] working single step with callbacks --- GleeBug/Debugger.Global.h | 9 +++++++-- GleeBug/Debugger.Loop.Dll.cpp | 12 ++++++------ GleeBug/Debugger.Loop.Exception.cpp | 19 +++++++++++++++++-- GleeBug/Debugger.Loop.Process.cpp | 14 +++++++------- GleeBug/Debugger.Loop.Thread.cpp | 14 +++++++------- GleeBug/Debugger.Loop.cpp | 18 +++++++++--------- GleeBug/Debugger.Process.cpp | 2 +- GleeBug/Debugger.Process.h | 2 +- GleeBug/Debugger.Thread.cpp | 12 ++++++++++++ GleeBug/Debugger.Thread.h | 7 +++++++ GleeBug/Debugger.h | 22 ++++++++++++++++++---- MyDebugger/MyDebugger.h | 9 ++++++++- 12 files changed, 100 insertions(+), 40 deletions(-) diff --git a/GleeBug/Debugger.Global.h b/GleeBug/Debugger.Global.h index 28f80e9..db8e746 100644 --- a/GleeBug/Debugger.Global.h +++ b/GleeBug/Debugger.Global.h @@ -36,8 +36,13 @@ namespace GleeBug typedef std::map ThreadMap; //callback function typedefs - typedef std::function StepCallback; - + typedef std::function StepCallback; + + //vector typedefs + typedef std::vector StepCallbackVector; + + //macros + #define BIND(thisPtr, funcPtr) std::bind(&funcPtr, thisPtr) }; #endif //_DEBUGGER_GLOBAL_H \ No newline at end of file diff --git a/GleeBug/Debugger.Loop.Dll.cpp b/GleeBug/Debugger.Loop.Dll.cpp index ee0ddcc..1cc7397 100644 --- a/GleeBug/Debugger.Loop.Dll.cpp +++ b/GleeBug/Debugger.Loop.Dll.cpp @@ -7,12 +7,12 @@ namespace GleeBug //DLL housekeeping MODULEINFO modinfo; memset(&modinfo, 0, sizeof(MODULEINFO)); - GetModuleInformation(_curProcess->hProcess, + GetModuleInformation(_process->hProcess, (HMODULE)loadDll.lpBaseOfDll, &modinfo, sizeof(MODULEINFO)); DllInfo dll(loadDll.lpBaseOfDll, modinfo.SizeOfImage, modinfo.EntryPoint); - _curProcess->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll }); + _process->dlls.insert({ Range(dll.lpBaseOfDll, dll.lpBaseOfDll + dll.sizeOfImage - 1), dll }); //call the debug event callback cbLoadDllEvent(loadDll, dll); @@ -25,14 +25,14 @@ namespace GleeBug { //call the debug event callback ULONG_PTR lpBaseOfDll = (ULONG_PTR)unloadDll.lpBaseOfDll; - auto dll = _curProcess->dlls.find(Range(lpBaseOfDll, lpBaseOfDll)); - if (dll != _curProcess->dlls.end()) + auto dll = _process->dlls.find(Range(lpBaseOfDll, lpBaseOfDll)); + if (dll != _process->dlls.end()) cbUnloadDllEvent(unloadDll, dll->second); else cbUnloadDllEvent(unloadDll, DllInfo(unloadDll.lpBaseOfDll, 0, 0)); //DLL housekeeping - if (dll != _curProcess->dlls.end()) - _curProcess->dlls.erase(dll); + if (dll != _process->dlls.end()) + _process->dlls.erase(dll); } }; \ No newline at end of file diff --git a/GleeBug/Debugger.Loop.Exception.cpp b/GleeBug/Debugger.Loop.Exception.cpp index 9be1187..ca6feea 100644 --- a/GleeBug/Debugger.Loop.Exception.cpp +++ b/GleeBug/Debugger.Loop.Exception.cpp @@ -4,9 +4,9 @@ namespace GleeBug { void Debugger::exceptionBreakpoint(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) { - if (!_curProcess->systemBreakpoint) //handle system breakpoint + if (!_process->systemBreakpoint) //handle system breakpoint { - _curProcess->systemBreakpoint = true; + _process->systemBreakpoint = true; _continueStatus = DBG_CONTINUE; //call the callback @@ -19,6 +19,21 @@ namespace GleeBug void Debugger::exceptionSingleStep(const EXCEPTION_RECORD & exceptionRecord, const bool firstChance) { + if (_thread->isSingleStepping) //handle single step + { + _thread->isSingleStepping = false; + _continueStatus = DBG_CONTINUE; + + //call the callbacks + StepCallbackVector cbStepCopy = _thread->stepCallbacks; + _thread->stepCallbacks.clear(); + for (auto cbStep : cbStepCopy) + cbStep(); + cbStep(); + } + else //handle other single step exceptions + { + } } void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) diff --git a/GleeBug/Debugger.Loop.Process.cpp b/GleeBug/Debugger.Loop.Process.cpp index aeb9951..a86675f 100644 --- a/GleeBug/Debugger.Loop.Process.cpp +++ b/GleeBug/Debugger.Loop.Process.cpp @@ -9,22 +9,22 @@ namespace GleeBug createProcess.hProcess, _debugEvent.dwThreadId); _processes.insert({ process.dwProcessId, process }); - _curProcess = &_processes.find(process.dwProcessId)->second; + _process = &_processes.find(process.dwProcessId)->second; //thread housekeeping (main thread is created implicitly) ThreadInfo thread(_debugEvent.dwThreadId, createProcess.hThread, createProcess.lpThreadLocalBase, createProcess.lpStartAddress); - _curProcess->threads.insert({ thread.dwThreadId, thread }); - _curProcess->curThread = &_curProcess->threads.find(thread.dwThreadId)->second; + _process->threads.insert({ thread.dwThreadId, thread }); + _thread = _process->thread = &_process->threads.find(thread.dwThreadId)->second; //read thread context from main thread - if (!_curProcess->curThread->RegReadContext()) + if (!_thread->RegReadContext()) cbInternalError("ThreadInfo::RegReadContext() failed!"); //call the debug event callback - cbCreateProcessEvent(createProcess, *_curProcess); + cbCreateProcessEvent(createProcess, *_process); //close the file handle CloseHandle(createProcess.hFile); @@ -37,12 +37,12 @@ namespace GleeBug _breakDebugger = true; //call the debug event callback - cbExitProcessEvent(exitProcess, *_curProcess); + cbExitProcessEvent(exitProcess, *_process); //process housekeeping _processes.erase(_debugEvent.dwProcessId); //set the current process - _curProcess = nullptr; + _process = nullptr; } }; \ No newline at end of file diff --git a/GleeBug/Debugger.Loop.Thread.cpp b/GleeBug/Debugger.Loop.Thread.cpp index fcb92be..df09de3 100644 --- a/GleeBug/Debugger.Loop.Thread.cpp +++ b/GleeBug/Debugger.Loop.Thread.cpp @@ -5,27 +5,27 @@ namespace GleeBug void Debugger::createThreadEvent(const CREATE_THREAD_DEBUG_INFO & createThread) { //thread housekeeping - _curProcess->threads.insert({ _debugEvent.dwThreadId, + _process->threads.insert({ _debugEvent.dwThreadId, ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) }); //set the current thread - _curProcess->curThread = &_curProcess->threads.find(_debugEvent.dwThreadId)->second; - if (!_curProcess->curThread->RegReadContext()) + _thread = _process->thread = &_process->threads.find(_debugEvent.dwThreadId)->second; + if (!_thread->RegReadContext()) cbInternalError("ThreadInfo::RegReadContext() failed!"); //call the debug event callback - cbCreateThreadEvent(createThread, *_curProcess->curThread); + cbCreateThreadEvent(createThread, *_thread); } void Debugger::exitThreadEvent(const EXIT_THREAD_DEBUG_INFO & exitThread) { //call the debug event callback - cbExitThreadEvent(exitThread, *_curProcess->curThread); + cbExitThreadEvent(exitThread, *_thread); //thread housekeeping - _curProcess->threads.erase(_debugEvent.dwThreadId); + _process->threads.erase(_debugEvent.dwThreadId); //set the current thread - _curProcess->curThread = nullptr; + _thread = _process->thread = nullptr; } }; \ No newline at end of file diff --git a/GleeBug/Debugger.Loop.cpp b/GleeBug/Debugger.Loop.cpp index 6fa63ce..2c33b68 100644 --- a/GleeBug/Debugger.Loop.cpp +++ b/GleeBug/Debugger.Loop.cpp @@ -21,18 +21,18 @@ namespace GleeBug //set the current process and thread if (_processes.count(_debugEvent.dwProcessId)) { - _curProcess = &_processes[_debugEvent.dwProcessId]; - if (_curProcess->threads.count(_debugEvent.dwThreadId)) + _process = &_processes[_debugEvent.dwProcessId]; + if (_process->threads.count(_debugEvent.dwThreadId)) { - _curProcess->curThread = &_curProcess->threads[_debugEvent.dwThreadId]; - if (!_curProcess->curThread->RegReadContext()) + _thread = _process->thread = &_process->threads[_debugEvent.dwThreadId]; + if (!_thread->RegReadContext()) cbInternalError("ThreadInfo::RegReadContext() failed!"); } else - _curProcess->curThread = nullptr; + _thread = _process->thread = nullptr; } else - _curProcess = nullptr; + _process = nullptr; //dispatch the debug event switch (_debugEvent.dwDebugEventCode) @@ -67,9 +67,9 @@ namespace GleeBug } //write the register context - if (_curProcess && _curProcess->curThread) + if (_thread) { - if (!_curProcess->curThread->RegWriteContext()) + if (!_thread->RegWriteContext()) cbInternalError("ThreadInfo::RegWriteContext() failed!"); } @@ -80,6 +80,6 @@ namespace GleeBug //cleanup _processes.clear(); - _curProcess = nullptr; + _process = nullptr; } }; \ No newline at end of file diff --git a/GleeBug/Debugger.Process.cpp b/GleeBug/Debugger.Process.cpp index 7c96cce..3e9f772 100644 --- a/GleeBug/Debugger.Process.cpp +++ b/GleeBug/Debugger.Process.cpp @@ -4,7 +4,7 @@ namespace GleeBug { ProcessInfo::ProcessInfo() { - this->curThread = nullptr; + this->thread = nullptr; this->systemBreakpoint = false; this->hProcess = INVALID_HANDLE_VALUE; } diff --git a/GleeBug/Debugger.Process.h b/GleeBug/Debugger.Process.h index ba9d690..c1bb2a2 100644 --- a/GleeBug/Debugger.Process.h +++ b/GleeBug/Debugger.Process.h @@ -17,7 +17,7 @@ namespace GleeBug DWORD dwProcessId; DWORD dwMainThreadId; - ThreadInfo* curThread; + ThreadInfo* thread; bool systemBreakpoint; ThreadMap threads; diff --git a/GleeBug/Debugger.Thread.cpp b/GleeBug/Debugger.Thread.cpp index 1272e8e..8877b08 100644 --- a/GleeBug/Debugger.Thread.cpp +++ b/GleeBug/Debugger.Thread.cpp @@ -41,4 +41,16 @@ namespace GleeBug ResumeThread(this->hThread); return bReturn; } + + void ThreadInfo::StepInto(StepCallback cbStep) + { + StepInto(); + stepCallbacks.push_back(cbStep); + } + + void ThreadInfo::StepInto() + { + registers.SetTrapFlag(); + isSingleStepping = true; + } }; \ No newline at end of file diff --git a/GleeBug/Debugger.Thread.h b/GleeBug/Debugger.Thread.h index 4c33f41..cfc6a76 100644 --- a/GleeBug/Debugger.Thread.h +++ b/GleeBug/Debugger.Thread.h @@ -16,7 +16,10 @@ namespace GleeBug HANDLE hThread; ULONG_PTR lpThreadLocalBase; ULONG_PTR lpStartAddress; + RegistersInfo registers; + StepCallbackVector stepCallbacks; + bool isSingleStepping; /** \brief Default constructor. @@ -43,6 +46,10 @@ namespace GleeBug */ bool RegWriteContext(); + void StepInto(StepCallback cbStep); + + void StepInto(); + private: CONTEXT _oldContext; }; diff --git a/GleeBug/Debugger.h b/GleeBug/Debugger.h index 9038c47..30647d5 100644 --- a/GleeBug/Debugger.h +++ b/GleeBug/Debugger.h @@ -101,6 +101,12 @@ namespace GleeBug virtual void cbRipEvent(const RIP_INFO & rip) {}; protected: //other callbacks + /** + \brief Internal error callback. Provide an implementation to use this callback. + \param error The error message. + */ + virtual void cbInternalError(const std::string & error) {}; + /** \brief Unhandled exception callback. Provide an implementation to use this callback. \param exceptionRecord The exception record. @@ -114,10 +120,9 @@ namespace GleeBug virtual void cbSystemBreakpoint() {}; /** - \brief Internal error callback. Provide an implementation to use this callback. - \param error The error message. + \brief Step callback. Provide an implementation to use this callback. */ - virtual void cbInternalError(const std::string & error) {}; + virtual void cbStep() {}; protected: //core debug event handlers /** @@ -195,8 +200,17 @@ namespace GleeBug bool _breakDebugger; DEBUG_EVENT _debugEvent; ProcessMap _processes; - ProcessInfo* _curProcess; bool _isRunning; + + /** + \brief The current process (can be null in some cases). + */ + ProcessInfo* _process; + + /** + \brief The current thread (can be null in some cases). Should be a copy of _process->thread. + */ + ThreadInfo* _thread; }; }; diff --git a/MyDebugger/MyDebugger.h b/MyDebugger/MyDebugger.h index 9c1a54b..8486087 100644 --- a/MyDebugger/MyDebugger.h +++ b/MyDebugger/MyDebugger.h @@ -69,10 +69,17 @@ protected: rip.dwError); }; + void boobs() + { + printf("(.)Y(.) 0x%p\n", + _thread->registers.Rip); + } + virtual void cbSystemBreakpoint() { 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)