模块 83 - NTDLL 取消挂钩 (Unhooking) - 简介
恶意软件开发课程 - NTDLL 取消挂钩 (Unhooking) - 简介
模块 83 - NTDLL 取消挂钩 (Unhooking) - 简介#
NTDLL 取消挂钩 (Unhooking) - 简介#
简介#
前面的模块展示了如何使用 Direct Syscalls(直接系统调用) 来绕过用户态挂钩 (Userland Hooks)。在本模块中,我们将介绍另一种实现相同目标的策略:取消挂钩 (Unhooking)。
💡 初学者提示:什么是取消挂钩 (Unhooking)?
类比理解: 想象 EDR 在你的办公桌(
ntdll.dll)上装了许多监控(Hooks)。
- 之前的策略(直接系统调用):你决定不在桌子上办公了,直接跑去地下的工厂(内核)干活,以此避开监控。
- 现在的策略(取消挂钩):你找了一张一模一样、但没有装监控的新桌子,悄悄把原来的旧桌子给换掉。这样你就能继续在大摇大摆地在桌面上干活,而 EDR 的监控却失效了。
这种技术的核心在于:将进程中被挂钩的 DLL 替换为一个未经修改的、干净的版本。
处理核心难点:.text 节替换#
替换整个 DLL 会涉及繁琐的 IAT(导入地址表)重新设置、重定位修复等任务。为了简化操作,我们通常只替换 DLL 中真正被挂钩的部分,即 .text 节。
.text 节包含了 DLL 导出的所有函数代码,也是监控代码(Hooks)被注入的地方。替换它需要以下关键信息:
- 基地址 (Base Address):
.text节在内存中的起始位置。 - 大小 (Size):
.text节占据的字节数。
这些信息可以在 PE 文件的 IMAGE_OPTIONAL_HEADER 中的 BaseOfCode 和 SizeOfCode 字段找到。
关键概念:文件 vs 内存中的对齐差异#
实现取消挂钩时,必须理解 DLL 在“磁盘上”和“内存中”的布局差异。
📚 知识扩展:为什么会有对齐差异?
- 磁盘对齐 (File Alignment):通常为 1024 字节 (1KB)。这是为了优化磁盘 I/O(读写速度),让硬件能够大块大块地读取。
- 内存对齐 (Section Alignment/Page Alignment):通常为 4096 字节 (4KB)。这是因为现代 CPU 和操作系统管理虚拟内存的最小单位是“页” (Page),通常就是 4KB。
偏移量的变化#
- 在磁盘上:多数 DLL 的
.text节文件偏移量 (Raw Offset) 是0x400(1024)。 - 在内存中:当 DLL 被加载到进程空间后,
.text节的虚拟偏移量 (Virtual Offset) 通常变为0x1000(4096)。
这种位移差异至关重要。当你从磁盘读取一个干净的 ntdll.dll 打算替换内存中的挂钩版本时,你必须根据读取方式(是作为原始文件读取,还是作为映像映射)来正确计算 .text 节的起始位置,否则你的数据拷贝将会完全错位,导致程序崩溃。
NTDLL 取消挂钩的几种获取来源#
在接下来的模块中,我们将学习如何从以下不同渠道获取“干净”的 ntdll.dll 副本:
- 来自磁盘 (From Disk):直接读取
C:\Windows\System32\ntdll.dll。 - 来自 KnownDlls 目录 (From KnownDlls):利用 Windows 内部维护的 DLL 缓存路径。
- 来自挂起状态的进程 (From a Suspended Process):从另一个未被 EDR 挂钩的“干净”进程中读取。
- 来自 Web 服务器 (From a Webserver):从远程服务器下载匹配版本的 DLL。
我们将逐一深入探讨这些实战方法。