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;
|
||||
|
||||
//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
|
||||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -4,7 +4,7 @@ namespace GleeBug
|
|||
{
|
||||
ProcessInfo::ProcessInfo()
|
||||
{
|
||||
this->curThread = nullptr;
|
||||
this->thread = nullptr;
|
||||
this->systemBreakpoint = false;
|
||||
this->hProcess = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace GleeBug
|
|||
DWORD dwProcessId;
|
||||
DWORD dwMainThreadId;
|
||||
|
||||
ThreadInfo* curThread;
|
||||
ThreadInfo* thread;
|
||||
bool systemBreakpoint;
|
||||
|
||||
ThreadMap threads;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue