钩取
钩取是一种截取信息、更改程序执行流向、添加新功能的技术。钩取的整个流程如下:
#使用反汇编器/调试器把握程序的结构与工作原理。
#开发需要的“钩子”代码,用于修改Bug、改善程序功能。
#灵活操作可执行文件与进程内存,设置“钩子”代码。
API是什么
API(Application Programming Interface,应用程序编程接口)。Windows OS中,用户程序要使用系统资源(内存、文件、网络、视频、音频等)时无法直接访问。这些资源都是由Windows OS直接管理,出于多种考虑(稳定性、安全、效率等),Windows OS禁止用户程序直接访问它们。用户程序需要使用这些资源时,必须向系统内核(Kernel)申请,申请的方法就是使用微软提供的Win32 API(或是其他OS开发公司提供的API)。也就是说,若没有API函数,则不能创建出任何有意义的应用程序,因为它不能访问进程、线程、内存、文件、网络、注册表、图片、音频以及其他系统资源。
为运行实际的应用程序代码,需要加载许多系统库(DLL)。所有进程都会默认加载kernel32.dll库,kernel.dll优惠加载ntdll.dll库。
用户模式中的应用程序代码要访问系统资源时,由ntdll.dll向内核模式提出访问申请,例如:
假设notepad.exe要打开c:\abc.txt文件,首先在程序代码中调用msvcrt!fopen() API,然后引发一系列的API调用,如下所示:
-msvcrt!fopen( )
kernel32!CreateFileW( )
ntdll!ZwCreateFile( )
ntdll!KiFastSystemCall( )
SYSENTER //IA-32 Instruction
->进入内核模式
如上所示,使用常规系统资源的API会经由kernel32.dll与ntdll.dll不断向下调用,最后通过SYSENTER命令进入
内核模式。
API钩取
通过API钩取技术可以实现对某些Win32 API调用过程的拦截,并获得相应的控制权限。使用API钩取技术的优势如下:
#在API调用前后运行用户的“钩子”代码。
#查看或操作传递给API参数或API函数的返回值。
#取消对API的调用或更改执行流,运行用户代码。
正常调用API
图29-2描述了正常调用API的情形。首先在应用程序代码区域中调用CreateFile() API,由于CreateFile() API是kernel32.dll的导出函数,所以kernel32.dll区域中的CreateFile() API会被调用执行并正常返回。
![90~GYVIUEFPQLW%G2RA_MC.png
钩取API调用
图29-3描述的是钩取kernel32!CreateFile()调用情形。用户先使用DLL注入技术将hook.dll注入目标进程的内存空间,然后用hook!MyCreateFile()钩取对kernel32!CreateFile()的调用。这样,每当目标进程要调用kernel32!CreateFile() API时都会先调用hook!MyCreateFile()。
![%UAE4G@A%_YY7]UXQH(_KK.png
钩取某函数的用处有很多,如调用它之前或之后运行用户代码,或者干脆阻止它调用执行等等。
技术图表
方法对象(是什么)
根据针对的对象(Object)不同,API钩取方法大致可以分为静态方法与动态方法。
静态方法针对的是“文件”,而动态方法针对的是进程内存。一般API钩取技术指动态方法。
位置(何处)
IAT
IAT将其内部的API地址更改为钩取函数地址。该方法的优点是实现起来非常简单,缺点是无法钩取不在IAT而在程序中使用的API(如:动态加载并使用DLL时。)
代码
系统库(*.dll)映射到进程内存时,从中查找API的实际地址,并直接修改代码。该方法应用范围非常广泛,具体实现中常有如下几种选择:
#使用JMP指令修改起始代码;
#覆写函数局部;
#仅更改必需部分的局部。
EAT
将记录在DLL的EAT中的API起始地址更改为钩取函数地址,也可以实现API。该方法从概念上看非常简单,但在具体实现上不如前面的Code方法简单、强大。所以修改EAT的这种方法并不常见。
技术(如何)
大致分为调试法与注入法,注入法又细分为代码注入与DLL注入两种
调试
调试法通过调试目标进程钩取API。调试器拥有被调试者(被调试进程)的所有权限(执行控制、内存访问等),所以可以向被调试进程的内存任意设置钩取函数。
此处的调试器不是指OD、IDA等,而是用户直接编写的、用来钩取程序。也就是说在用户编写的程序中使用调试API附加到目标进程,然后(执行处于暂停状态)设置钩取函数。重启运行时就能完全实现API钩取了。
也可以向已有调试器使用自动化脚本,自动钩取API。
注入
DLL注入
使用DLL注入技术可以驱使目标进程强制加载用户指定的DLL文件。使用该技术时,先在要注入的DLL中创建钩取代码与设置代码,然后在DllMain()中调用设置代码,注入的同时即可完成API钩取。
代码注入
代码注入不像DLL注入技术那样针对的是完整的PE映像,而是在执行代码与数据被注入的状态下直接获取自身所需API地址。访问代码中内存地址时需小心反问道错误的地址。
API
后续详细讲解。