IAT HOOK

IAT HOOK

IAT hook,通过把IAT表中的函数地址修改成我所要执行的函数地址,完成改变程序流程

举例:

比如原本是静态(通过系统自己加载dll)使用函数MessageBox,程序会FF间接call,找IAT表里面存的函数地址。倘若我在程序使用函数MessageBox之前,就对IAT表里面的函数地址做修改。那么,程序再call函数MessageBox的地址时,就会call我修改的那个函数的地址那里。从而实现改变程序流程

案例:

实现IAT hook,要求返回函数MessageBox的参数、返回值到控制台,并且能正确执行MessageBox。在hook完后,程序后面能正常使用MessageBox

  • IAT hook 安装
    • 得到模块基址
    • 通过基址找到IAT表
    • 通过IAT表找到MessageBox的地址
    • 保存MessageBox的地址
    • 修改IAT表
  • 执行函数
    • 打印参数、返回值到控制台 (自已想要的功能)
    • 定义MessageBox函数指针
    • 执行MessageBox (让用户不知道被hook了)
  • IAT hook卸载
    • 得到模块基址
    • 通过基址找到IAT表
    • 通过IAT表找到MessageBox的地址
    • 修改为原本MessageBox的地址

注意点:MessageBox地址块处是不能写入的,需要用VirtualProtect更改保护属性

DWORD oldProtected;
VirtualProtect(pIATData, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);//修改内存保护属性
*pIATData = FuncAddr;
VirtualProtect(pIATData, 0x1000, oldProtected, &oldProtected);			//还原属性

C++编写风格,阅读可能不太方便
Hook_IAT.h头文件

#pragma once
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <string.h>
class Hook_IAT
{
	DWORD ImageBase;
	DWORD ImportAddr;
	DWORD SourceFunAddr;
	DWORD pIatAddr;
public:
	Hook_IAT()
	{
		ImageBase = 0;
		ImportAddr = 0;
		SourceFunAddr = 0;
		pIatAddr = 0;
	}
	Hook_IAT(DWORD num)
	{
		Init(num);
	}
public:
	DWORD GetPrcBase();
	DWORD GetDirAddr();
	DWORD ReplaceFuncAddr(char* DllName, char* FuncName,DWORD FuncAddr);
	void  Unstall(DWORD Addr);
private:
	void Init(DWORD num);
};

Hook_IAT.cpp源文件

#include "Hook_IAT.h"

//根据表序号初始化
void Hook_IAT::Init(DWORD num)
{
	//1.得到基址
	this->ImageBase = (DWORD)::GetModuleHandle(NULL);


	//2.得到导入表
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageBase;
	if (pDos->e_magic != IMAGE_DOS_SIGNATURE || *(PDWORD)((DWORD)pDos + pDos->e_lfanew) != IMAGE_NT_SIGNATURE)
	{
		//std::cout << std::hex<<pDos->e_lfanew << std::endl;
		return ;
	}
	PIMAGE_FILE_HEADER pFile = (PIMAGE_FILE_HEADER)((DWORD)pDos + pDos->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionalFile = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFile + IMAGE_SIZEOF_FILE_HEADER);
	DWORD ImportSec = ((DWORD)ImageBase + pOptionalFile->DataDirectory[num].VirtualAddress);
	this->ImportAddr = ImportSec;
}


//替换地址,返回原来地址
DWORD Hook_IAT::ReplaceFuncAddr(char* DllName, char* FuncName, DWORD FuncAddr)
{
	//1、找到对应dll
	PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)ImportAddr;
	while (pImport->Name!=0)			//最后会留一个空结构,这里就简单用Name判断
	{
		if (strcmp((char*)(this->ImageBase + pImport->Name), DllName) == 0)
		{
			std::cout << "DLL:"<<(char*)(this->ImageBase + pImport->Name) << std::endl;
			break;
		}
		pImport++;
	}
	//2、找到对应dll的IAT表和INT表
	PDWORD pIATData = (PDWORD)(this->ImageBase + pImport->FirstThunk);
	PDWORD pINTData = (PDWORD)(this->ImageBase + pImport->OriginalFirstThunk);
	
	//3、根据名字找到原函数位置(IAT表中的下标)
	while (*(PDWORD)pINTData != 0)
	{
		if ((*pINTData & 0x80000000) == 0x80000000)
		{
			std::cout << "序号:" << (*pINTData & 0x7fffffff) << std::endl;
		}
		else 
		{
			PIMAGE_IMPORT_BY_NAME pINTName = (PIMAGE_IMPORT_BY_NAME)(this->ImageBase+*pINTData);
			std::cout << "名字:" << pINTName->Name << std::endl;
			if (strcmp(pINTName->Name, FuncName) == 0)								//查找到相同名字
			{
				break;
			}
		}
		pINTData++;
		pIATData++;				
	}
	//4、保存原来的地址 和 记录改变的地址
	DWORD SourcePrcAddr = *pIATData;
	this->pIatAddr = (DWORD)pIATData;
	//5、替换函数
	DWORD oldProtected;
	VirtualProtect(pIATData, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);		//修改内存保护属性
	*pIATData = FuncAddr;
	VirtualProtect(pIATData, 0x1000, oldProtected, &oldProtected);					//还原属性
	//6、返回原来函数地址
	return SourcePrcAddr;
}

