IAT hook

在进程加载进内存后,找到IAT表的位置,然后将目标函数替换为自定义函数,并且参数需要完全一致

代码

使用看雪的教学代码

#include <windows.h>
#include <stdio.h>
#include <imagehlp.h>
#pragma comment(lib,"imagehlp.lib")


//以MessageBoxA的原型定义一个函数指针类型
typedef int
(WINAPI* PFN_MessageBoxA)(
    HWND hWnd,          // handle of owner window
    LPCSTR lpText,     // address of text in message box
    LPCSTR lpCaption,  // address of title of message box
    UINT uType          // style of message box
    );

//以MessageBoxA的原型定义一个函数来替代原始的MessageBoxA
int WINAPI My_MessageBoxA(
    HWND hWnd,          // handle of owner window
    LPCSTR lpText,     // address of text in message box
    LPCSTR lpCaption,  // address of title of message box
    UINT uType          // style of message box
);
//保存原始MessageBoxA的地址
PFN_MessageBoxA OldMessageBox = NULL;
//指向IAT中pThunk的地址
PULONG_PTR g_PointerToIATThunk = NULL;

BOOL InstallModuleIATHook(
    HMODULE hModToHook,// IN
    const char* szModuleName,// IN
    const char* szFuncName,// IN
    PVOID DetourFunc,// IN
    PULONG_PTR* pThunkPointer,//OUT
    ULONG_PTR* pOriginalFuncAddr//OUT
)
{
    PIMAGE_IMPORT_DESCRIPTOR  pImportDescriptor;
    PIMAGE_THUNK_DATA         pThunkData;
    ULONG ulSize;
    HMODULE hModule = 0;
    ULONG_PTR TargetFunAddr;
    PULONG_PTR lpAddr;
    char* szModName;
    BOOL result = FALSE;
    BOOL bRetn = FALSE;

    // 获取目标模块地址
    hModule = LoadLibraryA(szModuleName);
    TargetFunAddr = (ULONG_PTR)GetProcAddress(hModule, szFuncName);
    printf("[*]Address of %s:0x%p\n", szFuncName, TargetFunAddr);
    printf("[*]Module To Hook at Base:0x%p\n", hModToHook);
    // 获取IAT地址
    pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModToHook, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);;
    printf("[*]Find ImportTable,Address:0x%p\n", pImportDescriptor);
    while (pImportDescriptor->FirstThunk)
    {
    	szModName = (char*)((PBYTE)hModToHook + pImportDescriptor->Name);
    	printf("[*]Cur Module Name:%s\n", szModName);
    	if (_stricmp(szModName, szModuleName) != 0)
    	{
    		printf("[*]Module Name does not match, search next...\n");
    		pImportDescriptor++;
    		continue;
    	}
    	//程序的导入表处理完毕后OriginalFirstThunk可能是无效的,不能再根据名称来查找,而是遍历FirstThunk直接根据地址判断
    	pThunkData = (PIMAGE_THUNK_DATA)((BYTE*)hModToHook + pImportDescriptor->FirstThunk);
    	while (pThunkData->u1.Function)
    	{
    		lpAddr = (ULONG_PTR*)pThunkData;
    		//找到了地址
    		if ((*lpAddr) == TargetFunAddr)
    		{
    			printf("[*]Find target address!\n");
    			//通常情况下导入表所在内存页都是只读的,因此需要先修改内存页的属性为可写
    			DWORD dwOldProtect;
    			MEMORY_BASIC_INFORMATION  mbi;
    			VirtualQuery(lpAddr, &mbi, sizeof(mbi));
    			bRetn = VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);
    			if (bRetn)
    			{
    				//内存页属性修改成功,继续下一步操作,先保存原始数据
    				if (pThunkPointer != NULL)
    				{
    					*pThunkPointer = lpAddr;
    				}
    				if (pOriginalFuncAddr != NULL)
    				{
    					*pOriginalFuncAddr = *lpAddr;
    				}
    				//修改地址
    				*lpAddr = (ULONG_PTR)DetourFunc;
    				result = TRUE;
    				//恢复内存页的属性
    				VirtualProtect(mbi.BaseAddress, mbi.RegionSize, dwOldProtect, 0);
    				printf("[*]Hook ok.\n");
    			}

    			break;
    		}
    		//---------
    		pThunkData++;
    	}
    	pImportDescriptor++;
    }

    FreeLibrary(hModule);
    return result;
}
BOOL IAT_InstallHook()
{
    BOOL bResult = FALSE;
    HMODULE hCurExe = GetModuleHandle(NULL);
    PULONG_PTR pt;
    ULONG_PTR OrginalAddr;
    bResult = InstallModuleIATHook(hCurExe, "user32.dll", "MessageBoxA", (PVOID)My_MessageBoxA, &pt, &OrginalAddr);
    if (bResult)
    {
    	printf("[*]Hook安装完毕! pThunk=0x%p  OriginalAddr = 0x%p\n", pt, OrginalAddr);
    	g_PointerToIATThunk = pt;
    	OldMessageBox = (PFN_MessageBoxA)OrginalAddr;
    }
    return bResult;

}
VOID ShowMsgBox(const char* szMsg)
{
    MessageBoxA(NULL, szMsg, "Test", MB_OK);
}


