如何以编程方式确定帐户是否属于 Administrators 组?

How to determine if an account belongs to Administrators group programmatically?

我的 Windows 有几个属于管理员组的帐户,例如 "test1"、"test2" 和 "test3"。我正在开发一个应用程序,我希望该程序通过设计一个布尔函数来知道自己是否 运行 在属于 Administrators 组的帐户下:isCurrentUserAdminMember()isCurrentUserAdminMember() 函数仅应 return TRUE 如果进程是 运行 by "test1", "test2", "test3" 或内置 Administrator 帐户 无论进程是否提升.

我在 http://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime 中找到了一些代码,如下所示,但它似乎只是检查当前进程是否被提升为管理员。我不关心进程是否被提升,我只想知道进程的启动帐户是否是 Administrators 组的成员。我希望决定本身不需要特权。那可能吗?谢谢。

    BOOL IsAppRunningAsAdminMode()
    {
        BOOL fIsRunAsAdmin = FALSE;
        DWORD dwError = ERROR_SUCCESS;
        PSID pAdministratorsGroup = NULL;

        // Allocate and initialize a SID of the administrators group.
        SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
        if (!AllocateAndInitializeSid(
            &NtAuthority, 
            2, 
            SECURITY_BUILTIN_DOMAIN_RID, 
            DOMAIN_ALIAS_RID_ADMINS, 
            0, 0, 0, 0, 0, 0, 
            &pAdministratorsGroup))
        {
            dwError = GetLastError();
            goto Cleanup;
        }

        // Determine whether the SID of administrators group is enabled in 
        // the primary access token of the process.
        if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
        {
            dwError = GetLastError();
            goto Cleanup;
        }

    Cleanup:
        // Centralized cleanup for all allocated resources.
        if (pAdministratorsGroup)
        {
            FreeSid(pAdministratorsGroup);
            pAdministratorsGroup = NULL;
        }

        // Throw the error if something failed in the function.
        if (ERROR_SUCCESS != dwError)
        {
            throw dwError;
        }

        return fIsRunAsAdmin;
    }

最后,我们实现了检查Administrators组成员身份的目的,如下面的代码,但是如答案和评论所说,USELESS,留在这里供参考以防有人需要它作他用。

// PermTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdio.h"
#include "iostream"
using namespace std;
#include "windows.h"

#include <lm.h>
#pragma comment(lib, "netapi32.lib")

