IAT Hook

目录

IAT hook

一丶IAT

1.什么是 IAT表.

熟悉PE结构的应该知道.IAT 是导入表. 其IAT表如下:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            
        DWORD   OriginalFirstThunk;       指向INT表 4个字节一组.是RVA指向名字跟序号  
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;           
       

    DWORD   ForwarderChain;                 
    DWORD   Name;
    DWORD   FirstThunk;                  在文件中跟INT表一样.这是IAT                 
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

我们知道PE有两种状态.第一种.在文件中的状态. 所以才有 VA 转 FOA等等的互相转换. 扯多了. 在文件状态. IAT表(firstThunk)跟 INT表一样.都是指向一个很大的表.这个表里面是4个字节进行存储.存储的是Rva. 这些RVA分别指向 导入序号以及以0结尾的字符串.

如果在内存状态.则INT表跟上面说的文件状态一样指向 导入序号.以及导入的函数名字. 而IAT此时不同了.IAT此时就是保存着INT指向的导入函数的地址了.

如果还不理解.看下以前关于IAT博客. https://www.cnblogs.com/iBinary/p/9740757.html

如下图所示:

其实IAT就是保存函数地址.

2.怎么进行HOOK

熟悉了IAT 那么HOOK就很简单了.首先你要会解析PE. 原理就是: 1.编写DLL.注入到你想HOOK的程序中. 2.编写DLL,DLL里面获取你HOOK程序的 ImageBase以及各种头(DOS,NT,FILE,OPT) 3.DLL 里面通过OPT的数据目录第一项.得到导入表RVA.加上ImageBase定位到导入表 4.循环遍历导入表.导入表是一行04个字节.最后一项为0 5.通过导入表找到IAT表.继续遍历IAT表. 6.判断IAT中的函数地址,是否是你要进行HOOK的函数地址. 是: 则进行替换函数地址.比如替换为你的.一定要注入调用约定. 不是: 继续循环. 在IAT表中没找到.说明没在这个导入表中.导入表+1(一个导入表结构大小) 继续循环 4 5 6步. 说的比较复杂,其实原理很简单.

首先第一步.准备一个测试程序.测试程序调用MessageBoxA. 且加载我们的DLL(当然你编写的DLL一般是注入的别的进程中.我这里演示就直接加载自己进行HOOK自己).

测试程序如下:

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

int main()
{
    getchar();
    ::MessageBoxA(NULL, "没有HOOK", NULL, NULL);
    LoadLibrary("IAThook.dll");      //加载HOOK的DLL
    getchar();
    
//HOOK后进行测试的程序.
    __asm
    {
        push 0
        push 0
        push 0
        push 0
        call dword ptr ds : [MessageBoxA] ; 
    }

    __asm
    {
        push 0
        push 0
        push 0
        push 0
        call dword ptr ds : [MessageBoxA] ;
    }

    __asm
    {
        push 0
        push 0
        push 0
        push 0
        call dword ptr ds : [MessageBoxA] ;
    }
    
}

上面的内敛汇编是因为我自己HOOK自己了可以.但是都在第一次调用MessageBox函数的时候编译器会保存这个MessageBox函数的地址.就算我HOOK完毕了.它再次调用还是调用的以前的.所以我先改成下面这样.

HOOK的DLL

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "framework.h"
#include <windows.h>


//创建相同函数指针.
typedef int (WINAPI *PfnMsgA)(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCSTR lpText,
    _In_opt_ LPCSTR lpCaption,
    _In_ UINT uType);

PfnMsgA g_OldPfnMsgA = nullptr;


