mirror of https://github.com/x64dbg/GleeBug
working single step with callbacks
This commit is contained in:
parent
25b4dd40de
commit
1a072a78c5
|
|
@ -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
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue