// IATHookingRevisited.cpp : Defines the entry point for the console application. #include #include #include #include #include #include #include "Patcher.h" #include "Hunter.h" #define BUFFER_SIZE 0x2000 // Define the function signature for NtQueryInformationProcess typedef NTSTATUS(NTAPI* NtQueryInformationProcess_t)( HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength ); uintptr_t FindRemotePEB(HANDLE hProcess) { HMODULE hNTDLL = LoadLibraryA("ntdll"); if (!hNTDLL) return 0; FARPROC fpNtQueryInformationProcess = GetProcAddress( hNTDLL, "NtQueryInformationProcess" ); if (!fpNtQueryInformationProcess) return 0; NtQueryInformationProcess_t ntQueryInformationProcess = (NtQueryInformationProcess_t)fpNtQueryInformationProcess; PROCESS_BASIC_INFORMATION pBasicInfo; ULONG dwReturnLength = 0; NTSTATUS status = ntQueryInformationProcess( hProcess, ProcessBasicInformation, &pBasicInfo, sizeof(PROCESS_BASIC_INFORMATION), &dwReturnLength ); if (status != 0) { return 0; } return (uintptr_t)pBasicInfo.PebBaseAddress; } IPEB* ReadRemotePEB(HANDLE hProcess) { uintptr_t pebAddress = FindRemotePEB(hProcess); if (pebAddress == 0) { return NULL; } IPEB* pPEB = new IPEB(); BOOL bSuccess = ReadProcessMemory( hProcess, (LPCVOID)pebAddress, pPEB, sizeof(IPEB), 0 ); if (!bSuccess) { delete pPEB; return NULL; } return pPEB; } PLOADED_IMAGE ReadRemoteImage(HANDLE hProcess, LPCVOID lpImageBaseAddress) { BYTE* lpBuffer = new BYTE[BUFFER_SIZE]; BOOL bSuccess = ReadProcessMemory( hProcess, lpImageBaseAddress, lpBuffer, BUFFER_SIZE, 0 ); if (!bSuccess) { delete[] lpBuffer; return NULL; } PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER)lpBuffer; PLOADED_IMAGE pImage = new LOADED_IMAGE(); pImage->FileHeader = (PIMAGE_NT_HEADERS)(lpBuffer + pDOSHeader->e_lfanew); pImage->NumberOfSections = pImage->FileHeader->FileHeader.NumberOfSections; pImage->Sections = (PIMAGE_SECTION_HEADER)(lpBuffer + pDOSHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64)); return pImage; } PIMAGE_SECTION_HEADER FindSectionHeaderByName(PIMAGE_SECTION_HEADER pHeaders, DWORD dwNumberOfSections, const char* pName) { PIMAGE_SECTION_HEADER pHeaderMatch = 0; for (DWORD i = 0; i < dwNumberOfSections; i++) { PIMAGE_SECTION_HEADER pHeader = &pHeaders[i]; if (!_stricmp((char*)pHeader->Name, pName)) { pHeaderMatch = pHeader; break; } } return pHeaderMatch; } PIMAGE_IMPORT_DESCRIPTOR ReadRemoteImportDescriptors(HANDLE hProcess, LPCVOID lpImageBaseAddress, PIMAGE_DATA_DIRECTORY pImageDataDirectory) { IMAGE_DATA_DIRECTORY importDirectory = pImageDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; PIMAGE_IMPORT_DESCRIPTOR pImportDescriptors = new IMAGE_IMPORT_DESCRIPTOR[importDirectory.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR)]; BOOL bSuccess = ReadProcessMemory( hProcess, (LPCVOID)((uintptr_t)lpImageBaseAddress + importDirectory.VirtualAddress), pImportDescriptors, importDirectory.Size, 0 ); if (!bSuccess) return 0; return pImportDescriptors; } char* ReadRemoteDescriptorName(HANDLE hProcess, LPCVOID lpImageBaseAddress, PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor) { char* pBuffer = new char[BUFFER_SIZE]; BOOL bSuccess = ReadProcessMemory( hProcess, (LPCVOID)((uintptr_t)lpImageBaseAddress + pImageImportDescriptor->Name), pBuffer, BUFFER_SIZE, 0 ); if (!bSuccess) { delete[] pBuffer; return 0; } return pBuffer; } PIMAGE_THUNK_DATA64 ReadRemoteILT(HANDLE hProcess, LPCVOID lpImageBaseAddress, PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor) { DWORD dwThunkArrayLen = BUFFER_SIZE / sizeof(IMAGE_THUNK_DATA64); PIMAGE_THUNK_DATA64 pILT = new IMAGE_THUNK_DATA64[dwThunkArrayLen]; BOOL bSuccess = ReadProcessMemory( hProcess, (LPCVOID)((uintptr_t)lpImageBaseAddress + pImageImportDescriptor->OriginalFirstThunk), pILT, BUFFER_SIZE, 0 ); if (!bSuccess) { delete[] pILT; return 0; } return pILT; } PIMAGE_THUNK_DATA64 ReadRemoteIAT(HANDLE hProcess, LPCVOID lpImageBaseAddress, PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor) { DWORD dwThunkArrayLen = BUFFER_SIZE / sizeof(IMAGE_THUNK_DATA64); PIMAGE_THUNK_DATA64 pIAT = new IMAGE_THUNK_DATA64[dwThunkArrayLen]; BOOL bSuccess = ReadProcessMemory( hProcess, (LPCVOID)((uintptr_t)lpImageBaseAddress + pImageImportDescriptor->FirstThunk), pIAT, BUFFER_SIZE, 0 ); if (!bSuccess) { delete[] pIAT; return 0; } return pIAT; } PIMAGE_IMPORT_BY_NAME ReadRemoteImportByName(HANDLE hProcess, LPCVOID lpImageBaseAddress, PIMAGE_THUNK_DATA64 pImageThunk) { BYTE* lpImportNameBuffer = new BYTE[BUFFER_SIZE]; BOOL bSuccess = ReadProcessMemory( hProcess, (LPCVOID)((uintptr_t)lpImageBaseAddress + pImageThunk->u1.AddressOfData), lpImportNameBuffer, BUFFER_SIZE, 0 ); if (!bSuccess) { delete[] lpImportNameBuffer; return 0; } PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)lpImportNameBuffer; return pImportByName; } PIPEB_LDR_DATA ReadRemoteLoaderData(HANDLE hProcess, PPEB pPEB) { PIPEB_LDR_DATA pLoaderData = new IPEB_LDR_DATA(); BOOL bSuccess = ReadProcessMemory( hProcess, pPEB->Ldr, pLoaderData, sizeof(IPEB_LDR_DATA), 0 ); if (!bSuccess) { delete pLoaderData; return 0; } return pLoaderData; } PVOID FindRemoteImageBase(HANDLE hProcess, PPEB pPEB, const char* pModuleName) { PIPEB_LDR_DATA pLoaderData = ReadRemoteLoaderData(hProcess, pPEB); PVOID firstFLink = pLoaderData->InLoadOrderModuleList.Flink; PVOID fLink = pLoaderData->InLoadOrderModuleList.Flink; PLDR_MODULE pModule = new LDR_MODULE(); do { BOOL bSuccess = ReadProcessMemory( hProcess, fLink, pModule, sizeof(LDR_MODULE), 0 ); if (!bSuccess) { delete pModule; return 0; } PWSTR pwBaseDllName = new WCHAR[pModule->BaseDllName.MaximumLength / sizeof(WCHAR)]; bSuccess = ReadProcessMemory( hProcess, pModule->BaseDllName.Buffer, pwBaseDllName, pModule->BaseDllName.Length + sizeof(WCHAR), 0 ); if (bSuccess) { size_t sBaseDllName = pModule->BaseDllName.Length / sizeof(WCHAR) + 1; char* pBaseDllName = new char[sBaseDllName]; WideCharToMultiByte( CP_ACP, 0, pwBaseDllName, pModule->BaseDllName.Length / sizeof(WCHAR) + 1, pBaseDllName, (int)sBaseDllName, 0, 0 ); if (!_stricmp(pBaseDllName, pModuleName)) { delete[] pwBaseDllName; delete[] pBaseDllName; return pModule->BaseAddress; } delete[] pBaseDllName; } delete[] pwBaseDllName; fLink = pModule->InLoadOrderModuleList.Flink; } while (pModule->InLoadOrderModuleList.Flink != firstFLink); delete pModule; return 0; } BOOL HookFunction(HANDLE hProcess, CHAR* pModuleName, CHAR* pFunctionName, PVOID hookAddress) { DWORD64 dwPEBAddress = FindRemotePEB(hProcess); if (!dwPEBAddress) { printf("Error finding remote PEB\r\n"); return FALSE; } IPEB* pPEB = ReadRemotePEB(hProcess); if (!pPEB) { printf("Error reading remote PEB\r\n"); return FALSE; } HMODULE hModule = (HMODULE)pPEB->ImageBaseAddress; PLOADED_IMAGE pImage = ReadRemoteImage(hProcess, hModule); if (!pImage) { printf("Error reading remote image\r\n"); return FALSE; } PIMAGE_IMPORT_DESCRIPTOR pImportDescriptors = ReadRemoteImportDescriptors( hProcess, hModule, pImage->FileHeader->OptionalHeader.DataDirectory ); if (!pImportDescriptors) { printf("Error reading remote import descriptors\r\n"); return FALSE; } for (PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = pImportDescriptors; pImportDescriptor->Name; pImportDescriptor++) { char* pName = ReadRemoteDescriptorName(hProcess, hModule, pImportDescriptor); if (!pName) { printf("Error reading remote descriptor name\r\n"); continue; } printf("Checking module: %s\r\n", pName); if (!_stricmp(pName, pModuleName)) { DWORD dwThunkArrayLen = BUFFER_SIZE / sizeof(IMAGE_THUNK_DATA64); PIMAGE_THUNK_DATA64 pILT = ReadRemoteILT(hProcess, hModule, pImportDescriptor); if (!pILT) { printf("Error reading remote ILT\r\n"); return FALSE; } DWORD dwOffset = 0; for (dwOffset = 0; dwOffset < dwThunkArrayLen; dwOffset++) { PIMAGE_IMPORT_BY_NAME pImportByName = ReadRemoteImportByName(hProcess, hModule, &pILT[dwOffset]); if (!pImportByName) { printf("Error reading remote import by name\r\n"); return FALSE; } if (!strcmp((char*)pImportByName->Name, pFunctionName)) { break; } } PIMAGE_THUNK_DATA64 pIAT = ReadRemoteIAT(hProcess, hModule, pImportDescriptor); if (!pIAT) { printf("Error reading remote IAT\r\n"); return FALSE; } DWORD64* dwOriginalAddress = &pIAT[dwOffset].u1.Function; printf("Original import address: 0x%p\r\n", (void*)dwOriginalAddress); printf("Writing: 0x%p\r\n", (void*)hookAddress); if (WriteProcessMemory(hProcess, (PVOID)pIAT[dwOffset].u1.Function, hookAddress, sizeof(DWORD64), 0) != 0) { printf("New import address: 0x%p\r\n", hookAddress); return TRUE; } else { printf("Error writing new import address: 0x%08x\r\n", GetLastError()); return FALSE; } } } return FALSE; } VOID GetModuleTextSection(HMODULE hModule, PDWORD pTextSection, PDWORD pTextSectionSize) { printf("[*] Module address: 0x%llx\n", (ULONGLONG)hModule); PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule; if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { printf("Invalid DOS signature\n"); return; } PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hModule + dosHeader->e_lfanew); if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) { printf("Invalid NT signature\n"); return; } WORD nSections = ntHeaders->FileHeader.NumberOfSections; printf("[*] Number of sections: %d\n", nSections); PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(ntHeaders); for (WORD i = 0; i < nSections; i++) { if (strcmp((char*)Section->Name, (char*)".text") == 0) { *pTextSection = Section->VirtualAddress; *pTextSectionSize = Section->SizeOfRawData; break; } else { printf("Section: %s\n", Section->Name); } Section++; } } void PatchRpcCfg(HANDLE hProcess) { const char* pModuleName = "rpcrt4.dll"; DWORD textRva = 0; DWORD textSize = 0; PVOID copAddress; PVOID callAddress; PVOID targetAddress; BYTE patch[] = { 0xc3 }; HMODULE hMod = GetModuleHandleA(pModuleName); BOOL bSuccess = FALSE; if (!hMod) { goto end; } GetModuleTextSection(hMod, &textRva, &textSize); printf("[*] Text section RVA: 0x%x, Size: 0x%x\n", textRva, textSize); copAddress = HuntForCopInstruction((PVOID)((UINT64)hMod + textRva), textSize); if (copAddress == NULL) { printf("CALL R10 not found\r\n"); goto end; } callAddress = HuntForCall((PVOID)((UINT64)copAddress), 0x200, TRUE); if (callAddress == NULL) { printf("CALL not found\r\n"); goto end; } targetAddress = (PVOID)CalculateCallTarget(hMod, (UINT64)callAddress); printf("[*] Target address: 0x%llx\n", (ULONGLONG)targetAddress); bSuccess = WriteProcessMemory(hProcess, targetAddress, patch, 1, 0); end: if (!bSuccess) printf("[-] Error patching function\r\n"); else printf("[+] CFG patched successfully\r\n"); } // Use HookFunction to replace RaiseException in kernelbase.dll with a pointer to ExitThread void PatchKernelBase(HANDLE hProcess) { const char* pModuleName = "kernel32.dll"; const char* pFunctionName = "RaiseException"; BOOL bSuccess = HookFunction( hProcess, (char*)pModuleName, (char*)pFunctionName, ExitThread ); if (!bSuccess) printf("Error hooking function\r\n"); else printf("Function hooked successfully\r\n"); } void generate_jmp_shellcode(DWORD address, unsigned char* shellcode) { shellcode[0] = 0xE9; // jmp instruction DWORD relative_address = address - 0x5; memcpy(shellcode + 1, &relative_address, sizeof(DWORD)); } void NtdllExceptionPatch(HANDLE hProcess) { const char* pModuleName = "ntdll.dll"; const char* hookedFunctionName = "RtlRaiseException"; const char* targetFunctionName = "RtlExitUserThread"; unsigned char patch[5] = { 0 }; HMODULE hMod = GetModuleHandleA(pModuleName); if (!hMod) { printf("Error getting module handle\r\n"); return; } PVOID targetAddress = (PVOID)GetProcAddress(hMod, hookedFunctionName); PVOID targetFunction = (PVOID)GetProcAddress(hMod, targetFunctionName);; if (!targetAddress || !targetFunction) { printf("Error getting function address\r\n"); return; } DWORD relativeAddress = (DWORD)((UINT64)targetFunction - (UINT64)targetAddress); generate_jmp_shellcode(relativeAddress, patch); BOOL bSuccess = WriteProcessMemory(hProcess, targetAddress, patch, sizeof(patch), 0); if (!bSuccess) printf("Error hooking function\r\n"); else printf("Function hooked successfully\r\n"); }