模块 56 - IAT 隐藏与混淆 - 自定义伪句柄 (Pseudo Handles)
恶意软件开发课程 - IAT 隐藏与混淆 - 自定义伪句柄 (Pseudo Handles)
模块 56 - IAT 隐藏与混淆 - 自定义伪句柄 (Pseudo Handles)#
[!IMPORTANT] 本知识库声明
本知识库由本人整理自互联网 MalDev Academy 泄露资源,并由本人手动翻译为中文,过程中增加了大量关键技术提示与实践心得。
- 内容完整性:并未修改任何核心代码与技术逻辑,仅做汉化与注释加强。
- 版权归属:原始知识产权归原作者/官方所有。
- 支持正版:本仓库仅供内部学习交流,如果您有经济能力,请务必支持正版课程。
- 权利申诉:如相关内容侵犯了您的权益,请联系我,我将立即核实并删除。
IAT 隐藏与混淆 - 自定义伪句柄#
简介#
如前所述,利用 API 哈希来掩盖程序的 IAT 是一种有效的方法。然而,有时如果可行的话,直接替换 WinAPI 本身可以进一步增强 IAT 的隐密性,减少哈希值的数量,并降低与 API 哈希算法相关的潜在启发式特征。此外,为 WinAPI 函数实现自定义代码可以跨各种项目使用,简化了整个 IAT 隐藏过程的自动化。
话虽如此,本模块将通过使用调试器分析两个检索 伪句柄 (Pseudo Handles) 的函数,然后创建它们的自定义版本。我们的目标同样是避免这些函数出现在 IAT 中,而且这次不需要借助于 API 哈希。我们将分析的函数是:
- GetCurrentProcess ↗ - 检索调用进程的伪句柄。
- GetCurrentThread ↗ - 检索调用线程的伪句柄。
什么是伪句柄?#
伪句柄 (Pseudo Handle) 是一种特殊类型的句柄,它并不对应具体的系统资源项,而是作为对当前进程或线程的一种“硬编码”引用。
💡 初学者提示:真假句柄的区别
- 真句柄:像是一个临时借书证,你必须通过
OpenProcess等函数去申请,用完还要通过CloseHandle还回去。- 伪句柄:像是一个特殊的代码(比如“我自己”),它是永远有效的,不需要申请,也不需要(也不能)关闭。
分析函数#
本节我们将使用 xdbg 调试器分析这两个函数,以了解其内部工作原理。
首先,在导出 DLL kernel32.dll 中搜索 GetCurrentProcess 函数。

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

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

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

自定义实现#
既然 GetCurrentProcess 返回 -1,而 GetCurrentThread 返回 -2,我们可以直接用宏来替代它们。注意需要将这些数值强制转换为 HANDLE 类型。
// 定义用于替代 GetCurrentProcess 的宏
#define NtCurrentProcess() ((HANDLE)-1)
// 定义用于替代 GetCurrentThread 的宏
#define NtCurrentThread() ((HANDLE)-2) c32 位系统#
64 位和 32 位的这些函数区别仅在于 HANDLE 数据类型的大小。在 32 位系统中,HANDLE 是 4 字节的。下图展示了 32 位系统下的 GetCurrentProcess。

🎯 总结#
在本模块中,我们学习了:
- 直接替换法:对于功能极其简单的 API,不需要费力去哈希它们,直接使用它们的底层逻辑即可。
- 伪句柄原理:理解了 -1 和 -2 在 Windows 内核中分别代表“当前进程”和“当前线程”。
- 零依赖方案:在代码中使用
NtCurrentProcess()宏不仅能达到同样的效果,而且不会在 IAT 中留下任何痕迹。
💡 关键要点
- 不要关闭伪句柄:千万不要对伪句柄调用
CloseHandle,这不仅没有意义,还可能在某些情况下引起异常。- 通用性:这类宏定义在大多数绕过或注入场景中都非常实用,它让代码更整洁且更难被检测。
📚 下一步学习
下一个模块将介绍 IAT Hiding & Obfuscation - Compile Time API Hashing。我们将学习一种更高端的技巧:让编译器在生成代码时自动帮我们算好哈希,从而彻底杜绝代码中出现显式的哈希计算。