Skip to main content

Hooking

Hook,即钩子,在网络安全用语中,指的是拦截并且修改特定的 API 执行流程,通常用于 Debugging,逆向工程,游戏作弊,检测恶意软件行为。API Hook 将原有的 API 替换为自定义的以进行额外的检视,如果非恶意,则继而调用原有的 API,否则会被拦截。

安全产品,例如 EDR,可能会实施 SSDT HookingIAT Hooking内联 Hooking。不过对于 SSDT Hooking,因为是内核层的,虽然安全产品可以实施 SSDT Hooking 从而实现更彻底的检视,但也会被恶意软件用来实现文件、网络连接、注册表键等的隐藏。基于内核层的更改,无论目的是好是坏,都可能影响系统安全性、完整性、以及稳定性,因此微软后来引入了 PatchGuard 来阻止对内核的补丁。作为"补偿",微软引入了我们之前简述过的内核回调,供安全产品进行内核层面的检视。


IAT Hooking

我们在 PE 小节介绍过 IAT 表了,IAT 表记录了映像文件所引用的模块以及其中的导出函数。我们在编写恶意软件时,调用 Win32 API 或者 NTAPI 的话,则会使 IAT 表中增加该 API 以及其所在的模块。

以 calc 为例,我们使用 PE Bear 可以查看其在磁盘时候的 IAT 表,这时候 IAT 与 INT 是一致的,没有函数地址。但当 calc 被载入到内存中时,IAT 中会更新函数的地址。例如,我们在下图可以看到 KERNEL32 模块中第一个导入函数是 GetCurrentThreadId,当前 IAT 条目中的值是 HintName 表的 RVA。

 

image.png

在 WinDBG 中,我们印证了,并且该条目的值被更新成了函数的地址。

image.png

但如果,IAT 条目中的值被修改成安全产品模块的导出函数,那么是不是就意味着调用该函数的时候,安全产品都在检视了?IAT Hooking,就是这么一个原理。不过,如今安全产品,尤其是 EDR,主要使用下面要讲的内联 Hooking 进行函数调用检视。

 

内联 Hooking

内联 Hooking 是如今更主流的 Hooking 方案,EDR 通常会给 NTAPI 设置内联 Hook,因为 NTAPI 作为用户态与内核态的桥梁。

image.png

下图是常被恶意软件所利用的 NtWriteVirtualMemory,其 Win32 API 是 WriteProcessMemory。我们可以看到,第 2 条指令跳转到了别处,这是被 hook 的特征。当然了,不同的 EDR hook 的函数可能所有不同,hook 的指令位置也可能有所不同,例如有的 EDR 会覆盖 mov r10, rcx 这条指令。

image.png

而对于不怎么在恶意软件中被利用的良性 NTAPI,则没有被 hook 的迹象。

image.png

实际上,对于大多数 NTAPI,代码都形如下图,这是 syscall 的格式。至于和上图相差的几条指令,至少在 x64 中,并非必须的,也就是有着下述这几条指令,就可以完成 syscall。

mov r10, rcx
mov rax, [SSN]
syscall
ret

例如,NtAllocateVirtualMemory 是 VirtualAlloc 的 NTAPI 版本。

image.png