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时在控制台输出该函数的参数