ret
复制代码有了这些信息,我们知道 EDR 的 Dll 名称以及这些 syscall 长什么样子,因此可以去寻找这些函数的差异,我们还知道 EDR 通过修改前 5 个字节来重定向执行流程,从跳转开始 (例如 JMP 指令,E9) ,我们可以使用它 (E9) 通过在 ntdll.dll 中搜索与之匹配的潜在钩子。
登录/注册后可看大图
Figure 8 Execution flow of a Procedure EDR Hooked_1.png (241.56 KB, 下载次数: 0)
下载附件
2021-8-20 11:16 上传
在这里我们可以很清楚地看到被 hook 的 syscalls。
登录/注册后可看大图
Figure 9 Execution flow of a Procedure EDR Hooked_0.png (242.04 KB, 下载次数: 0)
下载附件
2021-8-20 11:17 上传
现在情况并非总是如此,因为某些产品试图通过在跳转到 EDR 本身之前先跳转同一系统 Dll 中的不同区域或当前进程中的线程来掩盖它们的跳转。在许多情况下,结果是相同的。我们仍然可以通过对程序集进行任何修改的 syscall 来识别这些指令。
登录/注册后可看大图
Figure 10 EDR Indirect Jumps 1_0.png (118.24 KB, 下载次数: 0)
下载附件
2021-8-20 11:17 上传
登录/注册后可看大图
Figure 10 EDR Indirect Jumps 2_0.png (127.67 KB, 下载次数: 0)
下载附件
2021-8-20 11:18 上传
登录/注册后可看大图
Figure 10 EDR Indirect Jumps 3_0.png (91.98 KB, 下载次数: 0)
下载附件
2021-8-20 11:18 上传
有了已知所有钩子的知识,我们就可以通过 patch 正确的字节、覆盖 EDR 的钩子来恢复这些值。这可以防止任何遥测数据从进程传输到 agent,因为 EDR 的 Dll 没有要发送的数据。
这种方法理论上来讲非常棒,然而,有几个因素可能会使执行变得困难。第一个主要因素为在此进程完成之前,EDR 很有可能会重写所有钩子;另一个主要因素是准确了解每个 EDR 钩子的功能。每个产品会 hook 不同的 syscall,同时攻击者从不知道产品在使用哪个 syscall (取决于他们的开源情报),如果要 hook 不同 Windows 版本下的要被 hook 的函数,这样可能会导致 Payload 的大小以幂数级增长,需要额外的研究来确定在没有检测到所有产品的情况下在何处进行这些有针对性的修改。
一种更简单的方法是重新加载进程内存的一部分以刷新 EDR。 这是因为我们知道 EDR 的钩子是在进程生成时放置的。我们还知道 EDR 通常会对哪些 DLL 下钩子。我们可以通过使用 VirtualProtect 来定位这些 Dll 并在内存中操作它们,该函数将进程的内存权限的一部分更改为不同的值。这些值可以是读、写和执行的组合。
首先去寻找位于磁盘上的系统 Dll,这些文件位于 C:\Windows\System32\ 或 C:\Windows\SysWow64 (32 位) 目录下,这些存储在磁盘上的 Dll 是未被 hook 的,因为 EDR 仅 hook 加载到内存中的内容。一旦 Dll 在内存中打开,我们就可以获取 Dll 的 .text 区段的字节。Dll 的这一部分包含可执行程序集 - 在 NTDLL 的情况下,是带有 syscall 的可执行代码。