0%
毅种循环

模块 85 - NTDLL 取消挂钩 (Unhooking) - 来自 KnownDlls 目录

恶意软件开发课程 - NTDLL 取消挂钩 (Unhooking) - 来自 KnownDlls 目录


模块 85 - NTDLL 取消挂钩 (Unhooking) - 来自 KnownDlls 目录#

NTDLL 取消挂钩 (Unhooking) - 来自 KnownDlls 目录#

简介#

获取干净版本 ntdll.dll 的另一种方法是通过访问 KnownDlls 目录。

💡 初学者提示:什么是 KnownDlls?

类比理解: 想象你每次做饭都要去菜市场(磁盘)买同样的调料。为了快一点,你在厨房的**备餐台(KnownDlls)**上预先摆放了一套常用的调料。

  • Windows 也是如此:它会将一些极其常用的 DLL 加载到内存中的一个特殊区域。当新的程序启动需要这些 DLL 时,Windows 直接从内存里的“备餐台”映射过去,而不需要再从慢速的硬盘里读取一份。
  • 我们的机会:由于这个备餐台是由系统直接维护的,它通常包含的是最原始、最干净(未被 EDR 挂钩)的 DLL 镜像。

访问 KnownDlls#

在现代 Windows 版本中,KnownDlls 并不是一个真实的磁盘文件夹,而是操作系统内核维护的一个对象目录。你可以使用 Sysinternals 的 WinObj 工具查看其中的内容(通常位于 \KnownDlls 路径下)。

实现细节:利用 NtOpenSection#

由于 KnownDlls 在内核中的独特性,传统的 OpenFileMapping WinAPI 在访问 \KnownDlls\ntdll.dll 时往往会失败。因此,我们需要使用它的底层 Native API(原生 API)NtOpenSection

NtOpenSection 函数原型#

NTSTATUS NtOpenSection(
  OUT PHANDLE             SectionHandle,    // 接收打开的节句柄
  IN  ACCESS_MASK         DesiredAccess,    // 访问权限,通常设置为 SECTION_MAP_READ
  IN  POBJECT_ATTRIBUTES  ObjectAttributes  // 对象属性,包含路径名
);
c

为了使用此函数,我们需要使用 InitializeObjectAttributes 宏来初始化 OBJECT_ATTRIBUTES 结构,并将路径指向 \KnownDlls\ntdll.dll

核心实现:MapNtdllFromKnownDlls#

替换逻辑#

一旦我们通过上述函数获取了干净的映像基址,就可以像 Module 84 一样调用 ReplaceNtdllTxtSection

📚 知识扩展:内存对齐的一致性

由于已知 DLL 是以“节” (Section) 的形式被打开并映射的,它的 .text 节偏移量将始终保持为 VirtualAddress (通常是 4096)。这意味着在计算替换偏移时,它的逻辑与“磁盘映射”模式完全一致,极大地降低了数据对齐错误的风险。

为什么这个方法更优秀?#

  1. 更隐蔽:不涉及直接的磁盘文件读取行为(不触发 CreateFile 获取 System32 下文件的警报)。
  2. 更可信:使用的是系统自身管理并保证一致性的“权威副本”。
  3. 版本匹配: KnownDlls 中的版本必然与当前运行系统的版本完全一致,避免了从外网下载可能导致的版本冲突。

总结#

利用 KnownDlls 是执行高质量 Unhooking(取消挂钩)的首选实战方案之一。它兼顾了隐蔽性与稳定性,是绕过成熟 EDR 方案的关键技术。