diff --git a/.gitignore b/.gitignore index d397081..9fc6d1d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ Release/ *.orig *.vcxproj.user docs/ +.vs/ \ No newline at end of file diff --git a/GleeBug/Debugger.Loop.Exception.cpp b/GleeBug/Debugger.Loop.Exception.cpp index 0a2be5d..b267ae5 100644 --- a/GleeBug/Debugger.Loop.Exception.cpp +++ b/GleeBug/Debugger.Loop.Exception.cpp @@ -29,6 +29,10 @@ namespace GleeBug mProcess->permanentDep = true; #endif //_WIN64 + //call the attach callback if appropriate + if(mAttachedToProcess && mProcess->dwProcessId == mMainProcess.dwProcessId) + cbAttachBreakpoint(); + //call the callback cbSystemBreakpoint(); } diff --git a/GleeBug/Debugger.Loop.Process.cpp b/GleeBug/Debugger.Loop.Process.cpp index da18173..cb278ea 100644 --- a/GleeBug/Debugger.Loop.Process.cpp +++ b/GleeBug/Debugger.Loop.Process.cpp @@ -4,6 +4,15 @@ namespace GleeBug { void Debugger::createProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess) { + //initial attach housekeeping + if(mAttachedToProcess && !mMainProcess.dwProcessId) + { + mMainProcess.hProcess = createProcess.hProcess; + mMainProcess.hThread = createProcess.hThread; + mMainProcess.dwProcessId = mDebugEvent.dwProcessId; + mMainProcess.dwThreadId = mDebugEvent.dwThreadId; + } + //process housekeeping mProcesses.insert({ mDebugEvent.dwProcessId, Process(createProcess.hProcess, diff --git a/GleeBug/Debugger.Loop.cpp b/GleeBug/Debugger.Loop.cpp index f9e3c67..3ff251b 100644 --- a/GleeBug/Debugger.Loop.cpp +++ b/GleeBug/Debugger.Loop.cpp @@ -113,7 +113,7 @@ namespace GleeBug break; } - //clear trap flag when set by GleeBug (to prevent an EXCEPTION_SINGLE_STEP after detach + //clear trap flag when set by GleeBug (to prevent an EXCEPTION_SINGLE_STEP after detach) if (mDetach && mThread) { if (mThread->isInternalStepping || mThread->isSingleStepping) diff --git a/GleeBug/Debugger.Thread.cpp b/GleeBug/Debugger.Thread.cpp index 970bea9..88d355f 100644 --- a/GleeBug/Debugger.Thread.cpp +++ b/GleeBug/Debugger.Thread.cpp @@ -42,17 +42,14 @@ namespace GleeBug bool Thread::RegReadContext() { - SuspendThread(this->hThread); memset(&this->mOldContext, 0, sizeof(CONTEXT)); - this->mOldContext.ContextFlags = CONTEXT_ALL; - bool bReturn = false; + this->mOldContext.ContextFlags = CONTEXT_ALL; //TODO: granular control over what's required if (GetThreadContext(this->hThread, &this->mOldContext)) { this->registers.SetContext(this->mOldContext); - bReturn = true; + return true; } - ResumeThread(this->hThread); - return bReturn; + return false; } bool Thread::RegWriteContext() const @@ -61,10 +58,7 @@ namespace GleeBug if (memcmp(&this->mOldContext, 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; + return !!SetThreadContext(this->hThread, this->registers.GetContext()); } void Thread::StepInto() diff --git a/GleeBug/Debugger.cpp b/GleeBug/Debugger.cpp index 2efcff1..facf5c7 100644 --- a/GleeBug/Debugger.cpp +++ b/GleeBug/Debugger.cpp @@ -15,8 +15,8 @@ namespace GleeBug const wchar_t* szCommandLine, const wchar_t* szCurrentDirectory) { - STARTUPINFOW si; - memset(&si, 0, sizeof(si)); + memset(&mMainStartupInfo, 0, sizeof(mMainStartupInfo)); + memset(&mMainProcess, 0, sizeof(mMainProcess)); const wchar_t* szFileNameCreateProcess; wchar_t* szCommandLineCreateProcess; wchar_t* szCreateWithCmdLine = nullptr; @@ -42,14 +42,28 @@ namespace GleeBug DEBUG_PROCESS | CREATE_NEW_CONSOLE, nullptr, szCurrentDirectory, - &si, + &mMainStartupInfo, &mMainProcess); delete[] szCreateWithCmdLine; + mAttachedToProcess = false; return result; } + bool Debugger::Attach(DWORD processId) + { + //don't allow attaching when still debugging + if(mIsDebugging) + return false; + if(!DebugActiveProcess(processId)) + return false; + mAttachedToProcess = true; + memset(&mMainStartupInfo, 0, sizeof(mMainStartupInfo)); + memset(&mMainProcess, 0, sizeof(mMainProcess)); + return true; + } + bool Debugger::Stop() const { return !!TerminateProcess(mMainProcess.hProcess, 0); diff --git a/GleeBug/Debugger.h b/GleeBug/Debugger.h index 57cc5e2..5a205f6 100644 --- a/GleeBug/Debugger.h +++ b/GleeBug/Debugger.h @@ -35,6 +35,13 @@ namespace GleeBug const wchar_t* szCommandLine, const wchar_t* szCurrentDirectory); + /** + \brief Attach to a debuggee. + \param processId Process to attach to. + \return true if the debuggee was attached to successfully, false otherwise. + */ + bool Attach(DWORD processId); + /** \brief Stops the debuggee (terminate the process) \return true if the debuggee was stopped correctly, false otherwise. @@ -161,6 +168,11 @@ namespace GleeBug */ virtual void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) {}; + /** + \brief Attach breakpoint callback. Called just before cbSystemBreakpoint, only for the process that was attached to. Provide an implementation to use this callback. + */ + virtual void cbAttachBreakpoint() {}; + /** \brief System breakpoint callback. Called after the event is internally processed. Provide an implementation to use this callback. */ @@ -264,6 +276,7 @@ namespace GleeBug virtual void exceptionAccessViolation(const EXCEPTION_RECORD & exceptionRecord, bool firstChance); protected: //variables + STARTUPINFOW mMainStartupInfo; PROCESS_INFORMATION mMainProcess; uint32 mContinueStatus = DBG_EXCEPTION_NOT_HANDLED; bool mBreakDebugger = false; @@ -273,6 +286,7 @@ namespace GleeBug bool mIsDebugging = false; bool mDetach = false; bool mDetachAndBreak = false; + bool mAttachedToProcess = false; Capstone mCapstone; /** diff --git a/GleeBug/GleeBug.cpp b/GleeBug/GleeBug.cpp new file mode 100644 index 0000000..e80795f --- /dev/null +++ b/GleeBug/GleeBug.cpp @@ -0,0 +1,41 @@ +#include "GleeBug.h" + +namespace GleeBug +{ + //Conversion functions taken from: http://www.nubaria.com/en/blog/?p=289 + std::string Utf16ToUtf8(const std::wstring & wstr) + { + std::string convertedString; + auto requiredSize = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr); + if(requiredSize > 0) + { + std::vector buffer(requiredSize); + WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &buffer[0], requiredSize, nullptr, nullptr); + convertedString.assign(buffer.begin(), buffer.end() - 1); + } + return convertedString; + } + + std::string Utf16ToUtf8(const wchar_t* wstr) + { + return Utf16ToUtf8(wstr ? std::wstring(wstr) : std::wstring()); + } + + std::wstring Utf8ToUtf16(const std::string & str) + { + std::wstring convertedString; + int requiredSize = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0); + if(requiredSize > 0) + { + std::vector buffer(requiredSize); + MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &buffer[0], requiredSize); + convertedString.assign(buffer.begin(), buffer.end() - 1); + } + return convertedString; + } + + std::wstring Utf8ToUtf16(const char* str) + { + return Utf8ToUtf16(str ? std::string(str) : std::string()); + } +}; \ No newline at end of file diff --git a/GleeBug/GleeBug.h b/GleeBug/GleeBug.h index 27d6969..9c58ab4 100644 --- a/GleeBug/GleeBug.h +++ b/GleeBug/GleeBug.h @@ -53,6 +53,11 @@ namespace GleeBug return a.second < b.first; } }; + + std::string Utf16ToUtf8(const std::wstring & wstr); + std::string Utf16ToUtf8(const wchar_t* wstr); + std::wstring Utf8ToUtf16(const std::string & str); + std::wstring Utf8ToUtf16(const char* str); } #endif //GLEEBUG_H \ No newline at end of file diff --git a/GleeBug/GleeBug.vcxproj b/GleeBug/GleeBug.vcxproj index 03ec159..b1ecb74 100644 --- a/GleeBug/GleeBug.vcxproj +++ b/GleeBug/GleeBug.vcxproj @@ -168,6 +168,7 @@ + diff --git a/GleeBug/GleeBug.vcxproj.filters b/GleeBug/GleeBug.vcxproj.filters index e21dc23..41f6f89 100644 --- a/GleeBug/GleeBug.vcxproj.filters +++ b/GleeBug/GleeBug.vcxproj.filters @@ -83,6 +83,9 @@ Source Files\capstone_wrapper + + Source Files + diff --git a/MyDebugger/MyDebugger.h b/MyDebugger/MyDebugger.h index 08cdb5a..0261454 100644 --- a/MyDebugger/MyDebugger.h +++ b/MyDebugger/MyDebugger.h @@ -153,6 +153,12 @@ protected: rip.dwError); } + void cbAttachBreakpoint() override + { + printf("Attach breakpoint reached, GIP: 0x%p\n", + mRegisters->Gip()); + } + void cbSystemBreakpoint() override { printf("System breakpoint reached, GIP: 0x%p\n", diff --git a/TitanEngineEmulator/Emulator.h b/TitanEngineEmulator/Emulator.h index 9f4590f..faf9f56 100644 --- a/TitanEngineEmulator/Emulator.h +++ b/TitanEngineEmulator/Emulator.h @@ -9,6 +9,7 @@ public: //Debugger PROCESS_INFORMATION* InitDebugW(const wchar_t* szFileName, const wchar_t* szCommandLine, const wchar_t* szCurrentFolder) { + mCbATTACHBREAKPOINT = nullptr; if (!Init(szFileName, szCommandLine, szCurrentFolder)) return nullptr; return &mMainProcess; @@ -27,13 +28,16 @@ public: bool AttachDebugger(DWORD ProcessId, bool KillOnExit, LPVOID DebugInfo, LPVOID CallBack) { - //TODO - return false; + if(!Attach(ProcessId)) + return false; + mCbATTACHBREAKPOINT = STEPCALLBACK(CallBack); + mAttachProcessInfo = (PROCESS_INFORMATION*)DebugInfo; + DebugLoop(); + return true; } bool DetachDebuggerEx(DWORD ProcessId) { - //TODO Detach(); return true; } @@ -141,6 +145,16 @@ public: mSetDebugPrivilege = VariableSet; } + PROCESS_INFORMATION* TitanGetProcessInformation() + { + return &mMainProcess; + } + + STARTUPINFOW* TitanGetStartupInformation() + { + return &mMainStartupInfo; + } + //Misc bool IsJumpGoingToExecuteEx(HANDLE hProcess, HANDLE hThread, ULONG_PTR InstructionAddress, ULONG_PTR RegFlags) { @@ -475,6 +489,13 @@ public: return false; } + //Threader + ULONG_PTR ThreaderCreateRemoteThread(ULONG_PTR ThreadStartAddress, bool AutoCloseTheHandle, LPVOID ThreadPassParameter, LPDWORD ThreadId) + { + //TODO + return 0; + } + protected: void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const Process & process) override { @@ -530,6 +551,16 @@ protected: mCbDEBUGEVENT(&debugEvent); } + void cbAttachBreakpoint() override + { + if(mCbATTACHBREAKPOINT) + { + if(mAttachProcessInfo) + *mAttachProcessInfo = mMainProcess; + mCbATTACHBREAKPOINT(); + } + } + void cbSystemBreakpoint() override { if (mCbSYSTEMBREAKPOINT) @@ -586,12 +617,16 @@ private: //functions Thread* threadFromHandle(HANDLE hThread) const { + if(!hThread) + return mThread; //TODO: properly implement this return mThread; } Process* processFromHandle(HANDLE hProcess) const { + if(!hProcess) + return mProcess; //TODO: properly implement this return mProcess; } @@ -664,4 +699,6 @@ private: //variables CUSTOMHANDLER mCbOUTPUTDEBUGSTRING = nullptr; CUSTOMHANDLER mCbUNHANDLEDEXCEPTION = nullptr; CUSTOMHANDLER mCbDEBUGEVENT = nullptr; + STEPCALLBACK mCbATTACHBREAKPOINT = nullptr; + PROCESS_INFORMATION* mAttachProcessInfo = nullptr; }; \ No newline at end of file diff --git a/TitanEngineEmulator/TitanEngineEmulator.cpp b/TitanEngineEmulator/TitanEngineEmulator.cpp index 7a3ca4d..ba809d9 100644 --- a/TitanEngineEmulator/TitanEngineEmulator.cpp +++ b/TitanEngineEmulator/TitanEngineEmulator.cpp @@ -81,6 +81,16 @@ __declspec(dllexport) void TITCALL SetEngineVariable(DWORD VariableId, bool Vari emu.SetEngineVariable(VariableId, VariableSet); } +__declspec(dllexport) PROCESS_INFORMATION* TITCALL TitanGetProcessInformation() +{ + return emu.TitanGetProcessInformation(); +} + +__declspec(dllexport) STARTUPINFOW* TITCALL TitanGetStartupInformation() +{ + return emu.TitanGetStartupInformation(); +} + //Misc __declspec(dllexport) bool TITCALL IsJumpGoingToExecuteEx(HANDLE hProcess, HANDLE hThread, ULONG_PTR InstructionAddress, ULONG_PTR RegFlags) { @@ -118,6 +128,11 @@ __declspec(dllexport) ULONG_PTR TITCALL GetContextDataEx(HANDLE hActiveThread, D return emu.GetContextDataEx(hActiveThread, IndexOfRegister); } +__declspec(dllexport) ULONG_PTR TITCALL GetContextData(DWORD IndexOfRegister) +{ + return GetContextDataEx(nullptr, IndexOfRegister); +} + __declspec(dllexport) bool TITCALL SetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister, ULONG_PTR NewRegisterValue) { return emu.SetContextDataEx(hActiveThread, IndexOfRegister, NewRegisterValue); @@ -149,6 +164,11 @@ __declspec(dllexport) bool TITCALL StaticFileLoadW(const wchar_t* szFileName, DW return emu.StaticFileLoadW(szFileName, DesiredAccess, SimulateLoad, FileHandle, LoadedSize, FileMap, FileMapVA); } +__declspec(dllexport) bool TITCALL StaticFileLoad(const char* szFileName, DWORD DesiredAccess, bool SimulateLoad, LPHANDLE FileHandle, LPDWORD LoadedSize, LPHANDLE FileMap, PULONG_PTR FileMapVA) +{ + return StaticFileLoadW(Utf8ToUtf16(szFileName).c_str(), DesiredAccess, SimulateLoad, FileHandle, LoadedSize, FileMap, FileMapVA); +} + __declspec(dllexport) bool TITCALL StaticFileUnloadW(const wchar_t* szFileName, bool CommitChanges, HANDLE FileHandle, DWORD LoadedSize, HANDLE FileMap, ULONG_PTR FileMapVA) { return emu.StaticFileUnloadW(szFileName, CommitChanges, FileHandle, LoadedSize, FileMap, FileMapVA); @@ -164,6 +184,11 @@ __declspec(dllexport) ULONG_PTR TITCALL ConvertVAtoFileOffsetEx(ULONG_PTR FileMa return emu.ConvertVAtoFileOffsetEx(FileMapVA, FileSize, ImageBase, AddressToConvert, AddressIsRVA, ReturnType); } +__declspec(dllexport) ULONG_PTR TITCALL ConvertVAtoFileOffset(ULONG_PTR FileMapVA, ULONG_PTR AddressToConvert, bool ReturnType) +{ + return ConvertVAtoFileOffsetEx(FileMapVA, 0, 0, AddressToConvert, false, ReturnType); +} + __declspec(dllexport) ULONG_PTR TITCALL GetPE32DataFromMappedFile(ULONG_PTR FileMapVA, DWORD WhichSection, DWORD WhichData) { return emu.GetPE32DataFromMappedFile(FileMapVA, WhichSection, WhichData); @@ -174,6 +199,11 @@ __declspec(dllexport) ULONG_PTR TITCALL GetPE32DataW(const wchar_t* szFileName, return emu.GetPE32DataW(szFileName, WhichSection, WhichData); } +__declspec(dllexport) ULONG_PTR TITCALL GetPE32Data(const char* szFileName, DWORD WhichSection, DWORD WhichData) +{ + return GetPE32DataW(Utf8ToUtf16(szFileName).c_str(), WhichSection, WhichData); +} + __declspec(dllexport) bool TITCALL IsFileDLLW(const wchar_t* szFileName, ULONG_PTR FileMapVA) { return emu.IsFileDLLW(szFileName, FileMapVA); @@ -268,4 +298,10 @@ __declspec(dllexport) void TITCALL SingleStep(DWORD StepCount, LPVOID StepCallBa __declspec(dllexport) void TITCALL StepInto(LPVOID traceCallBack) { emu.StepInto(traceCallBack); +} + +//Threader +__declspec(dllexport) ULONG_PTR TITCALL ThreaderCreateRemoteThread(ULONG_PTR ThreadStartAddress, bool AutoCloseTheHandle, LPVOID ThreadPassParameter, LPDWORD ThreadId) +{ + return emu.ThreaderCreateRemoteThread(ThreadStartAddress, AutoCloseTheHandle, ThreadPassParameter, ThreadId); } \ No newline at end of file diff --git a/capstone_wrapper b/capstone_wrapper index 7fbeb7e..619f5e0 160000 --- a/capstone_wrapper +++ b/capstone_wrapper @@ -1 +1 @@ -Subproject commit 7fbeb7edaad3ffda7a7f37bd31086662e56f7a42 +Subproject commit 619f5e0a0c43b19ca9dabf34da4ddd19cb84a704