前言
最近看到各位师傅疯狂蹂躏TX安全竞赛的题,文章写得好到让我泪流满面。不由的羡慕起来师傅们的技术...

ETW HOOK是一个经久不衰的话题了,本质上是微软的漏洞,再微软进行记录ETW时候系统调用的时候,被ETW相关组件拦截跑到记录的代码,因为涉及到的代码量实在太大,微软这里面老是会有一些函数指针的使用,从而可以把他替换成我们自己函数回调,而不会触发PG拦截系统调用(无法拦截直接内核NtXXX
)。
早期的ETW HOOK实现概要
早期的ETW HOOK替换的一些HalPxx指针已经被PG监控
43bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6W2N6X3g2J5k6r3!0^5i4K6u0r3d9h3&6X3K9h3&6A6N6s2W2t1L8$3!0C8
到后来第二个版本的ETW,原理和EAC接管系统异常差不多,这一版本的也是再ETW HOOK的必经之路上面修改函数指针:
原理是EAC通过修改HalpStallCounter[0xE]
的这个位置,以及NtGlobalFlags
这个标志位。
HalpStallCounter[0xE] 函数原本是HalpTscQueryCounterOrdered
,修改这个之后,一些异常(包括kernel mode)就会走到这从而被EAC接管;
下图是发生异常时候的调用栈从windg可以看到,EAC
修改了HalpStallCounter
来进行接管异常

可以兼容最新版 windows 的ETW HOOK
第二版的ETW Hook现在还可以用,但是用起来非常复杂,光是不同系统兼容、修栈就要耗费巨大精力。
因此这里参考国外的一个大佬文章,他提出了更新版本的ETW-HOOK,具体原理如下
WINDOWS的.data节一般是存放可以变的全局变量的,所谓的偷指针就是修改.data节区的指针。
而在这里,最好玩的是HalPrivateDispatchTable
,这个是windows 的ntoskenl.exe为了方便使用HAL的导出函数,把他们存放在统一的地方。而HAL,用到的地方肯定很多,ETW 正是如此。
我们来看一下系统调用ETW的调用路径


这里其实可以看到,call rax
其实就是正常的系统调用,而再进入ETW系统调用之前,他把原始的系统调用存放在了栈上,这就导致我们拦截到ETW的时候,可以修改栈上的位置,来进行HOOK Syscall。
进入这个函数


如果说之前无法定位,现在可以通过这个栈上面的magic number
来定位syscall的地址,从而替换了。
继续跟到EtwTraceSiloKernelEvent
里面,可以发现,无论参数怎么样,这个函数调用了EtwpLogKernelEvent
void __fastcall EtwTraceSiloKernelEvent(
__int64 a1,
__int64 a2,
unsigned int a3,
unsigned int a4,
unsigned __int16 a5,
int a6)
{
unsigned __int64 v9; // rsi
unsigned int v10; // ebx
bool v11; // zf
unsigned int v12; // ecx
__int64 v13; // r8
__int64 v14; // rcx
__int64 v15; // rbx
unsigned int v16; // edi
__int64 v17; // rdx
__int64 v18; // rcx
unsigned int v19; // ecx
v9 = a4;
v10 = *(_DWORD *)(EtwpHostSiloState + 4224);
while ( 1 )
{
v11 = !_BitScanForward(&v12, v10);
if ( v11 )
break;
v10 &= v10 - 1;
v13 = v12;
v14 = 32i64 * v12 + EtwpHostSiloState + 4260;
if ( v14 )
{
if ( ((unsigned int)v9 & *(_DWORD *)(v14 + 4 * (v9 >> 29)) & 0x1FFFFFFF) != 0 )
EtwpLogKernelEvent(a2, EtwpHostSiloState, *(unsigned __int8 *)(EtwpHostSiloState + 2 * v13 + 4208), a3, a5, a6);
}
}
if ( a1 )
{
v15 = *(_QWORD *)(*(_QWORD *)(a1 + 1272) + 864i64);
if ( v15 )
{
v16 = *(_DWORD *)(v15 + 4224);
while ( 1 )
{
v11 = !_BitScanForward(&v19, v16);
if ( v11 )
break;
v17 = v19;
v16 &= v16 - 1;
v18 = 32i64 * v19 + v15 + 4260;
if ( v18 && ((unsigned int)v9 & *(_DWORD *)(v18 + 4 * (v9 >> 29)) & 0x1FFFFFFF) != 0 )
EtwpLogKernelEvent(a2, v15, *(unsigned __int8 *)(v15 + 2 * v17 + 4208), a3, a5, a6);
}
}
}
}
而EtwpLogKernelEvent
就是这次事件的主角,关键部分代码为
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2024-4-23 09:27
被Oxygen1a1编辑
,原因: 啦啦啦