父进程欺骗

3.1.简介

父进程欺骗技术是说,把一个恶意进程的 PID指定为一个合法的进程(lsass.exe)的 PID

安全软件会通过对父子进程间关系的检测来判断该进程是否异常,攻击者以此技术规避启发式检测等防御手段。

3.2.原理

父进程欺骗用的最多的方法就是通过 C r e a t e P r o c e s s \textcolor{cornflowerblue}{CreateProcess} CreateProcess函数实现,其原型如下:

BOOL
WINAPI
CreateProcessA(
    _In_opt_ LPCSTR lpApplicationName,						
    _Inout_opt_ LPSTR lpCommandLine,			
    _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,		
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ BOOL bInheritHandles,
    _In_ DWORD dwCreationFlags,
    _In_opt_ LPVOID lpEnvironment,
    _In_opt_ LPCSTR lpCurrentDirectory,
    _In_ LPSTARTUPINFOA lpStartupInfo,
    _Out_ LPPROCESS_INFORMATION lpProcessInformation
    );
[in, optional] lpApplicationName

要执行的模块的名称。 该模块可以是基于 Windows 的应用程序。 如果适当的子系统在本地计算机上可用,它可以是某种其他类型的模块。

该字符串可以指定要执行的模块的完整路径和文件名,也可以指定部分名称。 在部分名称的情况下,该函数使用当前驱动器和当前目录来完成规范。 该函数不会使用搜索路径。 该参数必须包含文件扩展名; 假定没有默认扩展名。

lpApplicationName 参数可以是 NULL 。 在这种情况下,模块名称必须是 lpCommandLine字符串中第一个以空格分隔的标记。 如果您使用包含空格的长文件名,请使用带引号的字符串来指示文件名的结束位置和参数的开始位置; 否则,文件名不明确。 例如,考虑字符串 “c:\program\files\subdir\programname”。 这个字符串可以用多种方式解释。 系统尝试按以下顺序解释可能性:

  1. c:\程序.exe
  2. c:\程序文件\sub.exe
  3. c:\程序文件\子目录\program.exe
  4. c:\程序文件\子目录\程序名称.exe

如果可执行模块是 16 位应用程序, lpApplicationName 应该是 NULL 指向的字符串 lpCommandLine 应该指定可执行模块以及它的参数。

[in, out, optional] lpCommandLine

要执行的命令行。

此字符串的最大长度为 32,767 个字符,包括 Unicode 终止空字符。 如果 lpApplicationNameNULL 的模块名称部分 lpCommandLine 仅限于 MAX_PATH 字符。

此函数的 Unicode 版本 CreateProcessW 可以修改此字符串的内容。 因此,此参数不能是指向只读内存的指针(例如 const 变量或文字字符串)。 如果此参数是一个常量字符串,该函数可能会导致访问冲突。

lpCommandLine 参数可以为 NULL 在这种情况下,函数使用 lpApplicationName 作为命令行。

[in, optional] lpProcessAttributes

一个指针 SECURITY_ATTRIBUTES结构,确定返回的新进程对象的句柄是否可以被子进程继承。 如果 lpProcessAttributesNULL ,则不能继承句柄。

lpSecurityDescriptor 成员指定新进程的安全描述符。 如果 lpProcessAttributesNULLlpSecurityDescriptorNULL ,则进程获取默认安全描述符。 进程的默认安全描述符中的 ACL 来自创建者的主令牌。 Windows XP: 进程的默认安全描述符中的 ACL 来自创建者的主令牌或模拟令牌。 这种行为在带有 SP2Windows XPWindows Server 2003 中发生了变化。

[in, optional] lpThreadAttributes

一个指针 SECURITY_ATTRIBUTES 结构,确定返回的新线程对象的句柄是否可以被子进程继承。 如果 lpThreadAttributesNULL,则不能继承句柄。

lpSecurityDescriptor 成员指定主线程的安全描述符。 如果 lpThreadAttributesNULLlpSecurityDescriptorNULL,则线程获取默认安全描述符。 线程的默认安全描述符中的 ACL 来自进程令牌。 Windows XP: 线程的默认安全描述符中的 ACL 来自创建者的主令牌或模拟令牌。 这种行为在带有 SP2Windows XPWindows Server 2003 中发生了变化。

[in] bInheritHandles

如果此参数为 TRUE,则调用进程中的每个可继承句柄都由新进程继承。 如果参数为 FALSE,则不继承句柄。

[in] dwCreationFlags

控制优先级和进程创建的标志。参见下表

