HOOK钩子技术3 IATHook

原理

如果程序中使用了静态链接库文件,那么PE文件中就会有关于这些函数的导入表的存在,程序通过调用IAT表来定位函数地址从而实现调用。如果将这些已经确定好的函数地址给替换成为恶意函数地址,那么就会欺骗 程序运行恶意函数。

编码测试

  • IDE: VS 2008
  • APP:DLL TYPE
  • OS: WINDOWS XP SP3
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include <windows.h>

//定义函数指针,和CreateFileW一致
typedef HANDLE ( WINAPI *CRETEFILEW)
(
 LPCTSTR,              
 DWORD,                
 DWORD ,               
 LPSECURITY_ATTRIBUTES,
 DWORD                ,
 DWORD                ,
 HANDLE               
 );

CRETEFILEW dwCreateFileWAddr = 0;

//msdn的搬运工T_T
// HANDLE WINAPI CreateFile(
//                       _In_     LPCTSTR               lpFileName,
//                       _In_     DWORD                 dwDesiredAccess,
//                       _In_     DWORD                 dwShareMode,
//                       _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
//                       _In_     DWORD                 dwCreationDisposition,
//                       _In_     DWORD                 dwFlagsAndAttributes,
//                       _In_opt_ HANDLE                hTemplateFile
//                       );

//fake func replace the one above
HANDLE WINAPI myCreateFile(
                           _In_     LPCTSTR               lpFileName,
                           _In_     DWORD                 dwDesiredAccess,
                           _In_     DWORD                 dwShareMode,
                           _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                           _In_     DWORD                 dwCreationDisposition,
                           _In_     DWORD                 dwFlagsAndAttributes,
                           _In_opt_ HANDLE                hTemplateFile
                           )
{
    WCHAR wFileName[MAX_PATH] ={0};
    wcscpy(wFileName,lpFileName);
    if (wcscmp(wcslwr(wFileName),L"c:\\test.txt")==0)
    {
        if (MessageBoxW(NULL,L"OPEN FILE?",L"NOTICE",MB_YESNO)==IDYES)
        {
            return   dwCreateFileWAddr(                             //为什么没有用createFileW,而使用的是dwCreateFile呢,因为iat已经被劫持了,否则就成了递归,永远到不了真正的实现了。
                lpFileName,
                dwDesiredAccess,
                dwShareMode,
                lpSecurityAttributes,
                dwCreationDisposition,
                dwFlagsAndAttributes,
                hTemplateFile
                );
        } 
        else
        {
            return INVALID_HANDLE_VALUE;
        }
    } 
    else
    {
        return dwCreateFileWAddr(
            lpFileName,
            dwDesiredAccess,
            dwShareMode,
            lpSecurityAttributes,
            dwCreationDisposition,
            dwFlagsAndAttributes,
            hTemplateFile
            );
    }
}

VOID HookNotePadIAT()
{
    //get iid_addr 
    HMODULE notepad_module = GetModuleHandleA(NULL);
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)notepad_module;
    PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)notepad_module+pDosHeader->e_lfanew);
    DWORD RVA_FirstIID = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    PIMAGE_IMPORT_DESCRIPTOR pIID=(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)notepad_module+RVA_FirstIID);
    //PIMAGE_IMPORT_DESCRIPTOR pIIDtemp =pIID;

    //real addr of "CreateFileW"
    HMODULE handle=LoadLibraryA("kernel32.dll");
    DWORD dwFuncAddr = (DWORD)GetProcAddress(handle,"CreateFileW");


    //find the IID remains 'kernel32.dll'
    BOOL isExist = FALSE;
    while (pIID->Name)
    {
        char* dllname=(char*)(pIID->Name+(DWORD)notepad_module);
        char szName[MAXBYTE]={0};
        strcpy(szName,dllname);
        if (strcmp(strlwr(szName),"kernel32.dll")==0) //wrong here KERNEL32.dll
        {
            isExist = TRUE;
            break;
        }
        pIID++;
    }

    //check the iat addr is right ?
    if (isExist==TRUE)
    {
        isExist= FALSE;
        PIMAGE_THUNK_DATA pIAT=(PIMAGE_THUNK_DATA)(pIID->FirstThunk+(DWORD)notepad_module); //forget the baseimage...
        while (pIAT->u1.Function)
        {
            DWORD* pAddr=(DWORD*)(&pIAT->u1.Function); //get IAT addr
            if (*pAddr == dwFuncAddr)         //check contents of iat if right.
            {
                printf("isExist\n");
                isExist=TRUE;         
                dwCreateFileWAddr = (CRETEFILEW)*pAddr;    //real addr.
                DWORD dwMyHookAddr = (DWORD) myCreateFile;
                WriteProcessMemory(GetCurrentProcess(),(LPVOID)pAddr,&dwMyHookAddr,sizeof(DWORD),NULL); //replace the iat content
                break;
            }
            pIAT++;
        }
    }

}

BOOL APIENTRY DllMain( HMODULE hModule,
                      DWORD  ul_reason_for_call,
                      LPVOID lpReserved
                      )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        HookNotePadIAT();
        break;
    }
    return TRUE;
}

编码说明

上述代码原理:
1. 首先找到第一个IID的地址,用pIID 来保存。
2. 遍历IID,通过查找name字段 ,来确定程序中目标函数所在的DLL在导入表中,找到的IID指针用pIID来表示。
3. 用动态调用的方式得到目标函数的地址,保存为dwFuncAddr
4. 读取PIID 指向的IAT表,检查IAT表中的内容和动态获取的地址是否一致。
5. 内存中替换,写入伪造的函数地址。

注意
  • 在恶意函数中,有时候必须要实现被挂钩函数的功能。在inlineHook 中,通过unhook操作来恢复内存。而在IAT挂钩中,首先保存了原来的函数入口地址。不管使用什么方式挂钩,原来的内容一定要通过一个变量保存下来。

  • 编译与运行过程出现的问题:

    1. 在查询IID的时候, if (strcmp(strlwr(szName),"kernel32.dll")==0) //wrong here KERNEL32.dll 之前没有转小写,调试后发现kernel32.dll为KERNEL32.dll
    2. while (pIAT->u1.Function) 测试错误,调试之后发现问题是pIAT 忘了没有加基址,FirstThunk 是个RVA
    3. 不同类型的指针在使用时一定需要转化,一般而言,函数指针在赋值的时候必须转化。
    4. DLL主函数中:case不一定要全写,本例中就写了一个目标消息DLL_PROCESS_ATTACH 这也是可以的。

证明

打开notepad.exe后用dlljector.exe注入此进程

C:\Documents and Settings\Administrator\桌面>DLLInjector.exe C:\VC6\MyProjects\i
atHook_dll\Debug\iatHook_dll.dll 456

有意思的是选中文件的时候也会调用CreateFileW.
选中文件的时候也有
弹窗选择否之后,返回INVALID_HANDLE_VALUE ,也即打开失败。
选择否的时候不能正确打开

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值