内存免杀
av/edr 检测的方式
静态
- 特征值
可以通过甲壳,加密等方式来进行绕过
或者是垃圾代码混淆
动态
动态也是比较难的部分
r3 层
- Hook 高危的api
- 内存中特征检测
- 检测父子关系
r0 层
- 内核回调 windows /内核指针 linux
- 内核回调指的是使用psSetCreateProcessNotifyRoutine、CmRegisterCallback等API来注册回调函数
- 当制定的时间发生的时候,比如创建进程,删除进程,动注册表的时候edr 调用对应的回调函数,进行检测
内核指针是用于linux
Kprobes(Kernel Probes)是Linux提供的一种动态调试机制。它允许用户在几乎任何内核指令处设置断点,并在命中这些断点时执行一些预定义的操作,比如收集数据或执行额外的检查。Kprobes可以分为以下几类:
- Kprobe:可以在任何内核模块或核心内核函数的入口处插入探测点。
- Jprobe:允许你在内核函数的入口处放置一个探测点,并且你的处理函数会在这个函数被调用时自动获得相同的参数列表。
- Kretprobe:用于在内核函数返回时捕获控制权。
- 内核钩子 - SSDT系统调用表、全局描述符表GDT、中断描述符表(IDT)钩子会和x64下的patch guard冲突,但依然有绕过方式。
patch guard 是一个内核的保护系统,防止未经授权的内核代码修改
- 借助ETW实现对底层调用的监控 - ETW是Windows提供的一个强大的消息跟踪机制,允许收集包括内核事件在内的各种系统级事件。通过订阅特定的ETW提供者和事件,EDR可以获得关于系统行为的详细信息。
- 硬件辅助 - Intel VT-x或AMD-V,在更低的硬件级别提供对执行环境的控制和监视。
绕过方法
Shellcode 自解密
可以在shellcode 之前添加一个e8 地址的方式
由于 e8 在x86 的汇编当中,意思是call
/xe8 揭秘函数的地址
的这样的方式进行解密后面的代码
当call 执行完了之后下面执行的就是shellcode 原始的代码了
栈区伪造
- 重写高风险的api
比如NtAllocateVirtualMemory 用于创建内存
- 将返回地址可以放入一个全局的结构体中
这个返回的地址可以使用一个标签,然后直接jmp就可以了
- 进入函数之后抬高栈区地址
可以使用sub rsp, N 的方式抬高
- Push 0
将栈区进行分割
- 在这之上部署一个假栈(伪造一些常见的返回地址制作一个栈底和看上去合理的调用链);
- 在假栈 上部署一个Gadget Frame 用来跳转到fixup 函数
跳转回高风险函数调用前的位置,比如预先从内存中找好的JMP [RBX]片段);
- 为跳转和堆栈恢复做准备,将真正的返回地址、RBX寄存器值放入结构体暂存,然后将堆栈恢复函数fixup()的地址给RBX,最后JMP到真正的函数调用;
整个调用过过程可以理解为下面的代码
1 |
|
内存免杀
https://tsy244.github.io/2025/03/10/免杀/内存免杀/