edr对抗本质是想办法就是绕过edr对某些函数的监控,让我们的调用链要么不被发现,要么被认为是安全的。
edr检测方式
- 调用链监控:EDR通常会监控系统中的敏感行为(如系统调用、DLL注入、进程创建等),并通过分析调用堆栈来追踪这些行为的源头。例如,EDR可能会检查调用是否来自某个受信任的模块或函数调用链,或者是否与常见的攻击模式(如ROP攻击、Shellcode执行)相匹配。
- api监控:也可能直接hook敏感函数,只要调用就会记录日志。
- 流量监控
- 注册表监控
- 文件监控
- 日志监控
绕过方式
分为unhook和卸载dll两种方式来对抗edr。
- 恢复被hook的api
- 直接调用➕伪造调用栈。使用汇编手动发起系统调用,这种方法是直接系统调用.
- 寻找未被hook的函数
- 应用层更改传统调用链来实现相同的效果。
- 加载未被hook的干净的dll文件
- 使用间接系统调用的方式,先进入一个安全的系统调用,然后更改调用号,让实际调用的函数发生改变。如果edr没有验证内核层调用函数和系统调用的返回地址是否匹配的话,就可以绕过hook。
- 使用一个有漏洞的驱动进入内核空间,在内核空间抹掉edr的驱动的回调函数,实现edr的致盲,这样子新的进程就不会有edr的dll了。
- 使用early bird injection,挂起一个新的进程,并给新的进程发送apc消息,这个指令会在新进程的线程恢复执行的时候优先执行,所有apc例程执行完毕后才会执行进程入口点代码,这可以绕过一部分dll实在程序入口点之后被注入进来的edr。
- 创建一个挂起的进程,hook进程中的ldrloaddll函数,让其拒绝加载edr的dll.然后恢复那个挂起的进程.
- 修改AvrfpAPILookupCallbackRoutine回调函数的地址为我们自己的回调函数的地址的方式来阻止edr的dll的加载,这个回调中的代码会在tls回调和apc调度之前执行,但是只能执行ntdll中的函数,我们可以在回调函数中看当前进程PEB中的ldr列表得到对应edr的dl的详细信息,然后使用writeprocessmemory函数修改进程中对应dll的入口点地址,让dll无法使用,进而绕过了edr的用户层hook。或者可以在回调函数中hookldrloaddl函数,如果发现加载了edr的dll,我们直接进行阻止即可,这种技术是edr-preloader技术.
https://github.com/MalwareTech/EDR-Preloader
edr如何让自己的dll加载到用户层进程中
- 利用内核层回调函数监控进程创建,直接修改进程的iat表让其加载自己的dll。
- 给进程注入apc消息,等待进程进入alertable状态的时候会加载edr的dll
edr希望自己的dll被加载的时间
在进程初始化阶段越晚加载越好,但是必须在调用进程入口点之前完成所有操作。
为什么不开发一个内核驱动来同时监控用户层和内核层行为
理论上是可行的,但实际执行中有如下几个问题。
- 开发难度巨大,有一些在用户层几行就能文现的功能在內核层可能需要数百行,又因为代码全在內核层,稍有不慎就会引起系统萌溃,所以稳定性就很难得到保障。
- 即使开发成功,那么当用户层任何一个操作产生的时候,都会触发R3-R0的转换,会带来大量的性能损耗,十分影响用户体验。
- 代码全在内核层,且数量巨大,容易产生内核漏洞。
因此安全厂商采用内核层回调+用户层hook的方式来实现自己的edr产品,更小的成本达到一样的效果和更佳的用户体验。