api钩子

api钩子


2024年3月17日发(作者:绝地求生配置要求2022)

一、

序言对大多数的Windows开发者来说,如何在Win32系统中对API函数的调用

进行拦截一直是项极富挑战性的课题,因为这将是对你所掌握的计算机知识较为

全面的考验,尤其是一些在如今使用RAD进行软件开发时并不常用的知识,这

包括了操作系统原理、汇编语言甚至是关于机器指令代码的(听上去真是有点恐

怖,不过这是事实)。

当前广泛使用的Windows操作系统中,像Win 9x和Win NT/2K,都提供了一种

比较稳健的机制来使得各个进程的内存地址空间之间是相互独立,也就是说一个

进程中的某个有效的内存地址对另一个进程来说是无意义的,这种内存保护措施

大大增加了系统的稳定性。不过,这也使得进行系统级的API拦截的工作的难

度也大大加大了。

当然,我这里所指的是比较文雅的拦截方式,通过修改可执行文件在内存中的映

像中有关代码,实现对API调用的动态拦截;而不是采用比较暴力的方式,直

接对可执行文件的磁盘存储中机器代码进行改写。

二、

API钩子系统一般框架通常,我们把拦截API的调用的这个过程称为是安装一个

API钩子(API Hook)。一个API钩子至少有两个模块组成:一个是钩子服务器

(Hook Server)模块,一般为EXE的形式;一个是钩子驱动器(Hook Driver)

模块,一般为DLL的形式。

服务器主要负责向目标进程注入驱动器,使得驱动器工作在目标进程的地址空间

中,这是关键的第一步。驱动器则负责实际的API拦截工作,以便在我们所关

心的API函数调用的前后能做一些我们需要的工作。

一个大家比较常见的API钩子的例子就是一些实时翻译软件(像金山词霸)中

必备的的功能:屏幕抓词,它主要是对一些GDI 函数进行了拦截,获取它们的

输入参数中的字符串,然后在自己的窗口中显示出来。针对上述的两个部分,有

以下两点需要我们重点考虑的: 选用何种DLL注入技术 采用何种API拦截机

三、

注入技术的选用由于在Win32系统中各个进程的地址是互相独立的,因此我们无

法在一个进程中对另一个进程的代码进行有效的修改。而你要完成API钩子的

工作就必须进行这种操作。因此,我们必须采取某种独特的手段,使得API钩

子(准确的说是钩子驱动器)能够成为目标进程中的一部分,才有较大的可能来

对目标进程数据和代码进行有控制的修改。

通常有以下几种注入方式:

1.利用注册表如果我们准备拦截的进程连接了,也就是使用了User32

中的API(一般图形界面的应用程序都符合这个条件),那么就可以简单把你

的钩子驱动器DLL的名字作为值添加在下面注册表的键下:

HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsNTCurrentVersionW

indowsAppInit_DLLs 值的形式可以为单个DLL的文件名,或者是一组DLL

的文件名,相邻的名称之间用逗号或空格间隔。所有由该值标识的DLL将在

符合条件的应用程序启动的时候装载。这是一个操作系统内建的机制,相对

其他方式来说危险性较小,但它有一些比较明显的缺点: 该方法仅适用于

NT/2K操作系统。看看键的名称你就应该明白 为了激活或停止钩子的注入,

必须重新启动Windows。这个就似乎太不方便了 不能用此方法向没有使用

User32的应用程序注入DLL,例如控制台应用程序 不管需要与否,钩子DLL

将注入每一个GUI应用程序,这将导致整个系统性能的下降

2.

建立系统范围的Windows钩子要向某个进程注入DLL,一个十分普遍也是比较

简单的方法就是建立在标准的Windows钩子的基础上。Windows钩子一般是在

DLL中实现的,这是一个全局性的Windows钩子的基本要求,这也符合我们的

需要。当我们成功地调用SetWindowsHookEx函数之后,便在系统中安装了某种

类型的消息钩子,这个钩子可以是针对某个进程,也可以是针对系统中的所有进

程。一旦某个进程中产生了该类型的消息,操作系统会自动把该钩子所在的DLL

映像到该进程的地址空间中,从而使得消息回调函数(在SetWindowsHookEx的

参数中指定)能够对此消息进行适当的处理,在这里,我们所感兴趣的当然不是

对消息进行什么处理,因此在消息回调函数中只需把消息钩子向后传递就可以

了,但是我们所需的DLL已经成功地注入了目标进程的地址空间,从而可以完

成后续工作。

我们知道,不同进程中使用的DLL之间是不能直接共享数据的,因为它们活动

在不同的地址空间中。但在Windows钩子DLL中,有一些数据,例如Windows

钩子句柄HHook,这是由SetWindowsHookEx函数返回值得到的,并且作为参数

将在CallNextHookEx函数和UnhookWindoesHookEx函数中使用,显然使用

SetWindowsHookEx函数的进程和使用CallNextHookEx函数的进程一般不会是

同一个进程,因此我们必须能够使句柄在所有的地址空间中都是有效的有意义

的,也就是说,它的值必须必须在这些钩子DLL所挂钩的进程之间是共享的。

为了达到这个目的,我们就应该把它存储在一个共享的数据区域中。

在VC++中我们可以采用预编译指令#pragma data_seg在DLL文件中创建一个新

的段,并且在DEF文件中把该段的属性设置为“shared”,这样就建立了一个共

享数据段。对于使用Delphi的人来说就没有这么幸运了:没有类似的比较简单

的方法(或许是有的,但我没有找到)。不过我们还是可以利用内存映像技术来

申请使用一块各进程可以共享的内存区域,主要是利用了CreateFileMapping和

MapViewOfFile这两个函数。这倒是一个通用的方法,适合所有的开发语言,只

要它能使用Windows的API。

在Borland的BCB中有一个指令#pragma codeseg与VC++中的#pragma data_seg


发布者:admin,转转请注明出处:http://www.yc00.com/xitong/1710685278a1799248.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信