6

在这篇很棒的MSDN 文章的帮助下,我的第一个想法是简单地检查进程是否使用提升的管理员组,并使用AdjustTokenGroups()我将管理员组设置为SE_GROUP_USE_FOR_DENY_ONLY. 不幸的是,我们无法修改当前运行进程的管理员组,因为它也具有SE_GROUP_MANDATORY属性,这使得它无法更改。

MSDN 文档对此有这样的说法:

AdjustTokenGroups函数不能禁用结构中具有该SE_GROUP_MANDATORY属性的组TOKEN_GROUPS。改为使用CreateRestrictedToken

所以,我完成了以下代码来实现这一点;

bool _IsNewProcessLaunched()
{
    HANDLE hToken = NULL;   
    bool hasRestarted = false;

    if (!OpenProcessToken( GetCurrentProcess(), 
        TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ADJUST_GROUPS, 
        &hToken )) 
    {
        return hasRestarted;
    }

    PSECURITY_DESCRIPTOR pSID = NULL;
    SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;

    if(! AllocateAndInitializeSid( &SIDAuth, 2,
        SECURITY_BUILTIN_DOMAIN_RID,
        DOMAIN_ALIAS_RID_ADMINS,
        0, 0, 0, 0, 0, 0,
        &pSID) ) 
    {
        CloseHandle(hToken);
        hToken = NULL;
        return hasRestarted;
    }

    BOOL isAdmin = FALSE;
    BOOL ok = CheckTokenMembership(NULL, pSID, &isAdmin);

    // Create the SID structure for the administrator SID
    SID_AND_ATTRIBUTES adminSID = {0};
    adminSID.Sid = pSID;

    // Create a restricted token which denies the administrator group
    HANDLE restrictedToken;

    CreateRestrictedToken(hToken,RESTR,DISABLE_MAX_PRIVILEGE,&adminSID,NULL,NULL,NULL,NULL,&restrictedToken);

    //Create startup info
    STARTUPINFO si = {0};
    PROCESS_INFORMATION pi = {0};
    si.lpDesktop = L"winsta0\\default";
    si.cb = sizeof( si );

    // Get the current executables name
    TCHAR exePath[MAX_PATH];
    GetModuleFileName(NULL,exePath,MAX_PATH);

    // Start the new (non-administrator elevated) restricted process
    if( CreateProcessAsUser(restrictedToken,exePath,NULL,NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi) == 0)
        hasRestarted = false;
    else
        hasRestarted  = true;

    return hasRestarted;
}

但是新进程仍然以管理员身份运行,而不是以普通用户身份运行。

我该如何做到这一点?

4

1 回答 1

8

由于您正在限制调用进程的令牌,因此启动的进程将使用与调用进程相同的用户帐户运行,只是具有受限的权限。请记住,在 UAC 下,管理员在没有提升的情况下没有完整的管理员权限。 CreateRestrictedToken()创建具有受限权限的令牌。因此,即使用户可能是管理员,也不意味着启动的进程将以管理权限运行。

顺便说一句,有一个更简单的 API,称为Safer API,您可以使用它来代替CreateRestrictedToken()

#include <WinSafer.h>

bool _IsNewProcessLaunched()
{
    // Create the restricted token.

    SAFER_LEVEL_HANDLE hLevel = NULL;
    if (!SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER, SAFER_LEVEL_OPEN, &hLevel, NULL))
    {
        return false;
    }

    HANDLE hRestrictedToken = NULL;
    if (!SaferComputeTokenFromLevel(hLevel, NULL, &hRestrictedToken, 0, NULL))
    {
        SaferCloseLevel(hLevel);
        return false;
    }

    SaferCloseLevel(hLevel);

    // Set the token to medium integrity.

    TOKEN_MANDATORY_LABEL tml = {0};
    tml.Label.Attributes = SE_GROUP_INTEGRITY; 
    // alternatively, use CreateWellKnownSid(WinMediumLabelSid) instead...
    if (!ConvertStringSidToSid(TEXT("S-1-16-8192"), &(tml.Label.Sid)))
    {
        CloseHandle(hRestrictedToken);
        return false;
    }

    if (!SetTokenInformation(hRestrictedToken, TokenIntegrityLevel, &tml, sizeof(tml) + GetLengthSid(tml.Label.Sid))))
    {
        LocalFree(tml.Label.Sid);
        CloseHandle(hRestrictedToken);
        return false;
    }

    LocalFree(tml.Label.Sid);

    // Create startup info

    STARTUPINFO si = {0};
    si.cb = sizeof( si );
    si.lpDesktop = L"winsta0\\default";

    PROCESS_INFORMATION pi = {0};

    // Get the current executable's name
    TCHAR exePath[MAX_PATH+1] = {0};
    GetModuleFileName(NULL, exePath, MAX_PATH);

    // Start the new (non-elevated) restricted process
    if (!CreateProcessAsUser(hRestrictedToken, exePath, NULL, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
    {
        CloseHandle(hRestrictedToken);
        return false;
    }

    CloseHandle(hRestrictedToken);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    return true;
}
于 2013-04-19T17:17:48.610 回答