如何检测是否设置了“调试程序”Windows权限?

时间:2011-02-02 21:42:47

标签: winapi

安装SQL Server 2008时,如果没有为执行安装的用户启用此权限,则安装将无法正常运行。所以在我的应用程序中,在安装SQL Server(使用其静默安装)之前,我想检测当前正在运行的用户是否具有“调试程序”权限集(即SeDebugPrivilege,SE_DEBUG_NAME ......)

我不想知道当前进程是否设置了它(因为,显然,大多数情况下它都没有设置,即使在系统上启用了特权)。我原本以为“PrivilegeCheck”API可以工作,但事实并非如此。如果您在VS调试器下运行此代码,则它会告诉您已启用该权限。如果从命令行运行它,它会告诉您该权限已被禁用。我该如何更正此程序以实际检查该权限是否可用?


HANDLE hToken;

// Get the calling thread's access token.
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken)) 
{
    if (GetLastError() != ERROR_NO_TOKEN)
    {
        printf("CAN'T GET THREAD TOKEN!!!\n");
        return -1;
    }

    // Retry against process token if no thread token exists.
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
    {
        printf("CAN'T GET PROCESS TOKEN!!!\n");
        return -1;
    }
}

//Find the LUID for the debug privilege token
LUID luidDebugPrivilege;
if ( !LookupPrivilegeValue( 
    NULL,            // lookup privilege on local system
    "SeDebugPrivilege",   // privilege to lookup 
    &luidDebugPrivilege ) )        // receives LUID of privilege
{
    printf("LookupPrivilegeValue error: %u\n", GetLastError() ); 
    return -1; 
}

PRIVILEGE_SET privs; 
privs.PrivilegeCount = 1;
privs.Control = PRIVILEGE_SET_ALL_NECESSARY;

privs.Privilege[0].Luid = luidDebugPrivilege;
privs.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; 

BOOL bResult;
::PrivilegeCheck(hToken, &privs, &bResult);

if(bResult)
{
    printf("DEBUG ENABLED!\n");
}
else
{
    printf("DEBUG NOT ENABLED!\n");
}

// Get the calling thread's access token. if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken)) { if (GetLastError() != ERROR_NO_TOKEN) { printf("CAN'T GET THREAD TOKEN!!!\n"); return -1; } // Retry against process token if no thread token exists. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { printf("CAN'T GET PROCESS TOKEN!!!\n"); return -1; } } //Find the LUID for the debug privilege token LUID luidDebugPrivilege; if ( !LookupPrivilegeValue( NULL, // lookup privilege on local system "SeDebugPrivilege", // privilege to lookup &luidDebugPrivilege ) ) // receives LUID of privilege { printf("LookupPrivilegeValue error: %u\n", GetLastError() ); return -1; } PRIVILEGE_SET privs; privs.PrivilegeCount = 1; privs.Control = PRIVILEGE_SET_ALL_NECESSARY; privs.Privilege[0].Luid = luidDebugPrivilege; privs.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; BOOL bResult; ::PrivilegeCheck(hToken, &privs, &bResult); if(bResult) { printf("DEBUG ENABLED!\n"); } else { printf("DEBUG NOT ENABLED!\n"); }

3 个答案:

答案 0 :(得分:2)

函数GetTokenInformation可用于检索进程的权限列表。 PrivilegeCheck检查是否启用了特权,并且始终禁用用户未保留的特权。用户持有的权限可能被禁用(也可能没有被禁用)

从您的问题来看,我认为您真正想要的是检查用户是否是管理员。

答案 1 :(得分:2)

好的,我们在发布原始问题后想出了这个问题。我们实际需要做的是尝试为当前进程设置“调试程序”权限。如果我们可以启用该权限,那么这意味着当前登录用户在本地安全策略编辑器中为它们启用了该权限(XP上的gpedit.msc ...)

请参阅下面的示例代码,以防其他人需要解决此问题!重要的是:

  • 使用LookupPrivilegeValue()查找SeDebugPrivilege的LUID。 (这些东西的所有API都需要LUID ......)
  • 使用GetTokenInformation()查找已在此进程上启用的权限。如果进程已经启用了权限,则意味着该进程很可能在调试器下运行,并且当前登录的用户确实已启用该权限。
  • 如果进程没有设置权限,请使用AdjustTokenPrivileges()尝试设置权限。这是在我们的方法AttemptToAddDebugPrivilegeToProcess()下面;如果可以设置权限(意味着当前登录用户启用了“debug programs”权限),则返回true;如果不能,则返回false。