int WINAPI MyMessageBox(_In_opt_ HWND hWnd,_In_opt_ LPCSTR lpText,_In_opt_ LPCSTR lpCaption,_In_ UINT uType)
{

    char szHookText[] = "IBinary -> Iat Hook";
    if (g_OldPfnMsgA != nullptr)
    {
        return g_OldPfnMsgA(hWnd, szHookText, lpCaption, uType);//调用以前的
    }
    return 0;
}
void SetIatHook()
{
    MessageBoxA(NULL, "开始进行HOOK", NULL, NULL);
    PVOID pHookAddress = nullptr;
    pHookAddress = GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA"); //你要HOOK的函数.
    if (nullptr == pHookAddress)
    {
        OutputDebugString(TEXT("获取函数地址失败"));
        MessageBoxA(NULL, "获取函数地址失败HOOK", NULL, NULL);

        return;
    }
    g_OldPfnMsgA =(PfnMsgA) pHookAddress; //保存旧的函数指针.
    //解析PE头.寻找IAT.

    HMODULE hModImageBase = GetModuleHandle(NULL);//获取当前的ImagBase
    PIMAGE_DOS_HEADER pDosHead =(PIMAGE_DOS_HEADER)(DWORD)hModImageBase; //获取DOS头
    DWORD dwTemp = (DWORD)pDosHead + (DWORD)pDosHead->e_lfanew;
    PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)dwTemp;
    PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)& pNtHead->FileHeader;
    PIMAGE_OPTIONAL_HEADER pOptHead = (PIMAGE_OPTIONAL_HEADER)& pNtHead->OptionalHeader;

    //寻找导出表的位置.
    DWORD dwExportLocal = pOptHead->DataDirectory[1].VirtualAddress; //找到导出表偏移.
    //定位到导出表
    dwTemp = (DWORD)GetModuleHandle(NULL) + dwExportLocal;
    PIMAGE_IMPORT_DESCRIPTOR   pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwTemp;
    PIMAGE_IMPORT_DESCRIPTOR   pCurrent = pImport;
    DWORD *pFirstThunk; //导入表子表,也就是IAT存储函数地址的表.
    //遍历导入表

    while (pCurrent->Characteristics && pCurrent->FirstThunk != NULL)
    {
        dwTemp = pCurrent->FirstThunk + (DWORD)GetModuleHandle(NULL);//找到导入表
        pFirstThunk = (DWORD *)dwTemp; //加上偏移才是真正的导入表.
        while (*(DWORD*)pFirstThunk != NULL)
        {
            //遍历子表
            if (*(DWORD*)pFirstThunk == (DWORD)g_OldPfnMsgA)
            {
                //找到要修改的导入表了//修改内存保护属性.写入我们新的函数地址.
                DWORD oldProtected;
                VirtualProtect(pFirstThunk,0x1000, PAGE_EXECUTE_READWRITE,&oldProtected);
                dwTemp = (DWORD)MyMessageBox;
                memcpy(pFirstThunk, (DWORD *)&dwTemp,4); //将变量中保存的函数地址拷贝到导入表中.
                VirtualProtect(pFirstThunk,0x1000,oldProtected,&oldProtected);
            }
            pFirstThunk++; //继续遍历.
        }
        pCurrent++; //每次是加一个导入表结构.
    }

}

void UnIatHook()
{
    /*
      1.遍历导入表.恢复导入表即可.
    */

    MessageBoxA(NULL, "开始进行HOOK", NULL, NULL);
    PVOID pHookAddress = nullptr;
    pHookAddress = MyMessageBox;
    if (nullptr == pHookAddress)
    {
        OutputDebugString(TEXT("获取函数地址失败"));
        MessageBoxA(NULL, "恢复函数地址失败HOOK", NULL, NULL);
        return;
    }
    
    //解析PE头.寻找IAT.

    HMODULE hModImageBase = GetModuleHandle(NULL);//获取当前的ImagBase
    PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)(DWORD)hModImageBase; //获取DOS头
    DWORD dwTemp = (DWORD)pDosHead + (DWORD)pDosHead->e_lfanew;
    PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)dwTemp;
    PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)& pNtHead->FileHeader;
    PIMAGE_OPTIONAL_HEADER pOptHead = (PIMAGE_OPTIONAL_HEADER)& pNtHead->OptionalHeader;

    //寻找导出表的位置.
    DWORD dwExportLocal = pOptHead->DataDirectory[1].VirtualAddress; //找到导出表偏移.
    //定位到导出表
    dwTemp = (DWORD)GetModuleHandle(NULL) + dwExportLocal;
    PIMAGE_IMPORT_DESCRIPTOR   pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwTemp;
    PIMAGE_IMPORT_DESCRIPTOR   pCurrent = pImport;
    DWORD* pFirstThunk; //导入表子表
    //遍历导入表

    while (pCurrent->Characteristics && pCurrent->FirstThunk != NULL)
    {
        dwTemp = pCurrent->FirstThunk + (DWORD)GetModuleHandle(NULL);
        pFirstThunk = (DWORD*)dwTemp; //加上偏移才是真正的导入表.
        while (*(DWORD*)pFirstThunk != NULL)
        {
            //遍历子表
            if (*(DWORD*)pFirstThunk == (DWORD)MyMessageBox) //如果是我们的函数地址.则进行恢复.
            {
                //找到要修改的导入表了//修改内存保护属性.写入我们新的函数地址.
                DWORD oldProtected;
                VirtualProtect(pFirstThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);
                dwTemp = (DWORD)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
                memcpy(pFirstThunk, (DWORD*)& dwTemp, 4); //将变量中保存的函数地址拷贝到导入表中.
                VirtualProtect(pFirstThunk, 0x1000, oldProtected, &oldProtected);
            }
            pFirstThunk++; //继续遍历.
        }
        pCurrent++; //每次是加一个导入表结构.
    }


}
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        SetIatHook();
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:

        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

