2024年6月14日发(作者:)

第26卷第5期

2009年5月

计算机应用与软件

ComputerApplications

andSoftware

VoI.26No.5

May

2009

HOOK

API时代码注入方法和函数重定向技术研究

舒敬荣朱安国齐善明

(解放军炮兵学院二系安微合肥230031)

摘要HOOK

API是一种高级编程技术,在介绍WindowsHOOK技术的基础上,阐述了HOOKAPI技术的概念,分析了HOOK

API技术的实现原理,给出了三种实现HOOKAPI技术时的代码注入方法,即使用钩子注入DLL、使用注册表注入DLL及使用远程

线程注入DLL。探讨两种实现HOOKAPI技术时的函数重定向技术,即利用PE文件中的导入表实现函数的重定向及通过嵌入汇编

代码实现函数的重定向。

关键词HOOK机制HOOKAPI代码注入函数重定向Windows编程

STUDYONCODE

EMBEDDINGMETHoD

TECHNIQUE

WHEN

Shu

Jingrong

ANDFUNCTIoNREDIRECTloN

HooKINGAPI

Zhu

Anguo

Qi

Shanming

(Two

Department,ArtilleryAcademy

ofP上A.,Hefei230031,Anhui。China)

Abstract‘|HOOKAPIiskindof

advanced

programmingtechnique.On

thebasisof

introducing

Windows

HOOK

technique,in

this

paper

it

expounds

the

concept

ofHOOKAPI

technique,analyses

itsrealization

principle,andputs

forwardthreekindsofDLLcode

embedding

meth-

ods

when

realizing

HOOK

API:(1)by

using

hooks;(2)by

usingregistration

table;(3)byusing

remotethread.Italsodiscusses

functionredirection

techniques

when

realizing

HOOK

Keywords

HOOK

two

kindsof

API:(I)by

using

PEfile

importingtable;(2)by

embedding

assemble

language

code.

mechanism

HOOKAPICode

embedding

Functionredirection

Windows

programming

0引

HOOK

API是一种高级编程技术,很多问题的实现和解决

Windows系统中的HooK(钩子)机制

Windows系统中HoOK机制的概念

Windows系统是建立在消息驱动机制上的,整个系统都是

1.1

都要用到这种技术。这里所说的API,是广义上的API,包括

DOS下的中断、WINDOWS里的API、中断服务、IFS和NDIS过

滤等。比如大家熟悉的即时翻译软件,就是靠HOOK

TextOut()

或ExtTextOut()这两个函数实现的,在操作系统用这两个函数

输出文本之前,就把相应的英文替换成中文而达到即时翻译;

IFS和NDIS过滤也是如此,在读写磁盘和收发数据之前,系统

会调用第三方提供的回调函数来判断操作是否可以放行,它与

普通HOOK不同,它是操作系统允许的,由操作系统提供接口

来安装回调函数。HOOKAPI技术还可用于网络攻击和网络防

御。因为HOOKAPI技术是实现黑客、病毒及反黑客、反病毒软

件的基础。不管是DOS下的病毒或WINDOWS里的病毒,都是

靠HOOK系统服务来实现自己的功能的:DOS下的病毒靠

HOOK

INT

通过消息的传递来实现的。而HOOK(钩子)是Windows系统中

非常重要的系统接口,用它可以截获并处理送给其他应用程序

的消息,然后完成普通应用程序难以实现的功能。钩子可以监

视系统或进程中的各种事件消息,截获发往目标窗口的消息并

进行处理。因此,就可以通过在系统中安装自定义的钩子,监视

系统中特定事件的发生,完成特定的功能,比如截获键盘/鼠标

的输入、屏幕取词、日志监视等。可见,利用钩子可以实现许多

特殊而有用的功能。对于高级编程人员来说,掌握钩子的编程

方法是很有必要的。

关于Windows钩子必须要掌握以下几点:

(1)钩子是用来截获系统中的消息流的。利用钩子,可以

处理任何消息,包括其他进程的消息;

(2)截获消息后,用于处理消息的子程序叫做钩子函数,它

是应用程序自定义的一个函数,在安装钩子时要把这个函数的

地址告诉Windows;

(3)系统中同一时间可能有多个进程安装了钩子,多个钩

收稿13期:2007—12—06。舒敬荣,讲师,主研领域:自动化,指挥自

动化,飞行力学。

21来感染文件(文件型病毒),靠HOOK

INT

13来感

染引导扇区(引导型病毒);WINDOWS下的病毒靠HOOK系统

API,或者安装IFS(CIH病毒所用的方法)来感染文件。

由于涉及到知识产权和商业机密,微软一直不提倡编程者

HOOK它的系统API,而提供IFS和NDIS等其他过滤接口,也是

为了适应杀毒软件和防火墙的需要才开放的。所以在大多数时

候,HOOK

APl要靠自己的编程来完成。

万方数据

108

计算机应用与软件

2009篮

子函数在一起组成钩子链。所以在处理截获到的消息时,应该

把消息事件传递F去,以便其它钩子也有机会处理这一消息。

而且最近安装的钩子放在链的开始,而最早安装的钩子放在最

后,也就是后加入的先获得控制权;

(4)钩子函数有很多类型。按事件类型分类,主要有键盘

钩子、鼠标钩子、外壳钩子、13志钩子和窗口过程钩子等;按使用

范围分类,主要有线程钩子和系统钩子。线程钩子监视指定线

程的事件消息,系统钩子监视系统中的所有线程的事件消息。

因为系统钩子会影响系统中所有的应用程序,所以钩子函数必

须放在独立的动态链接库(DLL)中。如果对于同一事件(如鼠

标消息)既安装了线程钩子又安装了系统钩子,那么系统会自

动先调用线程钩子,然后调用系统钩子:

(5)钩子会使系统变慢,因为它增加了系统对每个消息的

处理量。仅在必要时才安装钩子,而且在不需要时应尽快移除。

1.2

Windows系统中HooK(钩子)机制的使用步骤

使用HOOK机制可以分为定义钩子函数、安装钩子和卸载

钩子3步,具体方法如下:

(1)定义钩子函数

钩子函数是一种特殊的回调函数。钩子监视的特定事件发

生后,系统会调用钩子函数进行处理。不同事件的钩子函数的

形式是各不相同的,此处以鼠标钩子函数举例说明钩子函数的

原型:

LRESULTCALLBACK

HookProc(int

nCode,WPARAM

wParam,

LPARAM

IParam);

参数wParam和IParam包含所钩消息的信息,比如鼠标位

置/状态、键盘按键等。nCode包含有关消息本身的信息,比如

是否从消息队列中移出。

先在钩子函数中实现自定义的功能,然后调用函数Call.

NextHookEx,把钩子信息传递给钩子链的下一个钩子函数。

(2)安装钩子

在程序初始化的时候,调用函数SetWindowsHookEx安装钩

子。其函数原型为:

HHOOK

SetWindowsHookEx(int

idHook,HOOKPROC

Ipf.,HIN—

STANCE

hMod,DWORD

dwThreadld);

参数idHook表示钩子类型,和钩子函数类型对应。比如

WH—KEYBOARD表示键盘钩子等。lpfn是钩子函数的地址。

hMod是钩子函数所在的实例的句柄。对于线程钩子,该参数为

NULL;对于系统钩子,该参数为钩子函数所在的DLL句柄。

dwThreadld指定钩子所监视的线程的线程号。对于全局(系统)

钩子,该参数为NULL。SetWindowsHookEx返回所安装的钩子

句柄。

(3)卸栽钩子

当不再使用钩子时,必须及时卸载。简单地调用函数

BOOL

UnhookWindowsHookEx(HHOOK

hhk)即可。

2HOOK

API(挂钩API)技术

HOOK

API是指截获特定进程或系统对某个API函数的调

用,使得API的执行流程转向指定的代码。Windows下的应用

程序都有自己的地址空间,它们只能调用自己地址空间中的函

数,所以在HOOKAPI之前,必须将一个可以代替API执行的自

定义函数(一般称这个函数为代理函数)的执行代码注入到目

标进程,然后再想办法将目标进程对该API的调用改为对注入

万方数据

到目标进程中的自定义函数的调用,这样即可实现拦截API函

数。Windows下的应用程序都建立在API函数之上,所以截获

API是一项相当有用的技术,它使得用户有机会干预其他应用

程序的程序流程。

HOOK

API时的代码注入方法

注入代码到目标进程是实现拦截API很蕈要的一步。比较

简单的方法是把要注入的代码写到DLL中,然后让目标进程加

载这个DLL。这就是所谓的DLL注入技术。如果在这个被注

入到目标进程的DLL中写一个与所要HOOK的API函数的签

名完全相同的函数(即代理函数),当DLL执行初始化代码的时

候,把目标进程对这个API的调用全部改为对代理函数的调用,

即可实现拦截API函数。通过编程实践可知,DLL注入技术有

以下几种:

3.1使用钩子注入DLL

我们知道,对系统钩子而言,当安装钩子的函数SetWindow-

sHookEx调用成功后,Windows在系统内部对系统中的所有进程

自动调用LoadLibrary函数,强迫它们加载包含钩子函数执行代

码的模块,这就是这些进程能够访问钩子函数的原因。从这里

可以得到一个重要启示,那就是如果我们创建一个系统钩子,并

将包含钩子函数执行代码的模块编译成DLL(当然这个DLL中

还必须包含代理函数的代码),就可以实现DLL的自动注入。

这就是所谓的使用钩子注入DLL。

使用Windows钩子注入特定DLL到其他进程,一般都安装

WH

GETMESSAGE钩子,这是因为Windows下的应用程序大部

分都需要调用GetMessage或PeekMessage函数从消息队列中获

取消息,所以它们都会加载钩子函数所在的DLL。

由于此处安装WH—GETMESSAGE钩子的目的仅仅是让其

他进程加载钩子函数所在的DLL,所以一般仅在钩子函数中调

用CallNextHookEx函数即可,如下面代码所示:

LRESULTWINAPI

GetMsgProc(int

code,WPARAM

wParam,

LPARAM

IParam)

{return::CaUNextHookEx(g_hHook,code,wParam,1Pamm);}

如果要将DLL注入到特定进程中,一般是将该进程中主线

程的线程ID传递给SetWindowsHookEx函数;而如果要将DLL

注入到所有进程中,安装一个系统范围内的钩子即可(将0作

为线程ID传递给SetWindowsHookEx函数)。

3.2

使用注册表注入DLL

若要插入一个DLL到链接系统模块User32.du的进程(一

般GUI程序都要使用User32.d11),可以简单地向下面的注册表

键下添加键值数据。

HKEY—LOCAL—MACHINE\SOImI'WARE、Microsoft\Windows

NT\Cur-

rentVersion\Windows\Applnit—DLLs

键值数据可以是单一的DLL名称,也可以是逗号或空格间

隔的DLL集合。所有这个键指定的DLL将被当前帐户下的每

个应用程序加载,它们是在User32.dll初始化的时候被加载的。

User32读取上面提到的键值,在DLL入口函数DllMain中为这

些DLL调用LoadLibrary函数。

这种方法仅仅对使用User32.dll的应用程序有效;另一个

限制是这个机制仅被Windows2000系列的操作系统支持。通

过注册表向进程插入DLL还有如下不足:

(1)为了激活/取消对进程的插入,不得不重新启动Win—