0%
毅种循环

模块 47 - 伪装 PPID

恶意软件开发课程 - 伪装 PPID


模块 47 - 伪装 PPID#

[!IMPORTANT] 本知识库声明

本知识库由本人整理自互联网 MalDev Academy 泄露资源,并由本人手动翻译为中文,过程中增加了大量关键技术提示实践心得

  1. 内容完整性:并未修改任何核心代码与技术逻辑,仅做汉化与注释加强。
  2. 版权归属:原始知识产权归原作者/官方所有。
  3. 支持正版:本仓库仅供内部学习交流,如果您有经济能力,请务必支持正版课程
  4. 权利申诉:如相关内容侵犯了您的权益,请联系我,我将立即核实并删除。

伪装 PPID#

简介#

父进程 ID (PPID) 伪装 (Parent Process ID Spoofing) 是一种用于修改进程 PPID 的技术,可以有效地隐藏子进程与其真实父进程之间的关系。通过将子进程的 PPID 更改为不同的值,可以使进程看起来像是由于另一个合法的 Windows 进程派生的,而不是真正的父进程。

安全解决方案和防御者通常会寻找异常的父子进程关系。例如,如果 Microsoft Word 派生了 cmd.exe,这通常是执行恶意宏的指标。如果 cmd.exe 以不同的 PPID 派生,它将隐藏真实的父进程,而是看起来像是由于另一个进程派生的。

Early Bird APC 队列代码注入 模块中,RuntimeBroker.exe 是由 EarlyBird.exe 派生的,安全解决方案可以利用这一点来检测恶意活动。

图片
图片

💡 初学者提示:谁是你爸爸?

在 Windows 中,每个进程都有一个“父亲”(父进程)。通常,如果你双击运行一个程序,它的父进程就是 explorer.exe(资源管理器)。

查杀软件(AV/EDR)非常看重这种血缘关系。如果一个不该生孩子的进程(比如 Word 或记事本)突然生出了一个黑窗口(cmd.exe)或一个网络工具(powershell.exe),这就像是在监控摄像机下“当众作案”。

PPID 伪装就是给新进程找一个“干爹”(比如 lsass.exesvchost.exe),让它看起来根正苗红,从而躲过监控。

属性列表 (Attributes List)#

属性列表是一种存储与进程或线程关联的属性列表的数据结构。这些属性可以包括进程或线程的优先级、调度算法、状态、CPU 亲和力和内存地址空间等信息。属性列表可用于有效地存储和检索有关进程和线程的信息,以及在运行时修改进程或线程的属性。

PPID 伪装需要使用和操作进程的属性列表来修改其 PPID。接下来的章节将通过代码展示属性列表的使用。

创建进程#

伪装 PPID 的过程需要使用 CreateProcess 创建进程,并设置 EXTENDED_STARTUPINFO_PRESENT 标志,该标志用于进一步控制创建的进程。此标志允许修改有关进程的一些信息,例如 PPID 信息。微软关于 EXTENDED_STARTUPINFO_PRESENT 的文档指出:

进程是使用扩展启动信息创建的;lpStartupInfo 参数指定一个 STARTUPINFOEX 结构。

这意味着还需要使用 STARTUPINFOEXA 数据结构。

STARTUPINFOEXA 结构#

STARTUPINFOEXA 数据结构如下所示:

typedef struct _STARTUPINFOEXA {
  STARTUPINFOA                 StartupInfo;
  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList; // 属性列表
} STARTUPINFOEXA, *LPSTARTUPINFOEXA;
c
  • StartupInfo 是在之前的模块中用于创建新进程的相同结构。唯一的区别是需要将 cb 成员设置为 sizeof(STARTUPINFOEX)
  • lpAttributeList 是使用 InitializeProcThreadAttributeList WinAPI 创建的。

初始化属性列表#

InitializeProcThreadAttributeList 函数如下所示。

BOOL InitializeProcThreadAttributeList(
  [out, optional] LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
  [in]            DWORD                        dwAttributeCount,
  [in]            DWORD                        dwFlags, 		// NULL (保留)
  [in, out]       PSIZE_T                      lpSize
);
c

