DErDYAST1R/NmiCallbackBlocker
GitHub: DErDYAST1R/NmiCallbackBlocker
通过修改内核 NMI 回调链和处理器亲和性来阻断反作弊系统 NMI 扫描的 Windows 内核驱动概念验证项目。
Stars: 167 | Forks: 17
# 警告 ⚠️
***本项目不包含任何反作弊保护措施,请使用一个已有的、未被检测的基础驱动程序,这只是一个概念验证项目。***
# 说明
该漏洞利用方式涉及在内核内存中扫描特定特征码,并修改处理器关联掩码以阻止 NMI 执行。该方法采用了规避检测和追踪的技术。
# 功能
1. 我使用 23H2 版本的 NMI_IN_PROGRESS 特征码对其进行特征扫描,并将该结构导入为 (PKNMI_HANDLER_CALLBACK) 以便进行 DKOM 修改。
```
// nmi_in_progress function (signature)
char NmiSignature[] = "\x81\x25\x00\x00\x00\x00\x00\x00\x00\x00\xB9\x00\x00\x00\x00"; // use XOR to encrypt this (will get sig scanned by ac)
char NmiSignatureMask[] = "xx????????x????"; // use XOR to encrypt this (will get sig scanned by ac)
uintptr_t nmi_in_progress = modules::find_pattern(ntos_base_address,
NmiSignature,
NmiSignatureMask);
return reinterpret_cast(nmi_in_progress);
```
2. 导入结构后,我遍历 KiNmiCallbackList 并更改特定资产的进程亲和性,以阻止 NMI 执行。
```
PKNMI_HANDLER_CALLBACK KiNmiCallbackListHead = nullptr;
extern "C" NTSTATUS PreventNMIExecution() {
KiNmiCallbackListHead = SigscanKiNmiCallbackListHead();
PKNMI_HANDLER_CALLBACK CurrentNMI = KiNmiCallbackListHead;
while (CurrentNMI) {
uint8_t* nmi_in_progress = reinterpret_cast(KiNmiCallbackListHead);
while (*nmi_in_progress != 0x48) {
++nmi_in_progress;
}
nmi_in_progress = reinterpret_cast(reinterpret_cast(nmi_in_progress) + 3);
auto irql = KfRaiseIrql(0); // Use Udman Spoof to not get logged by this
ULONG cores = KeQueryActiveProcessorCount(NULL); // Use Udman Spoof to not get logged by this
for (auto i = 0ul; i < cores; ++i) {
KeInterlockedSetProcessorAffinityEx((PKAFFINITY_EX)nmi_in_progress, i); // Use Udman Spoof to not get logged by this
InterlockedBitTestAndSet64(reinterpret_cast(nmi_in_progress), i);
}
KeLowerIrql(irql); // Use Udman Spoof to not get logged by this
CurrentNMI = CurrentNMI->Next;
}
return STATUS_SUCCESS;
}
```
# EAC NMI Walker
```
BOOLEAN EAC::NmiCallbackRoutine( PVOID Context, BOOLEAN Handled )
{
auto* callback_context = reinterpret_cast< EAC_NMI_CALLBACK_CONTEXT* >( Context );
auto* data = &callback_context->data_blocks[ KeGetCurrentProcessorNumberEx( NULL ) ];
if ( !data->gdtr_value.base )
{
const auto* current_thread = PsGetCurrentThread();
__sgdt( &data->gdtr_value );
data->thread_id = PsGetCurrentThreadId();
data->thread_process_id = PsGetThreadProcessId( current_thread );
data->thread_SystemCallNumber = current_thread->SystemCallNumber;
data->thread_StartAddress = current_thread->StartAddress;
data->thread_StackLimit = current_thread->StackLimit;
data->thread_StackBase = current_thread->StackBase;
data->pcr_HalReserved_8 = KeGetPcr()->HalReserved[ 8 ];
data->cr3_value = __readcr3();
data->stack_copy_number_of_bytes = 1024;
std::memcpy( &data->stack_copy, _AddressOfReturnAddress(), 1024 );
_InterlockedIncrement( &callback_context->counter );
}
return TRUE;
}
// Not My Code
```
# 注意事项
你需要添加并使用,因为默认情况下这会被检测用于追踪和跟踪调用(如果使用标准的 NtLoad 或标准服务运行)。
- 使用 Udman 欺骗调用 以避免追踪
- 对字符串和特征码使用 XOR 加密
- SpoofCall 和 SpoofFunc 函数
# PatchGuard & HVCI
这将触发 PatchGuard 保护,如果试图绕过 PatchGuard 将触发 HyperGuard 高级保护;如果你还使用了 HVCI(例如在 Valorant/VGK 中),这将导致蓝屏死机 (BSOD) 或阻止修改 NMI 列表的请求,从而导致没有任何变化。我已经在我个人的驱动程序中独立解决了这些问题,但如果你有针对 PatchGuard / HyperGuard 的绕过方法且不使用 HVCI 保护(针对 BE/EAC),这将有效。
# 联系方式
Discord 用户名;bloodieys
标签:0day挖掘, DKOM, DOM解析, EDR对抗, NMI回调, rootkit, T1059, UML, Web报告查看器, Windows内核, 内核内存操作, 内核利用, 内核回调阻断, 内核安全, 反作弊, 反调试, 处理器亲和性, 字典生成, 安全攻防, 游戏安全, 特征扫描, 白帽子, 网络安全监控, 驱动开发