I just rummaged through my old hard disk and suddenly stumbled across some old C sources from around a year ago when I played with IAT hooking on windows 7. I will not explain much, but I made the bottom code around a year ago (Thus, in 2012) and it should be able to hook any code (depicted as the handler here) into running processes via the IAT. I suppose the code is not working properly, but it gives a good picture of how an IAT hooking approach might look like.
Hopefully I'll find some time and motivation (or more appropriate: discipline) to update the little library and finally complete it. Maybe I will also make it compatible with windows 8, but I assume it's not really different from windows 7 (Hell I don't know anything about the windows API)...
#include "main.h" /* * Implements a little library to Hook the WinApi on running programs. * Furthermore, the API provides functions too find code caves and little hook templates for the most common scenarios * when we use hooking: Intercept function parameters and monitor output... * Supports both, 32 and 64 bit Windows XP to Windows 7. The code is pretty bloated, because * I intended to catch as many errors as possbible and included some debug stuff. This hooking 'library' shall be reliable. * It provides just IAT hooking, no other code injections. */ int main(int argc, char *argv[]) { HANDLE hProcess; HOOK_CONTEXT *pHookContext; DWORD pid; BOOL bSuccess; char* handler = "\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90" "\x90\x90\x90\x90\x90\x90\x90\x90"; #ifdef _WIN64 printf("[i] 64 architecture detected\n"); fprintf(stderr, "[-] Sorry, currently not supported\n"); exit(EXIT_FAILURE); #endif #ifdef _WIN32 printf("[i] 32 architecture detected\n"); #endif if (argc < 2) { pid = GetCurrentProcessId(); printf("[i] using current process id as target\n"); } else if (argc >= 2) { pid = (DWORD) atoi(argv[1]); } else { fprintf(stderr, "Usage: %s PID", argv[0]); exit(EXIT_FAILURE); } /* Try to open the specified process */ hProcess = OpenProcess ( PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_SET_QUOTA, FALSE, pid ); if (hProcess == NULL) { fprintf(stderr, "[!] OpenProcess() failed with %d\n", GetLastError()); exit(EXIT_FAILURE); } else { printf("[i] Remote Process with PID=%d opened\n", pid); } /* Hook shit */ pHookContext = HookFunction ( hProcess, "USER32.DLL", "MessageBoxA", handler, strlen(handler) ); if (pHookContext == NULL) { fprintf(stderr, "[!] Hooking failed\n", GetLastError()); exit(EXIT_FAILURE); } else printf("[i] hooked\n", pid); Sleep(50000); // Sleep 60 seconds. Try now the new behaviour of the function :) bSuccess = ReleaseHook ( hProcess, pHookContext ); if (!bSuccess) { fprintf(stderr, "[!] Release Hook failed\n", GetLastError()); exit(EXIT_FAILURE); } else printf("[i] Hook released\n", pid); CloseHandle(hProcess); exit(EXIT_SUCCESS); } // ============================================================================================= DWORD FindRemotePEB(HANDLE hProcess) { HMODULE hNTDll; FARPROC fpNtQueryInformationProcess; NTSTATUS status; PROCESS_BASIC_INFORMATION procBasicInformation; ULONG returnLength; hNTDll = LoadLibraryA("ntdll"); if (!hNTDll) { fprintf(stderr, "LoadLibraryA() failed with %d\n", GetLastError()); return 0; } fpNtQueryInformationProcess = GetProcAddress ( hNTDll, "NtQueryInformationProcess" ); if (!fpNtQueryInformationProcess) { fprintf(stderr, "GetProcAddress() failed with %d\n", GetLastError()); return 0; } NtQueryInformationProcess ntQueryInformationProcess = (NtQueryInformationProcess)fpNtQueryInformationProcess; status = ntQueryInformationProcess ( hProcess, 0, // ProcessBasicInformation &procBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &returnLength ); if (status != 0) { fprintf(stderr, "NtQueryInformationProcess() failed with %d\n", status); return 0; } return (DWORD)procBasicInformation.PebBaseAddress; } // ============================================================================================= /* Get's the PEB of the own process */ DWORD FindOwnPEB(void) { DWORD pebAddr; #ifdef _WIN32 _asm { push eax // push the values of the register eax on the stack mov eax, FS:[0x30] // store the values ad address FS:[0x30] in eax mov [pebAddr], eax // store the values of eax in the variable pebAddr pop eax // remake initial eax value } #endif #ifdef _WIN64 _asm { push rax mov rax, FS:[0x30] mov [pebAddr], rax pop rax } #endif return pebAddr; } // ============================================================================================= PIMAGE_DATA_DIRECTORY ReadRemoteDataDirectoryRVA(HANDLE hProcess, LPCVOID lpImageBaseAddress, DWORD index) { PIMAGE_NT_HEADERS32 pNTHeaders; PIMAGE_DATA_DIRECTORY dataDir; BYTE* lpBuffer; DWORD oldProtect; if (index < 0 || index > 16) { fprintf(stderr, "No valid DATA_DIRECTORY directory\n"); return 0; } lpBuffer = malloc(sizeof(BUFFER_SIZE)); ZeroMemory(lpBuffer, BUFFER_SIZE); if (lpBuffer == NULL) { fprintf(stderr, "malloc() failed with %d\n", GetLastError()); return 0; } BOOL bSuccess = VirtualProtectEx ( hProcess, (PVOID)lpImageBaseAddress, BUFFER_SIZE, PAGE_EXECUTE_READ, &oldProtect ); if (!bSuccess) { fprintf(stderr, "VirtualProtectEx() failed in ReadRemoteDataDirectoryRVA() with %d\n", GetLastError()); return 0; } bSuccess = ReadProcessMemory ( hProcess, lpImageBaseAddress, lpBuffer, BUFFER_SIZE, 0 ); if (!bSuccess) { fprintf(stderr, "ReadProcessMemory() failed in ReadRemoteDataDirectoryRVA() with %d\n", GetLastError()); return 0; } PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER)lpBuffer; if (pDOSHeader->e_magic != 0x5a4d) { fprintf(stderr, "Invalid DOS header. e_magic is not 0x5a4d\n"); return 0; } pNTHeaders = (PIMAGE_NT_HEADERS32)(lpBuffer + pDOSHeader->e_lfanew); if (pNTHeaders->OptionalHeader.Magic != 0x10b && // PE32 pNTHeaders->OptionalHeader.Magic != 0x20b) { // PE32+ fprintf(stderr, "Invalid Magic in OptionalHeader\n"); return NULL; } else printf("[i] Detected %s architecture\n", pNTHeaders->OptionalHeader.Magic == 0x10b ? "PE32" : "PE32+"); dataDir = &pNTHeaders->OptionalHeader.DataDirectory[index]; return dataDir; } // ============================================================================================= /* * Caller has to free the returned LOADED_IMAGE structure. */ PLOADED_IMAGE ReadRemoteImage(HANDLE hProcess, LPVOID lpImageBaseAddress) { PCHAR lpBuffer; PIMAGE_DOS_HEADER pDOSHeader; PLOADED_IMAGE pImage; BOOL bSuccess = RetReadProcessMemory ( &lpBuffer, hProcess, lpImageBaseAddress, BUFFER_SIZE ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory() failed in ReadRemoteImage() with %d\n", GetLastError()); return NULL; } pDOSHeader = (PIMAGE_DOS_HEADER)lpBuffer; pImage = malloc(sizeof(LOADED_IMAGE)); if (pImage == NULL) { fprintf(stderr, "malloc() failed in ReadRemoteImage() with %d\n", GetLastError()); return NULL; } pImage->FileHeader = (PIMAGE_NT_HEADERS32)(lpBuffer + pDOSHeader->e_lfanew); pImage->NumberOfSections = pImage->FileHeader->FileHeader.NumberOfSections; pImage->Sections = (PIMAGE_SECTION_HEADER)(lpBuffer + pDOSHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32)); if (pDOSHeader->e_magic != 0x5a4d) { fprintf(stderr, "Invalid DOS header. e_magic is not 0x5a4d\n"); return NULL; } if (pImage->FileHeader->OptionalHeader.Magic != 0x10b && // PE32 pImage->FileHeader->OptionalHeader.Magic != 0x20b) { // PE32+ fprintf(stderr, "Invalid Magic in OptionalHeader\n"); return NULL; } else printf("[i] Detected %s architecture\n", pImage->FileHeader->OptionalHeader.Magic == 0x10b ? "PE32" : "PE32+"); return pImage; } // ============================================================================================= PIMAGE_SECTION_HEADER FindSectionHeaderByName(PIMAGE_SECTION_HEADER pHeaders, DWORD dwNumberOfSections, LPCTSTR pSectionName) { PIMAGE_SECTION_HEADER pHeaderMatch = NULL; for (DWORD i = 0; i < dwNumberOfSections; i++) { PIMAGE_SECTION_HEADER pHeader = &pHeaders[i]; if (_stricmp((char*)pHeader->Name, pSectionName) == 0) { pHeaderMatch = pHeader; break; } } return pHeaderMatch; } /* * Finds a code cave in the .text section of the DLL. If this function is unable to * find a code cave at least minimalSize bytes long, it fails and so will the whole * hooking attempt. By failure, will return 0. */ DWORD FindRemoteCodeCave(HANDLE hProcess, LPVOID lpImageBaseAddress, LPCTSTR libName, SIZE_T minimalCodeCaveSize) { DWORD dwHandlerAddress; PLOADED_IMAGE pLoadedImage; PIMAGE_SECTION_HEADER pCodeSectionHeader; pLoadedImage = ReadRemoteImage ( hProcess, lpImageBaseAddress ); if (pLoadedImage == NULL) { fprintf(stderr, "ReadRemoteImage failed...\n"); return 0; } pCodeSectionHeader = FindSectionHeaderByName ( pLoadedImage->Sections, pLoadedImage->NumberOfSections, ".text" ); if (pCodeSectionHeader == NULL) { fprintf(stderr, "Couldn't locate the .text section. Maybe it's named differently\n"); return 0; } /* * Because there is a essential difference between PE Files in memory and on disk, * we might observe a phenomenon due to the different file alignment which comes handy * when we are in need to write our shell code to a process: */ dwHandlerAddress = (DWORD)lpImageBaseAddress + pCodeSectionHeader->VirtualAddress + pCodeSectionHeader->SizeOfRawData - minimalCodeCaveSize; return dwHandlerAddress; } // ============================================================================================= BOOL PrintImportDirectory(HANDLE hProcess, PIMAGE_DATA_DIRECTORY imageImportDirectory, DWORD imageBase) { PCHAR buf, dllNameBuf; PCHAR lpFunctionNameBuf; PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor; IMAGE_THUNK_DATA ThunkDataINT, ThunkDataIAT; PIMAGE_IMPORT_BY_NAME pImageImportByName; DWORD functionOffset, firstRVA, counter; firstRVA = 0; BOOL bSuccess = RetReadProcessMemory ( &buf, hProcess, (PVOID)(imageBase + imageImportDirectory->VirtualAddress), 50 * sizeof(IMAGE_IMPORT_DESCRIPTOR) // not more than 50 dll's in a module :) ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(buf) in PrintImportDirectory() failed with %d\n", GetLastError()); if (bSuccess != MEM_ALLOC_FAIL_CODE) free(&buf); return FALSE; } pImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)buf; /* pImageImportDescriptor[index].Characteristics is * set to 0 to indicate the end of the array of IMAGE_IMPORT_DESCRIPTORs. */ while (pImageImportDescriptor->Characteristics) { /* Read the memory of the DLLName:) */ bSuccess = RetReadProcessMemory ( &dllNameBuf, hProcess, (PVOID)(imageBase + pImageImportDescriptor->Name), BUFFER_SIZE_SMALL ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(dllNameBuf) in PrintImportDirectory() failed with %d\n", GetLastError()); if (bSuccess != MEM_ALLOC_FAIL_CODE) free(&dllNameBuf); return FALSE; } printf("\nDll \"%s\" found", (PCHAR)dllNameBuf); printf("\n\tOriginalFirstThunk is 0x%x", pImageImportDescriptor->OriginalFirstThunk); printf("\n\tFirstThunk is 0x%x", pImageImportDescriptor->FirstThunk); printf("\n\tTimeDateStamp is 0x%x", pImageImportDescriptor->TimeDateStamp); printf("\n\tForwarderChain is 0x%x", pImageImportDescriptor->ForwarderChain); free(&dllNameBuf); printf("\n\n\tFUNCTION-NAME : FUNCTION-ADDRESS : ADDRESS OF FUNCTION ADDRESS"); functionOffset = (imageBase + pImageImportDescriptor->FirstThunk); counter = 0; while (1) { /* Read the memory of the INT thunk table element :) */ bSuccess = ReadProcessMemory ( hProcess, (PVOID)(imageBase + pImageImportDescriptor->OriginalFirstThunk + counter*sizeof(PVOID)), &ThunkDataINT, sizeof(IMAGE_THUNK_DATA), NULL ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(lpThunkINTBuffer) in PrintImportDirectory() failed with %d\n", GetLastError()); return FALSE; } /* Read the memory of the IAT thunk table element :) */ bSuccess = ReadProcessMemory ( hProcess, (PVOID)(imageBase + pImageImportDescriptor->FirstThunk + counter*sizeof(PVOID)), &ThunkDataIAT, sizeof(IMAGE_THUNK_DATA), NULL ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(lpThunkINTBuffer) in PrintImportDirectory() failed with %d\n", GetLastError()); return FALSE; } /* Check if we reached the end of the array */ if (ThunkDataINT.u1.AddressOfData == 0 && ThunkDataIAT.u1.Function == 0) break; if (counter == 0) firstRVA = ThunkDataINT.u1.AddressOfData; /* * Huge problem here is that the RVA's pointing to the names of the function in the IAT * are not in a ascending order. The RVA's may even be broken (yeah the linkers are bad^^) * and we may get invalid indices. How can we figure out that we do have a valid RVA in * pThunkDataINT->u1.AddressOfData ?! * There are just bad solutions (or lazyness when it comes to * heuristic fine tuning, so we apply a heuristic function on all RVA's of the * IMAGE_THUNK_DATA INT array to ignore RVA's which have a absolute difference from * more than 0x5000 bytes to the first RVA. What happens if the first RVA is a invalid * one? We're screwed, but at least the other is able to locate the problem quickly. */ // test if we stumbled upon a suspicious RVA (after hoping that the first is not :/) if (abs(ThunkDataINT.u1.AddressOfData - firstRVA) > 0x5000) { fprintf(stderr, "\nRVA in INT->u1.AddressOfData might be broken (%x) - ignoring\n", ThunkDataINT.u1.AddressOfData); } else { bSuccess = RetReadProcessMemory ( &lpFunctionNameBuf, hProcess, (PVOID)(imageBase + ThunkDataINT.u1.AddressOfData), BUFFER_SIZE_SMALL ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(lpFunctionNameBuf) in HookFunction() failed with %d\n", GetLastError()); if (bSuccess != MEM_ALLOC_FAIL_CODE) free(&lpFunctionNameBuf); return FALSE; } pImageImportByName = (PIMAGE_IMPORT_BY_NAME)lpFunctionNameBuf; printf("\n\t%s: 0x%x : 0x%x", pImageImportByName->Name, ThunkDataIAT.u1.Function, functionOffset); } functionOffset += sizeof(PVOID); counter++; } printf("\n\n"); pImageImportDescriptor++; } /* We can free up now the allocated buffer */ free(&buf); return TRUE; } // ============================================================================================= /* * Looks up the function address in the IAT with LibName and funcName and * patches the pointer to the value in redirection. If the function succeeds, it will * return the OLD function pointer, so you can save it to restore the default behaviour. If * HookFunction fails, it will return FALSE(0). */ DWORD PatchIAT(HANDLE hProcess, PIMAGE_DATA_DIRECTORY imageImportDirectory, DWORD imageBase, LPCTSTR libName, LPCTSTR funcName, DWORD redirectionAddress) { PCHAR buf, dllNameBuf; PCHAR lpFunctionNameBuf; PIMAGE_IMPORT_DESCRIPTOR pImageImportDescriptor; IMAGE_THUNK_DATA ThunkDataINT, ThunkDataIAT; PIMAGE_IMPORT_BY_NAME pImageImportByName; DWORD functionOffset, firstRVA, counter, functionMemValue; firstRVA = 0; functionMemValue = 0; BOOL bSuccess = RetReadProcessMemory ( &buf, hProcess, (PVOID)(imageBase + imageImportDirectory->VirtualAddress), 50 * sizeof(IMAGE_IMPORT_DESCRIPTOR) // not more than 50 dll's in a module :) ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(buf) in PrintImportDirectory() failed with %d\n", GetLastError()); if (bSuccess != MEM_ALLOC_FAIL_CODE) free(&buf); return FALSE; } pImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)buf; /* * pImageImportDescriptor[index].Characteristics is * set to 0 to indicate the end of the array of IMAGE_IMPORT_DESCRIPTORs. */ while (pImageImportDescriptor->Characteristics) { /* Read the memory of the DLLName:) */ bSuccess = RetReadProcessMemory ( &dllNameBuf, hProcess, (PVOID)(imageBase + pImageImportDescriptor->Name), BUFFER_SIZE_SMALL ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(dllNameBuf) in PrintImportDirectory() failed with %d\n", GetLastError()); if (bSuccess != MEM_ALLOC_FAIL_CODE) free(&dllNameBuf); return FALSE; } functionOffset = (imageBase + pImageImportDescriptor->FirstThunk); counter = 0; while (1) { /* Read the memory of the INT thunk table element :) */ bSuccess = ReadProcessMemory ( hProcess, (PVOID)(imageBase + pImageImportDescriptor->OriginalFirstThunk + counter*sizeof(PVOID)), &ThunkDataINT, sizeof(IMAGE_THUNK_DATA), NULL ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(lpThunkINTBuffer) in PrintImportDirectory() failed with %d\n", GetLastError()); return FALSE; } /* Read the memory of the IAT thunk table element :) */ bSuccess = ReadProcessMemory ( hProcess, (PVOID)(imageBase + pImageImportDescriptor->FirstThunk + counter*sizeof(PVOID)), &ThunkDataIAT, sizeof(IMAGE_THUNK_DATA), NULL ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(lpThunkINTBuffer) in PrintImportDirectory() failed with %d\n", GetLastError()); return FALSE; } /* Check if we reached the end of the array */ if (ThunkDataINT.u1.AddressOfData == 0 && ThunkDataIAT.u1.Function == 0) break; if (counter == 0) firstRVA = ThunkDataINT.u1.AddressOfData; /* * Huge problem here is that the RVA's pointing to the names of the function in the IAT * are not in a ascending order. The RVA's may even be broken (yeah the linkers are bad^^) * and we may get invalid indices. How can we figure out that we do have a valid RVA in * pThunkDataINT->u1.AddressOfData ?! * There are just bad solutions (or lazyness when it comes to * heuristic fine tuning, so we apply a heuristic function on all RVA's of the * IMAGE_THUNK_DATA INT array to ignore RVA's which have a absolute difference from * more than 0x5000 bytes to the first RVA. What happens if the first RVA is a invalid * one? We're screwed, but at least the other is able to locate the problem quickly. */ // test if we stumbled upon a suspicious RVA (after hoping that the first is not :/) if (abs(ThunkDataINT.u1.AddressOfData - firstRVA) > 0x5000) { fprintf(stderr, "\nRVA in INT->u1.AddressOfData might be broken (%x) - ignoring\n", ThunkDataINT.u1.AddressOfData); } else { bSuccess = RetReadProcessMemory ( &lpFunctionNameBuf, hProcess, (PVOID)(imageBase + ThunkDataINT.u1.AddressOfData), BUFFER_SIZE_SMALL ); if (!bSuccess) { fprintf(stderr, "RetReadProcessMemory(lpFunctionNameBuf) in HookFunction() failed with %d\n", GetLastError()); if (bSuccess != MEM_ALLOC_FAIL_CODE) free(&lpFunctionNameBuf); return FALSE; } pImageImportByName = (PIMAGE_IMPORT_BY_NAME)lpFunctionNameBuf; /* When we are in the whished IAT entry, we write to the process the new value of the function pointer */ if ( _stricmp(pImageImportByName->Name, funcName) == 0 && _stricmp(dllNameBuf, libName) == 0 ) { functionMemValue = ThunkDataIAT.u1.Function; /* save because the struct will be freed up*/ bSuccess = RetWriteProcessMemory ( hProcess, (LPVOID)functionOffset, (LPCVOID)&redirectionAddress, (SIZE_T)sizeof(redirectionAddress) ); if (!bSuccess) { fprintf(stderr, "RetWriteProcessMemory() in HookFunction() failed with %d\n", GetLastError()); if (bSuccess != MEM_ALLOC_FAIL_CODE) free(&lpFunctionNameBuf); return FALSE; } else { fprintf(stdout, "[i] Patched the IAT API %s in DLL %s at address 0x%x :)\n", pImageImportByName->Name, dllNameBuf, functionOffset); break; /* break the while loop because we updated the IAT*/ } } } functionOffset += sizeof(PVOID); counter++; } /* have we just been to the searched DLL? Assumes that Dll-Names in the IAT are uniqe */ if (_stricmp(dllNameBuf, libName) == 0) { //free(&dllNameBuf); break; } pImageImportDescriptor++; } /* We can free up now the allocated buffer */ free(&buf); return functionMemValue; } // ============================================================================================= /* * Does the actual hooking. Finds a code cave in the .text section of the * DLL which exports the function specified by funcName. It writes the handler into * the code cave. The sanity of the handler is not a problem of this library. */ HOOK_CONTEXT * HookFunction(HANDLE hProcess, LPCTSTR libName, LPCTSTR funcName, PVOID handlerBuf, DWORD handlerSize) { DWORD pPEP, oldFunctionPointer, pHandler; SIZE_T nBytesWritten; PIMAGE_DATA_DIRECTORY imageImportDirectory; BOOL bSuccess; HOOK_CONTEXT *pHookContext; pHookContext = malloc(sizeof(HOOK_CONTEXT)); if (pHookContext == NULL) { fprintf(stderr, "malloc in HookFunction() failed\n"); return NULL; } /* Locate the Process Environment Block */ pPEP = FindRemotePEB(hProcess); if (pPEP == 0) { fprintf(stderr, "[!] FindRemotePEB() failed...\n"); return NULL; } else { printf("[i] Remote PEB found: 0x%x. ImageBase address is 0x%x\n", pPEP, (DWORD)((PPEB)pPEP)->ImageBaseAddress); } /* Read the RVA to the ImageImportDirectory */ imageImportDirectory = ReadRemoteDataDirectoryRVA(hProcess, (LPCVOID)((PPEB)pPEP)->ImageBaseAddress, 1); if (imageImportDirectory == 0) { fprintf(stderr, "[!] ReadRemoteDataDirectoryRV() failed...\n"); return NULL; } else { printf("[i] Remote Image Parsed. Virtual Address of RemoteDataDirectory: 0x%x\n", imageImportDirectory->VirtualAddress); } /* Find a code cave where to write the handler */ pHandler = FindRemoteCodeCave ( hProcess, ((PPEB)pPEP)->ImageBaseAddress, libName, handlerSize ); if (pHandler == 0) { fprintf(stderr, "[!] Cannot find code cave in remote image...\n"); return NULL; } else printf("[i] Code cave found.\n"); /* Write the shell code into the code cave :) */ bSuccess = WriteProcessMemory ( hProcess, (LPVOID)pHandler, (LPCVOID)handlerBuf, handlerSize, &nBytesWritten ); if (!bSuccess) { fprintf(stderr, "[!] Couldn't write shell code. Wrote %d bytes instead of %d...\n", nBytesWritten, handlerSize); return NULL; } else printf("[i] Handler written to address 0x%x!\n", pHandler); /* Patch the IAT with a pointer to the handler */ pHookContext->oldFuncPointer = PatchIAT ( hProcess, imageImportDirectory, (DWORD)((PPEB)pPEP)->ImageBaseAddress, libName, funcName, (DWORD)pHandler ); if (pHookContext->oldFuncPointer == 0) { fprintf(stderr, "[!] The specified API %s couldn't be located in the IAT\n", funcName); return NULL; } /* The hook should be sharp by now :) */ //pHookContext->pOldFuncPointer = return pHookContext; } BOOL ReleaseHook(HANDLE hProcess, HOOK_CONTEXT *pHookContext) { BOOL bSuccess; } /* * Caller has to pass a pointer. Caller has to free() then the mem allocated here * buf is a pointer to a pointer. Otherwise we loose the mem. This is C magic... :/ */ // ============================================================================================= BOOL RetReadProcessMemory(OUT PCHAR *buf, HANDLE hProcess, LPVOID lpBaseAddress, SIZE_T sizeBuf) { BOOL bSuccess; DWORD oldProtect, dummy; SIZE_T numBytesRead; *buf = calloc(sizeBuf, sizeof(CHAR)); if (buf == NULL) { fprintf(stderr, "calloc() in RetReadProcessMemory() failed with %d\n", GetLastError()); return 0x666; // Little hack here } bSuccess = VirtualProtectEx ( hProcess, lpBaseAddress, sizeBuf, PAGE_READONLY, &oldProtect ); if (!bSuccess) { fprintf(stderr, "VirtualProtectEx() in RetReadProcessMemory() failed with %d\n", GetLastError()); return FALSE; } /* Read finally the process memory */ bSuccess = ReadProcessMemory ( hProcess, lpBaseAddress, *buf, sizeBuf, &numBytesRead ); if (!bSuccess) { fprintf(stderr, "ReadProcessMemory() in RetReadProcessMemory() failed with %d\n", GetLastError()); return FALSE; } /* Restore old memory protection constants */ bSuccess = VirtualProtectEx ( hProcess, lpBaseAddress, sizeBuf, oldProtect, &dummy ); if (!bSuccess) { fprintf(stderr, "VirtualProtectEx(RESTORING) in RetReadProcessMemory() failed with %d\n", GetLastError()); return FALSE; } return TRUE; } // ============================================================================================= BOOL RetWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize) { BOOL bSuccess; DWORD oldProtect, dummy; SIZE_T numBytesWritten; bSuccess = VirtualProtectEx ( hProcess, lpBaseAddress, nSize, PAGE_READWRITE, &oldProtect ); if (!bSuccess) { fprintf(stderr, "VirtualProtectEx() in RetWriteProcessMemory() failed with %d\n", GetLastError()); return FALSE; } bSuccess = WriteProcessMemory ( hProcess, lpBaseAddress, lpBuffer, nSize, &numBytesWritten ); if (!bSuccess) { fprintf(stderr, "WriteProcessMemory in WriteProcessMemory() failed with %d\n", GetLastError()); return FALSE; } /* Restore old memory protection constants */ bSuccess = VirtualProtectEx ( hProcess, lpBaseAddress, nSize, oldProtect, &dummy ); if (!bSuccess) { fprintf(stderr, "VirtualProtectEx(RESTORING) in RetReadProcessMemory() failed with %d\n", GetLastError()); return FALSE; } return TRUE; }