首页
社区
课程
招聘
[原创]Windows 借助服务实现无UAC提示创建管理员权限的进程
发表于: 2025-10-27 08:52 758

[原创]Windows 借助服务实现无UAC提示创建管理员权限的进程

2025-10-27 08:52
758

上次写完Windows访问控制机制文章之后,想起之前的一个需求,如何让一个GUI程序以管理员权限实现自启动。有的朋友可能会说,方法有很多,比如:注册表、计划任务、启动文件夹和组策略设置启动脚本。上述这些方法只有一种可以生效,那就是计划任务,其他的方式会因为权限的问题导致目标程序启动失败,如下图所示:
auto boot error
而计划任务有可能会被杀软进行清除,导致目标程序启动失败。本篇文章介绍如何从服务进程启动一个GUI程序,新进程拥有管理员权限。

原理

User Account Control

UAC(User Account Control,用户账户控制)是从Windows Vista和Windows Server 2008版本开始引入的一项安全机制,旨在提高操作系统的安全性,防止未经授权的系统更改。在UAC机制下,如果隶属于管理员组的用户登录到系统之后,它得到的是一个经过过滤的标准权限token(filtered token)来运行程序。如果程序运行需要管理员权限,则filter token会被提升至unfiltered token,这个token拥有管理员应有的全部权限。

如果程序需要以管理员权限进行启动,可以在VS项目的Properties->Linker->Manifest File->UAC Execution Level中设置为requireAdministrator表示程序启动需要管理员权限。这样编译之后的程序,会显示一个小盾牌,该程序启动的时候会弹出一个安全提示框,表示当前程序将以管理员权限启动。经过签名和未签名的程序,弹出的提示框颜色不同,未经过签名的提示窗是黄色的,经过签名的程序的提示窗是蓝色的。
UAC unsigned
UAC signed

启动之后的注册表编辑器进程是管理员进程:
Admin Proc
该进程对应的token自然是一个具有管理员权限的token。这需要你当前登录的Windows账户本身就属于管理员组,如果不属于管理员组,那么就需要输入一个隶属于管理员组的成员的账号和密码进行验证。
UAC_username_passwd

根据Windows System Internals 7th中的描述,UAC机制是在可以设置中关闭的,关闭之后管理员组成员创建的任何进程都拥有管理权限。
UAC_any_process

实际工作中是存在这种需求的,比如:在云沙箱的环境下自动化运行恶意程序,需要充分暴露恶意程序的行为,那么就需要进行这样的设置。

LinkedToken

上文提到了用户登录到系统中之后,拿到的是一个filtered token,而LinkedToken对于filtered token就是拥有管理员权限的token(unfiltered token),这两种类型的token互为linked token。

1
2
3
4
5
6
7
BOOL GetTokenInformation(
  [in]            HANDLE                  TokenHandle,
  [in]            TOKEN_INFORMATION_CLASS TokenInformationClass,
  [out, optional] LPVOID                  TokenInformation,
  [in]            DWORD                   TokenInformationLength,
  [out]           PDWORD                  ReturnLength
);

使用该Win32 API函数,第二个参数传入一个TokenLinkedToken,就可以获取一个token的Linked Token。
那么此时就有一个问题,假如一个恶意程序通过filtered token拿到一个拥有管理员权限的unfiltered token,然后再调用CreateProcessAsUser函数就可以实现提权了。显然,这是不可能的。我们从内核中开始分析,GetTokenInformation调用的底层API是NtQueryInformationToken,

NT_NtQueryInformationToken_LinkedToken

上图中的591行有"v97 = -(SeSinglePrivilegeCheck(SeTcbPrivilege, v10) != 0);",这是检查当前进程是否具有SeTcbPrivilege权限,他的英文介绍是"Act as part of the operating system",普通进程不可能拥有这个权限,服务进程拥有这个权限。
此时SepDuplicateToken的第四个参数v99应该是2,TokenType对应是TokenImpersonation,第五个参数是1,ImpersonationLevel是SecurityIdentification。获取的token无法用于进程和线程的创建,原因如下:

  • CreateProcessAsUser的第一个参数hToken要求指向的token对象是一个Primary token而不是一个impersonate token。token的类型不符合。
  • SetThreadToken为特定线程设置impersonate token,要求token的ImpersonationLevel至少是SecurityImpersonation。token的level不符合。

普通进程获取的linked token只能用来进行信息查询。比如:查询当前用户是否属于管理员组以及完整的token拥有哪些权限等。

具体实现

方法一

使用服务的token作为GUI进程的token,服务的账户一般是Local System,它的token权限大于管理员权限。步骤如下:

  • OpenProcess当前进程,获取进程句柄,复制当前进程的token为dupToken。
  • 设置dupToken的参数信息,包括:session id和窗口工作站
  • 根据dupToken创建环境变量,调用CreateProcesssAsUser创建新的进程

该方法有一个缺点,有些环境变量信息是不正确的,比如:访问注册表HKEY_CURRENT_USER,该方法访问的路径则是,HKEY_USERS\S-1-5-18。使用该方法的话需要修改对应的代码才能正常使用。
registry problem
相关链接为:898K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3k6X3!0G2K9r3q4U0K9#2)9J5c8Y4m8Q4x3V1j5$3x3U0R3J5z5o6x3H3i4K6u0W2K9s2c8E0L8l9`.`.

方法二

