看流星社区

 找回密码
 注册账号
查看: 1874|回复: 0

ring3下的IAT HOOK

[复制链接]

该用户从未签到

发表于 2013-4-1 09:14:00 | 显示全部楼层 |阅读模式
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 != 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);
}
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-4-30 13:50

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表