0%
毅种循环

模块 56 - IAT 隐藏与混淆 - 自定义伪句柄 (Pseudo Handles)

恶意软件开发课程 - IAT 隐藏与混淆 - 自定义伪句柄 (Pseudo Handles)


模块 56 - IAT 隐藏与混淆 - 自定义伪句柄 (Pseudo Handles)#

[!IMPORTANT] 本知识库声明

本知识库由本人整理自互联网 MalDev Academy 泄露资源,并由本人手动翻译为中文,过程中增加了大量关键技术提示实践心得

  1. 内容完整性:并未修改任何核心代码与技术逻辑,仅做汉化与注释加强。
  2. 版权归属:原始知识产权归原作者/官方所有。
  3. 支持正版:本仓库仅供内部学习交流,如果您有经济能力,请务必支持正版课程
  4. 权利申诉:如相关内容侵犯了您的权益,请联系我,我将立即核实并删除。

IAT 隐藏与混淆 - 自定义伪句柄#

简介#

如前所述,利用 API 哈希来掩盖程序的 IAT 是一种有效的方法。然而,有时如果可行的话,直接替换 WinAPI 本身可以进一步增强 IAT 的隐密性,减少哈希值的数量,并降低与 API 哈希算法相关的潜在启发式特征。此外,为 WinAPI 函数实现自定义代码可以跨各种项目使用,简化了整个 IAT 隐藏过程的自动化。

话虽如此,本模块将通过使用调试器分析两个检索 伪句柄 (Pseudo Handles) 的函数,然后创建它们的自定义版本。我们的目标同样是避免这些函数出现在 IAT 中,而且这次不需要借助于 API 哈希。我们将分析的函数是:

什么是伪句柄?#

伪句柄 (Pseudo Handle) 是一种特殊类型的句柄,它并不对应具体的系统资源项,而是作为对当前进程或线程的一种“硬编码”引用。

💡 初学者提示:真假句柄的区别

  • 真句柄:像是一个临时借书证,你必须通过 OpenProcess 等函数去申请,用完还要通过 CloseHandle 还回去。
  • 伪句柄:像是一个特殊的代码(比如“我自己”),它是永远有效的,不需要申请,也不需要(也不能)关闭。

分析函数#

本节我们将使用 xdbg 调试器分析这两个函数,以了解其内部工作原理。

首先,在导出 DLL kernel32.dll 中搜索 GetCurrentProcess 函数。

图片
图片

跳转到该地址,注意到一条 jmp 指令。

图片
图片

跟随跳转到达函数代码。指令 or rax, FFFFFFFFFFFFFFFF 会将 RAX 寄存器设置为该值,随后 ret 指令返回 0xFFFFFFFFFFFFFFFF0xFFFFFFFFFFFFFFFF 的补码表示即为 -1

图片
图片

同样的步骤,分析 GetCurrentThread 函数。该函数返回 0xFFFFFFFFFFFFFFFE,其补码表示即为 -2

图片
图片

自定义实现#

既然 GetCurrentProcess 返回 -1,而 GetCurrentThread 返回 -2,我们可以直接用宏来替代它们。注意需要将这些数值强制转换为 HANDLE 类型。

// 定义用于替代 GetCurrentProcess 的宏
#define NtCurrentProcess() ((HANDLE)-1) 

// 定义用于替代 GetCurrentThread 的宏
#define NtCurrentThread()  ((HANDLE)-2) 
c

32 位系统#

64 位和 32 位的这些函数区别仅在于 HANDLE 数据类型的大小。在 32 位系统中,HANDLE 是 4 字节的。下图展示了 32 位系统下的 GetCurrentProcess

图片
图片


🎯 总结#

在本模块中,我们学习了:

  1. 直接替换法:对于功能极其简单的 API,不需要费力去哈希它们,直接使用它们的底层逻辑即可。
  2. 伪句柄原理:理解了 -1 和 -2 在 Windows 内核中分别代表“当前进程”和“当前线程”。
  3. 零依赖方案:在代码中使用 NtCurrentProcess() 宏不仅能达到同样的效果,而且不会在 IAT 中留下任何痕迹。

💡 关键要点

  • 不要关闭伪句柄:千万不要对伪句柄调用 CloseHandle,这不仅没有意义,还可能在某些情况下引起异常。
  • 通用性:这类宏定义在大多数绕过或注入场景中都非常实用,它让代码更整洁且更难被检测。

📚 下一步学习

下一个模块将介绍 IAT Hiding & Obfuscation - Compile Time API Hashing。我们将学习一种更高端的技巧:让编译器在生成代码时自动帮我们算好哈希,从而彻底杜绝代码中出现显式的哈希计算。