

RefleXXion 是一款旨在帮助绕过 AV/EPP/EDR 等安全产品所实施用户态钩子的工具。为了绕过用户态钩子,它首先收集 LdrpThunkSignature 数组中的 NtOpenFile、NtCreateSection、NtOpenSection 和 NtMapViewOfSection 系统调用编号。之后,用户可以选择两种技术来绕过用户态钩子。
技术一:从 C:\Windows\System32\ntdll.dll 文件中读取 NTDLL。解析后,用干净的 NTDLL 的 .TEXT 段替换内存中已加载的 NTDLL(即钩子所在位置)的 .TEXT 段。
技术二:NTDLL 以 Section 形式从 KnownDlls 读取,即 \KnownDlls\ntdll.dll。(因为 DLL 文件在 KnownDlls 中以 Section 形式缓存。)解析后,用干净的 NTDLL 的 .TEXT 段替换内存中已加载的 NTDLL(即钩子所在位置)的 .TEXT 段。
以下给出了该方法和所有技术的详细流程。

您可以使用 Visual Studio 打开并编译该项目。整个项目支持 Debug 和 Release 模式下的 x64 架构。
RefleXXion-EXE 解决方案生成用于 PoC 目的的 EXE。如果您想逐步了解项目的工作原理,它将使您的工作更轻松。Main 函数包含 Technique1 和 Technique2 函数的定义。请注释掉其中一个并编译。不要同时使用两个函数。
RefleXXion-DLL 解决方案生成 DLL,您可将其注入到需要绕过 NTDLL 用户态钩子的目标进程中。在 main.cpp 文件开头,有使用哪种技术的定义。您可以选择其中一种并编译。不要同时设置所有值,只设置您想要的那种技术。下面给出了示例配置。
// 技术配置区
#define FROM_DISK 1 // 如果设置为 1,将使用技术一。更多信息:https://github.com/hlldz/RefleXXion
#define FROM_KNOWNDLLS 0 // 如果设置为 1,将使用技术二。更多信息:https://github.com/hlldz/RefleXXion
RefleXXion 目前仅支持 x64 架构。
RefleXXion 仅解除 NTDLL 函数的钩子,您可能还需要解除其他 DLL(例如 kernel32.dll、advapi32.dll 等)的钩子。为此,您可以轻松编辑项目中的相关位置。
RefleXXion 在覆盖 .TEXT 段过程开始时仅使用 RWX 内存区域。此过程不会创建新的内存区域,而是将现有内存区域(已加载的 NTDLL 的 TEXT 段)设置为 RWX,然后转换回 RX。
ULONG oldProtection;
ntStatus = NtProtectVirtualMemory(NtCurrentProcess(), &lpBaseAddress, &uSize, PAGE_EXECUTE_READWRITE, &oldProtection);
memcpy()...
ntStatus = NtProtectVirtualMemory(NtCurrentProcess(), &lpBaseAddress, &uSize, oldProtection, &oldProtection);
附注:RefleXXion 通过干净安装的 NTDLL 调用 NtProtectVirtualMemory API。它为此使用 CustomGetProcAddress 函数,因为干净的 NTDLL 虽然已加载到内存中,但不在 InLoadOrderModuleList 中。因此,类似这里(https://stackoverflow.com/questions/6734095/how-to-get-module-handle-from-func-ptr-in-win32)的解决方案将不起作用。这就是自定义 GetProcAddress 函数存在并被使用的原因。
您可以将 RefleXXion DLL 从磁盘加载到目标进程中。对于红队行动等敏感工作,您可能不希望采用这样的运行方式。因此,您可以使用 sRDI 项目将 RefleXXion DLL 转换为 shellcode,或者将 RefleXXion 代码集成到您自己的加载器或项目中。
即使 NTDLL(作为文件或 Section)被重新加载到注入的进程中,它也不会保持加载状态。RefleXXion 会关闭自身进程的所有打开句柄(文件句柄和 Section 句柄)。