diff --git a/GleeBug/Debugger.Loop.cpp b/GleeBug/Debugger.Loop.cpp index cc19af9..4c0037f 100644 --- a/GleeBug/Debugger.Loop.cpp +++ b/GleeBug/Debugger.Loop.cpp @@ -7,6 +7,8 @@ namespace GleeBug //initialize loop variables mBreakDebugger = false; mIsDebugging = true; + mDetach = false; + mDetachAndBreak = false; //use correct WaitForDebugEvent function typedef BOOL(WINAPI *MYWAITFORDEBUGEVENT)( @@ -23,6 +25,20 @@ namespace GleeBug while (!mBreakDebugger) { + //execute the delayed-detach + if (mDetach) + { + if (!UnsafeDetach()) + cbInternalError("Debugger::Detach failed!"); + break; + } + if (mDetachAndBreak) + { + if (!UnsafeDetachAndBreak()) + cbInternalError("Debugger::DetachAndBreak failed!"); + break; + } + //wait for a debug event mIsRunning = true; if (!MyWaitForDebugEvent(&mDebugEvent, INFINITE)) @@ -63,7 +79,7 @@ namespace GleeBug } //call the pre debug event callback - cbPostDebugEvent(mDebugEvent); + cbPreDebugEvent(mDebugEvent); //dispatch the debug event (documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms679302(v=vs.85).aspx) switch (mDebugEvent.dwDebugEventCode) diff --git a/GleeBug/Debugger.cpp b/GleeBug/Debugger.cpp index 82ccac2..4d42506 100644 --- a/GleeBug/Debugger.cpp +++ b/GleeBug/Debugger.cpp @@ -57,8 +57,50 @@ namespace GleeBug return !!TerminateProcess(mMainProcess.hProcess, 0); } - bool Debugger::Detach() const + bool Debugger::UnsafeDetach() { return !!DebugActiveProcessStop(mMainProcess.dwProcessId); } + + void Debugger::Detach() + { + mDetach = true; + mDetachAndBreak = false; + } + + bool Debugger::UnsafeDetachAndBreak() //TODO check with child processes + { + if (!mProcess || !mThread || !mRegisters) //fail when there is no process or thread currently specified + return false; + + //write the code that breaks the process + auto codePtr = ptr(VirtualAllocEx(mProcess->hProcess, nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE)); + if (!codePtr) + { + cbInternalError("Debugger::UnsafeDetachAndBreak, VirtualAllocEx failed!"); + return false; + } + uint8 code[] = { 0xCC, 0xC3 }; + mProcess->MemWriteUnsafe(codePtr, code, sizeof(code)); + + //push the return address (current GIP) on the stack + mRegisters->Gsp -= sizeof(ptr); + auto gip = mRegisters->Gip(); + mProcess->MemWriteUnsafe(mRegisters->Gsp(), &gip, sizeof(gip)); + + //change the GIP to the code + mRegisters->Gip = codePtr; + + //flush the register cache (needed here explicitly because control will be out of the debugger after this). + mThread->RegWriteContext(); + + //detach from the process + return UnsafeDetach(); + } + + void Debugger::DetachAndBreak() + { + mDetachAndBreak = true; + mDetach = false; + } }; \ No newline at end of file diff --git a/GleeBug/Debugger.h b/GleeBug/Debugger.h index f44642d..3f6480f 100644 --- a/GleeBug/Debugger.h +++ b/GleeBug/Debugger.h @@ -45,7 +45,23 @@ namespace GleeBug \brief Detaches the debuggee. \return true if the debuggee was detached correctly, false otherwise. */ - bool Detach() const; + bool UnsafeDetach(); + + /** + \brief Detaches the debuggee. The detach happens at the end of the debug loop. + */ + void Detach(); + + /** + \brief Detaches the debuggee and breaks with an INT3 (to invoke the JIT debugger). + \return true if the debuggee was detached correctly, false otherwise. + */ + bool UnsafeDetachAndBreak(); + + /** + \brief Detaches the debuggee and breaks with an INT3 (to invoke the JIT debugger). The detach happens at the end of the debug loop. + */ + void DetachAndBreak(); /** \brief Run the debug loop (does not return until the debuggee is detached or terminated). This function should be run from the same thread as you ran Init. @@ -251,6 +267,8 @@ namespace GleeBug ProcessMap mProcesses; bool mIsRunning = false; bool mIsDebugging = false; + bool mDetach = false; + bool mDetachAndBreak = false; Capstone mCapstone; /** diff --git a/TitanEngineEmulator/Emulator.h b/TitanEngineEmulator/Emulator.h index 5881ed4..33e4490 100644 --- a/TitanEngineEmulator/Emulator.h +++ b/TitanEngineEmulator/Emulator.h @@ -34,7 +34,8 @@ public: bool DetachDebuggerEx(DWORD ProcessId) { //TODO - return Detach(); + Detach(); + return true; } void DebugLoop()