int WINAPI My_MessageBoxA(
    HWND hWnd,          // handle of owner window
    LPCSTR lpText,     // address of text in message box
    LPCSTR lpCaption,  // address of title of message box
    UINT uType          // style of message box
)
{
    //在这里,你可以对原始参数进行任意操作
    int ret;
    char newText[1024] = { 0 };
    char newCaption[256] = "pediy.com";
    printf("有人调用MessageBox!\n");
    //在调用原函数之前,可以对IN(输入类)参数进行干涉
    lstrcpyA(newText, lpText);//为防止原函数提供的缓冲区不够,这里复制到我们自己的一个缓冲区中再进行操作
    lstrcatA(newText, "\n\tMessageBox Hacked by pediy.com!");//篡改消息框内容
    uType |= MB_ICONERROR;//增加一个错误图标
    ret = OldMessageBox(hWnd, newText, newCaption, uType);//调用原MessageBox,并保存返回值
    //调用原函数之后,可以继续对OUT(输出类)参数进行干涉,比如网络函数的recv,可以干涉返回的内容
    return ret;//这里你还可以干涉原始函数的返回值

}

VOID IAT_UnInstallHook()
{

    DWORD dwOLD;
    MEMORY_BASIC_INFORMATION  mbi;
    if (g_PointerToIATThunk)
    {
    	//查询并修改内存页的属性
    	VirtualQuery((LPCVOID)g_PointerToIATThunk, &mbi, sizeof(mbi));
    	VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOLD);
    	//将原始的MessageBoxA地址填入IAT中
    	*g_PointerToIATThunk = (ULONG)OldMessageBox;
    	//恢复内存页的属性
    	VirtualProtect(mbi.BaseAddress, mbi.RegionSize, dwOLD, 0);
    }

}


typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

LPFN_ISWOW64PROCESS fnIsWow64Process;

BOOL IsWow64()
{
    BOOL bIsWow64 = FALSE;

    fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
    	GetModuleHandle(TEXT("kernel32")), "IsWow64Process");

    if (NULL != fnIsWow64Process)
    {
    	if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
    	{
    		// handle error
    	}
    }
    return bIsWow64;
}


int main(int argc, char* argv[])
{
    BOOL bIsWow64 = IsWow64();
    printf("IsWow64 = %d\n", bIsWow64);
    ShowMsgBox("Before IAT Hook");
    IAT_InstallHook();
    ShowMsgBox("After  IAT Hook");
    IAT_UnInstallHook();
    ShowMsgBox("After  IAT Hook UnHooked");
    return 0;
}

参考

https://www.ired.team/offensive-security/code-injection-process-injection/import-adress-table-iat-hooking

https://cougar.kim/posts/iat_hook/