在Windows上实现远程IAT hook

一、概述

IAT hook,就是我们要hook的目标函数在导入表IT中,通过修改目标函数所在IAT中项的地址为我们自定义函数的地址,从而实现函数hook。

在这里我们要hook的目标是一个远程进程,采用之前博客《Windows上的进程注入》一文中用到的反射式dll注入这一技术,在其中添加额外的IAT hook代码来实现hook。

二、远程进程 IAT hook 原理

hook的步骤:

  1. 将dll文件注入到目标进程中并完成加载;
  2. 在DllMain函数中调用hook处理函数;
  3. 遍历导入表寻找目标函数所在IAT中的位置;
  4. 保存原目标函数地址;
  5. 修改对应IAT中的项,将存储的地址修改为我们定义的函数。

我们可以通过调用GetModuleHandle(NULL)来获取该进程的映像基址,这样我们就可以访问该映像的PE头了,其中可选头就有我们需要的导入表描述符的地址信息。经过几次的成员访问,指针跳转(内容有点啰嗦,就略过了。不懂的同学可以参考PE头相关内容),找到导入表第一个dll成员描述符的地址。每一个dll成员描述符(IMAGE_IMPORT_DESCRIPTOR结构体)都有两个数组OriginalFirstThunk和FirstThunk,它们分别指向该dll的INT(导入名称表)和IAT(导入地址表)。IMAGE_IMPORT_DESCRIPTOR结构体如下:

复制代码
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD Characteristics;
        DWORD OriginalFirstThunk;     //该项指向INT
    };
    DWORD TimeDateStamp;               //时间戳
    DWORD ForwarderChain;          //指向前一个IMAGE_IMPORT_DESCRIPTOR
    DWORD Name;                                //dll的名字
    DWORD FirstThunk;                        //该项指向IAT
} IMAGE_IMPORT_DESCRIPTOR;
复制代码

INT和IAT的类型皆为_IMAGE_THUNK_DATA32,如下:

typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        //RVA 指向_IMAGE_IMPORT_BY_NAME 
    } u1;
} IMAGE_THUNK_DATA32;

它们每一项都按照顺序还是一一对应的。我们通过比较INT中对应项记录的函数名判断其是否为我们的目标函数,若是则修改对应IAT中的项记录的函数地址,并保存一份原始数据。

 

 

因为IAT所在的内存空间默认是不可写的,所以我们还需要修改一下权限,通过使用VirtualProtect函数添加一个写入权限即可。为了进程安全和稳定,完事后记得改回来。

最好,我们编写一个自定义的函数用于替换目标函数,这里我选取了MessageBoxA函数为目标。

int hook_MessageBoxA(HWND   hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT   uType) {
    char lpTextBak[100] = "Successfuly Hooked!";
    MESSAGEBOXA originalMessageBoxA = (MESSAGEBOXA)savedAddress;
    return originalMessageBoxA(hWnd, lpTextBak, lpCaption, uType);
}

三、代码实现

IAT hook 代码如下:

复制代码
void hookIATFunctionByName(char  *functionName, ULONG_PTR hookAddress) {

    ULONG_PTR pBaseAddress;
    ULONG_PTR pFuncAddress;
    ULONG_PTR pNameArray;
    ULONG_PTR pExportDir;
    ULONG_PTR pNameOrdinals;

    DWORD dwCounter = 0;

    savedAddress = 0;

    pBaseAddress = (ULONG_PTR)GetModuleHandle(NULL);
    ULONG_PTR pTmp1 = pBaseAddress + ((PIMAGE_DOS_HEADER)pBaseAddress)->e_lfanew;
    ULONG_PTR pTmp2 = (ULONG_PTR)&((PIMAGE_NT_HEADERS)pTmp1)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    // pTmp3 = 导入表第一个dll成员描述符的地址
    ULONG_PTR pTmp3 = (pBaseAddress + ((PIMAGE_DATA_DIRECTORY)pTmp2)->VirtualAddress);
    ULONG_PTR pTmp4 = 0;

    //遍历所有dll的导入表    
    while ( ((PIMAGE_IMPORT_DESCRIPTOR)pTmp3)->Name )
    {
        // pTmp4 = VA of the OriginalFirstThunk------  INT
        pTmp4 = (pBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)pTmp3)->OriginalFirstThunk);
        // pTmp1 = VA of the IAT (via first thunk not origionalfirstthunk)
        pTmp1 = (pBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)pTmp3)->FirstThunk);

        while (DEREF(pTmp4))
        {
            pTmp2 = (pBaseAddress + DEREF(pTmp4));
            if (strcmp((char*)((PIMAGE_IMPORT_BY_NAME)pTmp2)->Name, functionName) == 0) {
                MEMORY_BASIC_INFORMATION  mbi;
                DWORD dwOldProtect;
                VirtualQuery(pTmp1, &mbi, sizeof(mbi));
                BOOL bRetn = VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);
                if (bRetn) {
                    savedAddress = DEREF(pTmp1);
                    DEREF(pTmp1) = (ULONG_PTR)hookAddress;
                    VirtualProtect(mbi.BaseAddress, mbi.RegionSize, dwOldProtect, 0);
                }
                dwCounter = 1;
                break;
            }
            
            pTmp1 += sizeof(ULONG_PTR);
            if (pTmp4)
                pTmp4 += sizeof(ULONG_PTR);
        }

        if (dwCounter == 1)
            break;

        pTmp3 += sizeof(IMAGE_IMPORT_DESCRIPTOR);
    }
}
复制代码

关于DllMain函数的代码如下:

复制代码
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )
{
    BOOL bReturnValue = TRUE;
    switch( dwReason ) 
    { 
        case DLL_QUERY_HMODULE:
            if( lpReserved != NULL )
                *(HMODULE *)lpReserved = hAppInstance;
            break;
        case DLL_PROCESS_ATTACH:
            hAppInstance = hinstDLL;
            hookIATFunctionByName("MessageBoxA", (DWORD)hook_MessageBoxA);
            MessageBoxA( NULL, "Hello from DllMain!", "Reflective Dll Injection", MB_OK );
            break;
        case DLL_PROCESS_DETACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
            break;
    }
    return bReturnValue;
}
复制代码
posted @   An2i  阅读(80)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示