• HOOK IAT 代码示例


    // include
    #include "stdio.h"
    #include "wchar.h"
    #include "windows.h"
    
    
    // typedef
    typedef BOOL(WINAPI* PFSETWINDOWTEXTW)(HWND hWnd, LPWSTR lpString);
    
    
    // globals
    FARPROC g_pOrgFunc = NULL;
    
    
    // 
    BOOL WINAPI MySetWindowTextW(HWND hWnd, LPWSTR lpString)
    {
    	wchar_t* pNum = (wchar_t*)L"零一二三四五六七八九";
    	wchar_t temp[2] = { 0, };
    	int i = 0, nLen = 0, nIndex = 0;
    
    	nLen = wcslen(lpString);
    	for (i = 0; i < nLen; i++)
    	{
    		// 将阿拉伯数字转换为中文数字
    		//   lpString 是 wide-character (2 byte) 字符串
    		if (L'0' <= lpString[i] && lpString[i] <= L'9')
    		{
    			temp[0] = lpString[i];
    			nIndex = _wtoi(temp);
    			lpString[i] = pNum[nIndex];
    		}
    	}
    
    	// 调用user32!SetWindowTextW() API 
    	//   (修改 lpString 缓冲区中的内容)
    	return ((PFSETWINDOWTEXTW)g_pOrgFunc)(hWnd, lpString);
    }
    
    
    // hook_iat
    // 
    //  
    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);
    
    	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
    			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;
    }
    
    
    
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
    	switch (fdwReason)
    	{
    	case DLL_PROCESS_ATTACH:
    		// 保存原始API地址
    		g_pOrgFunc = GetProcAddress(GetModuleHandle(L"user32.dll"),
    			"SetWindowTextW");
    
    		// # hook
    		//   用hookiat!MySetWindowText()钩取 user32!SetWindowTextW()
    		hook_iat("user32.dll", g_pOrgFunc, (PROC)MySetWindowTextW);
    		break;
    
    	case DLL_PROCESS_DETACH:
    		// # unhook
    		//   calc.exe 的IAT恢复原值
    		hook_iat("user32.dll", (PROC)MySetWindowTextW, g_pOrgFunc);
    		break;
    	}
    
    	return TRUE;
    }
    

      DllMain 判断。  

      存储SetWindowTextW的地址

      hookiat钩取和恢复

      MySetWindowTextW 是对显示内容进行更改。

      为了知道一个可执行文件或DLL文件被加载到进程地址空间的什么位置,可以用GetModuleHandle函数来返回一个句柄/基地址:
      HMODULE GetModuleHandle(PCTSTR pszModule);
     
      调用这个函数时,要传递一个以0为终止的字符串,它指定了已在主调进程的地址空间中加载的一个可执行文件或DLL文件的名称。如果系统找到了指定的可执行文件或DLL文件名称,GetModuleHandle就会返回可执行文件/DLL文件映像加载到的基地址。如果参数为NULL,这样可以返回主调进程的可执行文件的基地址,也就是说即使调用GetModuleHandle(NULL)的代码是在一个DLL文件中,返回值仍是可执行文件的基地址,而非DLL文件的基地址。
     
     代码中很多结构体类型,通过VS2019 可以很方便查看结构体中的具体情况,非常方便,以前排除VS 现在的2019版不可谓不强大啊。
     
    这里主要说一下怎么查找到SetWindowWextW的。
      首先 hMod拿到程序的基地址,就是DOS文件开头,然后传给pAddr ,偏移0x3C处的数据就是PE头的位置,也就是0XF0。
    再便宜0x80 就是 0x170 ,然后取数据,再次偏移。

    拿到 01012B80 看看此处,正好是IDT的开头。

    找到这个地址我们将它定义为IDT结构体PIMAGE_IMPORT_DESCRIPTOR。

    然后遍历找到user32.dll这个名称,并且拿到IAT的地址,也就是FirstThunk。

    给它定义为另一个结构体PIMAGE_THUNK_DATA。这个结构体也就是为IAT而生的。。。

    然后遍历寻找Function和我们传进来的参数(也就是SetWindowTextW的地址)相等,这样就找到了这个API。




    然后将Function 的值改为MySetWindowText的地址。

    修改前要保证有可写权限,

    VirtualProtect((LPVOID)& pThunk->u1.Function,
    						4,
    						PAGE_EXECUTE_READWRITE,
    						&dwOldProtect);

    BOOL VirtualProtect(
    LPVOID lpAddress,
    DWORD dwSize,
    DWORD flNewProtect,
    PDWORD lpflOldProtect
    );

    各参数的意义为:

    lpAddress,要改变属性的内存起始地址。

    dwSize,要改变属性的内存区域大小。

    flNewProtect,内存新的属性类型,设置为PAGE_EXECUTE_READWRITE(0x40)时该内存页为可读可写可执行。

    pflOldProtect,内存原始属性类型保存地址。

    修改内存属性成功时函数返回非0,修改失败时返回0。

    到此,IAT钩取成功。

    如果要恢复的话,将hookiat参数对调即可。

     
  • 相关阅读:
    写在vue总结之前(一)
    前端应该掌握的web基础和网络知识
    sass之为什么要使用预处理器
    ThinkPHP简单的验证码实现
    ajax接收php返回得到一堆html代码
    Bootstrap 4,“未捕获错误:Bootstrap工具提示需要Tether(http://github.hubspot.com/tether/)”
    百度AI开放平台- API实战调用
    最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
    C#避免踩坑之如何添加paint事件
    php插入mysql中文数据出现乱码
  • 原文地址:https://www.cnblogs.com/whitehawk/p/11169227.html
Copyright © 2020-2023  润新知