diff --git a/GleeBug/Debugger.Dll.h b/GleeBug/Debugger.Dll.h index 810c4d0..6782df4 100644 --- a/GleeBug/Debugger.Dll.h +++ b/GleeBug/Debugger.Dll.h @@ -8,17 +8,26 @@ namespace GleeBug /** \brief DLL information structure. */ - struct DllInfo + class DllInfo { + public: ULONG_PTR lpBaseOfDll; DWORD sizeOfImage; ULONG_PTR entryPoint; + /** + \brief Default constructor. + */ 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); }; - - typedef std::map DllMap; }; #endif //_DEBUGGER_DLL_H \ No newline at end of file diff --git a/GleeBug/Debugger.Global.h b/GleeBug/Debugger.Global.h index 8aaa312..db8e746 100644 --- a/GleeBug/Debugger.Global.h +++ b/GleeBug/Debugger.Global.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -21,6 +23,26 @@ namespace GleeBug return a.second < b.first; } }; + + //forward declarations + class Debugger; + class ProcessInfo; + class DllInfo; + class ThreadInfo; + + //map typedefs + typedef std::map ProcessMap; + typedef std::map DllMap; + typedef std::map ThreadMap; + + //callback function typedefs + 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 d4e6883..a86675f 100644 --- a/GleeBug/Debugger.Loop.Process.cpp +++ b/GleeBug/Debugger.Loop.Process.cpp @@ -6,15 +6,25 @@ namespace GleeBug { //process housekeeping ProcessInfo process(_debugEvent.dwProcessId, + createProcess.hProcess, _debugEvent.dwThreadId); _processes.insert({ process.dwProcessId, process }); + _process = &_processes.find(process.dwProcessId)->second; - //set the current process and current thread - _curProcess = &_processes[process.dwProcessId]; - _curProcess->curThread = &_curProcess->threads[process.dwMainThreadId]; + //thread housekeeping (main thread is created implicitly) + ThreadInfo thread(_debugEvent.dwThreadId, + 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 - cbCreateProcessEvent(createProcess, *_curProcess); + cbCreateProcessEvent(createProcess, *_process); //close the file handle CloseHandle(createProcess.hFile); @@ -27,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 5fad0c0..df09de3 100644 --- a/GleeBug/Debugger.Loop.Thread.cpp +++ b/GleeBug/Debugger.Loop.Thread.cpp @@ -5,25 +5,27 @@ 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 }); + _process->threads.insert({ _debugEvent.dwThreadId, + ThreadInfo(_debugEvent.dwThreadId, createThread.hThread, createThread.lpThreadLocalBase, createThread.lpStartAddress) }); //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 - 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 02ef305..2c33b68 100644 --- a/GleeBug/Debugger.Loop.cpp +++ b/GleeBug/Debugger.Loop.cpp @@ -16,19 +16,23 @@ namespace GleeBug _isRunning = false; //set default continue status - _continueStatus = DBG_CONTINUE; + _continueStatus = DBG_EXCEPTION_NOT_HANDLED; //set the current process and thread if (_processes.count(_debugEvent.dwProcessId)) { - _curProcess = &_processes[_debugEvent.dwProcessId]; - if (_curProcess->threads.count(_debugEvent.dwThreadId)) - _curProcess->curThread = &_curProcess->threads[_debugEvent.dwThreadId]; + _process = &_processes[_debugEvent.dwProcessId]; + if (_process->threads.count(_debugEvent.dwThreadId)) + { + _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) @@ -62,6 +66,13 @@ namespace GleeBug break; } + //write the register context + if (_thread) + { + if (!_thread->RegWriteContext()) + cbInternalError("ThreadInfo::RegWriteContext() failed!"); + } + //continue the debug event if (!ContinueDebugEvent(_debugEvent.dwProcessId, _debugEvent.dwThreadId, _continueStatus)) break; @@ -69,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 7a126a3..3e9f772 100644 --- a/GleeBug/Debugger.Process.cpp +++ b/GleeBug/Debugger.Process.cpp @@ -4,23 +4,26 @@ namespace GleeBug { ProcessInfo::ProcessInfo() { - this->curThread = nullptr; + this->thread = nullptr; this->systemBreakpoint = false; this->hProcess = INVALID_HANDLE_VALUE; } - ProcessInfo::ProcessInfo(DWORD dwProcessId, DWORD dwMainThreadId) + ProcessInfo::ProcessInfo(DWORD dwProcessId, HANDLE hProcess, DWORD dwMainThreadId) { this->systemBreakpoint = false; this->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); this->dwProcessId = dwProcessId; 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) - CloseHandle(hProcess); + return !!ReadProcessMemory(this->hProcess, (const void*)address, buffer, size, NULL); + } + + bool ProcessInfo::MemWrite(ULONG_PTR address, const size_t size, const void* buffer) + { + return !!WriteProcessMemory(this->hProcess, (void*)address, buffer, size, NULL); } }; \ No newline at end of file diff --git a/GleeBug/Debugger.Process.h b/GleeBug/Debugger.Process.h index 0343da7..c1bb2a2 100644 --- a/GleeBug/Debugger.Process.h +++ b/GleeBug/Debugger.Process.h @@ -10,24 +10,49 @@ namespace GleeBug /** \brief Process information structure. */ - struct ProcessInfo + class ProcessInfo { + public: HANDLE hProcess; DWORD dwProcessId; DWORD dwMainThreadId; - ThreadInfo* curThread; + ThreadInfo* thread; bool systemBreakpoint; ThreadMap threads; DllMap dlls; + /** + \brief Default constructor. + */ ProcessInfo(); - ProcessInfo(DWORD dwProcessId, DWORD dwMainThreadId); - ~ProcessInfo(); - }; - typedef std::map 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 \ No newline at end of file diff --git a/GleeBug/Debugger.Thread.Registers.cpp b/GleeBug/Debugger.Thread.Registers.cpp new file mode 100644 index 0000000..b28d616 --- /dev/null +++ b/GleeBug/Debugger.Thread.Registers.cpp @@ -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; + } +}; \ No newline at end of file diff --git a/GleeBug/Debugger.Thread.Registers.h b/GleeBug/Debugger.Thread.Registers.h new file mode 100644 index 0000000..a95afc5 --- /dev/null +++ b/GleeBug/Debugger.Thread.Registers.h @@ -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 \ No newline at end of file diff --git a/GleeBug/Debugger.Thread.cpp b/GleeBug/Debugger.Thread.cpp index 5c9f3ff..8877b08 100644 --- a/GleeBug/Debugger.Thread.cpp +++ b/GleeBug/Debugger.Thread.cpp @@ -7,17 +7,50 @@ namespace GleeBug 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->hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId); + this->hThread = hThread; this->lpThreadLocalBase = (ULONG_PTR)lpThreadLocalBase; this->lpStartAddress = (ULONG_PTR)lpStartAddress; } - ThreadInfo::~ThreadInfo() + bool ThreadInfo::RegReadContext() { - if (this->hThread != INVALID_HANDLE_VALUE) - CloseHandle(hThread); + SuspendThread(this->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; } }; \ No newline at end of file diff --git a/GleeBug/Debugger.Thread.h b/GleeBug/Debugger.Thread.h index 1ea2ae9..57c71c6 100644 --- a/GleeBug/Debugger.Thread.h +++ b/GleeBug/Debugger.Thread.h @@ -1,26 +1,78 @@ -#ifndef _DEBUGGER_THREADS_H -#define _DEBUGGER_THREADS_H +#ifndef _DEBUGGER_THREAD_H +#define _DEBUGGER_THREAD_H #include "Debugger.Global.h" +#include "Debugger.Thread.Registers.h" namespace GleeBug { /** \brief Thread information structure. */ - struct ThreadInfo + class ThreadInfo { + public: DWORD dwThreadId; HANDLE hThread; ULONG_PTR lpThreadLocalBase; ULONG_PTR lpStartAddress; - ThreadInfo(); - ThreadInfo(DWORD dwThreadId, LPVOID lpThreadLocalBase, LPVOID lpStartAddress); - ~ThreadInfo(); - }; + RegistersInfo registers; + StepCallbackVector stepCallbacks; + bool isSingleStepping; - typedef std::map 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 + void StepInto(T* debugger, void(T::*callback)()) + { + static_cast(static_cast(debugger)); + StepInto(std::bind(callback, debugger)); + } + + private: + CONTEXT _oldContext; + }; }; #endif //_DEBUGGER_THREADS_H \ No newline at end of file diff --git a/GleeBug/Debugger.h b/GleeBug/Debugger.h index c8327ae..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. @@ -113,6 +119,11 @@ namespace GleeBug */ virtual void cbSystemBreakpoint() {}; + /** + \brief Step callback. Provide an implementation to use this callback. + */ + virtual void cbStep() {}; + protected: //core debug event handlers /** \brief Process creation debug event. Do not override this unless you know what you are doing! @@ -189,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/GleeBug/GleeBug.vcxproj b/GleeBug/GleeBug.vcxproj index ef28bcf..25d38a7 100644 --- a/GleeBug/GleeBug.vcxproj +++ b/GleeBug/GleeBug.vcxproj @@ -157,6 +157,7 @@ + @@ -164,6 +165,7 @@ + diff --git a/GleeBug/GleeBug.vcxproj.filters b/GleeBug/GleeBug.vcxproj.filters index 3c4e522..d02f2d2 100644 --- a/GleeBug/GleeBug.vcxproj.filters +++ b/GleeBug/GleeBug.vcxproj.filters @@ -48,6 +48,9 @@ Source Files + + Source Files + @@ -65,5 +68,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/MyDebugger/MyDebugger.h b/MyDebugger/MyDebugger.h index c49741f..8486087 100644 --- a/MyDebugger/MyDebugger.h +++ b/MyDebugger/MyDebugger.h @@ -10,52 +10,82 @@ class MyDebugger : public Debugger protected: 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) { - 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) { - 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) { - 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) { - 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) { - printf("DLL 0x%p unloaded\n", unloadDll.lpBaseOfDll); + printf("DLL 0x%p unloaded\n", + unloadDll.lpBaseOfDll); }; 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) { - 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) { - 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() { - 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()); } };