Yair-Men/HeapHunter
GitHub: Yair-Men/HeapHunter
利用 C++ 虚函数表机制在堆上劫持 AMSI provider 的 COM 对象,实现无内存修补的 AMSI 绕过。
Stars: 18 | Forks: 1
# HeapHunter
## 概述
一种独特的技术,利用 C++ 的内部机制,特别是 Pure Virtual Functions 和 Abstract Classes,在不修补 `.text` section 内存中任何 RX 的情况下劫持 AMSI。
## 解释
### C++ 中的 vftable 和 vfptr(多态)
在 C++ 中实现接口(Abstract class 或 pure virtual function)时,编译器会为该类生成一个 vftable(虚函数表)。这个 vftable 包含了指向该类虚函数的指针。
此类实例中的第一个成员是指向 `vftable` 的指针,称为 `vfptr`(虚函数指针)。
当调用实例的虚函数时,系统会查找 `vfptr` 以找到 `vftable`,从 vftable 中检索函数地址,然后调用该函数。 ### AMSI 和 COM AMSI provider 本质上是一个 COM 对象。
要创建一个 COM 对象,类必须实现 `IUnknown` 接口。
要创建一个 AMSI provider,类必须实现 `IAntimalwareProvider(2)` 接口(该接口也继承自 `IUnknown`) ### 初始化 COM 对象 (AMSI) 的初始化是通过 `CoCreateInstance` 函数完成的,该函数会在**堆**上为 COM 对象分配内存。 ### 狩猎 AMSI $HeapHunter$ 实现了 `IAntimalwareProvider` 接口,当调用该接口扫描缓冲区时不执行任何操作。
然后它实例化一个已注册 AMSI provider 的实例(合法的)
以获取 `vfptr` 指向的值。
由于使用的是同一个 `vftable`,该值在所有实例中都是相同的。 ### 劫持 AMSI $HeapHunter$ 扫描堆并寻找该值。
一旦找到,它会用我们的 `vfptr`(指向我们自己的 vftable)覆盖其 `vfptr`。
本质上就是劫持合法 provider 的 `vftable`。 ### 结果 当 AMSI 调用 COM 对象上的方法(例如 `IAntimalwareProvider::Scan`)时,
它将调用我们的方法,而不是合法 AMSI provider 的方法。 结果是 `AMSI.dll` 保持原样,provider 的 DLL 保持原样,
合法 AMSI provider 的 COM 实例仍然已注册并位于内存中,
但其 `vfptr` 现在指向我们的 `vftable`。 简单来说: - 无软件/硬件断点 - 不修补 `.text` 中的 RX 内存 - 有 AMSI 但无 AMSI :) 这里的解决方案仅仅是一个早期阶段的 POC,可以通过多种方式进行改进(等我有时间的时候)。 此技术可能被利用来劫持堆上分配的其他 COM 对象(ETW ?!)。 ## 视频 https://github.com/user-attachments/assets/bc01a661-ce3e-46f7-bad9-5f4ebe8c6f13
当调用实例的虚函数时,系统会查找 `vfptr` 以找到 `vftable`,从 vftable 中检索函数地址,然后调用该函数。 ### AMSI 和 COM AMSI provider 本质上是一个 COM 对象。
要创建一个 COM 对象,类必须实现 `IUnknown` 接口。
要创建一个 AMSI provider,类必须实现 `IAntimalwareProvider(2)` 接口(该接口也继承自 `IUnknown`) ### 初始化 COM 对象 (AMSI) 的初始化是通过 `CoCreateInstance` 函数完成的,该函数会在**堆**上为 COM 对象分配内存。 ### 狩猎 AMSI $HeapHunter$ 实现了 `IAntimalwareProvider` 接口,当调用该接口扫描缓冲区时不执行任何操作。
然后它实例化一个已注册 AMSI provider 的实例(合法的)
以获取 `vfptr` 指向的值。
由于使用的是同一个 `vftable`,该值在所有实例中都是相同的。 ### 劫持 AMSI $HeapHunter$ 扫描堆并寻找该值。
一旦找到,它会用我们的 `vfptr`(指向我们自己的 vftable)覆盖其 `vfptr`。
本质上就是劫持合法 provider 的 `vftable`。 ### 结果 当 AMSI 调用 COM 对象上的方法(例如 `IAntimalwareProvider::Scan`)时,
它将调用我们的方法,而不是合法 AMSI provider 的方法。 结果是 `AMSI.dll` 保持原样,provider 的 DLL 保持原样,
合法 AMSI provider 的 COM 实例仍然已注册并位于内存中,
但其 `vfptr` 现在指向我们的 `vftable`。 简单来说: - 无软件/硬件断点 - 不修补 `.text` 中的 RX 内存 - 有 AMSI 但无 AMSI :) 这里的解决方案仅仅是一个早期阶段的 POC,可以通过多种方式进行改进(等我有时间的时候)。 此技术可能被利用来劫持堆上分配的其他 COM 对象(ETW ?!)。 ## 视频 https://github.com/user-attachments/assets/bc01a661-ce3e-46f7-bad9-5f4ebe8c6f13
标签:AMSI绕过, COM对象劫持, Conpot, C++编程, HeapHunter, IAntimalwareProvider, Windows安全, 二进制安全, 云资产清单, 内存堆劫持, 威胁检测, 安全测试, 恶意软件检测逃逸, 攻击性安全, 无Patch绕过, 私有化部署, 端点可见性, 虚函数表篡改, 逆向工程, 防御规避