Implement UE_ENGINE_DISABLE_ASLR

This commit is contained in:
Duncan Ogilvie 2022-09-10 00:04:42 +02:00
parent 39934ea3ae
commit b435ee57d3
12 changed files with 9562 additions and 14 deletions

View File

@ -138,6 +138,18 @@ namespace GleeBug
switch(mDebugEvent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
// HACK: when hollowing the process the debug event still delivers the original image base
if (mDisableAslr && mDebugModuleImageBase != 0)
{
auto startAddress = ULONG_PTR(mDebugEvent.u.CreateProcessInfo.lpStartAddress);
if (startAddress)
{
startAddress -= ULONG_PTR(mDebugEvent.u.CreateProcessInfo.lpBaseOfImage);
startAddress += mDebugModuleImageBase;
mDebugEvent.u.CreateProcessInfo.lpStartAddress = LPTHREAD_START_ROUTINE(startAddress);
}
mDebugEvent.u.CreateProcessInfo.lpBaseOfImage = LPVOID(mDebugModuleImageBase);
}
createProcessEvent(mDebugEvent.u.CreateProcessInfo);
break;
case EXIT_PROCESS_DEBUG_EVENT:

View File

@ -1,5 +1,7 @@
#pragma once
#include "ntdll.h"
static DWORD BaseSetLastNTError(IN NTSTATUS Status)
{
DWORD dwErrCode;

View File

@ -1,3 +1,4 @@
#include "Debugger.NativeAttach.h"
#include "Debugger.h"
#include "Debugger.Thread.Registers.h"
@ -37,29 +38,52 @@ namespace GleeBug
szFileNameCreateProcess = nullptr;
}
auto creationFlags = DEBUG_PROCESS;
creationFlags |= DEBUG_ONLY_THIS_PROCESS; // TODO: support child process debugging
if (newConsole)
creationFlags |= CREATE_NEW_CONSOLE;
if (startSuspended)
creationFlags |= CREATE_SUSPENDED;
if (mDisableAslr)
{
creationFlags |= CREATE_SUSPENDED;
// We will attach manually later
creationFlags &= ~(DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS);
}
bool result = !!CreateProcessW(szFileNameCreateProcess,
szCommandLineCreateProcess,
nullptr,
nullptr,
FALSE,
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | (newConsole ? CREATE_NEW_CONSOLE : 0) | (startSuspended ? CREATE_SUSPENDED : 0),
creationFlags,
nullptr,
szCurrentDirectory,
&mMainStartupInfo,
&mMainProcess);
if (result && mDisableAslr)
{
HollowProcessWithoutASLR(szFileNameCreateProcess, mMainProcess);
DebugActiveProcess_(mMainProcess.dwProcessId);
DebugSetProcessKillOnExit(TRUE);
if (!startSuspended)
ResumeThread(mMainProcess.hThread);
}
delete[] szCreateWithCmdLine;
mAttachedToProcess = false;
return result;
}
bool Debugger::Attach(DWORD processId, decltype(&DebugActiveProcess) debugActiveProcess)
bool Debugger::Attach(DWORD processId)
{
//don't allow attaching when still debugging
if(mIsDebugging)
return false;
if(!debugActiveProcess(processId))
if(!DebugActiveProcess_(processId))
return false;
mAttachedToProcess = true;
memset(&mMainStartupInfo, 0, sizeof(mMainStartupInfo));
@ -102,4 +126,113 @@ namespace GleeBug
mDetachAndBreak = true;
mDetach = false;
}
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))
return false;
if (idh.e_magic != IMAGE_DOS_SIGNATURE)
return false;
if (!SetFilePointer(hFile, idh.e_lfanew, nullptr, FILE_BEGIN))
return false;
IMAGE_NT_HEADERS64 inth;
if (!ReadFile(hFile, &inth, sizeof(inth), &read, nullptr))
return false;
if (inth.Signature != IMAGE_NT_SIGNATURE)
return false;
switch (inth.FileHeader.Machine)
{
case IMAGE_FILE_MACHINE_AMD64:
{
imageBase = inth.OptionalHeader.ImageBase;
entryPoint = inth.OptionalHeader.AddressOfEntryPoint;
}
break;
case IMAGE_FILE_MACHINE_I386:
{
auto nth32 = (IMAGE_NT_HEADERS32*)&inth;
imageBase = nth32->OptionalHeader.ImageBase;
entryPoint = nth32->OptionalHeader.AddressOfEntryPoint;
}
break;
default:
return false;
}
return true;
}
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)
{
// Retrieve image base and entry point
ULONG_PTR debugModuleEntryPoint = 0;
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)
{
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_ALL;
if (GetThreadContext(pi.hThread, &ctx))
{
PVOID imageBase;
// TODO: support wow64 processes
#ifdef _WIN64
auto& pebRegister = ctx.Rdx;
auto& entryPointRegister = ctx.Rcx;
#else
auto& pebRegister = ctx.Ebx;
auto& entryPointRegister = ctx.Eax;
#endif // _WIN64
if (ReadProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr))
{
auto status = NtUnmapViewOfSection(pi.hProcess, imageBase);
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 (WriteProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr))
{
entryPointRegister = mDebugModuleImageBase + debugModuleEntryPoint;
if (SetThreadContext(pi.hThread, &ctx))
{
success = true;
#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;
#endif // _WIN64
}
}
}
}
}
}
CloseHandle(hMapping);
}
}
CloseHandle(hFile);
}
if (!success)
{
mDebugModuleImageBase = 0;
}
return success;
}
};

View File

@ -47,7 +47,7 @@ namespace GleeBug
\param processId Process to attach to.
\return true if the debuggee was attached to successfully, false otherwise.
*/
bool Attach(DWORD processId, decltype(&DebugActiveProcess) = &DebugActiveProcess);
bool Attach(DWORD processId);
/**
\brief Stops the debuggee (terminate the process)
@ -293,6 +293,7 @@ namespace GleeBug
bool mDetachAndBreak = false;
bool mAttachedToProcess = false;
bool mSafeStep = true;
bool mDisableAslr = false;
/**
\brief The current process (can be null in some cases).
@ -303,6 +304,10 @@ namespace GleeBug
\brief The current thread (can be null in some cases). Should be a copy of mProcess->thread.
*/
Thread* mThread = nullptr;
private:
bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMATION& pi);
ULONG_PTR mDebugModuleImageBase = 0;
};
};

View File

@ -188,6 +188,7 @@
<ItemGroup>
<ClInclude Include="Debugger.Breakpoint.h" />
<ClInclude Include="Debugger.Dll.h" />
<ClInclude Include="Debugger.NativeAttach.h" />
<ClInclude Include="Debugger.Process.h" />
<ClInclude Include="Debugger.h" />
<ClInclude Include="Debugger.Thread.h" />
@ -196,6 +197,7 @@
<ClInclude Include="Debugger.Thread.Registers.h" />
<ClInclude Include="Debugger.Thread.Registers.Register.h" />
<ClInclude Include="GleeBug.h" />
<ClInclude Include="ntdll.h" />
<ClInclude Include="oprintf.h" />
<ClInclude Include="Static.BufferFile.h" />
<ClInclude Include="Static.File.h" />

View File

@ -199,6 +199,12 @@
<ClInclude Include="stringutils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Debugger.NativeAttach.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ntdll.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="zyan-disassembler-engine\include\Zydis\Internal\GeneratedTypes.inc">

9394
GleeBug/ntdll.h Normal file

File diff suppressed because it is too large Load Diff

BIN
GleeBug/ntdll_x64.lib Normal file

Binary file not shown.

BIN
GleeBug/ntdll_x86.lib Normal file

Binary file not shown.

View File

@ -6,7 +6,6 @@
#include "TitanEngine.h"
#include "FileMap.h"
#include "PEB.h"
#include "NativeAttach.h"
#include "Global.Engine.Context.h"
#include "Hider.h"
@ -68,7 +67,7 @@ public:
bool AttachDebugger(DWORD ProcessId, bool KillOnExit, LPVOID DebugInfo, LPVOID CallBack)
{
if(!Attach(ProcessId, DebugActiveProcess_))
if(!Attach(ProcessId))
return false;
mCbATTACHBREAKPOINT = STEPCALLBACK(CallBack);
mAttachProcessInfo = (PROCESS_INFORMATION*)DebugInfo;
@ -188,12 +187,12 @@ public:
case UE_ENGINE_SET_DEBUG_PRIVILEGE:
mSetDebugPrivilege = VariableSet;
break;
case UE_ENGINE_SAFE_ATTACH:
mSafeAttach = VariableSet;
break;
case UE_ENGINE_SAFE_STEP:
mSafeStep = VariableSet;
break;
case UE_ENGINE_DISABLE_ASLR:
mDisableAslr = VariableSet;
break;
}
}
@ -1301,7 +1300,6 @@ private: //functions
private: //variables
bool mSetDebugPrivilege = false;
bool mSafeAttach = false;
typedef void(*CUSTOMHANDLER)(const void*);
typedef void(*STEPCALLBACK)();
typedef STEPCALLBACK BPCALLBACK;

View File

@ -154,7 +154,6 @@
<ClInclude Include="FileMap.h" />
<ClInclude Include="Global.Engine.Context.h" />
<ClInclude Include="Hider.h" />
<ClInclude Include="NativeAttach.h" />
<ClInclude Include="ntdll.h" />
<ClInclude Include="PEB.h" />
<ClInclude Include="resource.h" />

View File

@ -43,9 +43,6 @@
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NativeAttach.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ntdll.h">
<Filter>Header Files</Filter>
</ClInclude>