BOOL IsUserInGroup(const wchar_t* groupe)
{
    BOOL result = FALSE;
    SID_NAME_USE snu;
    WCHAR szDomain[256];
    DWORD dwSidSize = 0;
    DWORD dwSize = sizeof szDomain / sizeof * szDomain;

    if ((LookupAccountNameW(NULL, groupe, 0, &dwSidSize, szDomain, &dwSize, &snu) == 0)
        && (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
    {
        SID* pSid = (SID*)malloc(dwSidSize);

        if (LookupAccountNameW(NULL, groupe, pSid, &dwSidSize, szDomain, &dwSize, &snu))
        {
            BOOL b;

            if (CheckTokenMembership(NULL, pSid, &b))
            {
                if (b == TRUE)
                {
                    result = TRUE;
                }
            }
            else
            {
                result = FALSE;
            }
        }

        //Si tout vas bien (la presque totalitée des cas), on delete notre pointeur
        //avec le bon operateur.
        free(pSid);
    }

    return result;
}

void getUserInfo(WCHAR *domainName, WCHAR *userName)
{
    LPUSER_INFO_3 pBuf = NULL;
    int j = 0;
    DWORD nStatus = NetUserGetInfo(domainName, userName, 3, (LPBYTE *) &pBuf);

    LPUSER_INFO_2 pBuf2 = NULL;
    pBuf2 = (LPUSER_INFO_2) pBuf;
    if (pBuf)
    {
        wprintf(L"User account name: %s\%s\n", domainName, pBuf2->usri2_name);
        wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
    }



//  wprintf(L"\tPassword: %s\n", pBuf2->usri2_password);
//  wprintf(L"\tPassword age (seconds): %d\n",
//      pBuf2->usri2_password_age);
//  wprintf(L"Privilege level: %d\n\n", pBuf2->usri2_priv);
// #define USER_PRIV_GUEST     0
// #define USER_PRIV_USER      1
// #define USER_PRIV_ADMIN     2

//  wprintf(L"\tHome directory: %s\n", pBuf2->usri2_home_dir);
//  wprintf(L"\tComment: %s\n", pBuf2->usri2_comment);
//  wprintf(L"\tFlags (in hex): %x\n", pBuf2->usri2_flags);
//  wprintf(L"\tScript path: %s\n", pBuf2->usri2_script_path);
//  wprintf(L"\tAuth flags (in hex): %x\n",
//      pBuf2->usri2_auth_flags);
//  wprintf(L"\tFull name: %s\n", pBuf2->usri2_full_name);
//  wprintf(L"\tUser comment: %s\n", pBuf2->usri2_usr_comment);
//  wprintf(L"\tParameters: %s\n", pBuf2->usri2_parms);
//  wprintf(L"\tWorkstations: %s\n", pBuf2->usri2_workstations);
//  wprintf
//      (L"\tLast logon (seconds since January 1, 1970 GMT): %d\n",
//      pBuf2->usri2_last_logon);
//  wprintf
//      (L"\tLast logoff (seconds since January 1, 1970 GMT): %d\n",
//      pBuf2->usri2_last_logoff);
//  wprintf
//      (L"\tAccount expires (seconds since January 1, 1970 GMT): %d\n",
//      pBuf2->usri2_acct_expires);
//  wprintf(L"\tMax storage: %d\n", pBuf2->usri2_max_storage);
//  wprintf(L"\tUnits per week: %d\n",
//      pBuf2->usri2_units_per_week);
//  wprintf(L"\tLogon hours:");
//  for (j = 0; j < 21; j++) 
//  {
//      printf(" %x", (BYTE) pBuf2->usri2_logon_hours[j]);
//  }
//  wprintf(L"\n");
//  wprintf(L"\tBad password count: %d\n",
//      pBuf2->usri2_bad_pw_count);
//  wprintf(L"\tNumber of logons: %d\n",
//      pBuf2->usri2_num_logons);
//  wprintf(L"\tLogon server: %s\n", pBuf2->usri2_logon_server);
//  wprintf(L"\tCountry code: %d\n", pBuf2->usri2_country_code);
//  wprintf(L"\tCode page: %d\n", pBuf2->usri2_code_page);
}

#include <comdef.h>
#define MAX_NAME 256
BOOL GetLogonFromToken (HANDLE hToken, _bstr_t& strUser, _bstr_t& strdomain) 
{
    DWORD dwSize = MAX_NAME;
    BOOL bSuccess = FALSE;
    DWORD dwLength = 0;
    strUser = "";
    strdomain = "";
    PTOKEN_USER ptu = NULL;
    //Verify the parameter passed in is not NULL.
    if (NULL == hToken)
        goto Cleanup;

    if (!GetTokenInformation(
        hToken,         // handle to the access token
        TokenUser,    // get information about the token's groups 
        (LPVOID) ptu,   // pointer to PTOKEN_USER buffer
        0,              // size of buffer
        &dwLength       // receives required buffer size
        )) 
    {
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 
            goto Cleanup;

        ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
            HEAP_ZERO_MEMORY, dwLength);

        if (ptu == NULL)
            goto Cleanup;
    }

    if (!GetTokenInformation(
        hToken,         // handle to the access token
        TokenUser,    // get information about the token's groups 
        (LPVOID) ptu,   // pointer to PTOKEN_USER buffer
        dwLength,       // size of buffer
        &dwLength       // receives required buffer size
        )) 
    {
        goto Cleanup;
    }
    SID_NAME_USE SidType;
    char lpName[MAX_NAME];
    char lpDomain[MAX_NAME];

    if( !LookupAccountSidA( NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )                                    
    {
        DWORD dwResult = GetLastError();
        if( dwResult == ERROR_NONE_MAPPED )
            strcpy (lpName, "NONE_MAPPED" );
        else 
        {
            printf("LookupAccountSid Error %u\n", GetLastError());
        }
    }
    else
    {
//      printf( "Current user is  %s\%s\n", 
//          lpDomain, lpName );
        strUser = lpName;
        strdomain = lpDomain;
        bSuccess = TRUE;
    }

Cleanup: 

    if (ptu != NULL)
        HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
    return bSuccess;
}

HRESULT GetUserFromProcess( _bstr_t& strUser, _bstr_t& strdomain)
{
    //HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,procId); 
    HANDLE hProcess = GetCurrentProcess();
    if(hProcess == NULL)
        return E_FAIL;
    HANDLE hToken = NULL;

    if( !OpenProcessToken( hProcess, TOKEN_QUERY, &hToken ) )
    {
        CloseHandle( hProcess );
        return E_FAIL;
    }
    BOOL bres = GetLogonFromToken (hToken, strUser,  strdomain);

    CloseHandle( hToken );
    CloseHandle( hProcess );
    return bres?S_OK:E_FAIL;
}



int _tmain(int argc, _TCHAR* argv[])
{
    //cout << IsUserInGroup(L"administrators");


    getUserInfo(L"adtest.net", L"Administrator");
    getUserInfo(NULL, L"Administrator");
    getUserInfo(NULL, L"test");
    getUserInfo(NULL, L"test2");
    getUserInfo(NULL, L"testnormal");

    _bstr_t username;
    _bstr_t domain;
    GetUserFromProcess(username, domain);
    cout << "Current account running this program is: " << endl << domain << "\" << username << endl;

    getchar();
    return 0;
}

您可以通过打开进程令牌(OpenProcessToken, listing the SIDs using GetTokenInformation 并将每个 SID 与管理员 SID 进行比较来完成此操作。

微软在这里有示例代码:Searching for a SID in an Access Token in C++

然而,这很少是一件有用的事情。即使用户不是 Administrators 组的成员,他们仍然可以通过提供管理用户名和密码进行提升,因此您不应该(例如)仅在用户属于 Administrators 组时提供提升。

bool IsMemberOfGroup(const char *pszGroupName){
bool bFound = false;

HANDLE hToken=INVALID_HANDLE_VALUE;
BOOL bSuccess = OpenProcessToken( GetCurrentProcess(),
                                    TOKEN_QUERY,//|TOKEN_QUERY_SOURCE,
                                    &hToken);
if ( bSuccess )
{
    DWORD   dwSizeToken=0;
    DWORD   dwSizeName=0;
    DWORD   dwSizeReferencedDomainName = 0;
    // Get group information:
    GetTokenInformation(hToken, TokenGroups, NULL, dwSizeToken, &dwSizeToken);
    {
        const int MAX_NAME = 256;
        char *psName    = new char[MAX_NAME];
        char *psDomain  = new char[MAX_NAME];
        char *pBuf = new char[dwSizeToken+10];
        TOKEN_GROUPS *pGroupInfo = (TOKEN_GROUPS *)pBuf;
        bSuccess = GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSizeToken, &dwSizeToken);
        if ( bSuccess )
        {
            // find the group name we are looking for
            for ( UINT uiGroupNdx = 0; uiGroupNdx < pGroupInfo->GroupCount && !bFound; uiGroupNdx++ )
            {
                SID_NAME_USE    SidType;
                dwSizeName = MAX_NAME;
                dwSizeReferencedDomainName = MAX_NAME;

                bSuccess = LookupAccountSid(NULL,   // local system,
                                            pGroupInfo->Groups[uiGroupNdx].Sid,
                                            psName,
                                            &dwSizeName,
                                            psDomain,
                                            &dwSizeReferencedDomainName,
                                            &SidType);
                if ( bSuccess )
                {
                    if ( SidTypeGroup == SidType )
                    {
                        if ( !lstrcmpi(pszGroupName, psName) )
                        {
                            bFound = true;
                        }
                    }
                }
            }
        }

        delete [] pBuf;
        delete [] psName;
        delete [] psDomain;
    }

    CloseHandle(hToken);
}

return bFound;
}