Malware Dev 01 - 免杀之 PPID Spoofing 原理解析

news2025/1/12 1:38:36

写在最前

如果你是信息安全爱好者,如果你想考一些证书来提升自己的能力,那么欢迎大家来我的 Discord 频道 Northern Bay。邀请链接在这里:

https://discord.gg/9XvvuFq9Wb

我会提供备考过程中尽可能多的帮助,并分享学习和实践过程中的资源和心得,大家一起进步,一起 NB~


背景

把免杀主题放在 Malware Dev 里面有点不恰当,但是真的不想分太细了。我目前就两个方向,Active Directory,和 Malware Dev(包括 shellcode 编写,免杀,C2,Windows Kernel/Driver Exploit)。我也不知道自己顾不顾得过来,但是我相信有些东西是通的,越到后面学习曲线越平滑。呵呵呵~

今天先来看一下进程免杀的技巧第一篇,PPID Spoofing。

PPID Spoofing

PPID Spoofing,全称 Parent PID Spoofing。整个过程就是利用 OpenProcessInitializeProcThreadAttributeList, UpdateProcThreadAttribute, 以及 CreateProcess 这些 API,配合 STARTUPINFOEX 结构在创建进程的时候,做到父进程的切换。

该技术通常用于 Cobalt Strike Beacon 的免杀。通常如 shell, run, execute-assembly, shspawn 等 post-ex 命令默认会创建在 Beacon 进程下。例如,如果 Beacon 是通过 Powershell 拿到的,那么这些命令的进程就会被 fork 在 Powershell 进程之下。

在企业这样的注重安全的环境中,进程创建事件会被密切监控(如 Sysmon)。如果一个进程总是在创建非常规进程,那么 Beacon 就会大概率被查杀。例如我们通过 Powershell 已经拿到了 shell,Cobalt Strike 的 powerpick 命令默认使用 rundll32 进程。而通常情况下 Powershell 进程是不会生成 rundll32 进程的,造成 Beacon 被查杀(当然这有其他办法可以解决,今后有机会在 C2 部分细说)。

因此,PPID Spoofing 技术就是用来改变恶意进程的父进程,至少在某种程度上,混淆视听,增加防御或是溯源的难度。

接下来我们就来看一下 PPID Spoofing 的基本原理。

PPID Spoofing 原理概述

PPID Spoofing 是通过在 STARTUPINFOEXW 结构体中的 PPROC_THREAD_ATTRIBUTE_LIST lpAttributeList 成员中,使用 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 来告诉最终调用调用的 CreateProcess 函数,将即将创建的进程,归入到指定的父进程之下。

PPROC_THREAD_ATTRIBUTE_LIST lpAttributeList 成员是通过 InitializeProcThreadAttributeList 分配内存,并由 UpdateProcThreadAttribute 函数设置其属性(设置成 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS),来达到偷换父进程的目的。

PPID Spoofing 原理详解

我们开始拆解 PPID Spoofing 的整个原理,一步一步实践一个 PPID Spoofing。

初始化 STARTUPINFOEXW 结构

一切从 STARTUPINFOEXW 结构体说起。

STARTUPINFOEXW struct:

typedef struct _STARTUPINFOEXW {
  STARTUPINFOW                 StartupInfo;
  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
} STARTUPINFOEXW, *LPSTARTUPINFOEXW;

这个结构体包含了两个成员,一个是 STARTUPINFOW,一个是 LPPROC_THREAD_ATTRIBUTE_LIST。我们要关注的是 LPPROC_THREAD_ATTRIBUTE_LIST 这个成员。

首先,我们初始化一个 STARTUPINFOEXW 结构。

STARTUPINFOEX sie = { sizeof(sie) };

初始化 STARTUPINFOEXW 结构中的 lpAttributeList 成员

我们必须先为 lpAttributeList 成员分配一个内存空间。但是这个空间的大小怎么确定呢?