使用会话的LinkedToken来作为GUI进程的token,如果当前会话是管理员组成员,则获取的LinkedToken就是拥有管理员权限的token。步骤如下:

  • 调用WTSGetActiveConsoleSessionId和WTSQueryUserToken来获取用户的会话token
  • GetTokenInformation获取会话token的linked token
  • 根据linked token创建环境变量,调用CreateProcessAsUser创建GUI进程。

总体代码如下:

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
BOOL StartGameAssistantProcess(WCHAR* cmdline)
{
    int res = 0;
    DWORD dwSessionId = 0;
    HANDLE hTokenLinked = NULL;
    HANDLE hToken = NULL;
    HANDLE hTokenToUse = NULL;
    LPVOID pEnv = NULL;
    STARTUPINFO si = { sizeof(STARTUPINFO) };
    PROCESS_INFORMATION processInfo = { 0 };
    WCHAR lpDesktop[] = L"WinSta0\\Default";
    TOKEN_ELEVATION_TYPE tokenElvType = TokenElevationTypeDefault;
    DWORD dwSize = 0;
     
    dwSessionId = WTSGetActiveConsoleSessionId();
    if (dwSessionId == 0xFFFFFFFF)
    {
        return FALSE;
    }
 
    BOOL bRet = WTSQueryUserToken(dwSessionId, &hToken);
    if (bRet == FALSE)
    {
        goto Clean;
    }
 
    dwSize = sizeof(tokenElvType);
    if (!GetTokenInformation(hToken, TokenElevationType, &tokenElvType, sizeof(TOKEN_ELEVATION_TYPE), &dwSize))
    {
 
        goto Clean;
    }
 
    if (tokenElvType == TokenElevationTypeLimited)
    {
        dwSize = sizeof(hTokenLinked);
        bRet = GetTokenInformation(hToken, TokenLinkedToken, &hTokenLinked, dwSize, &dwSize);
        if (bRet == FALSE)
        {
            goto Clean;
        }
        hTokenToUse = hTokenLinked;
    }
    else
    {
        hTokenToUse = hToken;
    }
 
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(si);
    si.lpDesktop = lpDesktop;
    si.wShowWindow = SW_SHOW;
    si.dwFlags = STARTF_USESHOWWINDOW;
 
    bRet = CreateEnvironmentBlock(&pEnv, hTokenToUse, FALSE);
    if (!bRet)
    {
        goto Clean;
    }
 
    if (pEnv == NULL)
    {
        goto Clean;
    }
 
    if (!CreateProcessAsUser(hTokenToUse, NULL, cmdline, NULL, NULL, FALSE,
        NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
        pEnv, NULL, &si, &processInfo))
    {
        res = FALSE;
    }
    else
    {
        CloseHandle(processInfo.hThread);
        CloseHandle(processInfo.hProcess);
        res = TRUE;
    }
Clean:
    if (pEnv)
    {
        DestroyEnvironmentBlock(pEnv);
    }
 
    if (hTokenLinked)
    {
        CloseHandle(hTokenLinked);
    }
 
    if (hToken)
    {
        CloseHandle(hToken);
    }
     
    return res;
}

上面这种方法解决方法一的缺陷。但假如当前机器被多个用户使用RDP登录,则上述代码无法生效,上述代码仅适用于一般用户的PC机器。

总结

本文首先分析了UAC和LinkedToken机制,随后介绍了两种使用服务来实现GUI程序自启动的方式,启动的进程拥有管理员权限。

参考链接

b44K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6D9k6h3q4J5L8W2)9J5k6h3#2A6j5%4u0G2M7$3!0X3N6q4)9J5k6h3y4G2L8g2)9J5c8X3g2F1i4K6u0V1N6i4y4Q4x3V1k6%4K9h3&6V1L8%4N6K6i4K6u0r3M7$3g2U0N6i4u0A6N6s2W2Q4x3V1k6S2M7s2m8D9K9h3y4S2N6r3W2G2L8W2)9J5k6s2y4W2j5%4g2J5K9i4c8&6i4K6u0r3j5i4m8H3L8r3W2U0j5i4c8A6L8$3&6Q4x3X3c8U0L8$3&6@1M7X3!0D9i4K6u0r3N6i4y4W2M7W2)9J5k6r3q4U0j5$3!0#2L8Y4c8Q4x3X3c8U0L8$3&6@1M7X3!0D9i4K6u0r3
69fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1k6i4k6T1N6h3N6Q4x3X3g2S2M7Y4c8Q4x3V1k6H3L8%4y4@1M7#2)9J5c8Y4N6A6L8X3c8G2N6%4y4Q4x3X3c8@1L8$3E0W2L8W2)9J5k6s2N6W2K9i4u0W2k6q4)9J5k6r3u0#2k6%4y4Q4x3V1j5`.
5d8K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6B7L8$3&6F1P5g2)9J5k6r3A6G2K9r3&6K6L8$3&6Q4x3X3g2E0k6h3c8A6N6h3#2Q4x3X3g2U0L8$3#2Q4x3V1k6W2P5s2m8D9L8%4u0A6L8X3N6Q4x3X3c8@1L8$3E0W2L8W2)9J5k6r3#2W2L8h3u0W2M7Y4y4Q4x3X3c8H3j5i4u0@1i4K6u0V1x3g2)9J5k6o6b7^5j5X3y4W2z5o6l9H3y4r3x3$3j5b7`.`.
470K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8Y4c8#2M7$3!0F1k6K6R3$3i4K6u0r3j5i4u0@1K9h3y4D9k6g2)9J5c8X3c8W2N6r3q4A6L8s2y4Q4x3V1j5I4x3o6j5#2y4e0j5&6z5o6R3`.


[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回