~$: Introduction
API hooking is a technique used to monitor process in Windows. Antivirus either EDR can employ this technique to monitor process by intercepting and modifying the behavior of Windows API functions.
The installation of hook consist of two main parts - Hook handler - Trampoline
When the API function is invoked the hook redirects the call to the hook handler. The hook handler can then perform various actions such as logging the call, modifying parameters, blocking the call. After the hook handler the trampoline redirects control back to the original API function
~$: IAT Hooking
In this example i want to show you how can we inject a dll into a target process and install a hook in the MessageBox function.
This is a simple program that we'll use as our target
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "user32.lib")
int main()
{
printf("[+] Process test to hook started...\n[+] Waiting for injection of DLL with hooks\n");
getchar();
MessageBox(NULL, "First Message", "Title", MB_OK);
return 0;
}
Our purpose here is to inject our malicious dll that contains the hook handler and the trampoline for the MessageBox API. Our hook, once installed, simple notify us through a log when the MessageBox API will be called.
Now our dll will look like this:
#include <windows.h>
#include <stdio.h>
#include "..\shared\structure.h"
#include "..\shared\peb-walk.h"
#pragma comment(lib, "user32.lib")
// Pointer to the orginal MessageBox function
int(WINAPI *pOrigMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) = MessageBox;
// Pointer to SetProcessValidCallTargets_t to register our function in CFG
typedef VOID(WINAPI *SetProcessValidCallTargets_t)(HANDLE, PVOID, SIZE_T, ULONG, PCFG_CALL_TARGET_INFO);
// Custom hooked function
int WINAPI HookedMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
MessageBeep(0);
printf("[i] HookedTest() called.\n");
printf("[i] HookedTest() Simple message from hooked function.\n");
int ret = pOrigMessageBox(hWnd, lpText, lpCaption, uType);
return ret;
}
// Set a hook function to a specific dll function
BOOL Hookem(char *funcName, PROC hookingFunc)
{
printf("[+] Hooking in progress...\n");
//--- Get base address of current dll ---
PVOID baseAddress = GetBaseFormPeb(NULL);
printf("[+] Base address: %p\n", baseAddress);
//--- Get address of function that be hooked ---
PROC *funcAddress = (PROC *)GetFunctionFromImportAddressTable(baseAddress, funcName);
if (funcAddress == NULL)
{
printf("[-] Function not found in IAT!\n");
return FALSE;
}
printf("[+] IAT entry address: %p\n", funcAddress);
//--- Make sure memory is writable ----
DWORD oldProtect = 0;
VirtualProtect((LPVOID)funcAddress, sizeof(PVOID), PAGE_READWRITE, &oldProtect);
//--- Set the hook ----
*funcAddress = (PROC)HookedMessageBox;
//--- Restore the old memory protection ---
VirtualProtect((LPVOID)funcAddress, sizeof(PVOID), oldProtect, &oldProtect);
printf("[+] Hook setted correctly\n");
return TRUE;
}
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
Hookem("MessageBoxA", (PROC)HookedMessageBox);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
Let's break it down into sections
This is the the main function of an dll. When the process will be attached DLL_PROCESS_ATTACH we'll call the Hookem function with two parameters
- MessageBoxA: Is the name of the original function that we want hook
- (PROC)HookedMessageBox: Our custom hook function
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
Hookem("MessageBoxA", (PROC)HookedMessageBox);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
First examinate the HookedMessageBox function. Here we have a pointer function that points to the original API pOrigMessageBox and the sign of our HookedMessageBox have the same parameter of MessageBox API this because we'll be pass in the function pointer int ret = pOrigMessageBox(hWnd, lpText, lpCaption, uType);.
First of call the original function we use printf to log something and to test if our hook work properly.
// Pointer to the orginal MessageBox function
int(WINAPI *pOrigMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) = MessageBox;
// Custom hooked function
int WINAPI HookedMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
printf("[i] HookedTest() called.\n");
printf("[i] HookedTest() Simple message from hooked function.\n");
int ret = pOrigMessageBox(hWnd, lpText, lpCaption, uType);
return ret;
}
Now taking a look of the Hookem function
// Set a hook function to a specific dll function
BOOL Hookem(char *funcName, PROC hookingFunc)
{
printf("[+] Hooking in progress...\n");
//--- Get base address of current dll ---
PVOID baseAddress = GetBaseFormPeb(NULL);
printf("[+] Base address: %p\n", baseAddress);
//--- Get address of function that be hooked ---
PROC *funcAddress = (PROC *)GetFunctionFromImportAddressTable(baseAddress, funcName);
if (funcAddress == NULL)
{
printf("[-] Function not found in IAT!\n");
return FALSE;
}
printf("[+] IAT entry address: %p\n", funcAddress);
//--- Make sure memory is writable ----
DWORD oldProtect = 0;
VirtualProtect((LPVOID)funcAddress, sizeof(PVOID), PAGE_READWRITE, &oldProtect);
//--- Set the hook ----
*funcAddress = (PROC)HookedMessageBox;
//--- Restore the old memory protection ---
VirtualProtect((LPVOID)funcAddress, sizeof(PVOID), oldProtect, &oldProtect);
printf("[+] Hook setted correctly\n");
return TRUE;
}
First of all we need to the baseAddress of the current dll. In this case i use my custom function GetBaseFormPeb, you can find the full code on my github. Once we have the base address of our dll we can retrieve the address of target function (in our case is the MessageBox) i use my custom function GetFunctionFromImportAddressTable that use PEB Walking and Dancing with IAT to achieve the address of the target function.
Dissected PE by abhisek
Since now we have a function address we can modify the address to have it points to our HookedMessageBox function. But first we need to make sure that the memory of our target function is writable, for simplicity's sake I used VirtualProtect API, when the memory is writable we can change the address of the target function with our hook function and restore the memory protection.
//--- Set the hook ----
*funcAddress = (PROC)HookedMessageBox;
//--- Restore the old memory protection ---
VirtualProtect((LPVOID)funcAddress, sizeof(PVOID), oldProtect,
Perfect now we have installed our hooks.
Testing
TODO: Complete this section
~$: In line Patching
TODO: Complete this section
Testing
TODO: Complete this section