第29章 API钩取:逆向分析之“花”

本文最后更新于:2022年5月19日 晚上

第29章API钩取:逆向分析之“花”
本章将讲解有关API钩取的内容,详细学习在用户模式下进行API钩取的多种技术。

29.1 钩取

代码逆向分析中,钩取(Hooking)是一种截取信息、更改程序执行流向、添加新功能的技术。钩取的整个流程如下:

□使用反汇编器/调试器把握程序的结构与工作原理;

□开发需要的“钩子”代码,用于修改Bug、改善程序功能;

□灵活操作可执行文件与进程内存,设置“钩子”代码。

上述这一系列的工作就是代码逆向分析工程的核心(Core)内容,所以“钩取”被称为“逆向分析之花”。

钩取技术多种多样,其中钩取Win32 API的技术被称为API钩取。它与消息钩取共同广泛应用于用户模式。API钩取是一种应用范围非常宽泛的技术,希望各位认真学习并掌握。

(1)分析程序时若有程序源代码,大部分情况都不需要使用钓取技术。但是在某些特殊情况(无源代码或难以修改源代码)下使用钓取技术是非常有必要的。

(2)消息钓取的相关内容请参考第21章

29.2 API是什么

学习API钩取前首先要了解什么是API ( Application Programming Interface,应用程序编程接口)。Windows OS中,用户程序要使用系统资源(内存、文件、网络、视频、音频等)时无法直接访问。这些资源都是由Windows OS直接管理的,出于多种考虑(稳定性、安全、效率等),Windows OS禁止用户程序直接访问它们。用户程序需要使用这些资源时,必须向系统内核(Kernel)申请,申请的方法就是使用微软提供的Win32 API (或是其他OS开发公司提供的API )。也就是说,若没有API函数,则不能创建出任何有意义的应用程序(因为它不能访问进程、线程、内存、文件、网络、注册表、图片、音频以及其他系统资源)。图29-1大致描述岀了32位Windows
OS进程内存的情况。

图29-1 用户模式与内核模式

为运行实际的应用程序代码,需要加载许多系统库(DLL)。所有进程都会默认加载kernel32.dll库,kernel32.dll又会加载ntdll.dll库。

请注意一些例外情况:某些特定系统进程(如:smss.exe )不会加载kernel32.dll库。此外,GUI应用程序中,user32.dll与gdi32.dll是必需的库。

用户模式中的应用程序代码要访问系统资源时,由ntdll.dll向内核模式提岀访问申请。下面用一个例子简单说明。
假设notepad.exe要打开c:\abc.txt文件,首先在程序代码中调用msvcrt!fopen() API,然后引发一系列的API调用,如下所示:

1
2
3
4
5
6
-msvcrt!fopen()
kernel32!CreateFileW()
ntdll!ZwCreateFile()
ntdll!KiFastSystemCall()
SYSENTER // IA-32 Instruction
→进入内核模式

如上所示,使用常规系统资源的API会经由kernel32.dll与ntdll.dll不断向下调用,最后通过SYSENTER命令进人内核模式。

29.3 API 钩取

通过API钩取技术可以实现对某些Win32 API调用过程的拦截,并获得相应的控制权限。使用API钩取技术的优势如下:

□在API调用前/后运行用户的“钩子”代码。

□查看或操作传递给API的参数或API函数的返回值。

□取消对API的调用,或更改执行流,运行用户代码。

对照图29-2可以更好地理解以上内容。

29.3.1 正常调用API

图29-2描述了正常调用API的情形。首先在应用程序代码区域中调用CreateFile() API,由于CreateFile() API是kernel32.dll的导出函数,所以,kernel32.dll区域中的CreateFile() API会被调用执行并正常返回。

图29-2 正常调用API

29.3.2 钩取API调用

图29-3描述的是钩取kernel32!CreateFile()调用的情形。用户先使用DLL注入技术将hook.dll注入目标进程的内存空间,然后用hook!MyCreateFile()钩取对kernel32!CreateFile()的调用(有多种方法可以设置钩取函数)。这样,每当目标进程要调用kemd32!CreateFile() API时都会先调用hook!MyCreateFile()。

图29-3 钩取API调用

钩取某函数的目的有很多,如调用它之前或之后运行用户代码,或者干脆阻止它调用执行等等。实际操作中只要根据自身需要灵活运用该技术即可。这也是API钩取的基本理念。

实现API钩取的方法多种多样,但钩取的基本概念是不变的。只要掌握了上面的概念,就能 很容易地理解后面讲解的具体实现方法。

29.4 技术图表

图29-4是一张技术图表(Tech Map),涵盖了API钩取的所有技术内容。

图29-4 API钩取技术图表

借助这张技术图表,就能(从技术层面)轻松理解前面学过的(此前都是一头雾水)有关API钩取的内容。钩取API时,只要根据具体情况从图表中选择合适的技术即可(应用最广泛的技术已用下划线标出)。

下面通过示例逐一讲解图表中的技术