要传递一个修改所创建子进程父进程的属性列表,首先使用 InitializeProcThreadAttributeList 创建属性列表。根据微软的文档,必须调用该函数两次:

  1. 第一次调用:lpAttributeList 参数设置为 NULL。这次调用用于确定属性列表的大小,该大小将从 lpSize 参数中接收。
  2. 第二次调用:为 lpAttributeList 参数指定一个有效的指针(分配好内存后)。这次调用才是真正初始化属性列表的操作。

在本例中,dwAttributeCount 将设置为 1,因为我们只需要修改一个属性。

更新属性列表#

成功初始化属性列表后,使用 UpdateProcThreadAttribute WinAPI 将属性添加到列表中。

BOOL UpdateProcThreadAttribute(
  [in, out]       LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,   // 来自 InitializeProcThreadAttributeList 的返回值
  [in]            DWORD                        dwFlags,           // NULL (保留)
  [in]            DWORD_PTR                    Attribute,
  [in]            PVOID                        lpValue,           // 指向属性值的指针
  [in]            SIZE_T                       cbSize,            // lpValue 的大小
  [out, optional] PVOID                        lpPreviousValue,   // NULL (保留)
  [in, optional]  PSIZE_T                      lpReturnSize       // NULL (保留)
);
c
  • Attribute - 这个标志对 PPID 伪装至关重要。它需要设置为 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 标志,以更新父进程信息。
  • lpValue - 父进程的句柄(我们要指定的那个“干爹”进程的句柄)。
  • cbSize - 设置为 sizeof(HANDLE)

实现逻辑总结#

  1. 调用 CreateProcessA 并设置 EXTENDED_STARTUPINFO_PRESENT 标志。
  2. 创建包含 LPPROC_THREAD_ATTRIBUTE_LISTSTARTUPINFOEXA 结构。
  3. 调用 InitializeProcThreadAttributeList 两次。第一次确定大小,第二次进行初始化。
  4. 使用 UpdateProcThreadAttribute 并设置 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 标志来指定新的父进程。

PPID 伪装函数实现#

CreatePPidSpoofedProcess 函数创建一个具有伪装 PPID 的进程。它接受父进程句柄、要创建的进程名,并返回新进程的 PID 和句柄。

演示#

创建子进程 RuntimeBroker.exe,指定父进程为 PID 为 21956svchost.exe。注意,这个 svchost.exe 是以普通权限运行的。

图片
图片

PPID 伪装成功。在 Process Hacker 中,RuntimeBroker.exe 看起来就像是由 svchost.exe 派生出来的。

图片
图片

演示 2 - 更新当前目录 (Current Directory)#

在之前的演示中,你会注意到“Current Directory”(当前工作目录)的值指向了 PPidSpoofing.exe(我们的注入程序)的目录。

图片
图片

这可能是一个明显的 IoC(入侵指标),安全软件或防御者可能会快速标记这种异常。为了修复这个问题,只需将 CreateProcess WinAPI 中的 lpCurrentDirectory 参数设置为一个看起来不那么可疑的目录,例如 "C:\Windows\System32"

图片
图片


🎯 总结#

在本模块中,我们学习了:

  1. PPID 伪装:如何改变进程的“血缘关系”以规避父子关系检测。
  2. 属性列表:深入了解了如何通过 STARTUPINFOEX 和属性列表控制进程行为。
  3. 隐蔽性优化:通过修改 lpCurrentDirectory 参数,进一步消除异常特征,实现更完美的伪装。

💡 关键要点

  • 合法的父进程:通常选择 explorer.exe, svchost.exe, lsass.exe 等常备进程作为模拟对象。
  • 特权要求:伪装并不需要该进程真的是你创建的,只要你有目标父进程的句柄(通常需要 PROCESS_CREATE_PROCESS 访问权限)。

📚 下一步学习

下一个模块将介绍 Process Argument Spoofing (1)。我们将学习如何启动一个带有虚假参数的进程,并在启动后偷偷修改它们,让监控系统看到的参数和实际运行的参数完全不同!