zoukankan      html  css  js  c++  java
  • ring3下的IAT HOOK

    标 题: 【原创】ring3下的IAT HOOK
    作 者: hostzhen
    时 间: 2013-03-28,11:30:53
    链 接: http://bbs.pediy.com/showthread.php?t=166993


    IAT hooking
    当应用程序使用另一个动态库的函数时,PE装载器会找到每个IAMGE_IMPORT_BY_NAME结构所指向的输入函数的地址,然后把这些地址存储在一个叫做IAT的表。当函数CALL一个输入函数的时候,会先在IAT找到对应的函数地址,紧接着再进入该函数空间。熟悉PE结构的朋友应该清楚,IAT是一个IMAGE_THUNK_DATAj结构的数组。只要程序装载进内存中,就只与IAT查询信息,所以可见IAT表是一个非常重要的位置。
    如果在IAT表中把某个函数的地址修改为钩子函数的地址,当调用到函数的时候,就会执行到该钩子函数中去。示例代码如下:
    钩子函数,这里只是简单的弹出个窗口:

    代码:
    int
    WINAPI
    MyMessageBoxW(
    /* __in_opt HWND hWnd,
    __in_opt LPCWSTR lpText,
    __in_opt LPCWSTR lpCaption,
    __in UINT uType*/)
    {
    //todo yourself
    return MessageBox(NULL, "hello world", "caption", MB_OK);
    }

    ROOKIT函数,获取目标函数的地址,然后调用IAT HOOK函数ImportAddressTableHook,修改IAT表的值。

    代码:
    BOOL Rookits
    (
    IN HMODULE hModule,
    IN LPCTSTR pImageName,
    IN LPCTSTR pTargetFuncName
    )
    {
    LPDWORD pTargetFuncAddr = NULL;
    HMODULE hLib = LoadLibrary(pImageName);
    if (NULL != hLib)
    {
    pTargetFuncAddr = (LPDWORD)GetProcAddress(hLib, pTargetFuncName);
    return ImportAddressTableHook(hModule, pImageName, pTargetFuncAddr, MyMessageBoxW);
    }
     
    return FALSE;
    }

    修改IAT表的函数,通过所在模块的基地址hModule找到输入表的数据目录项,获取IAT的首指针,查询目标函数地址所在的位置,然后修改为钩子函数的地址。

    代码:
    BOOL ImportAddressTableHook
    (
     IN HMODULE hModule,
     IN LPCTSTR pImageName,
     IN LPCVOID pTargetFuncAddr,
     IN LPCVOID pReplaceFuncAddr
     )
    {
        IMAGE_DOS_HEADER* pImageDosHearder = (IMAGE_DOS_HEADER*)hModule;
        IMAGE_OPTIONAL_HEADER* pImageOptionalHeader = (IMAGE_OPTIONAL_HEADER*)((DWORD)hModule+pImageDosHearder->e_lfanew+24);    
        IMAGE_IMPORT_DESCRIPTOR* pImageImportDescriptor = (IMAGE_IMPORT_DESCRIPTOR*)
            ((DWORD)hModule+
            pImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
        IMAGE_THUNK_DATA* pImageThunkData = NULL;
        string TargetLibraryName;
        DWORD Value = 0, OldProtect = 0, NewProtect = 0;
        LPDWORD FunctionAddress = NULL;
        MEMORY_BASIC_INFORMATION InforMation;
     
     
        while(pImageImportDescriptor->Characteristics  != 0)   
        {   
            TargetLibraryName=(LPCTSTR)((DWORD)hModule+pImageImportDescriptor->Name);
            if(TargetLibraryName.compare(pImageName) == 0)
            {   
                pImageThunkData = (IMAGE_THUNK_DATA*)((DWORD)hModule + pImageImportDescriptor->FirstThunk);
                break; 
            } 
            pImageImportDescriptor++;   
        }  
        if (pImageThunkData == NULL)
        {
            return FALSE;
        } 
        while(pImageThunkData->u1.Function)   
        {   
            //循环查找目标函数地址所在的位置
            FunctionAddress = (LPDWORD)&(pImageThunkData->u1.Function);
            if(*FunctionAddress == (DWORD)pTargetFuncAddr)
            {    
                //找到目标函数的地址,然后修改为钩子函数的地址
                VirtualProtect(FunctionAddress, sizeof(DWORD), PAGE_READWRITE, &OldProtect);
                if(!WriteProcessMemory((HANDLE)-1, FunctionAddress, &pReplaceFuncAddr, 4, NULL))
                {
                    return FALSE;
                }
                VirtualProtect(FunctionAddress, sizeof(DWORD), OldProtect, NewProtect );   
                return TRUE; 
            }  
            pImageThunkData++;   
        }
        return FALSE;
    } 

    也许你会注意到,如果使用了延迟装入数据,那么示例代码是无效的,因为程序会使用___delayLoadHelper2来加载,具体代码可在delayhlp.cpp查看,里面直接GetProcAddress获取该函数地址,对于这种情况只能再HOOK多一个函数,即GetProcAddress。
    ___delayLoadHelper2代码片段:

    代码:
    // Go for the procedure now.
    //
    dli.hmodCur = hmod;
    if (__pfnDliNotifyHook2) {
    pfnRet = (*__pfnDliNotifyHook2)(dliNotePreGetProcAddress, &dli);
    }
    if (pfnRet == 0) {
    if (pidd->rvaBoundIAT && pidd->dwTimeStamp) {
    // bound imports exist...check the timestamp from the target image
    //
    PIMAGE_NT_HEADERS pinh(PinhFromImageBase(hmod));
     
    if (pinh->Signature == IMAGE_NT_SIGNATURE &&
    TimeStampOfImage(pinh) == idd.dwTimeStamp &&
    FLoadedAtPreferredAddress(pinh, hmod)) {
     
    // Everything is good to go, if we have a decent address
    // in the bound IAT!
    //
    pfnRet = FARPROC(UINT_PTR(idd.pBoundIAT[iIAT].u1.Function));
    if (pfnRet != 0) {
    goto SetEntryHookBypass;
    }
    }
    }
     
    pfnRet = ::GetProcAddress(hmod, dli.dlp.szProcName);
    }
  • 相关阅读:
    JMeter怎样测试WebSocket
    Android—基于OpenCV+Android实现人脸检测
    Android—实现科大讯飞语音合成
    Could not resolve com.android.support.constraint:constraint-layout:1.1.3.
    Mac上利用Aria2加速百度网盘下载
    将Excel表中的数据导入MySQL数据库
    Android Studio 添加模块依赖
    Mac上基于hexo+GitHub搭建个人博客(一)
    微信小程序—setTimeout定时器的坑
    微信小程序-腾讯地图显示偏差问题
  • 原文地址:https://www.cnblogs.com/FCoding/p/3163473.html
Copyright © 2011-2022 走看看