根据官方文档,这个成员由 InitializeProcThreadAttributeList 函数生成。

在这里插入图片描述

InitializeProcThreadAttributeList function:

BOOL InitializeProcThreadAttributeList(
  [out, optional] LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
  [in]            DWORD                        dwAttributeCount,
                  DWORD                        dwFlags,
  [in, out]       PSIZE_T                      lpSize
);

这个函数有两个 OUT Parameter,lpAttributeList 和 lpSize。lpSize 是 dwAttributeCount 个 lpAttributeList 中的 flag 的总大小,也就是我们要找的 lpAttributeList 的内存空间大小。在概述中,我们知道这里只需要关心 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 这一个 flag,因此,我们可以这样来获取 lpSize 参数的值。

SIZE_T lpSize;
InitializeProcThreadAttributeList
(
	NULL,			// lpAttributeList 先给 NULL,因为第一次调用这个函数是为了获取 lpSize 的值
	1,				// 我们需要往 lpAttributeList 中放存放 1 个 flag,即 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 
	0,				// 这个参数官方文档强制为 0
	&lpSize			// 给出 lpSize 的地址,存放函数的返回值
);

第一次调用之后,我们拿到了 lpSize。接下来,就可以用 lpSize 为 STARTUPINFOEXW 结构中的 lpAttributeList 成员分配 lpSize 大小的内存空间。

sie.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)malloc(lpSize);

lpAttributeList 在内存中有了空间,下一步就可以再次调用 InitializeProcThreadAttributeList,来初始化 lpAttributeList 成员。

if (!InitializeProcThreadAttributeList
	(
		sie.lpAttributeList,	// lpAttributeList,将被初始化
		1,						// 我们只需要 1 个 flag 的大小 (PROC_THREAD_ATTRIBUTE_PARENT_PROCESS )
		0,						// 文档强制为 0
		&lpSize 			// 拥有 1 个 flag 的 lpAttributeList 的大小
	)
)
{
	_tprintf(L"InitializeProcThreadAttributeList failed. Error code: %d.\n", GetLastError());
	return -1;
}

到这里,STARTUPINFOEXW 结构体中的 lpAttributeList 成员,就初始化完成了。

UpdateProcThreadAttribute 指定父进程

这里,我们要告诉指定的父进程,在创建新的进程的时候,以该指定的进程作为父进程。

我们调用 UpdateProcThreadAttribute 函数来完成这个任务。

if (!UpdateProcThreadAttribute(
	sie.lpAttributeList,					// 初始化好的 lpAttributeList 成员
	0,										// 文档强制为 0
	PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,	// 使用 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 来创建新的进程
	&hParentProcess, 						// 新进程的父进程
	sizeof(HANDLE),							// HANDLE 的 size
	NULL,									// 文档强制为 NULL
	NULL									// 文档强制为 NULL
	)
)
{
	_tprintf(L"UpdateProcThreadAttribute failed. Error code: %d.\n", GetLastError());
	return -1;
}

经过这一步,我们可以调用 CreateProcess,配合 EXTENDED_STARTUPINFO_PRESENT flag,在指定进程下,生成新进程。

在指定进程下 CreateProcess 创建新进程

剩下的就是创建新进程了,经过以上步骤,新的进程将会以指定的进程为父进程来创建。

PROCESS_INFORMATION pi;

if (!CreateProcess(
	L"C:\\Windows\\System32\\notepad.exe",
	NULL,
	0,
	0,
	FALSE,
	EXTENDED_STARTUPINFO_PRESENT,		// 告诉 CreateProcess 使用 STARTUPINFOEXW 中的 StartupInfo
	NULL,
	L"C:\\Windows\\System32",
	&sie.StartupInfo,
	&pi))
{
	_tprintf(L"CreateProcess failed. Error code: %d.\n", GetLastError());
	return 0;
}

_tprintf(L"New process created with PID: %d", pi.dwProcessId);
return 0;

