愚蠢的 EDR 绕过及其查找位置

滥用异常处理程序来挂钩和绕过用户模式 ​​EDR 挂钩。

来源:MalwareTech

最近,我正在测试 EDR 检测间接系统调用的能力,并且我有了一个古怪的绕过方法。如果您还不熟悉直接和间接系统调用,我建议您先阅读这篇文章。

先阅读这篇文章

直接和间接系统调用的缺点之一是,从调用堆栈可以清楚地看出您绕过了 EDR 的用户模式挂钩。下面是直接、间接和常规调用的一些示例调用堆栈。

直接系统调用的调用堆栈。

直接系统调用的调用堆栈。

间接系统调用的调用堆栈。

间接系统调用的调用堆栈。

常规挂钩的 Nt 函数调用的调用堆栈。

常规挂钩 Nt 函数调用的调用堆栈。

从最后一张图片中可以看到,当通过挂钩函数进行调用时,EDR 挂钩的返回地址会出现在调用堆栈中(在我的情况下是 hmpalert)。这是一个有趣的困境:我们不想调用挂钩函数,因为这可能会触发检测,但如果我们完全绕过挂钩,也可能会触发检测。

hmpalert

这时我有了一个有点搞笑的想法。如果我确实调用了挂钩函数,但这样做的方式使得 EDR 无法正确检查调用参数,会怎么样?我马上就有几个想法。

TOCTOU

检查时间到使用时间,简称 TOCTOU,是软件开发中经常使用的一种技术。当对对象执行安全检查,但在检查时间和使用时间之间没有任何东西可以阻止修改该对象时,就会出现漏洞。

让我们以以下代码为例:

BOOL CopyData(char *src_buffer, uint32_t *src_size) { static char dest_buffer[1024]; if(*src_size >= 1024) { printf("error, buffer overflow!"\n); return FALSE; } memcpy(dest_buffer, src_buffer, *src_size); return TRUE;}
BOOL CopyData ( char * src_buffer , uint32_t * src_size ) { static char dest_buffer [ 1024 ]; if ( * src_size >= 1024 ) { printf ( "错误,缓冲区溢出!" \ n ); return ; } ( ,