本期作者/shadow
前言
进程注入就是将代码注入到另一个进程中,并将注入的代码运行起来,可以发现进程注入的核心逻辑就两步:
1. 在目标进程中写入代码;
2. 将在目标进程中写入的代码运行起来。
只要满足这两个要求就算一个合格进程注入了,写入的代码可以包含多种,比如 DLL、EXE、shellcode。
本文将阐述 4 种 PE(这里特指 EXE) 的进程注入技术,它们将篡改 PE 映像从而执行恶意代码,包括 `Process Hollwoing`、`Process Doppelganging`、`Process Herpaderping`、`Process Ghosting`。
Process Hollwoing
Process Hollowing 是一种比较古老的进程注入技术,最早可追溯至 2011 年,其核心原理就是通过删除合法进程映射视图,并将恶意代码写入目标进程空间内,并在恢复挂起前重定向目标进程的入口点,从而执行恶意代码。
Process Hollowing 又被称为 Dynamic forking,RunPE,进程镂空,傀儡进程。Process Hollowing 有几种不同的实现,但基本步骤如下,主要在于实现其中一个步骤所使用的方式不同。
-
以 挂起 方式创建合法的目标进程;
-
删除(unmap)目标进程映射视图(非必须);
-
写入内存展开后的恶意代码;
-
进行基址重定位;
-
修改目标进程入口点;
-
恢复挂起进程主线程。
在这里给出一种实现流程:
-
以 挂起 方式创建合法的目标进程;
-
删除目标进程映射视图(非必须);
-
在目标进程开辟内存空间;
-
将内存展开后的恶意代码写入目标进程新开辟的空间中:
1)拷贝 PE 头;
2)依次写入内存展开的恶意代码节区;
-
修改目标进程的 OEP 和 ImageBase;
-
更新线程上下文,并恢复挂起进程主线程,随后恶意代码将运行。
CreateProcess(CREATE_SUPENDED)
-> NtQueryProcessInformation() + ReadProcessMemory() 或者 GetThreadContext()
-> NtUnmapViewOfSection() <非必须>
-> VirtualAllocEx()
-> WriteProcessMemory()
-> SetThreadContext()
-> ResumeThread()
实现过程中会用到目标进程的 ImageBase,这需要从 PEB 中获取,在该技术手段中,获取 PEB 有两种方式:
方式一:在进程挂起状态下,可以通过获取线程上下文函数 kernel32!GetThreadContext 来直接获取 PEB 地址;
#ifdef _WIN64
// 从 RDX 寄存器中获取 PEB 地址,并从 PEB 中读取 ImageBase
ReadProcessMemory(pi.hProcess, (LPVOID)(ctx.Rdx + 0x10),
&targetImageBase, sizeof(LPVOID), NULL);
#else
// 从 EBX 寄存器中获取 PEB 地址,并从 PEB 中读取 ImageBase
ReadProcessMemory(pi.hProcess, (LPVOID)(ctx.Ebx + 0x8),
&targetImageBase, sizeof(LPVOID), NULL);
#endif
具体验证方法可通过 windbg 查看对应架构程序的 PEB 结构验证:
比如 64 位程序 ImageBase 位于 PEB 结构 +0x10 偏移处
32 位程序 ImageBase 位于 PEB 结构 +0x8 偏移处
方式二:通过 ntdll!NtQueryInformationProcess 找到目标进程 PEB 地址
PROCESS_BASIC_INFORMATION pbi{};
NTSTATUS status = NtQueryInformationProcess(hProcess, 0, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL);
if (!NT_SUCCESS(status))
{
LOG_ERROR("NtQueryInformationProcess failed, status: %08X", status);
return false;
}
// 目标 PEB 地址: pbi.PebBaseAddress
完整代码可参考:https://github.com/NATsCodes/ProcessHollowing/blob/master/Process%20Hollowing.cpp
更加详细的描述可参考:https://github.com/m0n0ph1/Process-Hollowing
在接下来介绍的几种进程注入手段中,它们都与进程创建过程中的区域对象(section object)有关。
Process Doppelganging
Process Doppelganging 是另一种进程注入手段,在 2017 年的 Black Hat Europe 演讲中,由 Tal Liberman 和 Eugene Kogan 提出。
在进一步了解Process Doppelganging 方法前,需要先了解 NTFS 事务是什么,NTFS 事务机制通常在数据库操作中使用,它们也存在于 NTFS 文件系统中。NTFS 事务将一系列操作封装为一个单元。利用事务机制创建的文件,在事务提交之前,外部无法访问。Process Doppelganging 技术利用 事务机制 创建了 "隐藏" 的文件,并在其中放置了恶意代码。
工作流程如下:
-
创建 NTFS Transaction 对象;(NtCreateTransaction) -
在 TxF 事务中创建文件或者覆写文件;(CreateFileTransacted) -
将恶意代码覆盖处于事务中的文件;( WriteFile) -
利用 事务文件句柄 创建被恶意代码覆盖文件的映像区域,这将获取区域对象句柄;(NtCreateSection,SEC_IMAGE,hTransactedFile) -
撤消对原始文件的更改,这将导致恶意代码从文件系统中被删除;(NtRollbackTransaction) -
通过区域对象句柄创建进程;(NtCreateProcessEx,hSection) -
为创建的进程填充必要的参数和环境;(RtlCreateProcessParametersEx,NtWriteVirtualMemory) -
为目标进程创建主线程,并将执行的入口点指向恶意代码的入口点,这将导致恶意代码被执行。(NtCreateThreadEx,EntryPointAddress)
NtCreateTransaction
-> CreateFileTransacted
-> WriteFile
-> NtCreateSection(SEC_IMAGE, hTransactedFile)
-> NtRollbackTransaction
-> NtCreateProcessEx(hSectionObj)
-> NtAllocateVirtualMemory + RtlCreateProcessParametersEx(¶ms) + NtWriteVirtualMemory
-> NtCreateThreadEx(EntryPointAddress)
首先我们需要创建了一个事务对象,并使用 kernel32!CreateFileTransacted() 打开目标文件。然后用恶意代码覆盖了这个事务文件,随后创建了一个指向恶意代码的映像区域,并用 kernel32!RollbackTransaction() 回滚事务。此时,可执行文件将恢复到其原始状态,但是映像区域中缓存了恶意代码。接下来,调用 ntdll!NtCreateProcessEx(),将区域句柄作为参数传入,并创建指向恶意代码入口点的主线程。创建完这些对象后,恢复主线程的执行,允许 "伪装" 进程执行恶意代码。
更详细的描述可参考:
https://hshrzd.wordpress.com/2017/12/18/process-doppelganging-a-new-way-to-impersonate-a-process/
https://www.blackhat.com/docs/eu-17/materials/eu-17-Liberman-Lost-In-Transaction-Process-Doppelganging.pdf
完整代码可参考:https://github.com/hasherezade/process_doppelganging/tree/master
Process Herpaderping
Process Herpaderping 是由 Johnny Shaw 在 2020 年发明的,它利用了许多和 Process doppelganging 相同的技巧,即使用 ntdll!NtCreateProcessEx() 进程创建 API 从一个区域对象(section object)创建进程。其主要特点是规避对所传递的 可执行文件内容 的检测。
其工作流程如下:
-
创建一个空文件;
-
写入恶意代码到这个文件中;
-
根据包含恶意代码的文件创建一个映像区域;
-
通过区域对象句柄创建进程;
-
混淆包含恶意代码的文件的内容;
-
为创建的进程填充必要的参数和环境;
-
为目标进程创建主线程,并将执行的入口点指向恶意代码的入口点,这将导致恶意代码被执行;
为了进行 Process Herpaderping ,攻击者首先将要执行的恶意代码写入磁盘,并为其创建一个映像区域,同时保持对被传递的可执行文件的句柄打开。然后,使用 ntdll!NtCreateProcessEx() 进程创建 API,使用区域对象句柄作为参数,创建进程对象,在初始化进程之前,使用打开的文件句柄和 kernel32! WriteFile() 或类似的 API 来混淆保存在磁盘上的原始可执行文件。最后,创建主线程对象,并执行剩余的进程启动任务。
在此时,驱动程序的回调函数接收到通知,并且可以使用传递给驱动程序的结构体的 FileObject 成员来扫描文件的内容。然而,由于文件的内容已经被修改,扫描函数将获取到伪造的数据。此外,关闭文件句柄将向已注册的文件系统 minifilter 发送一个 IRP_MJ_CLEANUP I/O 控制码。如果 minifilter 希望扫描文件的内容,它将遭遇与驱动程序相同的命运,可能导致错误的扫描结果。
更详细的描述可参考:https://jxy-s.github.io/herpaderping/
完整的源代码可参考:https://github.com/jxy-s/herpaderping
Process Ghosting
Process Ghosting 是另一种进程注入技术,基于 PE 映像篡改,类似 Process Doppelganging 和 Process Herpaderping ,由 Gabriel Landau 在 2021 年 6 月提出。使用该技术,攻击者可以以一种难以扫描或删除的方式将恶意代码写入磁盘,并以与磁盘上的普通文件相同的方式执行已删除的恶意代码。这种技术不涉及代码注入、Process Hollowing 或事务性 NTFS(TxF)。它利用了 Windows 在将磁盘可执行文件映射到映像区域(image section)后将文件删除的特性,并且在删除文件时不会检查关联的映像区域是否存在,从而实现了“无文件攻击”。如果尝试打开映射的可执行文件以修改或删除它,Windows 将返回错误。
其工作流程如下:
1. 创建一个空文件(可以随机生成一个临时文件);
2. 将生成的空文件置于待删除状态;
3. 向该文件中写入恶意代码;
4. 为该文件创建映像区域,得到区域对象句柄;
5. 关闭文件句柄,
6. 利用 `ntdll!NtCreateProcessEx()` 创建进程;
7. 为创建的进程填充必要的参数和环境;
8. 为新进程创建主线程对象。
为了实现这个过程,攻击者首先需要在磁盘上创建一个空文件,然后使用 ntdll!NtSetInformationFile() 将其置于待删除状态;当文件处于此状态时,攻击者向其中写入恶意代码,此时,外部请求打开文件将失败,并显示 ERROR_DELETE_PENDING 错误;接下来为该文件创建映像区域(image section),这将获得一个区域对象(section object),随后关闭文件句柄,这样磁盘上包含恶意代码的文件将被删除但却保留了其映像区域,之后使用 ntdll!NtCreateProcessEx() ,将区域对象句柄作为参数创建一个程,这时,当驱动程序收到有关进程创建的通知并尝试访问支持进程的 FILE_OBJECT(Windows 用于表示文件对象的结构)时,它将收到一个 STATUS_FILE_DELETED 错误,阻止对文件的检查。
更详细的描述可参考:https://www.elastic.co/cn/blog/process-ghosting-a-new-executable-image-tampering-attack
完整的代码可参考:https://github.com/hasherezade/process_ghosting
检测
对于 Process Hollowing,由于实现比较简单,检测也相对容易,可以假设 PE 文件在磁盘中和内存中的 PE 头几乎相同,如果差别太大,则可猜测该进程被劫持了。
对于另外三种基于 PE 映像篡改的进程注入技术,没有一种确切的方案去检查,这些方法一定程度上阻止了相关进程创建回调的通知,但可以根据这类技术的原理,它们主要有两个重要步骤:
-
创建了一个与实际文件不符的映像区域(修改或者被删除);
-
使用了 ntdll!NtCreateProcessEx() 创建一个非最小进程。
可以根据这两方面对这类进程进行调查取证,但是这种检测策略是被动的,只能作为最终判定的一部分。
具体可以收集与这类进程相关的映像信息,这类信息通常在内核模式下的 EPROCESS 结构中存储,用户模式下的 PEB 结构中存储,但是由于可以在攻击者可以在用户模式下操控 PEB,所以 EPROCESS 的信息来源更可靠,可以收集的信息包括:ImageFileName、ImageFilePointer.FileName、SeAuditProcessCreationInfo.ImageFileName、ImagePathHash,分别表示了进程名,进程 WIN32 路径,进程 NT 路径,进程 NT 路径 HASH 值,通过这些映像信息的组合去判定是否是一个恶意程序。
原文始发于微信公众号(蛇矛实验室):进程注入-PE注入
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论