Anatomy of IAT and EAT Hooking
Import Address Table (IAT) and Export Address Table (EAT) hooking are techniques used to modify the flow of execution in a Windows process. These methods are often employed by malware to intercept and alter API calls, though they also have legitimate uses in debugging, instrumentation, and security tools.
IAT Hooking:
- The Import Address Table is used by Windows processes to store the addresses of functions that are imported from external DLLs.
- IAT hooking involves modifying the function pointers in the IAT so that they point to a different function (often one that is malicious or used to monitor the function calls).
- This technique is applicable when you have access to the process memory, and it is usually done early during the process initialization when the imports are being resolved.
How Is Importing Done?
Import Address Table (IAT): When a program or DLL needs to use functions from an external DLL, it declares them in its Import Address Table (IAT). The IAT lists the functions the program will use and the DLLs that provide these functions.
Linking:
- Static Linking: Occurs during the linking stage of the application’s build process. The linker embeds information in the executable about which DLLs it needs and which functions it will use.
- Dynamic Linking: Occurs at runtime when the program is loaded. The Windows loader resolves the function addresses from the external DLLs and populates the IAT with the correct addresses.
LoadLibrary and GetProcAddress: Functions like LoadLibrary
and GetProcAddress
allow dynamic loading and importing of functions during runtime.
What Functions Are Imported?
An application imports functions it needs to use that are not part of its own codebase. For instance:
- From
kernel32.dll
: Commonly imported functions includeWriteFile
,ReadFile
,CreateFile
, etc. - From
user32.dll
: Functions likeMessageBox
,CreateWindow
,ShowWindow
. - From
gdi32.dll
: Functions likeCreateFont
,BitBlt
,SetPixel
.
The specific functions imported depend on what functionality the application requires.
Where Are Functions Imported From?
Functions are imported from the DLLs that export them. The Windows operating system maintains a standard set of DLLs that are always available (like kernel32.dll
, user32.dll
, etc.), and applications rely on these DLLs for core functionality.
EAT Hooking:
- The Export Address Table contains the addresses of functions that a DLL exports, allowing other modules to call these functions.
- EAT hooking modifies the function pointers in the EAT to point to a different address. This is more challenging than IAT hooking as it requires modifying the DLL itself or the process that loaded the DLL.
What is Function Exporting?
- Function exporting in the context of a DLL (Dynamic Link Library) like
kernel32.dll
refers to making specific functions available for other programs or modules to call. When a function is exported, it can be invoked by any other process that links to the DLL.
How Does
kernel32.dll
Export Functions?
- Export Address Table (EAT):
kernel32.dll
, like any other DLL, has an Export Address Table (EAT), which contains the addresses of the functions it exports. - Export by Name and Ordinal: Functions can be exported by name (e.g.,
WriteFile
) or by ordinal (a number that acts as an index into the EAT). Most functions are exported by name, but some might be exported by ordinal for efficiency. - PE (Portable Executable) Format: The export table is part of the PE file format of the DLL, specifically within the
.edata
section. This section contains metadata about exported functions, including their names, ordinals, and memory addresses.
What Functions Are Exported?
kernel32.dll
exports a wide range of essential system functions, such as:- File I/O Functions:
WriteFile
,ReadFile
,CreateFile
. - Memory Management:
VirtualAlloc
,VirtualFree
,HeapAlloc
. - Process and Thread Management:
CreateProcess
,CreateThread
,TerminateProcess
. - Synchronization:
EnterCriticalSection
,LeaveCriticalSection
,Sleep
. - The list of exported functions can be viewed using tools like Dependency Walker, CFF Explorer, or dumpbin.
Where Are Functions Exported From?
Functions are typically exported from specific sections within the DLL where they are defined and implemented. In kernel32.dll
, these functions are implemented in the source code of the DLL, compiled, and then made available for export through the EAT.
IAT Hooking Code Example
#include <windows.h>
#include <stdio.h>
// Function pointer typedef for the original WriteFile function
typedef BOOL (WINAPI *pWriteFile)(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
// Global variable to store the original WriteFile function address
pWriteFile OriginalWriteFile = NULL;
// Custom WriteFile function
BOOL WINAPI MyWriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
) {
// Custom logic: logging the call or modifying the buffer before writing
printf("Intercepted WriteFile call\n");
// Call the original WriteFile function
return OriginalWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
}
// Function to perform IAT hooking
void HookIAT() {
// Get the base address of the current module (EXE)
HMODULE hModule = GetModuleHandle(NULL);
if (hModule == NULL) {
printf("Failed to get module handle\n");
return;
}
// Get the address of the IMAGE_DOS_HEADER (the base of the PE file)
PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER)hModule;
// Get the address of the IMAGE_NT_HEADERS
PIMAGE_NT_HEADERS pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hModule + pDOSHeader->e_lfanew);
// Get the address of the IMAGE_IMPORT_DESCRIPTOR (the IAT)
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(
(BYTE*)hModule + pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
);
// Iterate through the import descriptors to find kernel32.dll
while (pImportDescriptor->Name) {
char* moduleName = (char*)((BYTE*)hModule + pImportDescriptor->Name);
if (_stricmp(moduleName, "kernel32.dll") == 0) {
// Found kernel32.dll, now locate the IAT for WriteFile
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((BYTE*)hModule + pImportDescriptor->FirstThunk);
while (pThunk->u1.Function) {
FARPROC* pFunction = (FARPROC*)&pThunk->u1.Function;
// Get the function name
if (*pFunction == (FARPROC)GetProcAddress(GetModuleHandle("kernel32.dll"), "WriteFile")) {
// Found WriteFile, save the original function address
OriginalWriteFile = (pWriteFile)*pFunction;
// Change memory protection to allow writing to the IAT
DWORD oldProtect;
VirtualProtect(pFunction, sizeof(FARPROC), PAGE_EXECUTE_READWRITE, &oldProtect);
// Replace the IAT entry with our custom function
*pFunction = (FARPROC)MyWriteFile;
// Restore the original protection
VirtualProtect(pFunction, sizeof(FARPROC), oldProtect, &oldProtect);
printf("IAT hooking successful\n");
return;
}
pThunk++;
}
}
pImportDescriptor++;
}
printf("Failed to find WriteFile in the IAT\n");
}
int main() {
// Perform the IAT hooking
HookIAT();
// Test the hook by calling WriteFile
HANDLE hFile = CreateFile("test.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
DWORD written;
const char* data = "Hello, world!";
WriteFile(hFile, data, strlen(data), &written, NULL);
CloseHandle(hFile);
}
return 0;
}
EAT Hooking Code Example
#include <windows.h>
#include <stdio.h>
// Function pointer typedef for the original WriteFile function
typedef BOOL (WINAPI *pWriteFile)(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
// Global variable to store the original WriteFile function address
pWriteFile OriginalWriteFile = NULL;
// Custom WriteFile function
BOOL WINAPI MyWriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
) {
// Custom logic: logging the call or modifying the buffer before writing
printf("Intercepted WriteFile call\n");
// Call the original WriteFile function
return OriginalWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
}
// Function to perform EAT hooking
void HookEAT() {
// Get the base address of kernel32.dll
HMODULE hModule = GetModuleHandle("kernel32.dll");
if (hModule == NULL) {
printf("Failed to get module handle for kernel32.dll\n");
return;
}
// Get the address of the IMAGE_DOS_HEADER (the base of the PE file)
PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER)hModule;
// Get the address of the IMAGE_NT_HEADERS
PIMAGE_NT_HEADERS pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hModule + pDOSHeader->e_lfanew);
// Get the address of the IMAGE_EXPORT_DIRECTORY (the EAT)
PIMAGE_EXPORT_DIRECTORY pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(
(BYTE*)hModule + pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
);
// Get the list of function names and addresses
DWORD* pNames = (DWORD*)((BYTE*)hModule + pExportDirectory->AddressOfNames);
DWORD* pFunctions = (DWORD*)((BYTE*)hModule + pExportDirectory->AddressOfFunctions);
WORD* pOrdinals = (WORD*)((BYTE*)hModule + pExportDirectory->AddressOfNameOrdinals);
// Iterate through the function names to find WriteFile
for (DWORD i = 0; i < pExportDirectory->NumberOfNames; i++) {
char* functionName = (char*)((BYTE*)hModule + pNames[i]);
if (strcmp(functionName, "WriteFile") == 0) {
// Found WriteFile, now get the function's address
DWORD functionRVA = pFunctions[pOrdinals[i]];
OriginalWriteFile = (pWriteFile)((BYTE*)hModule + functionRVA);
// Modify the EAT to point to our custom function
DWORD oldProtect;
VirtualProtect(&pFunctions[pOrdinals[i]], sizeof(DWORD), PAGE_EXECUTE_READWRITE, &oldProtect);
pFunctions[pOrdinals[i]] = (DWORD)((BYTE*)MyWriteFile - (BYTE*)hModule);
VirtualProtect(&pFunctions[pOrdinals[i]], sizeof(DWORD), oldProtect, &oldProtect);
printf("EAT hooking successful\n");
return;
}
}
printf("Failed to find WriteFile in the EAT\n");
}
int main() {
// Perform the EAT hooking
HookEAT();
// Test the hook by calling WriteFile
HANDLE hFile = CreateFile("test.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
DWORD written;
const char* data = "Hello, world!";
WriteFile(hFile, data, strlen(data), &written, NULL);
CloseHandle(hFile);
}
return 0;
}
Explanation of the Code:
pWriteFile
Type Definition: This defines the function pointer typepWriteFile
that matches the signature of theWriteFile
function. This allows us to store the address of the originalWriteFile
function.OriginalWriteFile
Global Variable: This variable will hold the address of the originalWriteFile
function after we hook it.MyWriteFile
Custom Function: This is our custom implementation ofWriteFile
. It will be called instead of the originalWriteFile
function. You can log, modify, or intercept the data before passing it to the original function.HookIAT
Function:
- Get the Base Address of the Module: The
GetModuleHandle(NULL)
function retrieves the base address of the current module (the executable). - Locate the IMAGE_DOS_HEADER: This is the start of the PE (Portable Executable) file.
- Locate the IMAGE_NT_HEADERS: This structure contains the PE header.
- Locate the Import Directory: The
IMAGE_IMPORT_DESCRIPTOR
structure contains information about the DLLs that the executable imports. - Iterate Through the Import Descriptors: The code loops through the import descriptors to find
kernel32.dll
. - Find the WriteFile Function: The code then iterates through the import address table (IAT) to find the entry for
WriteFile
. - Hook the Function: If
WriteFile
is found, its address is saved inOriginalWriteFile
, and the IAT entry is modified to point toMyWriteFile
. - Memory Protection:
VirtualProtect
is used to change the memory protection of the IAT so that it can be modified, and then it is restored to its original protection.
5. main
Function:
- The
HookIAT
function is called to apply the hook. - The
WriteFile
function is then called, which will now executeMyWriteFile
instead of the originalWriteFile
.
#IAT #EAT #Hooking #ReverseEngineering