diff --git a/GleeBug/Debugger.Loop.cpp b/GleeBug/Debugger.Loop.cpp index 9082434..6f54e69 100644 --- a/GleeBug/Debugger.Loop.cpp +++ b/GleeBug/Debugger.Loop.cpp @@ -35,7 +35,7 @@ namespace GleeBug // Check if DBG_REPLY_LATER is supported based on Windows version (Windows 10, version 1507 or above) // https://www.gaijin.at/en/infos/windows-version-numbers const uint32_t NtBuildNumber = *(uint32_t*)(0x7FFE0000 + 0x260); - if (NtBuildNumber != 0 && NtBuildNumber >= 10240) + if(NtBuildNumber != 0 && NtBuildNumber >= 10240) { IsDbgReplyLaterSupported = mSafeStep; } @@ -71,27 +71,27 @@ namespace GleeBug } // Handle safe stepping - if (IsDbgReplyLaterSupported) + if(IsDbgReplyLaterSupported) { - if (mDebugEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + if(mDebugEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { // Check if there is a thread processing a single step - if (ThreadBeingProcessed != 0 && mDebugEvent.dwThreadId != ThreadBeingProcessed) + if(ThreadBeingProcessed != 0 && mDebugEvent.dwThreadId != ThreadBeingProcessed) { // Reply to the event later - if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, DBG_REPLY_LATER)) + if(!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, DBG_REPLY_LATER)) break; // Wait for the next event continue; } } - else if (mDebugEvent.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT) + else if(mDebugEvent.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT) { - if (ThreadBeingProcessed != 0 && mDebugEvent.dwThreadId == ThreadBeingProcessed) + if(ThreadBeingProcessed != 0 && mDebugEvent.dwThreadId == ThreadBeingProcessed) { // Resume the other threads since the thread being processed is exiting - for (auto& itr : SuspendedThreads) + for(auto & itr : SuspendedThreads) ResumeThread(itr.second); SuspendedThreads.clear(); @@ -139,10 +139,10 @@ namespace GleeBug { case CREATE_PROCESS_DEBUG_EVENT: // HACK: when hollowing the process the debug event still delivers the original image base - if (mDisableAslr && mDebugModuleImageBase != 0) + if(mDisableAslr && mDebugModuleImageBase != 0) { auto startAddress = ULONG_PTR(mDebugEvent.u.CreateProcessInfo.lpStartAddress); - if (startAddress) + if(startAddress) { startAddress -= ULONG_PTR(mDebugEvent.u.CreateProcessInfo.lpBaseOfImage); startAddress += mDebugModuleImageBase; @@ -168,10 +168,10 @@ namespace GleeBug unloadDllEvent(mDebugEvent.u.UnloadDll); break; case EXCEPTION_DEBUG_EVENT: - if (IsDbgReplyLaterSupported && mDebugEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_SINGLE_STEP) + if(IsDbgReplyLaterSupported && mDebugEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_SINGLE_STEP) { // Resume the other threads since we are done processing the single step - for (auto& itr : SuspendedThreads) + for(auto & itr : SuspendedThreads) ResumeThread(itr.second); SuspendedThreads.clear(); @@ -209,27 +209,27 @@ namespace GleeBug } // Handle safe stepping - if (IsDbgReplyLaterSupported && mDebugEvent.dwDebugEventCode != EXIT_THREAD_DEBUG_EVENT) + if(IsDbgReplyLaterSupported && mDebugEvent.dwDebugEventCode != EXIT_THREAD_DEBUG_EVENT) { // If TF is set (single step), then suspend all the other threads - if (mThread && mThread->isInternalStepping) + if(mThread && mThread->isInternalStepping) { ThreadBeingProcessed = mDebugEvent.dwThreadId; - for (auto& Thread : mProcess->threads) + for(auto & Thread : mProcess->threads) { auto dwThreadId = Thread.first; auto hThread = Thread.second->hThread; // Do not suspend the current thread - if (ThreadBeingProcessed == dwThreadId) + if(ThreadBeingProcessed == dwThreadId) continue; // Check if the thread is already suspended - if (SuspendedThreads.count(dwThreadId) != 0) + if(SuspendedThreads.count(dwThreadId) != 0) continue; - if (SuspendThread(hThread) != -1) + if(SuspendThread(hThread) != -1) SuspendedThreads.emplace(dwThreadId, hThread); } } diff --git a/GleeBug/Debugger.cpp b/GleeBug/Debugger.cpp index f0fc50d..e224e19 100644 --- a/GleeBug/Debugger.cpp +++ b/GleeBug/Debugger.cpp @@ -40,18 +40,20 @@ namespace GleeBug auto creationFlags = DEBUG_PROCESS; creationFlags |= DEBUG_ONLY_THIS_PROCESS; // TODO: support child process debugging - if (newConsole) + if(newConsole) creationFlags |= CREATE_NEW_CONSOLE; - if (startSuspended) + if(startSuspended) creationFlags |= CREATE_SUSPENDED; - if (mDisableAslr) + if(mDisableAslr) { creationFlags |= CREATE_SUSPENDED; // We will attach manually later creationFlags &= ~(DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS); } + int retries = 0; +retry_no_aslr: bool result = !!CreateProcessW(szFileNameCreateProcess, szCommandLineCreateProcess, nullptr, @@ -63,13 +65,23 @@ namespace GleeBug &mMainStartupInfo, &mMainProcess); - if (result && mDisableAslr) + if(result && mDisableAslr) { - HollowProcessWithoutASLR(szFileNameCreateProcess, mMainProcess); - DebugActiveProcess_(mMainProcess.dwProcessId); - DebugSetProcessKillOnExit(TRUE); - if (!startSuspended) - ResumeThread(mMainProcess.hThread); + if(!HollowProcessWithoutASLR(szFileNameCreateProcess, mMainProcess)) + { + TerminateThread(mMainProcess.hThread, STATUS_CONFLICTING_ADDRESSES); + TerminateProcess(mMainProcess.hProcess, STATUS_CONFLICTING_ADDRESSES); + if(retries++ < 10) + goto retry_no_aslr; + result = false; + } + else + { + DebugActiveProcess_(mMainProcess.dwProcessId); + DebugSetProcessKillOnExit(TRUE); + if(!startSuspended) + ResumeThread(mMainProcess.hThread); + } } delete[] szCreateWithCmdLine; @@ -127,26 +139,26 @@ namespace GleeBug mDetach = false; } - static bool GetPeData(HANDLE hFile, ULONG_PTR& imageBase, ULONG_PTR& entryPoint) + static bool GetPeData(HANDLE hFile, ULONG_PTR & imageBase, ULONG_PTR & entryPoint) { IMAGE_DOS_HEADER idh; DWORD read = 0; - if (!ReadFile(hFile, &idh, sizeof(idh), &read, nullptr)) + if(!ReadFile(hFile, &idh, sizeof(idh), &read, nullptr)) return false; - if (idh.e_magic != IMAGE_DOS_SIGNATURE) + if(idh.e_magic != IMAGE_DOS_SIGNATURE) return false; - if (!SetFilePointer(hFile, idh.e_lfanew, nullptr, FILE_BEGIN)) + if(!SetFilePointer(hFile, idh.e_lfanew, nullptr, FILE_BEGIN)) return false; IMAGE_NT_HEADERS64 inth; - if (!ReadFile(hFile, &inth, sizeof(inth), &read, nullptr)) + if(!ReadFile(hFile, &inth, sizeof(inth), &read, nullptr)) return false; - if (inth.Signature != IMAGE_NT_SIGNATURE) + if(inth.Signature != IMAGE_NT_SIGNATURE) return false; - switch (inth.FileHeader.Machine) + switch(inth.FileHeader.Machine) { case IMAGE_FILE_MACHINE_AMD64: { - imageBase = inth.OptionalHeader.ImageBase; + imageBase = (ULONG_PTR)inth.OptionalHeader.ImageBase; entryPoint = inth.OptionalHeader.AddressOfEntryPoint; } break; @@ -165,55 +177,87 @@ namespace GleeBug return true; } - bool Debugger::HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMATION& pi) +#ifndef _WIN64 + static bool isThisProcessWow64() + { + typedef BOOL(WINAPI * tIsWow64Process)(HANDLE hProcess, PBOOL Wow64Process); + BOOL bIsWow64 = FALSE; + static auto fnIsWow64Process = (tIsWow64Process)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); + + if(fnIsWow64Process) + { + fnIsWow64Process(GetCurrentProcess(), &bIsWow64); + } + + return (bIsWow64 != FALSE); + } +#endif + + bool Debugger::HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMATION & pi) { bool success = false; auto hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); - if (hFile != INVALID_HANDLE_VALUE) + if(hFile != INVALID_HANDLE_VALUE) { // Retrieve image base and entry point ULONG_PTR debugModuleEntryPoint = 0; - if (GetPeData(hFile, mDebugModuleImageBase, debugModuleEntryPoint)) + if(GetPeData(hFile, mDebugModuleImageBase, debugModuleEntryPoint)) { SetFilePointer(hFile, 0, nullptr, FILE_BEGIN); auto hMapping = CreateFileMappingW(hFile, nullptr, SEC_IMAGE | PAGE_READONLY, 0, 0, nullptr); - if (hMapping) + if(hMapping) { CONTEXT ctx; ctx.ContextFlags = CONTEXT_ALL; - if (GetThreadContext(pi.hThread, &ctx)) + if(GetThreadContext(pi.hThread, &ctx)) { PVOID imageBase; // TODO: support wow64 processes #ifdef _WIN64 - auto& pebRegister = ctx.Rdx; - auto& entryPointRegister = ctx.Rcx; + auto & pebRegister = ctx.Rdx; + auto & entryPointRegister = ctx.Rcx; #else - auto& pebRegister = ctx.Ebx; - auto& entryPointRegister = ctx.Eax; + auto & pebRegister = ctx.Ebx; + auto & entryPointRegister = ctx.Eax; #endif // _WIN64 - if (ReadProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr)) + if(ReadProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr)) { - auto status = NtUnmapViewOfSection(pi.hProcess, imageBase); - if (status == STATUS_SUCCESS) + if(ULONG_PTR(imageBase) == mDebugModuleImageBase) { - SIZE_T viewSize = 0; - imageBase = PVOID(mDebugModuleImageBase); - status = NtMapViewOfSection(hMapping, pi.hProcess, &imageBase, 0, 0, nullptr, &viewSize, ViewUnmap, 0, PAGE_READONLY); - if (status == STATUS_SUCCESS || status == STATUS_IMAGE_NOT_AT_BASE) + // Already at the right base + success = true; + } + else + { + auto status = NtUnmapViewOfSection(pi.hProcess, imageBase); + if(status == STATUS_SUCCESS) { - if (WriteProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr)) + SIZE_T viewSize = 0; + imageBase = PVOID(mDebugModuleImageBase); + status = NtMapViewOfSection(hMapping, pi.hProcess, &imageBase, 0, 0, nullptr, &viewSize, ViewUnmap, 0, PAGE_READONLY); + if(status == STATUS_CONFLICTING_ADDRESSES) { - entryPointRegister = mDebugModuleImageBase + debugModuleEntryPoint; - if (SetThreadContext(pi.hThread, &ctx)) + // Remap in a random location (otherwise the process will crash) + imageBase = 0; + status = NtMapViewOfSection(hMapping, pi.hProcess, &imageBase, 0, 0, nullptr, &viewSize, ViewUnmap, 0, PAGE_READONLY); + } + if(status == STATUS_SUCCESS || status == STATUS_IMAGE_NOT_AT_BASE) + { + if(WriteProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr)) { - success = true; + auto expectedBase = mDebugModuleImageBase == ULONG_PTR(imageBase); + mDebugModuleImageBase = ULONG_PTR(imageBase); + entryPointRegister = mDebugModuleImageBase + debugModuleEntryPoint; + if(SetThreadContext(pi.hThread, &ctx)) + { + success = expectedBase; #ifndef _WIN64 - // For Wow64 processes, also adjust the 64-bit PEB - if (IsThisProcessWow64() && !WriteProcessMemory(pi.hProcess, (char*)pebRegister - 0x1000 + 0x10, &imageBase, sizeof(PVOID), nullptr)) - success = false; + // For Wow64 processes, also adjust the 64-bit PEB + if(isThisProcessWow64() && !WriteProcessMemory(pi.hProcess, (char*)pebRegister - 0x1000 + 0x10, &imageBase, sizeof(PVOID), nullptr)) + success = false; #endif // _WIN64 + } } } } @@ -228,7 +272,7 @@ namespace GleeBug CloseHandle(hFile); } - if (!success) + if(!success) { mDebugModuleImageBase = 0; } diff --git a/GleeBug/Debugger.h b/GleeBug/Debugger.h index 8abc4fa..29824f7 100644 --- a/GleeBug/Debugger.h +++ b/GleeBug/Debugger.h @@ -306,7 +306,7 @@ namespace GleeBug Thread* mThread = nullptr; private: - bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMATION& pi); + bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMATION & pi); ULONG_PTR mDebugModuleImageBase = 0; }; }; diff --git a/GleeBug/stringutils.cpp b/GleeBug/stringutils.cpp index 6dd779a..f088dc2 100644 --- a/GleeBug/stringutils.cpp +++ b/GleeBug/stringutils.cpp @@ -1,42 +1,42 @@ -#include "stringutils.h" -#include -#include -#include - -// Functions from x64dbg project: https://github.com/x64dbg/x64dbg -//Conversion functions taken from: http://www.nubaria.com/en/blog/?p=289 -String Utf16ToUtf8(const WString & wstr) -{ - String convertedString; - int requiredSize = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, 0, 0, 0, 0); - if(requiredSize > 0) - { - std::vector buffer(requiredSize); - WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &buffer[0], requiredSize, 0, 0); - convertedString.assign(buffer.begin(), buffer.end() - 1); - } - return convertedString; -} - -String Utf16ToUtf8(const wchar_t* wstr) -{ - return Utf16ToUtf8(wstr ? WString(wstr) : WString()); -} - -WString Utf8ToUtf16(const String & str) -{ - WString convertedString; - int requiredSize = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, 0, 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; -} - -WString Utf8ToUtf16(const char* str) -{ - return Utf8ToUtf16(str ? String(str) : String()); -} +#include "stringutils.h" +#include +#include +#include + +// Functions from x64dbg project: https://github.com/x64dbg/x64dbg +//Conversion functions taken from: http://www.nubaria.com/en/blog/?p=289 +String Utf16ToUtf8(const WString & wstr) +{ + String convertedString; + int requiredSize = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, 0, 0, 0, 0); + if(requiredSize > 0) + { + std::vector buffer(requiredSize); + WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &buffer[0], requiredSize, 0, 0); + convertedString.assign(buffer.begin(), buffer.end() - 1); + } + return convertedString; +} + +String Utf16ToUtf8(const wchar_t* wstr) +{ + return Utf16ToUtf8(wstr ? WString(wstr) : WString()); +} + +WString Utf8ToUtf16(const String & str) +{ + WString convertedString; + int requiredSize = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, 0, 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; +} + +WString Utf8ToUtf16(const char* str) +{ + return Utf8ToUtf16(str ? String(str) : String()); +} diff --git a/GleeBug/stringutils.h b/GleeBug/stringutils.h index 8959373..b604185 100644 --- a/GleeBug/stringutils.h +++ b/GleeBug/stringutils.h @@ -1,16 +1,16 @@ -#ifndef _STRINGUTILS_H -#define _STRINGUTILS_H - -#include -#include - -typedef std::string String; -typedef std::wstring WString; - - -String Utf16ToUtf8(const WString & wstr); -String Utf16ToUtf8(const wchar_t* wstr); -WString Utf8ToUtf16(const String & str); -WString Utf8ToUtf16(const char* str); - +#ifndef _STRINGUTILS_H +#define _STRINGUTILS_H + +#include +#include + +typedef std::string String; +typedef std::wstring WString; + + +String Utf16ToUtf8(const WString & wstr); +String Utf16ToUtf8(const wchar_t* wstr); +WString Utf8ToUtf16(const String & str); +WString Utf8ToUtf16(const char* str); + #endif //_STRINGUTILS_H \ No newline at end of file diff --git a/ZydisExportConfig.h b/ZydisExportConfig.h index 6611dcc..f066993 100644 --- a/ZydisExportConfig.h +++ b/ZydisExportConfig.h @@ -1,41 +1,41 @@ -#ifndef ZYDIS_EXPORT_H -#define ZYDIS_EXPORT_H - -#ifdef ZYDIS_STATIC_DEFINE -# define ZYDIS_EXPORT -# define ZYDIS_NO_EXPORT -#else -# ifndef ZYDIS_EXPORT -# ifdef Zydis_EXPORTS -/* We are building this library */ -# define ZYDIS_EXPORT -# else -/* We are using this library */ -# define ZYDIS_EXPORT -# endif -# endif - -# ifndef ZYDIS_NO_EXPORT -# define ZYDIS_NO_EXPORT -# endif -#endif - -#ifndef ZYDIS_DEPRECATED -# define ZYDIS_DEPRECATED __declspec(deprecated) -#endif - -#ifndef ZYDIS_DEPRECATED_EXPORT -# define ZYDIS_DEPRECATED_EXPORT ZYDIS_EXPORT ZYDIS_DEPRECATED -#endif - -#ifndef ZYDIS_DEPRECATED_NO_EXPORT -# define ZYDIS_DEPRECATED_NO_EXPORT ZYDIS_NO_EXPORT ZYDIS_DEPRECATED -#endif - -#if 0 /* DEFINE_NO_DEPRECATED */ -# ifndef ZYDIS_NO_DEPRECATED -# define ZYDIS_NO_DEPRECATED -# endif -#endif - -#endif +#ifndef ZYDIS_EXPORT_H +#define ZYDIS_EXPORT_H + +#ifdef ZYDIS_STATIC_DEFINE +# define ZYDIS_EXPORT +# define ZYDIS_NO_EXPORT +#else +# ifndef ZYDIS_EXPORT +# ifdef Zydis_EXPORTS +/* We are building this library */ +# define ZYDIS_EXPORT +# else +/* We are using this library */ +# define ZYDIS_EXPORT +# endif +# endif + +# ifndef ZYDIS_NO_EXPORT +# define ZYDIS_NO_EXPORT +# endif +#endif + +#ifndef ZYDIS_DEPRECATED +# define ZYDIS_DEPRECATED __declspec(deprecated) +#endif + +#ifndef ZYDIS_DEPRECATED_EXPORT +# define ZYDIS_DEPRECATED_EXPORT ZYDIS_EXPORT ZYDIS_DEPRECATED +#endif + +#ifndef ZYDIS_DEPRECATED_NO_EXPORT +# define ZYDIS_DEPRECATED_NO_EXPORT ZYDIS_NO_EXPORT ZYDIS_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef ZYDIS_NO_DEPRECATED +# define ZYDIS_NO_DEPRECATED +# endif +#endif + +#endif