zoukankan      html  css  js  c++  java
  • 第4章 进程(3)

    4.5 管理员以标准用户权限运行时

    4.5.1访问控制模型ACM(Access Control Model)

     

    (1)进(线)程在访问对象时,系统会根据线程的访问令牌与需要访问的对象所持有的“安全描述符”进行匹配认证,来决定是否被允许访问。

    (2)访问令牌属进(线程)范围的,相当于进(线)程的身份证(即用户SID,可理解为一把有具有ID的钥匙)。

    (3)“安全描述符”属被访问对象的,相当于给对象加把锁。要访问该对象时,只有经过身份认证并且持有正确钥匙的进(线)程才有成功访问该对象。

    4.5.2 访问令牌与进(线)程权限

    (1)访问令牌(Token)的数据结构 

        ①访问令牌一般由两个部分:一个是令牌所表示的用户(包括会话ID、用户及其所属的组),这些信息告诉Token属于哪个用户的;另一部分是“特权列表”(Privilege),这用来告诉进程能够进行特定的系统操作,如关闭系统、修改系统时间、加载设备驱动等,拥有的特权越多当然就越牛B!

      ②从vista开始,当使用高特权的管理员帐号登录时,系统会同时创建两个访问令牌,其中一个是完全的管理员访问令牌,另一个是经过“过滤”的标准用户访问令牌(filtered token),并把后者Shell进程(explorer.exe),以后系统启动的所有新进程关联都会继承这个被“筛选令牌”,权限受限制的进程无法访问需要更高权限才能访问的安全资源。注意,虽然以管理员登录,但应用程序默认是以标准用户权限的运行。 

      ③每个进程都有一个Token(被称为主令牌)。可以从父进程处继承(也可以修改,但其最高权限不会超过登录账户的最高权限。即只能在进程的边界上提升权限!要获得更多的权限,就要以管理员的身份运行!)

      ④线程默认下会使用进程的令牌来访问对象。但它也可以拥有自己的访问令牌(被称为模仿令牌(ImperonaitonToken),但该令牌不是必须的,线程可以不拥有模仿令牌。模仿令牌的用处,如当一个线程要找开一个文件,但该文件只有User2才能打开,而主令牌属于User1,这时线程就可以模仿一个User2令牌来打开这个文件。

    (2)访问令牌的特权

            

    管理员身份运行(未筛选的令牌)                                     以标准用户权限运行(筛选令牌)   

      ①以上实验是同一程序相同登录帐号下,以管理员身份直接运行时的权限比较。

      ②从两图可以得到:管理员身份运行下,应用程序的权限一般要比直接运行的要多。

      ③所谓的应用程序提权,有两种情况:

        A、获得更多种的权限,如管理员身份运行下,有23种。而直接运行则只有5种。比如管理身份运行下有SeSystemEnvironmentPrivilege等权限,在直接运行(标准用户权限)时没有。

        B、第2种情况是上面两种图,都有多种特权在默认下是没开启的,可以通过AdjustTokenPrivileges(或SetTokenInformation)来开启。如上图的“筛选令牌”中还有4种没开启。

      ④一个Token中的特权列表中,已经指明该Token可以拥有哪些特权。但不并是所有特权都开启的,如果要使用该特权,需要使用SetTokenInformation修改。注意,特权列表中没有的特权,是不能开启的。比如在直接运行下,其Token中有SeShutdownPrivilege的特权,所以是可以开启的,列表中没有SeSecurityPrivilege特权,所以是不能开启的,即只能在进程的边界上提升权限。(当然你非要添加的话还是有办法的)!

      ⑤特权列表:用TOKEN_PRIVILEGES结构体表示

    字段

    描述

    DWORD PrivilegeCount

    特权数量(数组的长度)

    LUID_AND_ATTRIBUTES privilegs[N]

    特权数组。元素类型表示一种特权:由两部分组成

    ①Luid:局部唯一标识符,代表某特权的值

    ②Attributes:特权的属性,其值如下

    SE_PRIVILEGE_ENABLED表示启用该特权

    SE_PRIVILEGE_ENABLED_BY_DEFAULT表示使特权默认有效

    SE_PRIVILEGE_REMOVED:表示禁用特权

    SE_PRIVILEGE_USED_FOR_ACCESS:取得对象或服务的访问权

    4.5.3 安全描述符(SecurityDescriptor)——是访问控制模型的灵魂,每个内核对象中都一个SecurityDescriptor结构体的指针,指向一个SD,该SD的结构体如下

    (1)安全描述符的数据结构:

     

      ①SD中描述了该对象的拥有者Owner、用户Sid、SACL和DACL等信息。

      ②SACL:系统访问控制列表,用来记录某个安全对象被访问的情况,一般不用关心。

      ③DACL:自主访问控制列表,记录了哪些用户可以(/不可以)以何种方式访问该对象(重要)

    (2)ACE及安全访问机制

     

      ①DACL中包括访问控制项列表(AccessControl Entries,ACE) ,每个ACE指明哪个用户或组可以对该对象能否操作及何种操作。如上图的Tom用户不能读、写、执行。(注意SD上说的权限是指访问该对象的能力,而Token中所说的权限是指特权,如关机等系统操作)

      ②当打开一个对象时,会从线程所拥有的Token中(如果存在模仿令牌则使用模仿令牌,否则使用主令牌)获取用户名和用户所在组列表,与对象的安全描述符中的DACL比较,其匹配算法如下:

      A、如果被访问对象的DACL为NULL,则线程拥有完全的访问权限。

      B、对象的DACL不为NULL,但是AceCount ==0(ACE,访问控制项),则拒绝任何线程访问。

      C、遍历DACL,找到与Token中用户或组一致的ACE,如果该ACE没有提供线程要访问的那项权限(如Group1组的用户要求写入时),则直接退出安全检查函数,并拒绝该线程访问。

      D、遍历DACL,没找到跟令牌中用户或组一致的ACE,并拒绝该线程访问

      E、遍历DACL,找到与令牌中用户或组一致的ACE,如果该ACE中进(线)程要求的访问权限(如读写操作),结束安全检查,并允许该线程访问。

      ★注意:以上列表中的ACE排列顺序很重要,在匹配时会从列表的第1项开始一旦匹配,就不再检查后面的ACE项。比如线程1要求写入该对象时,由于第1项列表指明不能写,所以该线程是不可访问这个对象,尽管Tom1用户属Group1用户组的(该组是允许写的),当然,如果将ACE中的第2项Group1移动到第1项时,Tom也是可写该对象的。

    4.5.4 与访问令牌Token操作相关API

    (1)API参数中对Token可能进行的操作——以下值一般作为API参数被传入

    描述

    TOKEN_ADJUST_DEFAULT

    修改令牌所有者、主组或访问控制列表DACL

    TOKEN_ADJUST_GROUPS

    修改令牌的组属性

    TOKEN_ADJUST_PRIVILEGES

    Enable或Disable令牌的特权

    TOKEN_ADJUST_SESSIONID

    调整令牌的Session ID。进程需要 SE_TCB_NAME 特权。

    TOKEN_ASSIGN_PRIMARY

    为进程分配主令牌。需要 SE_ASSIGNPRIMARYTOKEN_NAME特权。

    TOKEN_DUPLICATE

    复制令牌

    TOKEN_EXECUTE

    合并 STANDARD_RIGHTS_EXECUTE 和 TOKEN_IMPERSONATE

    TOKEN_IMPERSONATE

    附加一个模拟令牌到进程

    TOKEN_QUERY

    查询令牌

    TOKEN_QUERY_SOURCE

    查询令牌源

    TOKEN_READ

    合并STANDARD_RIGHTS_READ 和TOKEN_QUERY

    TOKEN_WRITE

    合并 STANDARD_RIGHTS_WRITE, TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, 和 TOKEN_ADJUST_DEFAULT

    TOKEN_ALL_ACCESS

    合并所以可能的操作

    (2)操作Token的API

        ①OpenProcessToken、OpenThreadToken

        ②AdjustTokenPrivileges、AdjustTokenGroups

        ③GetTokenInformation、SetTokenInformation

        ④LookupPrivilegeValue、PrivilegeCheck

        ④LookupPrivilegeDisplayName、LookupPrivilegeName

    4.5.5 与安全描述符有关API

    (1)安全标识符SID

     ①SID的组成

    A、简访为S-R-I-S-S........

            B、S表示数字系列、R表示修订级、I表示标识符权限值,后面S为子权限值。

            C、SID实际上包含两个值:发行SID的机构的值,一个32位的相对标识符(RID)。RID指明了用户和组的信息。

    如:S-1-5-21-310440588-250036847-580389505-500

    我们来先分析这个重要的SID。第一项S表示该字符串是SID;第二项是SID的版本号,对于2000来说,这个就是1;然后是标志符的颁发机构(identifier authority),对于2000内的帐户,颁发机构就是NT,值是5。然后表示一系列的子颁发机构,前面几项是标志域的,最后一个标志着域内的帐户和组

     ②操作SID的相关API

            A、AllocateAndInitializeSid、FreeSid

            B、CopySid

            C、EqualSid、EqualPrefixSid

            D、GetLengthSid、GetSidLengthRequired

            E、 GetSidIdentifierAuthority、GetSidSubAuthority、GetSidSubAuthorityCount

            F、InitializeSid、IsValidSid

            G、LookupAccountName、LookUpAccountSid

    (2)安全描述符SD

        ①SD的格式

          A、绝对格式:可用InitializeSecurityDescriptor得到

      B、相对格式:SECURITE_DESCRIPTOR定义的

      C、将绝对格式转为相对格式:MakeSelfRelativeSD

      ②创建SD的方法

        //"D:(D;;GR;;;WD)(A;;GW;;;WD)" 的意思是: DACL添加Everyone用户,拒绝读,允许写权限

          InitSecurityDescriptor( sa, TEXT("D:(D;;GR;;;WD)(A;;GW;;;WD)") );

          //D:(A;;GA;;;WD) 的意思是: DACL添加Everyone用户,并让其拥有全部权限

          InitSecurityDescriptor( sa, TEXT("D:(A;;GA;;;WD)") );

    (3)操作ACL的API

      ①GetAclInformation、SetAclInformation

      ②GetSecurityDescriptorDacl、SetSecurityDescriptorDacl

      ③GetSecurityDescriptorSacl、SetSecurityDescriptorSacl

      ④InitializeAcl、IsValidAcl

     【TokenInfo程序】显示访问令牌信息  (直接运行和以管理员身份运行时,会出现不同的结果!)

    /********************************************************
    显示本进程访问令牌(Token)的信息
    *********************************************************/
    #include <windows.h>
    #include <tchar.h>
    #include <sddl.h>
    #include <stdio.h>
    
    #define CheckAndLocalFree(ptr)    
    if (ptr != NULL)    
                {                    
                LocalFree(ptr); 
                ptr = NULL;        
                }
    
    //获取指定项目的令牌信息
    LPVOID RetrieveTokenInfomationClass(
        HANDLE  hToken,
        TOKEN_INFORMATION_CLASS InfoClass,
        LPDWORD pdwSize)
    {
        LPVOID pInfo = NULL;
        BOOL  fSuccess = FALSE;
        *pdwSize = 0;
    
        __try
        {
            //第1次调用,获得返回令牌信息的所需的内存大小
            GetTokenInformation(hToken, InfoClass, NULL, 0, pdwSize);
            if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
            {
                _tprintf(_T("调用GetTokenInformation函数失败,错误代码:%d
    "), GetLastError());
                __leave;
            }
    
            //分配内存,以获取指定项目的令牌信息
            pInfo = LocalAlloc(LPTR, *pdwSize);
            if (pInfo == NULL)
            {
                _tprintf(_T("调用LocaAlloc失败,错误代码:%d
    "), GetLastError());
                __leave;
            }
    
            if (!GetTokenInformation(hToken, InfoClass, pInfo, *pdwSize, pdwSize))
            {
                _tprintf(_T("调用GetTokenInformation函数失败,错误代码:%d
    "), GetLastError());
                __leave;
            }
    
            fSuccess = TRUE;
        }
        __finally
        {
            if (fSuccess == FALSE)
            {
                CheckAndLocalFree(pInfo);
            }
        }
        return pInfo;
    }
    
    //显示用户SID
    BOOL DisplayUserInfo(HANDLE hToken)
    {
        PTOKEN_USER pUserInfo = NULL;
        DWORD dwSize = 0;
        PTSTR pName = NULL;
    
        //从令牌获取用户信息
        pUserInfo = (PTOKEN_USER)RetrieveTokenInfomationClass(hToken, TokenUser, &dwSize);
        if (NULL == pUserInfo)
            return FALSE;
    
        ConvertSidToStringSid(pUserInfo->User.Sid, &pName);
    
        if (NULL == pName)
        {
            CheckAndLocalFree(pUserInfo);
            return FALSE;
        }
    
        _tprintf(_T("User:		%s
    "), pName);
    
        CheckAndLocalFree(pUserInfo);
        CheckAndLocalFree(pName);
        return TRUE;
    }
    
    //显示所有者信息
    BOOL DisplayOwnerInfo(HANDLE hToken)
    {
        PTOKEN_OWNER pOwnerInfo = NULL;
        DWORD dwSize = 0;
        PTSTR pName = NULL;
    
        //从令牌获取所有者信息
        pOwnerInfo = (PTOKEN_OWNER)RetrieveTokenInfomationClass(hToken, TokenOwner, &dwSize);
        if (NULL == pOwnerInfo)
            return FALSE;
    
        ConvertSidToStringSid(pOwnerInfo->Owner, &pName);
    
        if (NULL == pName)
        {
            CheckAndLocalFree(pOwnerInfo);
            return FALSE;
        }
    
        _tprintf(_T("Owner:		%s
    "), pName);
    
        CheckAndLocalFree(pOwnerInfo);
        CheckAndLocalFree(pName);
        return TRUE;
    }
    
    //显示主用户组信息
    BOOL DisplayPrimaryGroupInfo(HANDLE hToken)
    {
        PTOKEN_PRIMARY_GROUP ptgr = NULL;
        DWORD dwSize = 0;
        PTSTR pName = NULL;
    
        //从令牌获取所有者信息
        ptgr = (PTOKEN_PRIMARY_GROUP)RetrieveTokenInfomationClass(hToken, TokenPrimaryGroup, &dwSize);
        if (NULL == ptgr)
            return FALSE;
    
        ConvertSidToStringSid(ptgr->PrimaryGroup, &pName);
    
        if (NULL == pName)
        {
            CheckAndLocalFree(ptgr);
            return FALSE;
        }
    
        _tprintf(_T("PrimaryGroup:	%s
    "), pName);
    
        CheckAndLocalFree(ptgr);
        CheckAndLocalFree(pName);
        return TRUE;
    }
    
    //显示源信息
    BOOL DisplaySource(HANDLE hToken)
    {
        PTOKEN_SOURCE pSrc = NULL;
        DWORD dwSize = 0;
        PTSTR pName = NULL;
    
        //从令牌获取源的信息
        pSrc = (PTOKEN_SOURCE)RetrieveTokenInfomationClass(hToken, TokenSource, &dwSize);
        if (NULL == pSrc)
            return FALSE;
    
        printf(("Source:		%s	SourceIdentifier:%08X%08X
    "), pSrc->SourceName,
            pSrc->SourceIdentifier.HighPart, pSrc->SourceIdentifier.LowPart);
    
        CheckAndLocalFree(pSrc);
        CheckAndLocalFree(pName);
        return TRUE;
    }
    
    //DisplayStatistics
    BOOL DisplayStatistice(HANDLE hToken)
    {
        PTOKEN_STATISTICS pst = NULL;
        DWORD dwSize = 0;
        PTSTR pName = NULL;
    
        //从令牌获取统计的信息
        pst = (PTOKEN_STATISTICS)RetrieveTokenInfomationClass(hToken, TokenStatistics, &dwSize);
        if (NULL == pst)
            return FALSE;
    
        //列出统计信息
        printf("TokenID:	%08X%08X
    ", pst->TokenId.HighPart, pst->TokenId.LowPart);
        printf("GroupCount:	%d
    ", pst->GroupCount);
        printf("PrivilegeCount:	%d
    ", pst->PrivilegeCount);
        printf("ImpersonationLevel:%d
    ", pst->ImpersonationLevel);
    
        if (pst->TokenType == TokenPrimary)
        {
            printf("TokenType:	TokenPrimary
    ");
        }
        else
            printf("TokenType:	TokenImpersonation
    ");
    
        CheckAndLocalFree(pst);
        CheckAndLocalFree(pName);
        return TRUE;
    }
    
    //显示用户组信息
    BOOL DisplayGroupsInfo(HANDLE hToken)
    {
        PTOKEN_GROUPS pgrp = NULL;
        DWORD dwSize = 0;
        PTSTR pName = NULL;
    
        //从令牌获取用户组信息
        pgrp = (PTOKEN_GROUPS)RetrieveTokenInfomationClass(hToken, TokenGroups, &dwSize);
        if (NULL == pgrp)
            return FALSE;
        printf("共找到token(0x%08x)的%d个Sid:
    ", hToken, pgrp->GroupCount);
    
        for (DWORD dwIndex = 0; dwIndex < pgrp->GroupCount; dwIndex++)
        {
            ConvertSidToStringSid(pgrp->Groups[dwIndex].Sid, &pName);
            _tprintf(_T("  %d SID: %s"), dwIndex, pName);
            CheckAndLocalFree(pName);
    
            if ((pgrp->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
            {
                dwSize = GetLengthSid(pgrp->Groups[dwIndex].Sid);
                _tprintf(_T("  (This is LogonID)"));
            }
            _tprintf(_T("
    "));
        }
        CheckAndLocalFree(pName);
        CheckAndLocalFree(pgrp);
        return TRUE;
    }
    
    
    //显示特权信息
    BOOL DisplayPrivileges(HANDLE hToken)
    {
        PTOKEN_PRIVILEGES ppv = NULL;
        DWORD dwSize = 0;
        PTSTR pName = NULL;
        TCHAR privilegeName[500] = {};
        TCHAR displayName[500] = {};
        DWORD privilegeNameSize;
        DWORD displayNameSize;
        DWORD langID = GetUserDefaultLangID();
    
        //从令牌获取特权信息
        ppv = (PTOKEN_PRIVILEGES)RetrieveTokenInfomationClass(hToken, TokenPrivileges, &dwSize);
        if (NULL == ppv)
            return FALSE;
        printf("token(0x%08x)的共有%d种权限:
    ", hToken, ppv->PrivilegeCount);
    
        for (DWORD dwIndex = 0; dwIndex < ppv->PrivilegeCount; dwIndex++)
        {
            privilegeNameSize = sizeof(privilegeName) / sizeof(privilegeName[0]);
            displayNameSize = sizeof(displayName) / sizeof(displayName[0]);
    
            LookupPrivilegeName(NULL, &ppv->Privileges[dwIndex].Luid,
                privilegeName, &privilegeNameSize);
    
            LookupPrivilegeDisplayName(NULL, privilegeName, displayName, &displayNameSize,
                &langID);
            _tprintf(_T("%-31s	"), privilegeName);
    
            if (ppv->Privileges[dwIndex].Attributes &(SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT))
            {
                _tprintf(_T("Enabled
    "));
            }
            else
                _tprintf(_T("Disabled
    "));
        }
        CheckAndLocalFree(pName);
        CheckAndLocalFree(ppv);
        return TRUE;
    }
    
    //显示Token的用户名、所有者、主用户组、源、权限及统计信息
    BOOL DisplayTokenInformation(HANDLE hToken)
    {
        //显示用户名
        DisplayUserInfo(hToken);
    
        //显示所有者信息
        DisplayOwnerInfo(hToken);
    
        //显示主用户组信息
        DisplayPrimaryGroupInfo(hToken);
    
        //显示源信息
        DisplaySource(hToken);
    
        //用户组信息
        DisplayGroupsInfo(hToken);
    
        //用户权限
        DisplayPrivileges(hToken);
    
        //显示统计信息
        DisplayStatistice(hToken);
        return TRUE;
    }
    
    //显示进程的访问令牌内容
    BOOL DisplayCallerAccessTokenInformation()
    {
        HANDLE hToken = NULL;
        BOOL bResult = FALSE;
    
        //使用OpenThreadToken()函数判断线程运行的状态
        bResult = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_QUERY_SOURCE,
            TRUE, &hToken);
        if (bResult == FALSE && GetLastError() == ERROR_NO_TOKEN)
        {
            //打开线程访问令牌失败后,尝试使用进程入口标志
            bResult = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE,
                &hToken);
        }
    
        if (bResult)
        {
            bResult = DisplayTokenInformation(hToken);
            CloseHandle(hToken);
        }
        else
        {
            _tprintf(_T("OpenThread/ProcessToken failed with %d
    "), GetLastError());
        }
    
        return bResult;
    }
    
    int main()
    {
        DisplayCallerAccessTokenInformation();
    
        _tsystem(_T("PAUSE"));
        return 0;
    }

    【修改Token的特权】  直接运行和以管理员身份运行时,会出现不同的结果!

              

    #include <windows.h>
    #include <tchar.h>
    #include <locale.h>
    #include <sddl.h>
    #include <stdio.h>
    #include <Shlobj.h>
    
    //提升(修改)权限
    BOOL SetPrivilege(HANDLE hToken, LPTSTR pszPrivilege, BOOL bEnablePrivilege)
    {
        BOOL rv;
        TOKEN_PRIVILEGES tp;
        //函数查看系统权限的特权值,返回信息到一个LUID结构体里
        rv = LookupPrivilegeValue(
            NULL,//表示所要查看的系统,本地系统直接用NULL
            pszPrivilege,//指向一个以零结尾的字符串,指定特权的名称,此参数可
            //指定常数,如宏SE_SHUTDOWN_NAME对应的字符串为"SeShutdownPrivilege"
            &tp.Privileges[0].Luid); //用来接收所返回的制定特权名称的信息
    
        if (!rv)
        {
            _tprintf(_T("LookupPrivilegeValue error:%d
    "), GetLastError());
            return FALSE;
        }
    
        tp.PrivilegeCount = 1;
        if (bEnablePrivilege)
            tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        else
            tp.Privileges[0].Attributes = 0;
    
        //启用或禁止 指定访问令牌的特权
        //返回值:ERROR_SUCCESS——成功
        //        ERROR_NOT_ALL_ASSIGNED——这个令牌没有参数要修改的那一项或多项的权限。(1个或多个没有修改)
        rv = AdjustTokenPrivileges(
            hToken,//要修改权限的访问令牌句柄
            FALSE, //禁用所有权限标志
            &tp, //新特权信息缓冲区的指针(结构体)
            sizeof(TOKEN_PRIVILEGES), //缓冲数据大小,以字节为单位
            0,    //接收被改变特权当前状态的Buffer
            0);   //接收当前状态缓冲区所需的大小
        if (!rv)
        {
            _tprintf(_T("AdjustPrivilegeValue error:%d
    "), GetLastError());
            return FALSE;
        }
    
        if (ERROR_NOT_ALL_ASSIGNED == GetLastError())
        {
            wprintf(L"分配指定的特权(%s)失败!
    ", pszPrivilege);
            return FALSE;
        }
        return TRUE;
    }
    
    LPTSTR g_pPrivileges[] =
    {
        SE_SHUTDOWN_NAME,
        SE_BACKUP_NAME,
        SE_DEBUG_NAME,
        SE_TIME_ZONE_NAME,
        SE_TCB_NAME
    };
    
    //用来返回提升类型和指出进程是否正在以管理员身份运行
    BOOL GetProcessElevation(TOKEN_ELEVATION_TYPE* pElevationType, BOOL* pIsAdmin)
    {
        HANDLE hToken = NULL;
        BOOL bResult = FALSE;
        DWORD dwSize;
    
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
            return FALSE;
        
        //获取提升权限的类型
        //TokenElevationTypeDefault     默认运行用户运行,UAC被禁用
        //TokenElevationTypeFull        权限被成功提升, 而且令牌没有被筛选过
        //TokenElevationTypeLimited      进程以受限的权限运行, 它对应于一个筛选过的令牌
        if (GetTokenInformation(hToken, TokenElevationType,
                pElevationType, sizeof(TOKEN_ELEVATION_TYPE),&dwSize))
        {
            //创建管理员组SID
            BYTE adminSID[SECURITY_MAX_SID_SIZE];
            dwSize = sizeof(adminSID);
            CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &adminSID, &dwSize);
    
            //进程是否受限的权限运行, 它对应于一个筛选过的令牌
            if (*pElevationType == TokenElevationTypeLimited)
            {
                //获取链接令牌(未筛选Token?)的句柄
                HANDLE hUnfilterToken = NULL;
                GetTokenInformation(hToken, TokenLinkedToken, (LPVOID)&hUnfilterToken,
                    sizeof(HANDLE), &dwSize);
    
                //检测令牌是否包含管理员SID
                if (CheckTokenMembership(hUnfilterToken,&adminSID,pIsAdmin))
                {
                    bResult = TRUE;
                }
                CloseHandle(hUnfilterToken);
            }
            else
            {
                //不是受限用户,则判断是否管理员
                *pIsAdmin = IsUserAnAdmin(); //须包含Shlobj.h
                bResult = TRUE;
            }
        }
    
        CloseHandle(hToken);
        return bResult;
    }
    
    int main()
    {
        setlocale(LC_ALL, "chs");
    
        HANDLE hToken = NULL;
        OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
        int iCnt = sizeof(g_pPrivileges) / sizeof(g_pPrivileges[0]);
        for (int i = 0; i < iCnt; i++)
        {
            if (SetPrivilege(hToken, g_pPrivileges[i], TRUE))
            {
                wprintf(L"特权%s打开成功!
    ", g_pPrivileges[i]);
            }
        }
        TOKEN_ELEVATION_TYPE ElevationType;
        BOOL IsAdmin;
        GetProcessElevation(&ElevationType, &IsAdmin);
    
        //当前进程权限上下文
        wprintf(L"
    ");
        if (IsAdmin)
            wprintf(L"当前是以管理员帐号登录!
    ");
        else
            wprintf(L"当前是以非管理员帐号登录!
    ");
    
        if (ElevationType == TokenElevationTypeLimited)
            wprintf(L"进程以受限的权限(筛选令牌)运行!
    ");
        else if (ElevationType == TokenElevationTypeFull)
            wprintf(L"进程以完全权限(未筛选令牌)运行!
    ");
        else
            wprintf(L"默认用户运行,UAC被禁用!
    ");
    
    
        _tsystem(_T("PAUSE"));
        return 0;
    }

     4.5.6 以管理员身份运行程序的方法

    (1)应用程序→右键→“以管理员身份运行”

    (2)自动提升进程的权限——VS2013下

      ①找到工程属性→“配置属性”→“链接器”→“清单文件”

      ②在“生成清单”中选择“是”,启动用户帐户控制(UAC)选“是”,UAC执行级别中选择“requireAdministrator”

      ★如果只是为了在VS中调试程序,可以“管理员身份”运行VS,但这只能在调试中提升权限。生成的应用程序本身并没有被改变过来。

    (3)手动提升进程的权限——函数ShellExcuteEx(LPSHELLEXECUTEINFO pExecInfo)

     参数

    描述

    PSHELLEXECUTEINFO pExecInfo

    SHELLEXECUTEINFO结构体设置

    ①lpVert字段:必须设为TEXT("runas")

    ②lpFile字段:TEXT("xxx.exe")

    ③nShow字段:SW_SHOWNORMAL

    ④lpParameters:用来传递给子进程的命令行参数

    返回值

    成功——TRUE

    失败——FALSE,如果用户拒绝提升权限,GetLastError返回ERROR_CANCELLED

      ★当以管理员身份运行后,表示进程访问令牌的特权就越多,但很多特权默认是禁用的,所以还得通过AdjustTokenPrivileges等函数来启用这些特权。

     4.5.7完整性级别(Integrity levels)

    (1)完整性级别简介

      ①在进行对进程“访问令牌”与“安全描述符”的匹配时,要先进行完整性级别的比较,注意这个比较是在检查DACL之前完成的。所以,即便进程拥有访问资源的权限,但由于进程的完整性级别低于资源所要求的完整性级别,访问仍会被拒绝!

    ②信任级别

     级别

    应用程序示例

    应用程序以低信任级别运行,就无法访问高任信级别的资源,如保护模式下的IE,就是运行在低级别的,目的就是拒绝从网上下载代码修改Windows环境。

    默认情况下,所有应用程序都以“中”信任级别来启动,并使用一个“筛选令牌”来运行

    如果应用程序以提升后的权限来启动,则以“高”信任级别来运行

    系统

    只有以LocalSystem或LocalService身份运行的进程,才能获得这个信任级别。

    (2)进程完整性级别

      ①获取和设置进程完整性级别

         PTOKEN_MANDATORY_LABEL pTokenInfo;

         GetTokenInformation(hToken,TokenIntegrityLevel,pTokenInfo,dwNeededSize,&dwNeededSize));

     ②LookupAccountSid 函数得到完整性级别的可显示名称

    (3)资源完整性级别(Resource integrity levels)

       ①资源的完整性级别存放在安全描述符的系统访问控制表(SACL)中的一个特殊的访问控制项(ACE)中。

       ②看到大多数资源并没有显式地设定其完整性级别。系统将没有显式声明完整性级别的资源看作带有中等完整性级别

       ③操作的API

          A、获取和设置: GetNamedSecurityInfo、SetNamedSecurityInfo——调用的参数LABEL_SECURITY_INFORMATION。

          B、增加:InitializeAcl、AddMandatoryAce

  • 相关阅读:
    04_面向对象之多态
    03_面向对象之继承
    02_对象和对象封装
    01_什么是类
    01_函数对象
    python_IO操作之B模式介绍
    python_IO操作之rwa模式介绍
    python之初始IO操作01
    Flink基础(十七): Flink CEP 简介
    解决:UserBehavior is already defined as case class UserBehavior
  • 原文地址:https://www.cnblogs.com/5iedu/p/4673283.html
Copyright © 2011-2022 走看看