测试代码如下:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • IAT HOOK

    在上一篇文章手动打造一个弹窗程序中,我们自己手写了一份导入表,在调用函数的时候,我们CALL的是导入地址表的一个地址,为什么要调用这里,而且在构造导入表的时候,...

    信安本原
  • IAT Hook 技术分析

    来源:https://pentest.blog/offensive-iat-hooking/

    安恒网络空间安全讲武堂
  • 红队 | IAT Hook技术实现

    导入表中有个IAT表,在导入表结构中的FirstThunk.在调用一些API时,只要是LoadLibrary的dll,其中的API都会在IAT表中,我们可以通过...

    HACK学习
  • Ring0和Ring3 HOOK 大检查

    1、HOOK SERVICE TABLE:HOOK SSDT 这种方法对于拦截 NATIVE API 来说用的比较多。

    战神伽罗
  • 实现hook OpenProcess实现

    /*********************************实现hook OpenProcess实现ring3保护进程、、C++完整代码、、******...

    py3study
  • 逆向实战第一讲,寻找OllyDbg调试工具的Bug并修复

               逆向实战第一讲,寻找OllyDbg调试工具的Bug并修复 首先我们要知道这个OD的Bug是什么. 我们调试一个UNICODE的窗口,看下其...

    IBinary
  • 红队 | InlineHook技术实现

    IATHOOK局限性较大,当我们想HOOK一个普通函数,并不是API,或者IAT表里并没有这个API函数(有可能他自己LoadLibrary,自己加载的),那我...

    HACK学习
  • ring3层恶意代码实例汇总

    之前一期我们学习了 IAT 的基本结构,相信大家对 C++ 有了一个基本的认识,这一期放点干货,我把 ring3 层恶意代码常用的编程技术给大家整理了一下,所有...

    信安之路
  • 19.9.21日报:修复flash中文问题

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    龙泉寺扫地僧
  • IAT 三连之什么是 IAT?

    IAT 的全称是 ImportAddress Table。在可执行文件中使用其他 DLL 可执行文件的代码或数据,称为导入或者输入,当 PE 文件载入内存时,w...

    信安之路
  • CTF实战23 木马攻击技术

    值得注意的是,木马屠城记并非于古希腊诗人荷马的两部著作伊利亚特与奥德赛里记载,而是在罗马帝国时期的诗人维吉尔所写的史诗《埃涅阿斯纪》中, 才第一次被记载

    用户1631416
  • 手工修复PE导入表

    可以看到导入表全是0,就是这里的原因使得无法正常打开,要想打开,我们需要修复导入表

    yichen
  • PE知识复习之PE的导入表

      上一讲讲解了导出表. 也就是一个PE文件给别人使用的时候.导出的函数 函数的地址 函数名称 序号 等等.

    IBinary
  • AntiSpy:一款功能强大的反病毒&反Rootkit免费工具套件

    AntiSpy是一款完全免费,并且功能强大的手工杀毒辅助工具。它可以枚举系统中隐藏至深的进程、文件、网络连接、内核对象等,并且也可以检测用户态、内核态各种钩子。...

    FB客服
  • PE格式第四讲,数据目录表之导入表,以及IAT表

               PE格式第四讲,数据目录表之导入表,以及IAT表 一丶IAT(地址表) 首先我们思考一个问题,程序加载的时候会调用API,比如我们以前写的...

    IBinary
  • PC微信逆向:使用HOOK拦截二维码

    微信二维码在内存中存放形式是 png 格式的二进制数据,所以我们需要眼熟一下 png 的文件格式,如图

    信安之路
  • PE知识复习之PE的绑定导入表

      根据前几讲,我们已经熟悉了导入表结构.但是如果大家尝试过打印导入表的结构. INT IAT的时候. 会出现问题.

    IBinary
  • 最新版chromium 76如何支持xp

    我知道,当我写下这个标题的时候,肯定一大波人会过来嘲讽:都什么年代了,还XP?

    龙泉寺扫地僧
  • 使用 JWT 技术,简单快速实现系统间的单点登录

    来源:blog.csdn.net/jewelry008/article/details/72771489

    芋道源码

扫码关注云+社区

领取腾讯云代金券