IAT Hook:
IAT Hook注意点:
1:在之前说的,
在自己挂钩的函数(MyMessageBoxW)中,执行完自己的代码后,调用return MessageBoxW,这样会形成Hook的递归,导致程序一直在这里Hook。解决这个问题:在挂钩的时候,
先将USER32.dll映射内存位置的MessageBoxW的地址记录下来,在调用MyMessageBoxW后,return的地方再接着记录的地址执行,相当于是在执行被Hook的MessageBoxW,只不过在执行前先去自己写的MyMessageBoxW中走了一圈,这样,就可以将自己的代码插入到程序的执行流程,而不影响程序本身执行。
特别注意:
平时,我们正常调用Windows的API的时候,程序都会在导入表里面找到这个函数的地址,然后调用,因此,我们更改这个地址后可以改变调用的函数,
但是,我们通过函数指针调用一个函数的话,相当于是已知了函数的位置,因此,就不会再在IAT表导入表里面去找这个函数的地址了,这样,就不会Hook到调用的这个函数了,
所以,我们在更改IAT表导入表里面函数地址的时候,应该记录原来的地址,在自己的函数里面在通过这个地址调用原来的函数,达到不影响程序执行的目的,由此也可以知道,一个好的Hook库,不仅要Hook需要Hook的这个函数,还要Hook的函数有:
LoadLibraryA,LoadLibraryW,LoadLibraryExA,LoadLibraryExW,GetProcAddress五个函数,
前面四个是为了确保进程加载的每个DLL的时候,对这些DLL都Hook,
第五个函数,不管是否全部DLL和EXE都挂钩,他都可以取到原始函数的地址,因此,也需要对这个函数挂钩,保证其取到的是我们写的函数的地址,这是IAT Hook必须挂钩的五个函数。
2:按这样的挂钩,只能挂当前程序自己的钩,而且,当程序有多个DLL里面使用了MessageBoxW,我们还只能挂到当前这个模块(EXE)的钩,局限性非常大。
例如,在main中挂钩后,再使用LoadLibrary,加载其他的DLL,那么他的钩就没挂上了,直接#pragma comment (lib, "MessageBoxWDllDemo.lib")这样加载的也是不行的,不管是在OnHook前还是后加载,都不行,除非,单独对其进行设置Hook,如下:
int _tmain(int argc, _TCHAR* argv[])
{
//MessageBoxW(nullptr, L"123", nullptr, MB_OK);
SetHook(nullptr, "MessageBoxW", "USER32.dll", "MyMessageBoxW");
MessageBoxW(nullptr, L"123", nullptr, MB_OK);
SetHook("MessageBoxWDllDemo.dll", "MessageBoxW", "USER32.dll", "MyMessageBoxW");
Call();//就是MessageBoxWDllDemo.dll中一个调用MessageBoxW的函数
SetHook("APIHook.dll", "MessageBoxW", "USER32.dll", "MyMessageBoxW");
MessageBoxW(nullptr, L"123", nullptr, MB_OK);//直接return MessageBoxW的话,就会无限递归,需要调用原始函数的地址。
return 0;
}
获取导入表:
1:在之前获取导入表的时候,我们是通过从开头往后找的方式,是为了熟悉PE结构,实际上,Windows提供了API可以直接取得里面的结构体:
ImageDirectoryEntryToData:位于Desktop technologies -> Diagnostics -> Debugging and Error Handling里面,实际上,他的本质也是通过计算偏移来找到的。
2:ImageDirectoryEntryToData函数原型:
PVOID WINAPI ImageDirectoryEntryToData(
_In_ PVOID Base,
_In_ BOOLEAN MappedAsImage,
_In_ USHORT DirectoryEntry,
_Out_ PULONG Size
);
函数参数:
1:Base:Image基地址,就是HModule模块的地址,可以使用GetModuleHandle来获取。
2:如果此参数为TRUE,则系统将该文件映射为图像。如果标志为FALSE,则该文件将通过MapViewOfFile函数映射为数据文件 。
3:需要获取的条目的索引,可以取一些值,详看
MSDN。
4:指向一个表示目录条目数据大小的变量的指针。
头文件:该函数需要包含头文件#include "ImageHlp.h",#pragma comment(lib, "ImageHlp.lib");
封装IAT Hook:
1:IAT Hook封装类里面必要的方法和成员变量:
1:需要Hook的模块名:对哪个模块进行Hook,一般对一个进程的所有模块都Hook
2:需要Hook的方法名和方法所在模块:Hook哪个方法,以及这个方法所在的模块名,也可以直接找,不要模块名,实际上可以通过方法名得到模块名。
3:新方法的地址:替换的方法地址。
4:挂钩函数:设置Hook的方法。
5:卸载挂钩函数:卸载Hook的方法。
2:方法名获取模块名:
通过GetProcAddr可以获取到方法名的地址,这个地址是属于一个模块的,然后通过查询虚拟地址得到BaseAddr,就是ModuleHandle了。