Windows 进程注入 Part 1 - 非覆写函数指针的进程注入方式

阅读量    76208 |

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

概述

进程注入是一种在单独的活动进程空间中执行代码的方法。在其它合法进程的上下文中运行代码可以达到防御规避的目的,同时有可能提升权限。进程注入通过将代码注入到目标进程或者迫使目标进程加载指定的代码库来实现。诸如 AppInit DLLs, COM 劫持 等技术除了提供持久化能力外,客观上也是在其他进程中执行代码(相应的 DLL 被加载到目标进程中),即达到进程注入的效果。但是本系列文件只关注前一种类型的注入,即将代码显示注入到目标进程的注入方式。这类的进程注入方法首先需要将代码以某种方式放到目标进程的进程空间中,然后借助某种机制使目标进程执行注入的代码。比如经典的 Windows 进程注入(shellcode 注入)通过 API WriteProcessMemeory 将代码写入到目标进程,然后通过 API CreateRemoteThread 创建远程线程执行注入的代码。

根据代码注入和被注入代码的执行方式,可以对进程注入进行归类。例如根据代码的注入方式,可以分为使用了 WriteProcessMemeory/NtWriteVirtualMemory/ZwWriteVirtualMemory 和未使用这几个个 API 的。根据注入代码的执行方式,可以分成覆盖了函数指针(回调函数,虚表等)的和不覆盖函数指针的(通过创建或劫持远程线程,利用 APC 等)。ATT&CK 的进程注入技术和 Elastic 的博客 Ten process injection techniques: A technical survey of common and trending process injection techniques 提到了多种在野的的 Windows 进程注入方法。本系列的文章将根据注入代码的执行方式对这些进程注入方式进行分类介绍,文章不会对每种注入方式做 step by step 的详细描述,而是会着重从代码注入方式(如何注入以及注入了什么)和被注入代码如何得到执行(控制流如何到达被注入的代码)这两个关键的步骤对这些技术进行简要的介绍,同时我们将指出最近有哪些 APT 或恶意软件在实际攻击中使用相应的进程注入方式。本文作为该系列的第一篇,将首先介绍非覆写函数指针的进程注入方式,其中包括两种上述链接中未提及的进程注入方式 Process HerpaderpingProcess Ghosting

 

DLL 注入

DLL 注入通常将需要被目标进程加载的 DLL 路径写入目标进程,然后通过 CreateRemoteThreadNtCreateRemoteThreadRtlCreateUserThread 创建远程线程执行 LoadLibray 来加载目标 DLL。为了不通过调用 LoadLibray API 加载 DLL,反射型 DLL 注入会将自带加载器的 DLL 写入目标进程,然后创建远程线程执行注入的 DLL 的加载器,加载器完成导入表解析,地址重定位和 DllMain 函数调用等 LoadLibrary 的功能。而内存模块(MemoryModule)为了可以从内存加载任意 DLL,将加载器与 DLL 分离,需要将 DLL 和加载器写入目标进程,然后使目标进程执行加载器,以加载已写入的 DLL。

DLL 注入写入的 payload 或者是 DLL 的路径,此时 DLL 需要落地,或者是带有加载器的 DLL 或加载器和 DLL 分离的情况,分别对应反射性注入和内存模块。后两者的 DLL 都可以不落地。写入 payload 时通常借助 WriteProcessMemeory。如下 APT 组织在最近的活动中使用了 DLL 注入技术:

PE 注入

PE 注入与 DLL 注入类似,在将 PE 写入目标进程后,在通过创建远程线程执行 PE (入口点)前,同样需要为注入的 PE 解析导入表(并加载相应的 DLL)和进行基址重定向。通常利用 WriteProcessMemeory 写入 PE 文件,PE 文件可以不落地。如下 APT 组织在最近的活动中使用了 PE 注入技术:

 

线程执行劫持

线程执行劫持 在将 payload(可以是 shellcode,DLL 路径等)写入目标进程之后,不是通过创建远程进程的方式执行 payload,而是通过
SuspendThread, SetThreadContext, ResumeThread 来挂起目标进程的线程,设置线程上下文(将 EIP/RIP 指向 payload),然后恢复线程的执行,达到劫持控制流并执行 payload 的目的。
payload 的写入通常通过 WriteProcessMemeory 完成。如下恶意软件使用了线程执行劫持技术:

  • Zloader:利用线程劫持将加密的恶意 DLL 和 shellcode(用于解密 DLL)注入到合法的 msexec.exe 中。

 

Process Hollowing(进程镂空)

Process Hollowing 首先基于合法的可执行文件创建一个挂起状态(CREATE_SUSPENDED)的进程,然后通过 ZwUnmapViewOfSection / NtUnmapViewOfSection 将合法文件映射的内存段释放,然后在相应位置写入 payload,之后通过 SetThreadContext, ResumeThread 劫持控制以执行 payload。payload 的写入通常通过 WriteProcessMemeory 完成,写入的目标是新建的合法进程。如下 APT 组织在最近的活动中使用了进程镂空技术:

 

APC 注入

APC 注入 在将 payload(可以是shellcode,DLL路径等)写入目标进程之后,不通过创建/劫持远程线程来执行 payload,而是通过异步过程调用(APC)触发 payload 的执行,通常利用 QueueUserAPC 为目标线程添加 APC 对象。由于 APC 只有当目标进程处于可唤醒状态(alertable state)时才会被执行。因此目标线程需要在被注入后处于/进入可唤醒状态。线程可以通过调用 SleepExSignalObjectAndWaitWaitForSingleObjectExWaitForMultipleObjectsExMsgWaitForMultipleObjectsEx 进入可唤醒状态。

如果线程在初次执行前 APC 队列已经将被添加了 APC 对象,则这些 APC 函数将先于线程的起始地址被执行,早鸟注入(Early Bird Injection)正式利用了这一点,它首先基于合法的可执行文件创建一个挂起状态(CREATE_SUSPENDED)的进程,然后写入 payload 并为主线程添加指向 payload 的 APC 对象,最后通过 ResumeThread 恢复进程执行以触发 APC。

APC 注入的另一变种 AtomBombing 利用了全局原子表(Global Atom Table)来存储 payload,然后通过 APC(如调用 GlobalGetAtomNameW)使目标进程将 payload 复制到自身进程空间,如此一来避免使用了 WriteProcessMemeory 来写入 payload。由于全局原子表中存储的内容会以空字符截断,因此 payload 需要是不包含空字符的 shellcode。另外为了避免通过调用 VirtualAllocEx 在目标进程申请 RWX 内存,AtomBombing 利用 ROP 链申请 RWX 内存,然后将之前写入的 payload 复制到申请的 RWX 内存中,最后将控制流转移到 payload。构造的 ROP 链同样存放在全局原子表中,并利用 APC 将其复制到目标进程。ROP 链的执行则通过 APC 使目标线程调用 SetThreadContext 实现。

如下 APT 组织或活动在最近的活动中使用了 APC 注入技术:

 

Process Doppelgänging

Process Doppelgänging 利用 NTFS 事务的特性隐藏进程注入动作。NTFS 事务(TxF)从 Windows Vista 开始引进,它允许对文件的写操作和数据库的事务机制一样,只允许一个事务在某一时刻对同一文件进行写操作,并且如果系统或应用程序在写入事务期间发生故障,TxF 会执行自动回滚,以避免文件损坏。由于在写事务完成前,其它进程只能读取写事务开始前已提交的文件版本,因此在整个写事务期间对文件的修改对其它进程都是不可见的。Process Doppelgänging 正是利用了这一点和回滚机制来隐藏 payload 注入操作。Process Doppelgänging 通常通过如下步骤实现:

  • 1) 创建一个针对合法可执行文件的写事务,并将该文件的内容覆盖为 payload
  • 2) 基于覆写的文件(payload)创建映像段(NtCreateSection, SEC_IMAGE)
  • 3) 回滚写事务(RollbackTransaction),此时对合法文件的修改会被撤销
  • 4) 基于创建的映像段创建进程,设置进程参数和环境变量,然后创建主线程执行 payload

Process Doppelgänging 不通过 WriteProcessMemeory 写入 payload,但是在为进程设置参数和环境变量时,通常仍需借助 WriteProcessMemeory。这里的 payload 与之前的进程注入方式略有不同,之前的 payload 是 DLL 路径,DLL/PE 文件或 shellcode,这里的 payload 是映像段。Process Doppelgänging 在较新版本的 Windows 10 中会被 Windows Defender 拦截。如下 APT 组织或恶意软件在最近的活动中使用了线程执行劫持技术:

  • Leafminer – Leafminer: New Espionage Campaigns Targeting Middle Eastern Regions:Leafminer 利用 Process Doppelgänging 来部署改名后的 Mimikatz。
  • Osiris dropper:Osiris 木马释放器利用 Process Doppelgänging 生成了恶意的映像段,然后类似 Process Hollowing 的方式将该映像段(通过 ZwMapViewOfSection) 映射到基于合法文件创建的进程中并开始执行,只是映射到目标的其它位置,而不是替换掉原先的合法映像段。

 

