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)
|
// 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
|
// https://www.gaijin.at/en/infos/windows-version-numbers
|
||||||
const uint32_t NtBuildNumber = *(uint32_t*)(0x7FFE0000 + 0x260);
|
const uint32_t NtBuildNumber = *(uint32_t*)(0x7FFE0000 + 0x260);
|
||||||
if (NtBuildNumber != 0 && NtBuildNumber >= 10240)
|
if(NtBuildNumber != 0 && NtBuildNumber >= 10240)
|
||||||
{
|
{
|
||||||
IsDbgReplyLaterSupported = mSafeStep;
|
IsDbgReplyLaterSupported = mSafeStep;
|
||||||
}
|
}
|
||||||
|
|
@ -71,27 +71,27 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle safe stepping
|
// 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
|
// 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
|
// Reply to the event later
|
||||||
if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, DBG_REPLY_LATER))
|
if(!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, DBG_REPLY_LATER))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Wait for the next event
|
// Wait for the next event
|
||||||
continue;
|
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
|
// Resume the other threads since the thread being processed is exiting
|
||||||
for (auto& itr : SuspendedThreads)
|
for(auto & itr : SuspendedThreads)
|
||||||
ResumeThread(itr.second);
|
ResumeThread(itr.second);
|
||||||
|
|
||||||
SuspendedThreads.clear();
|
SuspendedThreads.clear();
|
||||||
|
|
@ -139,10 +139,10 @@ namespace GleeBug
|
||||||
{
|
{
|
||||||
case CREATE_PROCESS_DEBUG_EVENT:
|
case CREATE_PROCESS_DEBUG_EVENT:
|
||||||
// HACK: when hollowing the process the debug event still delivers the original image base
|
// 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);
|
auto startAddress = ULONG_PTR(mDebugEvent.u.CreateProcessInfo.lpStartAddress);
|
||||||
if (startAddress)
|
if(startAddress)
|
||||||
{
|
{
|
||||||
startAddress -= ULONG_PTR(mDebugEvent.u.CreateProcessInfo.lpBaseOfImage);
|
startAddress -= ULONG_PTR(mDebugEvent.u.CreateProcessInfo.lpBaseOfImage);
|
||||||
startAddress += mDebugModuleImageBase;
|
startAddress += mDebugModuleImageBase;
|
||||||
|
|
@ -168,10 +168,10 @@ namespace GleeBug
|
||||||
unloadDllEvent(mDebugEvent.u.UnloadDll);
|
unloadDllEvent(mDebugEvent.u.UnloadDll);
|
||||||
break;
|
break;
|
||||||
case EXCEPTION_DEBUG_EVENT:
|
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
|
// Resume the other threads since we are done processing the single step
|
||||||
for (auto& itr : SuspendedThreads)
|
for(auto & itr : SuspendedThreads)
|
||||||
ResumeThread(itr.second);
|
ResumeThread(itr.second);
|
||||||
|
|
||||||
SuspendedThreads.clear();
|
SuspendedThreads.clear();
|
||||||
|
|
@ -209,27 +209,27 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle safe stepping
|
// 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 TF is set (single step), then suspend all the other threads
|
||||||
if (mThread && mThread->isInternalStepping)
|
if(mThread && mThread->isInternalStepping)
|
||||||
{
|
{
|
||||||
ThreadBeingProcessed = mDebugEvent.dwThreadId;
|
ThreadBeingProcessed = mDebugEvent.dwThreadId;
|
||||||
|
|
||||||
for (auto& Thread : mProcess->threads)
|
for(auto & Thread : mProcess->threads)
|
||||||
{
|
{
|
||||||
auto dwThreadId = Thread.first;
|
auto dwThreadId = Thread.first;
|
||||||
auto hThread = Thread.second->hThread;
|
auto hThread = Thread.second->hThread;
|
||||||
|
|
||||||
// Do not suspend the current thread
|
// Do not suspend the current thread
|
||||||
if (ThreadBeingProcessed == dwThreadId)
|
if(ThreadBeingProcessed == dwThreadId)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check if the thread is already suspended
|
// Check if the thread is already suspended
|
||||||
if (SuspendedThreads.count(dwThreadId) != 0)
|
if(SuspendedThreads.count(dwThreadId) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (SuspendThread(hThread) != -1)
|
if(SuspendThread(hThread) != -1)
|
||||||
SuspendedThreads.emplace(dwThreadId, hThread);
|
SuspendedThreads.emplace(dwThreadId, hThread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,18 +40,20 @@ namespace GleeBug
|
||||||
|
|
||||||
auto creationFlags = DEBUG_PROCESS;
|
auto creationFlags = DEBUG_PROCESS;
|
||||||
creationFlags |= DEBUG_ONLY_THIS_PROCESS; // TODO: support child process debugging
|
creationFlags |= DEBUG_ONLY_THIS_PROCESS; // TODO: support child process debugging
|
||||||
if (newConsole)
|
if(newConsole)
|
||||||
creationFlags |= CREATE_NEW_CONSOLE;
|
creationFlags |= CREATE_NEW_CONSOLE;
|
||||||
if (startSuspended)
|
if(startSuspended)
|
||||||
creationFlags |= CREATE_SUSPENDED;
|
creationFlags |= CREATE_SUSPENDED;
|
||||||
|
|
||||||
if (mDisableAslr)
|
if(mDisableAslr)
|
||||||
{
|
{
|
||||||
creationFlags |= CREATE_SUSPENDED;
|
creationFlags |= CREATE_SUSPENDED;
|
||||||
// We will attach manually later
|
// We will attach manually later
|
||||||
creationFlags &= ~(DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS);
|
creationFlags &= ~(DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int retries = 0;
|
||||||
|
retry_no_aslr:
|
||||||
bool result = !!CreateProcessW(szFileNameCreateProcess,
|
bool result = !!CreateProcessW(szFileNameCreateProcess,
|
||||||
szCommandLineCreateProcess,
|
szCommandLineCreateProcess,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|
@ -63,14 +65,24 @@ namespace GleeBug
|
||||||
&mMainStartupInfo,
|
&mMainStartupInfo,
|
||||||
&mMainProcess);
|
&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);
|
DebugActiveProcess_(mMainProcess.dwProcessId);
|
||||||
DebugSetProcessKillOnExit(TRUE);
|
DebugSetProcessKillOnExit(TRUE);
|
||||||
if (!startSuspended)
|
if(!startSuspended)
|
||||||
ResumeThread(mMainProcess.hThread);
|
ResumeThread(mMainProcess.hThread);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete[] szCreateWithCmdLine;
|
delete[] szCreateWithCmdLine;
|
||||||
mAttachedToProcess = false;
|
mAttachedToProcess = false;
|
||||||
|
|
@ -127,26 +139,26 @@ namespace GleeBug
|
||||||
mDetach = false;
|
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;
|
IMAGE_DOS_HEADER idh;
|
||||||
DWORD read = 0;
|
DWORD read = 0;
|
||||||
if (!ReadFile(hFile, &idh, sizeof(idh), &read, nullptr))
|
if(!ReadFile(hFile, &idh, sizeof(idh), &read, nullptr))
|
||||||
return false;
|
return false;
|
||||||
if (idh.e_magic != IMAGE_DOS_SIGNATURE)
|
if(idh.e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
return false;
|
return false;
|
||||||
if (!SetFilePointer(hFile, idh.e_lfanew, nullptr, FILE_BEGIN))
|
if(!SetFilePointer(hFile, idh.e_lfanew, nullptr, FILE_BEGIN))
|
||||||
return false;
|
return false;
|
||||||
IMAGE_NT_HEADERS64 inth;
|
IMAGE_NT_HEADERS64 inth;
|
||||||
if (!ReadFile(hFile, &inth, sizeof(inth), &read, nullptr))
|
if(!ReadFile(hFile, &inth, sizeof(inth), &read, nullptr))
|
||||||
return false;
|
return false;
|
||||||
if (inth.Signature != IMAGE_NT_SIGNATURE)
|
if(inth.Signature != IMAGE_NT_SIGNATURE)
|
||||||
return false;
|
return false;
|
||||||
switch (inth.FileHeader.Machine)
|
switch(inth.FileHeader.Machine)
|
||||||
{
|
{
|
||||||
case IMAGE_FILE_MACHINE_AMD64:
|
case IMAGE_FILE_MACHINE_AMD64:
|
||||||
{
|
{
|
||||||
imageBase = inth.OptionalHeader.ImageBase;
|
imageBase = (ULONG_PTR)inth.OptionalHeader.ImageBase;
|
||||||
entryPoint = inth.OptionalHeader.AddressOfEntryPoint;
|
entryPoint = inth.OptionalHeader.AddressOfEntryPoint;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -165,53 +177,84 @@ namespace GleeBug
|
||||||
return true;
|
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;
|
bool success = false;
|
||||||
auto hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
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
|
// Retrieve image base and entry point
|
||||||
ULONG_PTR debugModuleEntryPoint = 0;
|
ULONG_PTR debugModuleEntryPoint = 0;
|
||||||
if (GetPeData(hFile, mDebugModuleImageBase, debugModuleEntryPoint))
|
if(GetPeData(hFile, mDebugModuleImageBase, debugModuleEntryPoint))
|
||||||
{
|
{
|
||||||
SetFilePointer(hFile, 0, nullptr, FILE_BEGIN);
|
SetFilePointer(hFile, 0, nullptr, FILE_BEGIN);
|
||||||
|
|
||||||
auto hMapping = CreateFileMappingW(hFile, nullptr, SEC_IMAGE | PAGE_READONLY, 0, 0, nullptr);
|
auto hMapping = CreateFileMappingW(hFile, nullptr, SEC_IMAGE | PAGE_READONLY, 0, 0, nullptr);
|
||||||
if (hMapping)
|
if(hMapping)
|
||||||
{
|
{
|
||||||
CONTEXT ctx;
|
CONTEXT ctx;
|
||||||
ctx.ContextFlags = CONTEXT_ALL;
|
ctx.ContextFlags = CONTEXT_ALL;
|
||||||
if (GetThreadContext(pi.hThread, &ctx))
|
if(GetThreadContext(pi.hThread, &ctx))
|
||||||
{
|
{
|
||||||
PVOID imageBase;
|
PVOID imageBase;
|
||||||
// TODO: support wow64 processes
|
// TODO: support wow64 processes
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
auto& pebRegister = ctx.Rdx;
|
auto & pebRegister = ctx.Rdx;
|
||||||
auto& entryPointRegister = ctx.Rcx;
|
auto & entryPointRegister = ctx.Rcx;
|
||||||
#else
|
#else
|
||||||
auto& pebRegister = ctx.Ebx;
|
auto & pebRegister = ctx.Ebx;
|
||||||
auto& entryPointRegister = ctx.Eax;
|
auto & entryPointRegister = ctx.Eax;
|
||||||
#endif // _WIN64
|
#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);
|
auto status = NtUnmapViewOfSection(pi.hProcess, imageBase);
|
||||||
if (status == STATUS_SUCCESS)
|
if(status == STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
SIZE_T viewSize = 0;
|
SIZE_T viewSize = 0;
|
||||||
imageBase = PVOID(mDebugModuleImageBase);
|
imageBase = PVOID(mDebugModuleImageBase);
|
||||||
status = NtMapViewOfSection(hMapping, pi.hProcess, &imageBase, 0, 0, nullptr, &viewSize, ViewUnmap, 0, PAGE_READONLY);
|
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;
|
entryPointRegister = mDebugModuleImageBase + debugModuleEntryPoint;
|
||||||
if (SetThreadContext(pi.hThread, &ctx))
|
if(SetThreadContext(pi.hThread, &ctx))
|
||||||
{
|
{
|
||||||
success = true;
|
success = expectedBase;
|
||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
// For Wow64 processes, also adjust the 64-bit PEB
|
// 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;
|
success = false;
|
||||||
#endif // _WIN64
|
#endif // _WIN64
|
||||||
}
|
}
|
||||||
|
|
@ -220,6 +263,7 @@ namespace GleeBug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CloseHandle(hMapping);
|
CloseHandle(hMapping);
|
||||||
}
|
}
|
||||||
|
|
@ -228,7 +272,7 @@ namespace GleeBug
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success)
|
if(!success)
|
||||||
{
|
{
|
||||||
mDebugModuleImageBase = 0;
|
mDebugModuleImageBase = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -306,7 +306,7 @@ namespace GleeBug
|
||||||
Thread* mThread = nullptr;
|
Thread* mThread = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMATION& pi);
|
bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMATION & pi);
|
||||||
ULONG_PTR mDebugModuleImageBase = 0;
|
ULONG_PTR mDebugModuleImageBase = 0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue