mirror of https://github.com/x64dbg/GleeBug
203 lines
6.3 KiB
C++
203 lines
6.3 KiB
C++
#pragma once
|
|
|
|
#include "ntdll.h"
|
|
#include "PEB.h"
|
|
|
|
#ifdef _WIN64
|
|
#pragma comment(lib, "ntdll_x64.lib")
|
|
#else
|
|
#pragma comment(lib, "ntdll_x86.lib")
|
|
#endif
|
|
|
|
//Quote from The Ultimate Anti-Debugging Reference by Peter Ferrie
|
|
//Flags field exists at offset 0x0C in the heap on the 32-bit versions of Windows NT, Windows 2000, and Windows XP; and at offset 0x40 on the 32-bit versions of Windows Vista and later.
|
|
//Flags field exists at offset 0x14 in the heap on the 64-bit versions of Windows XP, and at offset 0x70 in the heap on the 64-bit versions of Windows Vista and later.
|
|
//ForceFlags field exists at offset 0x10 in the heap on the 32-bit versions of Windows NT, Windows 2000, and Windows XP; and at offset 0x44 on the 32-bit versions of Windows Vista and later.
|
|
//ForceFlags field exists at offset 0x18 in the heap on the 64-bit versions of Windows XP, and at offset 0x74 in the heap on the 64-bit versions of Windows Vista and later.
|
|
|
|
static bool
|
|
IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
|
|
{
|
|
OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
|
|
DWORDLONG const dwlConditionMask = VerSetConditionMask(
|
|
VerSetConditionMask(
|
|
VerSetConditionMask(
|
|
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
|
|
VER_MINORVERSION, VER_GREATER_EQUAL),
|
|
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
|
|
|
osvi.dwMajorVersion = wMajorVersion;
|
|
osvi.dwMinorVersion = wMinorVersion;
|
|
osvi.wServicePackMajor = wServicePackMajor;
|
|
|
|
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
|
|
}
|
|
|
|
static bool
|
|
IsWindowsVistaOrGreater()
|
|
{
|
|
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
|
|
}
|
|
|
|
static int getHeapFlagsOffset(bool x64)
|
|
{
|
|
if(x64) //x64 offsets
|
|
{
|
|
if(IsWindowsVistaOrGreater())
|
|
{
|
|
return 0x70;
|
|
}
|
|
else
|
|
{
|
|
return 0x14;
|
|
}
|
|
}
|
|
else //x86 offsets
|
|
{
|
|
if(IsWindowsVistaOrGreater())
|
|
{
|
|
return 0x40;
|
|
}
|
|
else
|
|
{
|
|
return 0x0C;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int getHeapForceFlagsOffset(bool x64)
|
|
{
|
|
if(x64) //x64 offsets
|
|
{
|
|
if(IsWindowsVistaOrGreater())
|
|
{
|
|
return 0x74;
|
|
}
|
|
else
|
|
{
|
|
return 0x18;
|
|
}
|
|
}
|
|
else //x86 offsets
|
|
{
|
|
if(IsWindowsVistaOrGreater())
|
|
{
|
|
return 0x44;
|
|
}
|
|
else
|
|
{
|
|
return 0x10;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void* GetPEBLocation_(HANDLE hProcess)
|
|
{
|
|
ULONG RequiredLen = 0;
|
|
void* PebAddress = 0;
|
|
PROCESS_BASIC_INFORMATION myProcessBasicInformation[5] = { 0 };
|
|
|
|
if(NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &RequiredLen) == 0)
|
|
{
|
|
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
|
|
}
|
|
else
|
|
{
|
|
if(NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == 0)
|
|
{
|
|
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
|
|
}
|
|
}
|
|
|
|
return PebAddress;
|
|
}
|
|
|
|
static bool PebPatchHeapFlags(PEB_CURRENT* peb, HANDLE hProcess)
|
|
{
|
|
#ifdef _WIN64
|
|
const auto is_x64 = true;
|
|
#else
|
|
const auto is_x64 = false;
|
|
#endif
|
|
|
|
std::vector<PVOID> heaps;
|
|
heaps.resize(peb->NumberOfHeaps);
|
|
|
|
if(ReadProcessMemory(hProcess, (PVOID)peb->ProcessHeaps, (PVOID)heaps.data(), heaps.size() * sizeof(PVOID), nullptr) == FALSE)
|
|
return false;
|
|
|
|
std::basic_string<uint8_t> heap;
|
|
heap.resize(0x100); // hacky
|
|
for(DWORD i = 0; i < peb->NumberOfHeaps; i++)
|
|
{
|
|
if(ReadProcessMemory(hProcess, heaps[i], (PVOID)heap.data(), heap.size(), nullptr) == FALSE)
|
|
return false;
|
|
|
|
auto flags = (DWORD*)(heap.data() + getHeapFlagsOffset(is_x64));
|
|
auto force_flags = (DWORD*)(heap.data() + getHeapForceFlagsOffset(is_x64));
|
|
|
|
if(i == 0)
|
|
{
|
|
// Default heap.
|
|
*flags &= HEAP_GROWABLE;
|
|
}
|
|
else
|
|
{
|
|
// Flags from RtlCreateHeap/HeapCreate.
|
|
*flags &= (HEAP_GROWABLE | HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_CREATE_ENABLE_EXECUTE);
|
|
}
|
|
|
|
*force_flags = 0;
|
|
|
|
if(WriteProcessMemory(hProcess, heaps[i], (PVOID)heap.data(), heap.size(), nullptr) == FALSE)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool FixPebInProcess(HANDLE hProcess)
|
|
{
|
|
PEB_CURRENT myPEB = { 0 };
|
|
SIZE_T ueNumberOfBytesRead = 0;
|
|
void* heapFlagsAddress = 0;
|
|
DWORD heapFlags = 0;
|
|
void* heapForceFlagsAddress = 0;
|
|
DWORD heapForceFlags = 0;
|
|
|
|
void* AddressOfPEB = GetPEBLocation(hProcess);
|
|
|
|
if(!AddressOfPEB)
|
|
return false;
|
|
|
|
if(ReadProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
|
|
{
|
|
myPEB.BeingDebugged = FALSE;
|
|
myPEB.NtGlobalFlag &= ~0x70;
|
|
|
|
#ifdef _WIN64
|
|
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(true));
|
|
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(true));
|
|
#else
|
|
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(false));
|
|
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(false));
|
|
#endif //_WIN64
|
|
|
|
ReadProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
|
|
ReadProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
|
|
|
|
heapFlags &= HEAP_GROWABLE;
|
|
heapForceFlags = 0;
|
|
|
|
WriteProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
|
|
WriteProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
|
|
|
|
PebPatchHeapFlags(&myPEB, hProcess);
|
|
|
|
if(WriteProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
} |