必备绝技--Hook大法( 整理 )

主要参考资料来源于看雪:

必备绝技–Hook大法(上)
http://bbs.pediy.com/showthread.php?t=42362

必备绝技–Hook大法(中)
http://bbs.pediy.com/showthread.php?t=42422

hook概念:是一种通过更改程序的数据结构或代码结构从而改变程序运行路线的一种方法。(纯属本人自己观点)
分类:从上面的概念来看,一种是改变程序的数据结构,如:IAT-hook,Dll-inject及Direct Kernel Object Manipulation(DKOM)。一种是Inline Function Hooking。
用途:现在这种方法普遍运用于各类程序中,如加壳,杀软,病毒,Rootkits等等。
本文从难以程度上主要分三块详细介绍:一.用户模式Hook:IAT-hook,Dll-inject二.内核模式Hook:ssdt-hook,idt-hook,int 2e/sysenter-hook三.Inline Function Hook;

1-4种方法作用于ring3,5种以后已经到了ring0.

一:ITA-HOOK(Import Address Table)输入地址表注入

需要了解win PE结构,现在应用程序中的大多数函数都是windows api,而这些函数一般都由几个系统dll导出,如user32.dll,kernel32.dll,advapi32.dll等。如果程序要运用这些函数,就的从这些dll文件中导入,程序会把导入的函数放到一个叫IAT的数据结构中。我们可以先找到自己需要hook的函数,然后把目标函数的地址改成我们自己的hook函数,最后在恢复到目标函数的地址。
局限性:

  1. 当程序运用一种叫late-demand binding技术,函数被调用时才定位地址,这样以来就不能在IAT中定位目标函数地址了;
  2. 当目标程序用动态加载(LoadLibrary)时,这种方法也将失效。
二:DLL-Injecting 即DLL注入

一般原理:Windows的注册表中有这样一个键值,HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_Dlls。在这个键下的值都会被系统的任何一个GUI程序(非命令行程序)所加载,其实就是只要程序调用了User32.dll,则User32.dll的DllMain函数在初始化时,会把这个键下的Dll自动加载。

局限性:

  1. 太明显;
  2. 可以执行自己的dll,但可能无法改变原程序执行逻辑。
三:Windows 消息钩子

微软自己定义了一个钩子函数(SetWindowsHookEx),这个钩子可以钩住系统的任何一类消息,并产生相关的回调函数。

局限性:

  1. SetWindowsHookEx可拦截类型是有限的,windows 支持的才可以;
  2. 会产生Dll体,虽然没有进程,但可以通过其他工具轻易发现。
四:线程远程注入(CreateRemoteThread、VirtualAllocEx、WriteProcessMemory)

局限性:

  1. 有时会失败;
  2. 注入其它程序了,一般杀软会报警。
五:SSDT-HOOK System service dispath table

 

1.系统组建

2. 调用过程

3. 通过KeServiceDescriptorTable获取SSDT表

Hook前的准备-改变SSDT内存的保护

四个有用的宏
SYSTEMSERVICE macro:可以获得由ntoskrnl.exe导出函数,以Zw开头函数的地址,这个函数的返回值就是Nt函数,Nt函数的地址就在SSDT中
SYSCALL_INDEX macro:获得Zw
函数的地址并返回与之通信的函数在SSDT中的索引。
这两个宏之所以能工作,是因为所有的Zw函数都开始于opcode:MOV eax, ULONG,这里的ULONG就是系统调用函数在SSDT中的索引。
HOOK_SYSCALL和UNHOOK_SYSCALL macros:获得Zw
函数的地址,取得他的索引,自动的交换SSDT中索引所对应的函数地址和我们hook函数的地址。
这四个宏具体是:

#define SYSTEMSERVICE(_func) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_func+1)]

#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)

#define HOOK_SYSCALL(_Function, _Hook, _Orig ) _Orig = (PVOID) InterlockedExchange( (PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)

#define UNHOOK_SYSCALL(_Func, _Hook, _Orig ) InterlockedExchange((PLONG) &MappedSystemCallTable[SYSCALL_INDEX(_Func)], (LONG) _Hook)

五:IDT-HOOK IDT(Interrupt Descriptor Table)中断描述符表(winxp,win2k3,vsta)

先在系统中找到IDT,然后确定0x2E在IDT中的地址,最后用我们的函数地址去取代它,这样以来,用户的进程(可以特定设置)一调用系统服务,我们的hook函数即被激发。

  1. IDT如何获取呢?SIDT指令;
  2. 中断。
六:SYSENTRY hook(xp后的系统)

首先获得sysentry的地址,然后改之。