常数/值描述
CREATE_BREAKAWAY_FROM_JOB 0x01000000与作业关联的进程的子进程不与该作业关联。 如果调用进程没有与作业相关联,则此常量无效。 如果调用进程与作业相关联,则作业必须设置 JOB_OBJECT_LIMIT_BREAKAWAY_OK 限制。
CREATE_DEFAULT_ERROR_MODE 0x04000000新进程不继承调用进程的错误模式。 相反,新进程获取默认错误模式。 此功能对于在禁用硬错误的情况下运行的多线程 shell 应用程序特别有用。 默认行为是让新进程继承调用者的错误模式。 设置此标志会更改该默认行为。
CREATE_NEW_CONSOLE 0x00000010新进程有一个新控制台,而不是继承其父控制台(默认)。
CREATE_NEW_PROCESS_GROUP 0x00000200新进程是新进程组的根进程。 进程组包括作为该根进程的后代的所有进程。 新进程组的进程标识符与进程标识符相同,在 lpProcessInformation 参数中返回。 使用进程组 GenerateConsoleCtrlEvent 来启用向一组控制台进程发送 CTRL+BREAK 信号。 如果指定了此标志,则将为新进程组中的所有进程禁用 CTRL+C 信号。 指定,则忽略此标志 CREATE_NEW_CONSOLE
CREATE_NO_WINDOW 0x08000000该进程是一个在没有控制台窗口的情况下运行的控制台应用程序。 因此,未设置应用程序的控制台句柄。 如果应用程序不是控制台应用程序,或者与 CREATE_NEW_CONSOLEDETACHED_PROCESS
CREATE_PROTECTED_PROCESS 0x00040000该进程将作为受保护进程运行。 系统限制对受保护进程和受保护进程线程的访问。 有关进程如何与受保护进程交互的更多信息,请参阅 进程安全和访问权限 。 要激活受保护的进程,二进制文件必须具有特殊签名。 此签名由 Microsoft 提供,但目前不适用于非 Microsoft 二进制文件。 目前有四个受保护的进程:媒体基础、音频引擎、Windows 错误报告和系统。 加载到这些二进制文件中的组件也必须经过签名。 多媒体公司可以利用前两个受保护的流程。 有关详细信息,请参阅 受保护媒体路径概述 Windows Server 2003 和 Windows XP: 不支持此值。
CREATE_PRESERVE_CODE_AUTHZ_LEVEL 0x02000000允许调用者执行绕过通常会自动应用于进程的进程限制的子进程。
CREATE_SECURE_PROCESS 0x00400000此标志允许在基于虚拟化的安全环境中运行的安全进程启动。
CREATE_SEPARATE_WOW_VDM 0x00000800此标志仅在启动基于 Windows16 位应用程序时有效。 如果设置,新进程将在专用虚拟 DOS 机 (VDM) 中运行。 默认情况下,所有基于 Windows16 位应用程序作为线程在单个共享 VDM 中运行。 单独运行的好处是崩溃只会终止单个 VDM; 在不同 VDM 中运行的任何其他程序继续正常运行。 此外,在单独的 VDM 中运行的基于 Windows16 位应用程序具有单独的输入队列。 这意味着如果一个应用程序暂时停止响应,不同 VDM 中的应用程序将继续接收输入。 单独运行的缺点是这样做需要更多的内存。 仅当用户请求 16 位应用程序应在其自己的 VDM 中运行时,才应使用此标志。
CREATE_SHARED_WOW_VDM 0x00001000该标志仅在启动基于 Windows16 位应用程序时有效。 如果 WIN.INIWindows 部分中的 DefaultSeparateVDM 开关为 TRUE ,则此标志将覆盖该开关。 新进程在共享的虚拟 DOS 机中运行。
CREATE_SUSPENDED 0x00000004新进程的主线程以挂起状态创建,直到 调用 ResumeThread 函数才运行。
CREATE_UNICODE_ENVIRONMENT 0x00000400如果设置了这个标志,lpEnvironment 使用 Unicode 字符。 否则,环境块使用 ANSI 字符。
DEBUG_ONLY_THIS_PROCESS 0x00000002调用线程启动并调试新进程。 接收所有相关的调试事件 WaitForDebugEvent 函数
DEBUG_PROCESS 0x00000001调用线程启动并调试新进程和新进程创建的所有子进程。 接收所有相关的调试事件 WaitForDebugEvent 函数 使用 DEBUG_PROCESS 成为调试链的根。 这一直持续到使用 DEBUG_PROCESS 。 如果此标志与 DEBUG_ONLY_THIS_PROCESS ,则调用者仅调试新进程,而不调试任何子进程。
DETACHED_PROCESS 0x00000008对于控制台进程,新进程不会继承其父控制台(默认)。 新进程可以稍后调用 AllocConsole 函数来创建控制台。 有关更多信息,请参阅 创建控制台 。 此值不能与 CREATE_NEW_CONSOLE
EXTENDED_STARTUPINFO_PRESENT 0x00080000该进程是使用扩展启动信息创建的; lpStartupInfo参数 指定一个 STARTUPINFOEX 结构。 Windows Server 2003 和 Windows XP: 不支持此值。
INHERIT_PARENT_AFFINITY 0x00010000该进程继承其父进程的亲和性。 如果父进程在多个处理器组,则新进程将继承父进程使用的任意组的组相对亲和性。 Windows Server 2008、Windows Vista、Windows Server 2003 和 Windows XP: 不支持此值。

C r e a t e P r o c e s s \textcolor{cornflowerblue}{CreateProcess} CreateProcess用于创建一个新进程,默认情况下由父进程创建。该函数的 lpStartupInfo参数允许调用者设定父进程,所以这就是用来实现父进程欺骗的关键点。 顺 便 说 一 句 , 该 功 能 最 初 用 于 W i n d o w s V i s t a 中 设 置 U A C 的 。 \textcolor{green}{顺便说一句,该功能最初用于 Windows Vista中设置UAC的。} 便WindowsVistaUAC

lpStartupInfo参数中有个 lpAttributeList属性,该属性可通过调用函数 I n i t i a l i z e P r o c T h r e a d A t t r i b u t e L i s t \textcolor{cornflowerblue}{InitializeProcThreadAttributeList} InitializeProcThreadAttributeList进行初始化,并调用 U p d a t e P r o c T h r e a d A t t r i b u t e \textcolor{cornflowerblue}{UpdateProcThreadAttribute} UpdateProcThreadAttribute函数给lpAttributeList属性添加 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS标志即可实现父进程欺骗。

3.3.代码

BOOL FatherProcessSpoofing(DWORD pid, char* cmd) {
	PROCESS_INFORMATION pi = { 0 };
	STARTUPINFOEXA si = { 0 };
	SIZE_T size = 0;
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
	if (hProcess == NULL) {
		printf("[-] Error(%d): OpenProcess failed!\n",__LINE__);
		return FALSE;
	}

	// 初始化进程启动属性
	InitializeProcThreadAttributeList(NULL, 1, 0, &size);
	si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, size);
	InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
	// 更新属性
	if (!UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(hProcess), NULL, NULL)) {
		printf("[-] Error(%d): UpdateProcThreadAttribute failed!\n", __LINE__);
		CloseHandle(hProcess);
		return FALSE;
	}
	
	si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
	if (!CreateProcessA(
		NULL,
		cmd,
		NULL,
		NULL,
		TRUE,
		CREATE_NEW_CONSOLE | EXTENDED_STARTUPINFO_PRESENT,
		NULL,
		NULL,
		(LPSTARTUPINFOA)&si,
		&pi
	)) {
		printf("[-] Error(%d): CreateProcessA failed!\n", __LINE__);
		CloseHandle(hProcess);
		return FALSE;
	}
	return TRUE;
}

3.4.演示

《父进程欺骗》

《父进程欺骗》

3.5.最后

最后想说说进程树。通过这种修改父进程的方式,可以以 notepad.exe为根节点,cmd.exe或者其他进程为子节点,

最后可以形成如下的树形结构:

《父进程欺骗》

《父进程欺骗》

  • notepad.exe是整棵树的根节点,也是 cmd.execalc.exe的父进程;同理,cmd.execalc.execmd.exe的父进程,calc.execmd.execmd.exe的父进程。

  • 如果以结束进程树的方式结束 notepad.exe进程,则整棵树下的所有子节点和叶子节点的进程都会被结束,如果一普通结束进程的方式结束 notepad.exe进程,则下面的进程不会被结束。

  • 如果以普通结束进程的方式结束树中某个节点的进程,进程树的连接性就会被破坏,例如这种情形:

    • 对应的树形结构:

《父进程欺骗》

  • 由于失去了父进程,最右下角的两个叶子结点进程 cmd.exe就会变成单独的两个进程。

  • 整棵树就退化成:

    • 《父进程欺骗》

​ 此时如果再以结束进程树的方式结束 notepad.exe,那么只有还在树上的进程会被关闭,最右下角的两个叶子节点 cmd.exe进程不会被结束。

3.6.参考

[0] https://blog.csdn.net/linlin003/article/details/108864860

[1] https://www.anquanke.com/post/id/168618

    原文作者:飞鸿踏雪(蓝屏选手)
    原文地址: https://blog.csdn.net/qq_41252520/article/details/124401035
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