mirror of https://github.com/x64dbg/GleeBug
Improve the DisableAslr functionality
It will now retry 10 times to get the image to load at the expected base
This commit is contained in:
parent
b435ee57d3
commit
807951bac6
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,14 +65,24 @@ namespace GleeBug
|
|||
&mMainStartupInfo,
|
||||
&mMainProcess);
|
||||
|
||||
if (result && mDisableAslr)
|
||||
if(result && mDisableAslr)
|
||||
{
|
||||
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
|
||||
{
|
||||
HollowProcessWithoutASLR(szFileNameCreateProcess, mMainProcess);
|
||||
DebugActiveProcess_(mMainProcess.dwProcessId);
|
||||
DebugSetProcessKillOnExit(TRUE);
|
||||
if (!startSuspended)
|
||||
if(!startSuspended)
|
||||
ResumeThread(mMainProcess.hThread);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] szCreateWithCmdLine;
|
||||
mAttachedToProcess = false;
|
||||
|
|
@ -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,53 +177,84 @@ 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))
|
||||
{
|
||||
if(ULONG_PTR(imageBase) == mDebugModuleImageBase)
|
||||
{
|
||||
// Already at the right base
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto status = NtUnmapViewOfSection(pi.hProcess, imageBase);
|
||||
if (status == STATUS_SUCCESS)
|
||||
if(status == STATUS_SUCCESS)
|
||||
{
|
||||
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)
|
||||
if(status == STATUS_CONFLICTING_ADDRESSES)
|
||||
{
|
||||
if (WriteProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr))
|
||||
// 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))
|
||||
{
|
||||
auto expectedBase = mDebugModuleImageBase == ULONG_PTR(imageBase);
|
||||
mDebugModuleImageBase = ULONG_PTR(imageBase);
|
||||
entryPointRegister = mDebugModuleImageBase + debugModuleEntryPoint;
|
||||
if (SetThreadContext(pi.hThread, &ctx))
|
||||
if(SetThreadContext(pi.hThread, &ctx))
|
||||
{
|
||||
success = true;
|
||||
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))
|
||||
if(isThisProcessWow64() && !WriteProcessMemory(pi.hProcess, (char*)pebRegister - 0x1000 + 0x10, &imageBase, sizeof(PVOID), nullptr))
|
||||
success = false;
|
||||
#endif // _WIN64
|
||||
}
|
||||
|
|
@ -220,6 +263,7 @@ namespace GleeBug
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(hMapping);
|
||||
}
|
||||
|
|
@ -228,7 +272,7 @@ namespace GleeBug
|
|||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
if(!success)
|
||||
{
|
||||
mDebugModuleImageBase = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue