0%

uiaccess

参考Window z-order in Windows 10 – ADeltaX Blog这篇文章,写了一个使用uiaccess权限启动任意(并非任意)程序的脚本,可以实现窗口“超级置顶”

先上代码 uiaccess_tool.cpp,(创建一个控制台项目)

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

static DWORD DuplicateWinloginToken(DWORD dwSessionId, DWORD dwDesiredAccess, PHANDLE phToken) {
DWORD dwErr;
PRIVILEGE_SET ps;

ps.PrivilegeCount = 1;
ps.Control = PRIVILEGE_SET_ALL_NECESSARY;

if (LookupPrivilegeValue(NULL, SE_TCB_NAME, &ps.Privilege[0].Luid)) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE != hSnapshot) {
BOOL bCont, bFound = FALSE;
PROCESSENTRY32 pe;

pe.dwSize = sizeof(pe);
dwErr = ERROR_NOT_FOUND;

for (bCont = Process32First(hSnapshot, &pe); bCont; bCont = Process32Next(hSnapshot, &pe)) {
HANDLE hProcess;

if (_wcsicmp(pe.szExeFile, L"winlogon.exe") != 0) {
continue;
}

hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID);
if (hProcess) {
HANDLE hToken;
DWORD dwRetLen, sid;

if (OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_DUPLICATE, &hToken)) {
BOOL fTcb;

if (PrivilegeCheck(hToken, &ps, &fTcb) && fTcb) {
if (GetTokenInformation(hToken, TokenSessionId, &sid, sizeof(sid), &dwRetLen) && sid == dwSessionId) {
bFound = TRUE;
if (DuplicateTokenEx(hToken, dwDesiredAccess, NULL, SecurityImpersonation, TokenImpersonation, phToken)) {
dwErr = ERROR_SUCCESS;
}
else {
dwErr = GetLastError();
}
}
}
CloseHandle(hToken);
}
CloseHandle(hProcess);
}

if (bFound) break;
}

CloseHandle(hSnapshot);
}
else {
dwErr = GetLastError();
}
}
else {
dwErr = GetLastError();
}

return dwErr;
}

static DWORD CreateUIAccessToken(PHANDLE phToken) {
DWORD dwErr;
HANDLE hTokenSelf;

if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &hTokenSelf)) {
DWORD dwSessionId, dwRetLen;

if (GetTokenInformation(hTokenSelf, TokenSessionId, &dwSessionId, sizeof(dwSessionId), &dwRetLen)) {
HANDLE hTokenSystem;

dwErr = DuplicateWinloginToken(dwSessionId, TOKEN_IMPERSONATE, &hTokenSystem);
if (ERROR_SUCCESS == dwErr) {
if (SetThreadToken(NULL, hTokenSystem)) {
if (DuplicateTokenEx(hTokenSelf, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_DEFAULT, NULL, SecurityAnonymous, TokenPrimary, phToken)) {
BOOL bUIAccess = TRUE;

if (!SetTokenInformation(*phToken, TokenUIAccess, &bUIAccess, sizeof(bUIAccess))) {
dwErr = GetLastError();
CloseHandle(*phToken);
}
}
else {
dwErr = GetLastError();
}
RevertToSelf();
}
else {
dwErr = GetLastError();
}
CloseHandle(hTokenSystem);
}
}
else {
dwErr = GetLastError();
}

CloseHandle(hTokenSelf);
}
else {
dwErr = GetLastError();
}

return dwErr;
}

DWORD PrepareForUIAccessAndStartProcess(LPCWSTR lpApplicationName) {
DWORD dwErr;
HANDLE hTokenUIAccess;

dwErr = CreateUIAccessToken(&hTokenUIAccess);
if (ERROR_SUCCESS == dwErr) {
STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

if (CreateProcessAsUser(hTokenUIAccess, lpApplicationName, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else {
dwErr = GetLastError();
}

CloseHandle(hTokenUIAccess);
}

return dwErr;
}

int wWinMain(int argc, wchar_t* argv[]) {
if (argc != 2) {
wprintf(L"Usage: %s <application_path>\n", argv[0]);
return 1;
}

DWORD result = PrepareForUIAccessAndStartProcess(argv[1]);
if (result == ERROR_SUCCESS) {
wprintf(L"Process started successfully with UI access.\n");
}
else {
wprintf(L"Failed to start process. Error: %lu\n", result);
}

return 0;
}

代码流程:

PixPin_2025-05-08_16-43-14

效果:现在有一个可以窗口置顶的demo(↓拍屏拍的)

0efe7acf00a70add801732d90a263fce

但是经过测试,比如使用tauri编写的程序,获取到uiaccess权限后无法正常运行,可能是因为tauri本身为了压缩体积,需要一些其他的依赖,比如Edge的一些东西(浏览器内核),所以这种程序可能启动失败,但是用普通的wpf,Python,rust的fltk等编写出来的程序运行起来没啥问题