写在最前

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

https://discord.gg/9XvvuFq9Wb

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


背景

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

今天先来看一下进程免杀的技巧第一篇,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,                                       // 文档强制为 0PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, // 使用 PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 来创建新的进程&hParentProcess,                      // 新进程的父进程sizeof(HANDLE),                           // HANDLE 的 sizeNULL,                                   // 文档强制为 NULLNULL                                   // 文档强制为 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 中的 StartupInfoNULL,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);DeleteProcThreadAttributeList(sie.lpAttributeList);return 0;

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

或者是 svchost.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

Malware Dev 01 - 免杀之 PPID Spoofing 原理解析相关推荐

  1. python加载shellcode免杀 简介

    目录 前言 0X00  基础概念 1. python ctypes模块介绍 2. dll动态链接库 3. pyinstaller 4. shellcode 5.关于windows defender 6 ...

  2. Atitit.木马 病毒 免杀 技术 360免杀 杀毒软件免杀 原理与原则 attilax 总结...

    Atitit.木马 病毒 免杀 技术 360免杀 杀毒软件免杀 原理与原则 attilax 总结 1. ,免杀技术的用途2 1.1. 病毒木马的编写2 1.2. 软件保护所用的加密产品(比如壳)中,有 ...

  3. 【Python】多线程FuzzWaf异或免杀爆破

    [Python]多线程Fuzz&Waf异或免杀&爆破 学习内容和目的 简单多线程脚本 利用FTP模块实现协议爆破脚本 不含多线程简单爆破 引入queue和threading 配合Fuz ...

  4. python通过异或运算构造无字符后门实现免杀

    1.免杀异或shell原理 php异或: ^为异或的符号 ( "!" ^ "@" )= 'a' //两个变量的值进行异或时,会先将两个变量的值转换为ASCII, ...

  5. 远控免杀专题(67)-白名单(113个)总结篇

    关于白名单程序 相信大家对白名单程序利用的手法也已经非常熟悉了,白名单程序利用其实是起源于LOLBins,全称"Living-Off-the-Land Binaries",直白翻译 ...

  6. 远控免杀从入门到实践之白名单(113个)总结篇

    郑重声明:文中所涉及的技术.思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担! <远控免杀从入门到实践>系列文章目录: 1.远控免杀从入 ...

  7. Kail Linux渗透测试教程之免杀Payload生成工具Veil

    Kail Linux渗透测试教程之免杀Payload生成工具Veil 免杀Payload生成工具--Veil Kail Linux渗透测试教程之免杀Payload生成工具Veil,Veil是一款利用M ...

  8. Webshell免杀绕过waf

    转自圈子404师傅 0x01 前言# 尽最大努力在一文中让大家掌握一些有用的WEBSHELL免杀技巧 0x02 目录# 关于eval 于 assert 字符串变形 定义函数绕过 回调函数 回调函数变形 ...

  9. 20155301实验三 免杀原理与实践

    20155301实验三 免杀原理与实践 实验内容 1 正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,自己利用shellcode编程等免杀工具或技巧: 2 ...

最新文章

  1. EMC首席数据治理官:“受托人”是数据湖问责的关键
  2. python pow和**_Python学习笔记 | 实例3:天天向上的力量
  3. Win2003 Server 安全的个人Web服务器
  4. python 语言教程(4)元组
  5. [IE编程] 如何获得IE版本号
  6. VTK:AnatomicalOrientation解剖定位用法实战
  7. (十三) 深入浅出TCPIP之setsockopt参数详解
  8. Magento模块开发之数据库SQL操作方法说明
  9. Multi-thread--C++11中atomic的使用
  10. 通过Lotusscript修改数据库主模板属性
  11. PHP配置问题(找不到指定模块)解决办法
  12. 【VBA研究】用VBA创建数据透视表
  13. 向系统日历添加日程提醒的规则
  14. yum源及常用安装包整理
  15. db2和相关驱动的下载
  16. Go语言基础教程:版本选择
  17. 运营人员必知!SPU和SKU是什么?
  18. 箱包卖家注意了!《淘宝网箱包行业标准》出炉 !
  19. 第六次网页前端培训(JavaScript)
  20. 系统集成特一级资质标准

热门文章

  1. 企业微信JSSDK接口页面加载完无法立即执行的问题
  2. fm算法详解_fm算法(基于fm推荐算法)
  3. Zookeeper后端开发工具Curator的使用 | Curator对节点的增删改查 | ACL权限控制 | 分布式锁 | 分布式计数器 | 附带最新版本下载
  4. 【spine】快速入门
  5. Android ps进程命令
  6. GA 遗传算法-含代码-多图
  7. VS2019中C语言中使用scanf 报错_CRT_SECURE_NO_WARNINGS,简单解决,一劳永逸
  8. next()和nextLine()区别
  9. Windows驱动 识别不成功的原因查找
  10. lpc1788开发之SDRAM