《Windows核心编程》之“API Hooking”(一)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Sagittarius_Warrior/article/details/52228240

    《Windows核心编程》中介绍了两种API Hooking的方法 —— “Overwritting Code”(代码覆盖)和“API Hooking by Manipulating a Module's Import Section”(修改导入段)。本文在以学习这两种API Hooking为目的,介绍相关的内容,包括:API Hooking的作用、导入段的获取和修改、detours库、使用WM_COPYDATA进行进程间通信、UIPI等知识。


一、What is API Hooking

    先来看Stack Overflow上对这个问题的答案:http://stackoverflow.com/questions/10562055/what-is-subclassing-and-api-hooking

    它的大意就是:API Hooking与Subclassing类似,都是通过拦截Windows固有的流程,添加自定义代码,来扩展新特性。Subclassing主要是拦截window message,扩展WndProcedure的特性;API Hooking主要是拦截应用程序对Windows API的调用,从而改变(扩展)Windows API的原有行为。广义来说,API Hooking不但可以拦截Windows API,也可以用于拦截一些第三方DLL库的API。

    API Hooking有什么用?

    Jeffrey从他遇到的一个客户需求——数据库扩展DLL卸载时的资源清理问题,引入API Hooking技术,控制“ExitProcess”系统函数的行为,让它先调用客户DLL的某个资源清理函数,待客户DLL清理完毕后,再执行原始的“ExitProcess”,卸载进程的各个DLL模块(顺序不可控)。

    除此之外,我还想到一个修改第三方DLL的api的应用。假设客户A的APP调用客户B的DLL,现需修改DLL中的某个API的行为(或者加一个打印log),一个比较暴力的做法就是,我们自己写一个DLL,调用客户B的DLL,并封装客户B的DLL的各个接口,在需要修改的API上,进行修改。这种方法就是“中间层”法,简单暴力,但工作量大。



    API Hooking从某种意义来说,也是设计一个“中间层”来修改原始行为。只不过,它针对的不是整个模块(DLL文件),而是模块中的某个接口(函数)。因此,在某些场景下,它会更灵活。

    API Hooking需要DLL注入吗?

    答案是:不一定。Jeffrey提到的那个数据库DLL案例,就不需要自己去实现DLL注入,而他给出的LastMessageBox示例又需要DLL注入。我也能想到一些不需要DLL注入的场景。比如:将qwt.dll嵌入QCreator中,就不需要我们自己去费心,直接拷贝到相关文件夹下即可。事实上,现在很多软件都支持这种简单的插件扩展。


二、API Hooking by Manipulating a Module's Import Section

    《Windows核心编程》一书介绍了两种API Hooking的技术,第一种是“Overwritting Code”,这种方法需要熟悉汇编指令,如JUMP等。因此,这种方法有两个缺点:1)CPU-dependent。汇编指令与CPU类型直接相关,该方法不能跨硬件架构。2)该方法不适合“preemptive, multithreaded environment”,多任务抢占式的环境。因为,覆盖CPU汇编指令需要时候,不能保证在这段时间,被Hook的API不被调用。因此,作者不鼓励使用这种方法,而是推荐大家使用“修改导入段”的方式来实现API Hooking。

    要理解“导入段修改”的API Hooking的原理,我们需要先理解以下内容:

1)EXE和DLL的编译和链接过程中,对export function(或import function)的处理。

2)Import Section and Export Section包含了什么信息。

3)EXE启动过程中(运行时),对DLL的加载和IAT(Import Address Table)的处理。

4)运行时,对EXE对DLL中的export function是如何调用的。


    下面,我们按照这个顺序来一条条讲解。

1,导出函数

    对于单Image文件的应用程序,函数都位于text段中,且每个函数由它的起始地址值表示。我们可以将这个起始地址值赋给一个函数指针,然后通过这个指针来引用(调用)这个函数。

    对于多Image文件的应用程序(一个EXE+多个DLL),可以参看《windows核心编程》第19章的图19-1。

1)DLL在链接阶段,链接器检测到它有导出函数或变量时(含__declspec(dllexport)修饰符),会产生一个.lib文件。该文件列出所有被导出的函数和变量的符号名(symbol)

2)EXE在编译阶段需要包含DLL导出函数和变量的头文件,EXE在链接阶段,需要相关的.lib文件(隐式加载方式)EXE在编译链接过程中不知道导入函数的真实地址。导入函数在EXE中,是由转换函数(thunk)替代进行占位。因此,在EXE中,我们将导入函数赋值给一个函数指针,得到的地址实际上是转换函数的地址。这个,在我将“远程线程注入DLL”的博文中有详细介绍。


2,导入段、导出段和IAT填充

1)导出段是链接器在DLL中嵌入的导出函数和变量相关的信息。它包括:(按字母顺序排列的)导出符号表和Relative Virtual Address。我们可以通过dumpbin.exe查看该信息。

2)导入段是链接器在EXE中嵌入的导入函数和变量相关的信息。它包含待加载的DLL名,隶属各个DLL的全部导入函数和变量的符号名和“Import Address Table”。我们可以通过Dumpbin.exe工具查看导入段的信息。

3)在静态的EXE文件中,我们唯一能获知的是关于导入函数的信息就是它的符号名。我们不知道它们的真实地址,因为IAT此时是空的。

4)程序在加载阶段,待到DLL加载进内存空间后,loader会通过计算DLL的基地址和RVA获知导出函数的真实地址,这之后,loader会用这些真实的函数地址去填充IAT。

5)IAT填充完毕,程序才能调用到DLL的导出函数。


3,运行时导入函数调用过程

1) 运行时,程序通过CALL指令调用转换函数(thunk)。

2)转换函数通过符号名查IAT,获得导入函数的真实地址

注:上面说的都是隐式加载,显示加载的时候,程序主动调GetProcAddress函数,通过符号名查IAT获得导入函数的真实地址。由此看来,两种方式的底层实现是一样的。(隐式加载是由系统去调LoadLibrary函数)。


    有了上面的知识铺垫,我们可以很容易地发现:

1)IAT就是一个“符号名” vs “函数地址”的映射表(关联容器)。

2)假如我们修改IAT,就可以实现“对导入函数调用跳转到我们自定义函数”的目的。

    这个就是“修改导入段”API Hooking的原理。


    


    


展开阅读全文

Windows核心编程的问题

11-25

Windows核心编程第五版的源代码vc6编译通不过 下了最后支持vc6的sdk(2004版的)也一样 路经也设了 结果还是报错 只是跟没更新前报错的行数不一样 文件都一样 谁知道是什么原因 rn新的sdk是安装在c:\program files\microsoft platform sdk for windows xp sp2这个目录的 rnrnCompiling... rnErrorShow.cpp rnc:\program files\microsoft platform sdk for windows xp sp2\include\prsht.h(532) : error C2146: syntax error : missing ';' before identifier 'hdr' rnc:\program files\microsoft platform sdk for windows xp sp2\include\prsht.h(532) : error C2501: 'NMHDR' : missing storage-class or type specifiers rnc:\program files\microsoft platform sdk for windows xp sp2\include\prsht.h(532) : error C2501: 'hdr' : missing storage-class or type specifiers rnc:\program files\microsoft platform sdk for windows xp sp2\include\commctrl.h(277) : error C2146: syntax error : missing ';' before identifier 'hdr' rnc:\program files\microsoft platform sdk for windows xp sp2\include\commctrl.h(277) : error C2501: 'NMHDR' : missing storage-class or type specifiers rnc:\program files\microsoft platform sdk for windows xp sp2\include\commctrl.h(277) : error C2501: 'hdr' : missing storage-class or type specifiers rnc:\program files\microsoft platform sdk for windows xp sp2\include\commctrl.h(284) : error C2146: syntax error : missing ';' before identifier 'hdr' rn。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 论坛

没有更多推荐了,返回首页