IAT Hook

@author: dlive

0X01 IAT Hook的优缺点

优点:工作原理与实现都比较简单

缺点:如果想钩取的API不在目标进程的IAT中,那么就无法使用该技术进行钩取操作。即如果要钩取的API是由程序动态加载DLL文件而的得以使用的,那么我们将无法使用这项技术钩取它。

0x02 IAT Hook的工作原理

程序开始运行时,PE装载器会将user32.SetWindowTextW()的API地址(77D0960E)记录到该地址(01001110 [calc.exe的IAT区域])。

IAT Hook的流程: 首先向calc.exe注入hookiat.dll,然后修改calc.exe内存IAT区域SetWindowTextW对应的地址为hookiat.dll中攻击者自定义的函数地址,这样当calc.exe调用SetWindowTextW时会跳转至hookiat.dll中的Hook函数,Hook函数执行到最后时调用SetWindowTextW API即可在完成该API正常功能的情况下监控API的参数和返回结果。(当然攻击者可以选择不执行SetWindowTextW的功能)

0x03 IAT Hook代码分析

DllMain

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	switch( fdwReason )
	{
		case DLL_PROCESS_ATTACH : 
            // 获取original API的地址
           	g_pOrgFunc = GetProcAddress(GetModuleHandle(L"user32.dll"), 
                                        "SetWindowTextW");

            // # hook
        	// MySetWindowTextW并未定义成导出函数
			hook_iat("user32.dll", g_pOrgFunc, (PROC)MySetWindowTextW);
			break;

		case DLL_PROCESS_DETACH :
            // # unhook
            hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrgFunc);
			break;
	}

	return TRUE;
}

代码比较简单,在DLL加载的时候获取SetWindowTextW的地址然后存放在全局变量中,因为被注入进程已经加载了user32.dll,所以直接GetModuleHandle获取其句柄即可(但最好先判断dll是否加载,若没有加载使用LoadLibrary加载DLL)

MySetWindowTextW

BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString)
{
    wchar_t* pNum = L"零一二三四五六七八九";
    wchar_t temp[2] = {0,};
    int i = 0, nLen = 0, nIndex = 0;

    nLen = wcslen(lpString);
    for(i = 0; i < nLen; i++)
    {
        // 阿拉伯数字转换为中文
        if( L'0' <= lpString[i] && lpString[i] <= L'9' )
        {
            temp[0] = lpString[i];
            nIndex = _wtoi(temp);
            lpString[i] = pNum[nIndex];
        }
    }

    // 调用user32!SetWindowTextW(),参数为修改后的字符串缓冲区
    return ((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString);
}

hook_iat

// hook_iat
// 修改IAT中的数据
// 将IAT中 pfnOrg 修改为 pfnNew
BOOL hook_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew)
{
	HMODULE hMod;
	LPCSTR szLibName;
	PIMAGE_IMPORT_DESCRIPTOR pImportDesc; 
	PIMAGE_THUNK_DATA pThunk;
	DWORD dwOldProtect, dwRVA;
	PBYTE pAddr;

    // hMod, pAddr = ImageBase of calc.exe
    //             = VA to MZ signature (IMAGE_DOS_HEADER)
	hMod = GetModuleHandle(NULL);
	pAddr = (PBYTE)hMod;

    // pAddr = VA to PE signature (IMAGE_NT_HEADERS)
	pAddr += *((DWORD*)&pAddr[0x3C]);

    // dwRVA = RVA to IMAGE_IMPORT_DESCRIPTOR Table
	dwRVA = *((DWORD*)&pAddr[0x80]);

    // pImportDesc = VA to IMAGE_IMPORT_DESCRIPTOR Table
	pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod+dwRVA);
	
  	// IMAGE_IMPORT_DESCRIPTOR[] 以空的IMAGE_IMPORT_DESCRIPTOR为结尾
	for( ; pImportDesc->Name; pImportDesc++ )
	{
        // szLibName = VA to IMAGE_IMPORT_DESCRIPTOR.Name
		szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name);
		if( !_stricmp(szLibName, szDllName) )
		{
            // pThunk = IMAGE_IMPORT_DESCRIPTOR.FirstThunk
            //        = VA to IAT(Import Address Table)
			pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod + 
                                         pImportDesc->FirstThunk);

            // pThunk->u1.Function = VA to API
          	// IAT Thunk 数组以空IAT Thunk为结尾
			for( ; pThunk->u1.Function; pThunk++ )
			{
				if( pThunk->u1.Function == (DWORD)pfnOrg )
				{
                    // 修改内存属性为 E R W
					VirtualProtect((LPVOID)&pThunk->u1.Function, 
                                   4, 
                                   PAGE_EXECUTE_READWRITE, 
                                   &dwOldProtect);

                    // 修改IAT值为新的函数地址
                    pThunk->u1.Function = (DWORD)pfnNew;
					
                    // 恢复内存属性为只读
                    VirtualProtect((LPVOID)&pThunk->u1.Function, 
                                   4, 
                                   dwOldProtect, 
                                   &dwOldProtect);						

					return TRUE;
				}
			}
		}
	}

	return FALSE;
}

IAT Hook的步骤如下:

calc.exe的ImageBase的地址 -> Image_Nt_Headers地址 -> Image_Import_Descriptor结构体组成的数组的起始地址(其中存储着DLL名称,IAT数组的起始地址)-> 通过DLL名称找到user32.dll对应的Image_Import_Descriptor -> 找到对应的IAT数组起始地址 -> 遍历IAT找到SetWindowTextW对应的条目,修改其值为MySetWindowTextW

posted @ 2017-02-14 18:58  dlive  阅读(1807)  评论(0编辑  收藏  举报