//替换原来的地址
void Hook_IAT::Unstall(DWORD Addr)
{
	DWORD oldProtected;
	PDWORD addr = (PDWORD)this->pIatAddr;
	VirtualProtect(addr, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);			//修改内存保护属性
	*addr = Addr;
	VirtualProtect(addr, 0x1000, oldProtected, &oldProtected);						//还原属性
}

提供私有变量返回
//获取Iamgebase
DWORD Hook_IAT::GetPrcBase()
{
	return ImageBase;
}
//获取表的地址
DWORD Hook_IAT::GetDirAddr()
{
	return ImportAddr;
}

主函数 main

#include "Hook_IAT.h"
using namespace std;
#define REPLACE 02E104B
#define IAT 0x1
//多字符
int WINAPI PrintMessageA(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
    //打印MessageBoxA的参数
    cout << "第一个参数:" << hWnd << endl;
    wcout << "第二个参数:" << lpText << endl;
    wcout << "第三个参数:" << lpCaption << endl;
    cout << "第四个参数:" << uType << endl;
 
    //执行真正的MessageBoxA
    HMODULE hKernel32Mod = NULL;
    hKernel32Mod = LoadLibrary(TEXT("User32.dll"));
    if (hKernel32Mod == NULL)
    {
        return 0;
    }
    typedef int(WINAPI* p)(HWND, LPCTSTR, LPCTSTR, UINT);     //WINAPI函数
    p func = NULL;
    func = (p)GetProcAddress(hKernel32Mod, "MessageBoxA");
    if (func == NULL)
    {
        return 0;
    }
    func(hWnd, lpText, lpCaption, uType);

    return 0;
}

//宽字符
 int WINAPI PrintMessageW(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType)
{
     //打印MessageBoxW的参数
     cout << "第一个参数:" << hWnd << endl;
     wcout << "第二个参数:" << lpText << endl;
     wcout << "第三个参数:" << lpCaption << endl;
     cout << "第四个参数:" << uType << endl;

     //执行真正的MessageBoxW
     HMODULE hKernel32Mod = NULL;
     hKernel32Mod = LoadLibrary(L"User32.dll");
     if (hKernel32Mod == NULL)
     {
         return 0;
     }
     typedef int(WINAPI* p)(HWND, LPCTSTR, LPCTSTR, UINT);     //WINAPI函数
     p func = NULL;
     func = (p)GetProcAddress(hKernel32Mod, "MessageBoxW");
     if (func == NULL)
     {
         return 0;
     }
     func(hWnd, lpText, lpCaption, uType);
    
     return 0;
}


 //并没有严格按照C++风格编写
int main()
{
    cout << hex;
    Hook_IAT Install(IAT);
  
    //1、安装IAT_HOOK     通过Dll名和函数名 保存函数地址并修改IAT表
    char DllName[20] = "USER32.dll";
    char FuncName[30] = "MessageBoxW";
    DWORD SourceFunAddr = Install.ReplaceFuncAddr(DllName,FuncName,(DWORD)PrintMessageW);
   
    //2、这时使用MessageBox就是其他函数
    MessageBox(NULL, L"ERROR", L"123", MB_OK);
  
    //3、卸载IAT_HOOK      
    Install.Unstall(SourceFunAddr);

    //4、这时使用MessageBox就是正常的
    MessageBox(NULL, L"ERROR", L"123", MB_OK);

    return 0;
}

实验结果:在调用MessageBox时在控制台输出该函数的参数
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用中提到,hook可以分为两类:一种是修改函数代码,一种是修改函数地址。其中,修改函数代码的方式可以通过Inline hook实现,而修改函数地址的方式可以通过IAT hook、SSDT hook、IRP hook、IDT hook等方法实现。引用中给出了一个使用memcpy函数进行hook的示例代码。在这个示例中,先定义了一个结构体Thook修改代码,结构体中包含了一些汇编指令和跳转地址等信息。然后通过调用memcpy_s函数,将这个结构体的内容拷贝到目标函数的地址,从而实现对目标函数的hook。同样地,引用中也给出了另一个使用memcpy函数进行hook的示例代码,并且提到了备份被覆盖的代码以及跳转地址等操作。综上所述,可以使用memcpy函数进行hook操作,通过拷贝特定的指令或者结构体内容到目标函数的地址来实现hook。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [浅谈hook攻防](https://blog.csdn.net/hongduilanjun/article/details/124676926)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [各种HOOK方式和检测对抗方法](https://blog.csdn.net/qq_43355637/article/details/127061136)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值