逆向 | IAT Hook

通过修改IAT来hook。

注意点:由于IAT不一定是连续的,因此有时候会要先定位那个模块,再找对应的IAT表。

主要测试代码如下:

1.dll(用于注入的dll):

// 1.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"


DWORD g_dwOldAddr;         // 原始函数地址
DWORD g_dwNewAddr;         // Hook函数地址
DWORD g_dwIATHookFlag;     // 标志有没有被hook

BOOL SetIATHook(DWORD dwOldAddr, DWORD dwNewAddr){
	BOOL bFlag = FALSE;
	DWORD dwImageBase = 0;
	PDWORD pFuncAddr = NULL;
	PIMAGE_NT_HEADERS pNtHeader = NULL;
	PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL;
	DWORD dwOldProtect = 0;

	// 得到exe模块基址
	dwImageBase = (DWORD)GetModuleHandle(NULL);
	pNtHeader = (PIMAGE_NT_HEADERS)(dwImageBase + ((PIMAGE_DOS_HEADER)dwImageBase)->e_lfanew);
	pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase + 
		pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
	
	// 遍历IAT表 找到这个函数的地址
	while (pImportDescriptor->FirstThunk != 0 && bFlag == FALSE)
	{
		pFuncAddr = (PDWORD)(dwImageBase + pImportDescriptor->FirstThunk);
		while (*pFuncAddr) // 遍历该模块中的函数
		{
			if(dwOldAddr == *pFuncAddr){
				// 找到要Hook的函数,先修改内存页的属性
				VirtualProtect(pFuncAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
				*pFuncAddr = dwNewAddr;   // !!!更改过IAT中函数的地址
				VirtualProtect(pFuncAddr, sizeof(DWORD), dwOldProtect, 0);
				bFlag = TRUE;
				break;
			}
			pFuncAddr ++;
		}
		pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportDescriptor+sizeof(IMAGE_IMPORT_DESCRIPTOR));   // 这里之前搞错了,现在更正一下
	}
	// 修改状态
	g_dwOldAddr = dwOldAddr;
	g_dwNewAddr = dwNewAddr;
	g_dwIATHookFlag = 1;
	return bFlag;
}        

BOOL UnIATHook(){
	BOOL bFlag = FALSE;
	DWORD dwImageBase = 0;
	PDWORD pFuncAddr = NULL;
	PIMAGE_NT_HEADERS pNtHeader = NULL;
	PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL;
	DWORD dwOldProtect = 0;

	// 判断是否hook
	if (!g_dwIATHookFlag)
	{
		OutputDebugString("UnIATHook失败:尚未进行IAT Hook!");
		return bFlag;
	}
	
	// 得到exe模块基址
	dwImageBase = (DWORD)GetModuleHandle(NULL);
	pNtHeader = (PIMAGE_NT_HEADERS)(dwImageBase + ((PIMAGE_DOS_HEADER)dwImageBase)->e_lfanew);
	pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(dwImageBase + 
		pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
	
	// 遍历IAT表 找到这个函数的地址
	while (pImportDescriptor->FirstThunk != 0 && bFlag == FALSE)
	{
		pFuncAddr = (PDWORD)(dwImageBase + pImportDescriptor->FirstThunk);
		while (*pFuncAddr) // 遍历该模块中的函数
		{
			if(g_dwNewAddr == *pFuncAddr){
				// 找到要Hook的函数,先修改内存页的属性
				VirtualProtect(pFuncAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
				*pFuncAddr = g_dwOldAddr;   // !!!更改过IAT中函数的地址
				VirtualProtect(pFuncAddr, sizeof(DWORD), dwOldProtect, 0);
				bFlag = TRUE;
				break;
			}
			pFuncAddr ++;
		}
		pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportDescriptor+sizeof(PIMAGE_IMPORT_DESCRIPTOR));
	}
	// 修改状态
	g_dwOldAddr = 0;
	g_dwNewAddr = 0;
	g_dwIATHookFlag = 1;
	return bFlag;
}       


int WINAPI MyMessageBox(HWND hWnd, LPCSTR lpText,LPCSTR lpCaption, UINT uType){
	char lpNewText[] = "你被hook了";
	// 定义MessageBox函数指针
	typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCSTR, LPCSTR, UINT);

	// 执行真正的函数
	int ret = ((PFNMESSAGEBOX)g_dwOldAddr)(hWnd, lpNewText, lpCaption, uType);
	return ret;
}




// 线程函数
DWORD WINAPI ThreadProc(LPVOID lpParameter){
	// 保存原始函数地址
	DWORD pOldFuncAddr = (DWORD)GetProcAddress(LoadLibrary("user32.dll"), "MessageBoxA");
	// 安装或者卸载HOOK
	if (!g_dwIATHookFlag){
		SetIATHook(pOldFuncAddr, (DWORD)MyMessageBox);
	}else{
		UnIATHook();
	}
	return 0;
}




BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	switch ( ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CreateThread(NULL,0,
            (LPTHREAD_START_ROUTINE)ThreadProc,
            NULL, 0,NULL);//创建新线程执行代码
        break;
    case DLL_PROCESS_DETACH:
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
	}
    return TRUE;
}

injection.cpp(运行来注入dll的程序):

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

DWORD GetPid(char* szName){
    HANDLE hprocessSnap = NULL;
    PROCESSENTRY32 pe32 = {0};
    hprocessSnap = CreateToolhelp32Snapshot(
        TH32CS_SNAPPROCESS,
        0);//捕捉所有进程的快照
    if (hprocessSnap == INVALID_HANDLE_VALUE){
        //快照失败
        return 0;
    }
    //初始化pe32结构体
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (Process32First(hprocessSnap, &pe32)){
        do{
            if (!strcmp(szName, pe32.szExeFile)){
                printf("Process Found, PID: %d 
", (int)pe32.th32ProcessID);
                return (int)pe32.th32ProcessID;
            }
            //遍历查找进程名
        }while (Process32Next(hprocessSnap, &pe32));
    }else{
        CloseHandle(hprocessSnap);
    }
    return 0;
}



//远程线程注入
BOOL load_dll(DWORD dwProcessID, char* szDllPathName)
//进程PID和dll完整的路径
{
    BOOL bRet;
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwLength;
    DWORD dwLoadAddr;
    LPVOID lpAllocAddr;
    DWORD dwThreadID;
    HMODULE hModule;
    //获取进程句柄
    hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessID);
    printf("%x 
", hProcess);
    if (hProcess == NULL)
    {
        OutputDebugString("fail to open process 
");
        return FALSE;
    }
    //把DLL文件路径字符串存入被注入进程的内存空间
    //计算dll路径名字长度,并且加上结尾0的空间
    dwLength = strlen(szDllPathName)+1;
    //远程申请内存空间
    lpAllocAddr = (LPVOID)VirtualAllocEx(hProcess,NULL,dwLength,MEM_COMMIT,PAGE_READWRITE);
    if (lpAllocAddr == NULL){
        OutputDebugString("VirtualAllocEx error 
");
        CloseHandle(hProcess);
        return FALSE;
    }
    //拷贝dll路径名字到目标进程的内存
    bRet = WriteProcessMemory(hProcess, lpAllocAddr,szDllPathName,dwLength,NULL);
    if (bRet == NULL){
        OutputDebugString("bRet error 
");
        CloseHandle(hProcess);
        return FALSE;
    }
    //获取kernel32.dll的地址
    hModule = GetModuleHandle("Kernel32.dll");
    if (!hModule)
    {
        OutputDebugString("GetModuleHandle error 
");
        CloseHandle(hProcess);
        return FALSE;
    }
    //获取LoadLibraryA函数地址
    dwLoadAddr = (DWORD)GetProcAddress(hModule, "LoadLibraryA");
    if (!dwLoadAddr )
    {
        OutputDebugString("GetProcAddress error 
");
        CloseHandle(hProcess);
        CloseHandle(hModule);
        return FALSE;
    }
	
    //创建远程线程,加载dll
    hThread = CreateRemoteThread(hProcess, NULL, 0, (unsigned long (__stdcall *)(void *))dwLoadAddr, lpAllocAddr, 0, NULL);
    printf("%x 
", hThread);
    if (hThread == NULL)
    {
        OutputDebugString("fail to open RomoteThread 
");
        CloseHandle(hProcess);
        return FALSE;
    }
    CloseHandle(hProcess);
	
    return TRUE;
}
void main(){
	load_dll(GetPid("1.exe"), "C:\Users\thinkpad\Desktop\IATHook\dll\1\Debug\1.dll");
}

被注入的程序:

#include <windows.h>

int main(){
	while (1){
		MessageBox(0,0,0,0);
		Sleep(1000);
	}
	return 0;
}

经过测试可以成功hookMessageBoxA这样一个函数。
但是有些细节做的不是很好,有空改进一下。

本文来自博客园,作者:Mz1,转载请注明原文链接:https://www.cnblogs.com/Mz1-rc/p/15308779.html

如果有问题可以在下方评论或者email:mzi_mzi@163.com

原文地址:https://www.cnblogs.com/Mz1-rc/p/15308779.html