#include "stdafx.h"
#include <strsafe.h>

void ShowLastError(LPTSTR lpszFunction) { 
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    printf((LPTSTR)lpDisplayBuf);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}



bool LuidsMatch(LUID l1, LUID l2)
{
    return l1.LowPart == l2.LowPart && l1.HighPart == l2.HighPart; }

bool AttemptToAddDebugPrivilegeToProcess(HANDLE hToken) {
    //Find the LUID for the debug privilege token
    LUID luidDebugPrivilege;
    if ( !LookupPrivilegeValue( 
        NULL,            // lookup privilege on local system
        "SeDebugPrivilege",   // privilege to lookup 
        &luidDebugPrivilege ) )        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError() ); 
        return false; 
    }

    TOKEN_PRIVILEGES newState;
    newState.PrivilegeCount = 1;
    newState.Privileges[0].Luid = luidDebugPrivilege;
    newState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if(AdjustTokenPrivileges(
        hToken,
        FALSE,
        &newState,
        sizeof(newState),
        NULL, //&previousState, 
        0))
    {
        if(GetLastError() == ERROR_NOT_ALL_ASSIGNED)
        {
            printf("Couldn't set debug!!!");
            return false;
        }

        //*************************************************************
        //IF YOU MADE IT HERE, THE USER HAS THE DEBUG PROGRAMS PRIVILEGE
        //*************************************************************
        printf("DEBUG OK!!!");
        return true;
    }

    printf("AdjustTokenPrivileges returned false!!!");
    ShowLastError("AdjustTokenPrivileges");
    return false;
}

int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hToken;

    // Get the calling thread's access token.
    if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, TRUE, &hToken)) 
    {
        if (GetLastError() != ERROR_NO_TOKEN)
        {
            printf("CAN'T GET THREAD TOKEN!!!\n");
            return -1;
        }

        // Retry against process token if no thread token exists.
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken))
        {
            printf("CAN'T GET PROCESS TOKEN!!!\n");
            return -1;
        }
    }

    //Find the LUID for the debug privilege token
    LUID luidDebugPrivilege;
    if ( !LookupPrivilegeValue( 
        NULL,            // lookup privilege on local system
        "SeDebugPrivilege",   // privilege to lookup 
        &luidDebugPrivilege ) )        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError() ); 
        return -1; 
    }


    //Find if the "debug programs" privilege is already assigned to this process
    DWORD dwReturnedDataSize;
    GetTokenInformation(
        hToken,
        TokenPrivileges,
        NULL,
        0,
        &dwReturnedDataSize);

    BYTE* pData = new BYTE[dwReturnedDataSize];
    GetTokenInformation(
        hToken,
        TokenPrivileges,
        pData,
        dwReturnedDataSize,
        &dwReturnedDataSize);

    TOKEN_PRIVILEGES* pPrivileges = (TOKEN_PRIVILEGES*)pData;

    bool bFound = false;

    for(unsigned int count = 0; count PrivilegeCount; count++)
    {
        LUID_AND_ATTRIBUTES& luidAndAttrs = pPrivileges->Privileges[count];

        if(LuidsMatch(luidAndAttrs.Luid, luidDebugPrivilege))
        {
            bFound = true;
            if((luidAndAttrs.Attributes & SE_PRIVILEGE_ENABLED) == SE_PRIVILEGE_ENABLED)
            {
                //**************************************************************
                //IF YOU MADE IT HERE, THE USER HAS THE DEBUG PROGRAMS PRIVILEGE
                //**************************************************************
            }
            else
            {
                printf("THIS PROCESS DOES NOT HAVE THE DEBUG PROGRAMS PRIVILEGE ENABLED\n");                                AttemptToAddDebugPrivilegeToProcess(hToken);
            }
        }
    }

    if(!bFound)
    {
        printf("THIS PROCESS DOES NOT HAVE THE DEBUG PROGRAMS PRIVILEGE ENABLED\n");
        AttemptToAddDebugPrivilegeToProcess(hToken);
    }

    return 0;
}

答案 2 :(得分:1)

如果我理解你的错误,你可以使用LsaEnumerateAccountRights获取用户拥有的权限列表。