29.4.1 方法对象(是什么)

首先是关于API钩取方法(Method )的分类,根据针对的对象( Object)不同,API钩取方法大致可以分为静态方法与动态方法。

静态方法针对的是“文件”,而动态方法针对的是进程内存。一般API钩取技术指动态方法,当然在某些非常特殊的情形下也可以使用静态方法。关于这两种方法的说明见表29-1。

image-20220225160340360

静态方法在API钩取中并不常用,这里只简单提及并跳过。

29.4.2 位置(何处)

技术图表中的这一栏用来指出实施API钩取时应该操作哪部分(通常有3个部分)。

IAT

IAT将其内部的API地址更改为钩取函数地址。该方法的优点是实现起来非常简单,缺点是无法钩取不在IAT而在程序中使用的API (如:动态加载并使用DLL时)。

代码

系统库(*.dll)映射到进程内存时,从中查找API的实际地址,并直接修改代码。该方法应用范围非常广泛,具体实现中常有如下几种选择:

□使用JMP指令修改起始代码;

□覆写函数局部;

□仅更改必需部分的局部。

EAT

将记录在DLL的EAT中的API起始地址更改为钩取函数地址,也可以实现API钩取。这种方法从概念上看非常简单,但在具体实现上不如前面的Code方法简单、强大,所以修改EAT的这种方法并不常用。

29.4.3 技术(如何)

技术图表中的这一栏是向目标进程内存设置钩取函数的具体技术,大致分为调试法与注入法两类,注入法又细分为代码注入与DLL注入两种。

调试

调试法通过调试目标进程钩取API。可能有人不太明白这句话的意思,“那不是调试吗,怎么会是API钩取呢?”调试器拥有被调试者(被调试进程)的所有权限(执行控制、内存访问等),所以可以向被调试进程的内存任意设置钩取函数。

这里所说的调试器并不是OllyDbg、WinDbg、IDAPro等,而是用户直接编写的、用来钩取的程序。也就是说,在用户编写的程序中使用调试API附加到目标进程,然后(执行处于暂停状态)设置钩取函数。这样,重启运行时就能完全实现API钩取了(XP以上的系统中也可在被调试者终止之前分离(Detach )调试器)。

当然也可以向已有调试器(OllyDbg、WinDbg、IDAPro )使用自动化脚本,自动钩取API。这种方法的优点是,只要顺利实现,就能获得(对一个进程的)非常强大的钩取效果。不仅可以钩取API,还可以根据需要完全控制程序的执行流向。使用这种方法,即便是在钩取API的过程中,用户也可以暂停程序运行,进行添加、修改、删除API钩取等操作(这是与其他方法最大的不同)。不足之处是需要用户具备调试器的相关知识(或自动化脚本的知识),并且需要大量测试以保证行为的稳定性。这些不足导致该方法(尽管非常强大)的实际应用并不广泛。

注入

注入技术是一种向目标进程内存区域进行渗透的技术,根据注入对象的不同,可细分为DLL注入与代码注入两种,其中DLL注入技术应用最为广泛。

  • DLL注入
    使用DLL注入技术可以驱使目标进程强制加载用户指定的DLL文件(关于DLL注入技术的详细说明请参考第23章)。使用该技术时,先在要注入的DLL中创建钩取代码与设置代码,然后在DllMain()中调用设置代码,注入的同时即可完成API钩取。

  • 代码注入
    代码注入技术比DLL注入技术更发达(更复杂),广泛应用于恶意代码(病毒、ShellCode等)(杀毒软件能有效检测出DLL注入操作,却很难探测到代码注入操作,所以恶意代码大量使用代码注入技术,以防被杀毒软件查杀)。代码注入技术实现起来要略复杂一些。原因在于,它不像DLL注入技术那样针对的是完整的PE映像,而是在执行代码与数据被注入的状态下直接获取自身所需API地址来使用的。访问代码中的内存地址时必须十分小心,防止访问到错误地址(关于代码注入技术的详细讲解请参考第27章)。

29.4.4 API

技术图表最后一列给岀各技术具体实现过程中要使用的API。现在大致浏览即可,后面讲解各技术时会详细说明。

除了技术图表中列出的API外,访问其他进程内存时也常常使用OpenProcess()、WriteProcessMemory()、ReadProcessMemory()等 API。

上述讲解十分冗长,虽然令人有些厌倦,但继续学习具体技术之前,先掌握这些理论是十分必要的。若能通过上面的技术图表从理论上掌握所有技术,那么后面的实战中就会轻松得多,并且钩取API时也能快速找到符合具体情况的技术。

后面我们会逐一学习技术图表中的各种方法(省略对静态方法的说明),通过相应的练习示例再详细讲解。

参考

《逆向工程核心原理》 第29章


第29章 API钩取:逆向分析之“花”
https://m0ck1ng-b1rd.github.io/1999/02/27/逆向工程核心原理/第29章 API钩取:逆向分析之“花”/
作者
何语灵
发布于
1999年2月27日
许可协议