最后看一下效果。我们制定 ProcessHacker.exe 为父进程,那么,notepad.exe 就会生成在 ProcessHacker.exe 下面。

在这里插入图片描述

总结

PPID Spoofing 通常结合 Beacon 使用。Cobalt Strike 中也有专门的 PPID 命令来开启 PPID Spoofing。操作系统提供的 API 也是被利用的对象。通过对 PPID Spoofing 的原理的了解,可以发散更多的 API 组合来绕过特定的防御机制。

免杀部分,我们会逐步总结更多的技巧,在本地搭建的 Lab 中逐一实践。

参考链接

  • https://learn.microsoft.com/en-us/windows/win32/psapi/enumerating-all-processes?redirectedfrom=MSDN
  • https://stackoverflow.com/questions/5202114/compare-tchar-with-string-value-in-vc
  • https://www.geeksforgeeks.org/command-line-arguments-in-c-cpp/
  • https://stackoverflow.com/questions/5669173/is-there-a-format-specifier-that-always-means-char-string-with-tprintf
  • https://learn.microsoft.com/en-us/cpp/text/how-to-convert-between-various-string-types?view=msvc-170

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/379770.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第十五天笔记

1. 编程实现计算2023-2-1到2023-3-1相隔多少天? from datetime import datetimestart_date_str "2023-2-1"end_date_str "2023-3-1"start_date datetime.strptime(start_date_str, "%Y-%m-%d")end_date datetime.strptime(end_d…

pmp项目管理考完有什么好处?

作为曾经5A(现在改3A了)通过考试的老学姐说下经验 做好规划 一定要合理安排自己预习、复习和做题的时间,提前规划。其中不要小看课前预习这件事,带着问题去上课,绝对能事半功倍。同时也能及时知道老师到底在讲解哪个知…

网络安全入门:不可不知的8款免费Web安全测试工具

随着 Web 应用越来越广泛,Web 安全威胁日益凸显。黑客利用网站操作系统的漏洞和 Web服务程序的 SQL 注入漏洞等得到Web服务器的控制权限,轻则篡改网页内容,重则窃取重要内部数据,更为严重的则是在网页中植入恶意代码,使…

互联网时代,学什么专业就业好?

互联网时代的手机、智能电视、家具、机械设备等各种有形产品都将会嵌入智能芯片,都会有嵌入式软件或App与之相连,从而形成智能产品。这是我们开启智能化硬件的开始,在这样的环境下,如果要问学什么就业最好?当然首选Jav…

串口、终端应用程序 API termios

UART简介 串口全称为串行接口,也称为COM接口,串行接口指的是比特一位位顺序传输,通信线路简单。使用两根线就可以实现双向通信,一条为TX,一个为RX。串口通信距离远,但速度相对慢,是一种常用的工…

软测入门(二)测试用例、自动化测试理念

测试用例(test case) 特性 有效性:测试用例能够被使用,且被不同的人员使用测试结果一致可复用性:如回归测试的使用可评估性可管理性 八大要素 测试编码:方便归档和查询测试模块/功能预置条件&#xff1a…

2023年功能测试还值得入行吗?

前言 鉴于笔者从13年入行IT行业,经历了只有开发没有测试的阶段,经历了14年只要会基本的功能测试在一线就能薪资过万的阶段,经历了17年只要会一点自动化,会一点性能就能蒙骗过面试官的阶段,更经历了19年所有面试官对于…

操作系统发展历程

手工操作阶段(此阶段无操作系统) 用户在计算机上算题的所有工作都要人工干预。该阶段有两个突出缺点: 用户独占全机,虽然不会出现因资源已被其他用户占用而等待的现象,但资源利用率低。 CPU等待手工操作,CPU的利用不充分 唯一的…

【虚拟机搭建】win11搭建虚拟机两种方式:【virtualbox+vagrant】【VMware】(附centos系统、附安装包)

描述 本教程windows系统搭建虚拟机方式,主要包含两种方式,分别是:【vagrantvirtualbox】和【VMware】推荐大家使用【vagrantvirtualbox】方式进行安装,也可根据自己喜好进行选择本教程安装包 包含三种下载方式,分别是…

关于Could not build wheels for opencv-python-headless, which is...报错的解决方案

在通过最新版pip在线安装package:opencv-python-headless的时候,会产生报错信息,主要为 ERROR: Failed building wheel for opencv-python-headless ERROR: Could not build wheels for opencv-python-headless, which is required to insta…

Active Directory(活动目录)用户登录管理

活动目录用户登录管理 ADManager Plus 通过其预定义的用户登录报告简化了跟踪,监控和整合Active Directory用户登录特定数据的艰巨任务。Active Directory用户登录特定信息,如登录时间,登录历史记录,登录尝试,用户登录…

【钓鱼实测】写bug给new bing和chatGPT查。问他们林黛玉倒拔垂杨柳

BUG 错误代码 #include <iostream> #include <vector> using namespace std; int main() {vector<int> vec{1,2,3,2,4};for (auto iter vec.begin(); iter ! vec.end(); iter ){if (*iter 2) {vec.erase(iter);}}cout << vec.size() << endl…

Elasticsearch:如何正确处理 Elasticsearch 摄取管道故障

在我之前的文章 “Elastic&#xff1a;开发者上手指南” 中的 “Ingest pipeline” 章节中个&#xff0c;我有很多文章是关于 ingest pipeline 的。在今天的文章中&#xff0c;我将重点介绍如何处理在摄取管道中的错误。在我之前的文章 “Elasticsearch&#xff1a;如何处理 in…

Mybatis-Plus 开发提速器:mybatis-plus-generator-ui

Mybatis-Plus 开发提速器&#xff1a;mybatis-plus-generator-ui 1.简介 github地址 &#xff1a; https://github.com/davidfantasy/mybatis-plus-generator-ui 提供交互式的Web UI用于生成兼容mybatis-plus框架的相关功能代码&#xff0c;包括Entity,Mapper,Mapper.xml,Se…

Python(青铜时代)——模块与包

模块 模块是Python 程序架构的一个核心概念 模块好比是 工具包&#xff0c;要想使用这个工具包中的工具&#xff0c;需要使用 import 这个关键字进行导入这个工具包 每一个以扩展名 py 结尾的 Python 源代码文件都是一个 模块 在模块中定义的 全局变量、函数 都是模块能够提…

Laravel-admin之自定义操作日志

laravel-admin是封装性极好的框架&#xff0c;自带的就有操作日志的记录&#xff0c;但是对于非开发人员可能看不懂这个日志&#xff0c;所以就想着给修改一下&#xff0c;以谁修改了什么&#xff0c;谁删除了什么&#xff0c;谁审核了什么&#xff0c;谁添加了什么类似&#x…

【java web篇】数据库连接池Driud的使用

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…

Apache DolphinScheduler 3.1.4 版本发布,修复一键安装报错问题

点击蓝字 关注我们2 月 27 日&#xff0c;Apache DolphinScheduler 发布了 3.1.4 版本。此版本共计修复 11 个 bug&#xff0c;并更新 1 个文档修复。其中的较为重要的 Bug fix 为&#xff1a;修复任务唤醒失败会阻塞事件处理 (#13466)修复 k8s 任务运行失败 (#13348) 修复 Me…

NodeJs 中的 HTML 模板

&#x1f482; 个人网站:【海拥】【摸鱼游戏】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 HTML 模板是一种允许我…

信息系统基本知识(二)

大纲 信息系统与信息化信息系统开发方法常规信息系统集成技术软件工程新一代信息技术信息系统安全技术信息化发展与应用信息系统服务管理信息系统服务规划企业首席信息管及其责任 1.3 常规信息系统集成技术 系统集成&#xff1a;是指将计算机软硬件、网络通信等技术和产品集…