Process Herpaderping

Process Herpaderping 通过在映像映射后修改磁盘上的内容来掩盖进程意图。Process Herpaderping通常通过如下 6 个步骤实现:

  • 1) 写恶意代码 – 将恶意负载写入目标文件(不存在将被创建),保持目标文件句柄打开。
  • 2) 映射恶意代码 – 将文件映射为一个映像段(NtCreateSection, SEC_IMAGE)。
  • 3) 创建进程对象 – 使用映射的段创建进程对象(NtCreateProcessEx)。
  • 4) 模糊目标文件 – 使用打开的再次修改目标文件,比如改成合法程序(当原来的文件不存在时)。
  • 5) 创建主线程 – 为进程创建初始线程并开始执行,这时通过内核回调 PsSetCreateProcessNotifyRoutineEx 注册的进程创建回调将被调用。
  • 6) 关闭文件句柄 – 关闭文件句柄,这时 IRP_MJ_CLEANUP IRP 包被发送。

如果杀毒软件通过内核回调 PsSetCreateProcessNotifyRoutineEx 或接收 IRP_MJ_CLEANUP IRP 包后对进程对应的文件进行检查,则可能得到
预期之外的结果,因为此时文件已经在 模糊目标文件 步骤时被修改了,与进程实际执行的代码不一致。

与 Process Doppelgänging 类似,Process Herpaderping 不通过 WriteProcessMemeory 写入 payload,并且注入的 payload 是映像段。Process Herpaderping 的步骤 3,5 和 Process Doppelgänging 的第 4 步完成的操作基本相同,都是为了完成从映像段到进程并执行的转变,通常仍需借助 WriteProcessMemeory 来完成。但是与 Process Doppelgänging 不同的是,Process Herpaderping 并不借助 NTFS 事务的特性隐藏恶意代码的注入,而是利用(基于恶意映像段)进程对象的创建要早于内核回调的调用这一时间差来隐藏 payload 的注入。Sysmon 目前已经能检测该种进程注入方式(Event ID 25)。

 

Process Ghosting

Process Ghosting 利用待删除文件的特性来掩盖进程意图。Process Ghosting 通常通过如下 6 个步骤实现:

  • 1) 创建待删除文件 – 创建文件,并通过 NtSetInformationFile 将文件状态设置为待删除。
  • 2) 写入恶意代码 – 将恶意代码写入文件。由于文件处于待删除状态,写入的内容不会持久化,并且待删除状态的文件会阻止其它进程打开该文件。
  • 3) 映射恶意代码 – 将文件映射为一个映像段。
  • 4) 关闭文件句柄 – 关闭文件句柄,此时文件被删除。
  • 5) 创建进程对象 – 使用映射的段创建进程。
  • 6) 创建主线程 – 为进程创建初始线程并开始执行。

由于待删除文件会阻止其它进程打开文件,并且该文件在进程开始执行后已经从文件系统删除,因此可能会逃逸安全产品的检测。Process Ghosting 与 Process Herpaderping 和 Process Doppelgänging 类似,不通过 WriteProcessMemeory 写入 payload,并且注入的 payload 是映像段。Process Ghosting 的步骤 5,6 和 Process Herpaderping 的步骤 3,5 及 Process Doppelgänging 的第 4 步完成的操作基本相同,都是为了完成从映像段到进程并执行的转变,通常仍需借助 WriteProcessMemeory 来完成。但是与前两者不同的是,Process Ghosting 不通过 NTFS 事务的特性或利用进程对象的创建与内核回调的调用之间的窗口期进行覆写来隐藏恶意代码的注入,而是通过待删除文件不会持久化且不能被其它进程打开的特性来隐藏 payload 的注入。

已知如下软件使用了 Process Ghosting 注入技术:

  • Skrull :Skrull 是一种恶意软件 DRM,可防止 AV/EDR 自动提交样本和内核签名扫描。它使用 Process Ghosting 技术生成可以在受害者身上运行恶意软件的启动器。

以上进程注入方法大多数通过 WriteProcessMemeory/NtWriteVirtualMemory/ZwWriteVirtualMemory 写入 payload;Process Doppelgänging、Process Herpaderping 和 Process Ghosting 虽然不通过 WriteProcessMemeory/NtWriteVirtualMemory 写入 payload,但是它们为新建进程设置参数和环境变量时,仍然借助这几个 API;APC 注入的变种 AtomBombing 通过 APC 读取全局原子表的方式注入 payload。执行 payload 的方法包括创建或劫持远程线程、APC。

 

参考链接

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多