概括
在本博客中,我们讨论了 AV/EDR 静态分析和检测的不同方法。传统的防病毒软件依赖于基于签名的检测。它们计算二进制文件的哈希值,并查看此特定签名是否与数据库中已知的恶意软件签名匹配,然后相应地将二进制文件标记为恶意或良性。绕过基于哈希的检测过程非常简单。您只需更改一个字节即可绕过基于哈希的检测。但现在 AV 已经相当先进,它们不仅依赖于已知的恶意软件哈希值,如今 EDR 也开始发挥作用,它会寻找模式、IAT 导入,EDR 解决方案使用模式匹配来识别文件中通常与恶意软件相关的可疑代码序列、字符串或结构。EDR 工具利用 YARA 规则根据规则中定义的特定模式和特征来检测恶意软件。这些规则可以通过寻找入侵指标 (IOC) 来识别已知和未知的威胁。EDR 解决方案分析文件属性和行为以了解恶意软件的典型特征。这包括检查文件熵、不常见的 API 调用、可疑导入表和其他异常特征。我们使用不同的技术来绕过 EDR 解决方案的静态分析。我们将武器库准备分为 4 个主要阶段,我们尝试隐藏字符串、通过混淆 API 导入、使用不同方式(例如动态遍历进程环境块 (PEB))解析 API 以及通过解析内存中的 kernel32.dll 来隐藏导入,从而解析导出函数。最后,我们查看应用不同技术后的检测率结果,看看哪种技术更能有效地避开 EDR 静态检测的雷达。
PEB结构
进程环境块 (PEB) 是 Windows 操作系统中一个重要的数据结构,其中包含有关进程状态的信息。它是 Windows API 中未记录的结构,但因其包含有关进程的丰富信息而为恶意软件分析师和开发人员所熟知。
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID Reserved4[3];
PVOID AtlThunkSListPtr;
PVOID Reserved5;
ULONG Reserved6;
PVOID
Reserved7; ULONG Reserved8;
ULONG AtlThunkSListPtr32;
PVOID Reserved9[45];
BYTE Reserved10[96];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved11[128];
PVOID Reserved12[1];
ULONG SessionId;
} PEB, *PPEB;
从上面提到的结构成员中,我们可以看到突出显示的Ldr成员。此成员包含一个指向PEB_LDR_DATA结构的指针,该结构保存有关当前进程中所有已加载模块(EXE/DLL)的信息。在此结构中,InMemoryOrderModuleList有一个双向链接列表,用于查找已加载 DLL 的地址。
typedef struct _PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA,*PPEB_LDR_DATA;
在此结构中,进程将使用InMemoryOrderModuleList枚举已加载的模块。此链接列表包含每个模块的条目,这些条目由LDR_DATA_TABLE_ENTRY结构表示,提供有关每个模块的详细信息。
PEB 步行概览
PEB walk 是从进程空间访问 PEB 结构,动态枚举进程空间中所有已加载的模块的过程。枚举完已加载的模块后,解析模块中的函数和变量,并将它们使用到代码中。
X86 汇编:
mov eax, fs:[30h] ; EAX 现在指向 PEB
X64 汇编:
mov rax, gs:[60h] ; RAX 现在指向 PEB
LoadLibraryA概括一下这个过程,解析和地址的PEB过程GetProcAddress如下:
-
获取并访问当前进程的PEB结构。
-
PEB_LDR_DATA使用LdrPEB 的成员导航到结构。
-
遍历以InLoadOrderModuleList找到LDR_DATA_TABLE_ENTRYkernel32.dll。
-
一旦找到 kernel32.dll 的条目,就提取其基地址。
-
LoadLibraryA手动解析kernel32.dll的导出表,解析和的地址GetProcAddress。
武器库准备和阶段
我们使用一种简单的进程注入技术,即使用 Windows API(例如 VirtualAllocEx、WriteProcessMemory 和 CreateRemoteThread)将 msfvenom 生成的 shellcode 注入进程。
-
VirtualAllocEx:将 RWX 内存区域分配到远程进程。
-
WriteProcessMemory:将shellcode写入创建的内存部分。
-
CreateRemoteThread:创建一个新线程,在启动时执行我们的shellcode。
第一阶段(简单注射)
在第一阶段,我们编写了一个简单的进程注入技术,利用上述 API 将恶意 shellcode 注入远程进程。但在第一阶段,我们直接使用武器库中的这些 API,而不是动态解析这些 API。
简单注入
在上面的代码中,我们使用 OpenProcess API 获取进程句柄,并分配 RWX 内存区域,写入 shellcode,即打开 calc.exe 并创建新线程以在远程进程中执行我们的 shellcode。这是一个非常简单明了的代码。
IAT检查
在每个阶段,我们使用三个 PE 编辑工具 PE Bear、CFF Explorer 和 PE studio 进行 IAT 检查。让我们使用这些工具检查我们编译的二进制文件,看看可以检测到我们的恶意软件的指标是什么,并尝试在接下来的阶段克服它们。
CFF Explorer 结果
您可以在编译后的二进制文件的 IAT 表中清楚地看到 API 调用,通过查看这些调用,恶意软件分析师可以清楚地表明该二进制文件正在进行 shellcode 注入。这些是执行注入的非常著名的 API 调用序列。另一方面,EDR 可以在静态分析中检测到二进制文件,因为它们会对 IAT 进行检查。
PE工作成果
PE Studio
你看,PE Studio 将这些 API 标记为恶意的。PE Studio 的妙处在于它将标记 API 调用映射到 MITRE ATT&CK 框架上。因此,根据 PE Studio 的说法,该恶意软件正在执行进程注入,这在这种情况下非常正确。因此,我们必须在下一阶段的武器库准备中克服这些挑战。
执行
在每个阶段,我们都会执行二进制文件来验证恶意软件的运行情况。每次恶意软件都会将恶意 shellcode 注入远程进程并执行 calc.exe。在此阶段,我们直接在代码中使用 Windows API 调用。
第一阶段执行
第 2 阶段(动态 API 注入)
在第 2 阶段中,我们使用相同的注入技术将恶意 shellcode 注入进程,但这一次,我们使用两个主要函数 GetProcAddress 和 LoadLibraryA 动态解析 Windows API。
GetProcessAddress:此函数解析给定模块内任何函数的地址。此 API 带有两个参数,一个是我们要从中获取函数地址的模块,另一个是要解析的函数名称。
LoadLibraryA:此函数获取我们想要从中获取函数地址的模块的句柄。在我们的例子中,kernell32.dll 就是模块。
原型
在这个阶段,首先,我们必须定义每个想要动态解析的 API 的原型。我们定义一个表示函数指针的类型。
动态API注入
上面的代码解释了我们使用 LoadLibrayA 函数来获取 kernel32.dll 的句柄,然后我们使用 GetProcAddress 来解析 kernel32.dll 中的 API。现在,这一次,我们使用动态 API 解析技术,看看在我们的编译二进制文件中什么变得更好。
IAT检查
在每个阶段,我们使用三个 PE 编辑工具 PE Bear、CFF Explorer 和 PE studio 进行 IAT 检查。让我们使用这些工具检查我们编译的二进制文件,看看可以检测到我们的恶意软件的指标是什么,并尝试在接下来的阶段克服它们。
CFF 探索结果
您可以清楚地看到,在这个阶段我们做得更好,因为这一次我们导入的恶意软件行为更少。但是,我们仍然看到一些指标,例如 LoadLibrarayA 和 GetProcAddress,这些指标可以在静态分析中检测到。我们试图在下一阶段的准备中克服这个问题。
PE studio
PE studio 仍然标记了一些 API,并将它们映射到 MITRE ATT&CK 上的进程注入类别下。
PE Bear Results
哎呀,我们看到 PE 文件的 .rdata 部分下此阶段有一些字符串。这些字符串是二进制文件行为的一个很好的指标。恶意软件仍然可以在 EDR 的静态分析中检测到。我们必须在接下来的阶段克服这个问题。
执行
在每个阶段,我们都会执行二进制文件来验证恶意软件的运行情况。每次恶意软件都会将恶意 shellcode 注入远程进程并执行 calc.exe。在此阶段,我们使用 Windows API 调用的动态解析来注入 shellcode。
第 2 阶段执行
第 3 阶段(PEB 步行注射)
在第三阶段,我们使用同样的注入技术将恶意的 shellcode 注入到进程中,但这次我们使用 PEB 遍历来动态解析 API。我们访问 PEB 并枚举进程空间中所有已加载的模块,并找到 kernel32.dll 的基址。我们使用 kernel32.dll 的基址来解析 API 的函数地址,然后使用 PEB 遍历执行进程注入。
PEB 结构
在这个阶段,首先,我们必须定义执行 PEB 遍历所需的所有结构。你可以在 Microsoft 文档中找到这些结构。
PEB structure (winternl.h) - https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
我们定义所有需要的结构,并为我们需要的 Windows API 函数定义函数指针类型。
解析函数地址
上面的代码将 kernel32.dll 解析为 PE 文件,因为 DLL 是 PE 文件格式,并且首先获取 DOS 头,然后使用 DOS 头成员 e_lfanew(4 字节字段)来指示 NT 头的偏移量。现在,NT 头包含选项头,其中包含数据目录字段,包括模块的所有导出函数。因此,此函数返回匹配函数名的地址。
PE Access and Walk
此代码片段访问 PEB,然后遍历以InLoadOrderModuleList找到LDR_DATA_TABLE_ENTRYkernel32.dll.
解析 API 函数
最后我们解析并使用API来执行进程注入。
IAT检查
在每个阶段,我们使用三个 PE 编辑工具 PE Bear、CFF Explorer 和 PE studio 进行 IAT 检查。让我们使用这些工具检查我们编译的二进制文件,看看可以检测到我们的恶意软件的指标是什么,并尝试在接下来的阶段克服它们。
CFF Explorer 结果
太好了,在这个阶段,我们改进了 IAT,这一次,我们可以看到没有恶意导入,这可以为恶意行为提供指标。我们看到这次没有 GetProcAddress 和 LoadLibraryA 函数。这对恶意软件开发人员来说是一个好兆头,因为这可以绕过 EDR 解决方案的静态分析。
恶意字符串
哎呀,我们看到 PE 文件的 .rdata 部分下此阶段仍有一些字符串。这些字符串是二进制文件行为的一个很好的指标。恶意软件仍然可以在 EDR 的静态分析中检测到。我们克服了一个问题,即 IAT 导入指示,但这个问题可以在下一阶段解决。
执行
在每个阶段,我们都会执行二进制文件来验证恶意软件的运行情况。每次恶意软件都会将恶意 shellcode 注入远程进程并执行 calc.exe。在此阶段,我们使用 PEB 遍历对 Windows API 进行动态解析来注入 shellcode。
第 3 阶段执行
第四阶段(PEB 遍历、API 导入混淆、字符串隐藏)
在第 4 阶段,我们使用相同的技术将恶意 shellcode 注入进程。但这是最后一个阶段,所以我们必须克服上一阶段面临的所有挑战。我们需要隐藏恶意字符串并动态解析 API。
PEB 结构
在这个阶段,首先,我们必须定义执行 PEB 遍历所需的所有结构,与阶段 3 相同。您可以在 Microsoft 文档中找到这些结构。
PEB structure (winternl.h) - https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
我们定义所有需要的结构,并为我们需要的 Windows API 函数定义函数指针类型。
异或运算
在此阶段,我们使用异或加密来混淆 API 调用并隐藏字符串以绕过静态分析。此函数将使用密钥“offensivepanda”并在运行时解密所有 API 调用,这些调用已加密并存储在代码中。
解密并注入
您可以在这段代码片段中看到,我们解密了 API 的调用并将其传递给函数,该函数动态解析 API 调用的地址,所有 API 调用都经过加密。
IAT检查
在每个阶段,我们使用三个 PE 编辑工具 PE Bear、CFF Explorer 和 PE studio 进行 IAT 检查。让我们使用这些工具检查我们最终阶段编译的二进制文件,看看我们是否已经克服了所有问题。
CFF 探索结果
太棒了,在这个阶段,我们改进了 IAT,这次我们可以看到没有恶意导入,这可以为恶意行为提供指标。我们看到这次没有 GetProcAddress 和 LoadLibraryA 函数。
Strings Stage Final
太好了,这次没有恶意字符串,因为我们混淆了代码中的所有 API 调用,并且我们没有任何字符串和 API 导入,这表明静态分析中的恶意软件的行为。
执行
在每个阶段,我们都会执行二进制文件来验证恶意软件的运行情况。每次恶意软件都会将恶意 shellcode 注入远程进程并执行 calc.exe。在此阶段,我们通过 PEB 遍历使用 Windows API 的动态解析并混淆 API 调用来注入 shellcode。
第 4 阶段执行
检测结果
我们从代码中删除了 msfvenom shellcode,并将第一阶段和最后一阶段的恶意软件上传到virustotal以查看检测结果。我们删除shellcode是因为msfvenom生成的shellcode非常容易被检测到,所以我们想看看我们在本文中使用的其他技术的有效性。我们知道virustotal也会检查行为,但让我们看看结果。
第一阶段结果(简单注射)
最终阶段结果(PEB 遍历和 Xor)
笔记
这些技术有助于绕过 EDR 解决方案的静态分析,也有助于使恶意软件在静态分析中更难被发现,因此分析师不能仅仅通过查看 IAT 和字符串来了解恶意软件的行为。但在动态和基于行为的分析中仍然可以检测到二进制文件。因为动态绕过不是这篇文章的范围,但您可以查看我们之前的博客,主要关注动态行为绕过。
完整代码
此漏洞利用了 PEB walk 技术来动态解析 API 调用,混淆所有 API 调用以执行进程……
https://github.com/Offensive-Panda/PEB_WALK_AND_API_OBFUSCATION_INJECTION
原文始发于微信公众号(Ots安全):PEB Walk:避免分析师在 IAT 中检查 API 调用并绕过 AV/EDR 的静态检测
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论