首页 > 解决方案 > 使用 DisableAllPrivileges 禁用 AdjustTokenPrivileges 的所有权限?

问题描述

我试图AdjustTokenPrivileges通过将参数设置DisableAllPrivilegesTRUE

#include <Windows.h>
#include <cwchar>

int main()
{
  auto process = GetCurrentProcess();
  HANDLE primary_token;

  if (OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &primary_token) == FALSE)
  {
    fwprintf(stderr, L"OpenProcessToken: failed");
  }

  if (AdjustTokenPrivileges(primary_token, TRUE, nullptr, 0, nullptr, nullptr) == FALSE)
  {
    fwprintf(stderr, L"AdjustTokenPrivileges: failed");
  }

  CloseHandle(primary_token);

  auto event = CreateEventW(nullptr, FALSE, FALSE, nullptr);
  WaitForSingleObject(event, INFINITE);
}

在Sysinternals Process Explorer中查看进程权限时,它似乎不起作用。

我通过查询所有权限并将属性更改为解决了这个问题,SE_PRIVILEGE_REMOVED但我不确定为什么设置DisableAllPrivilegesTRUE不起作用。

标签: securitywinapi

解决方案


在 Sysinternals Process Explorer 中查看进程权限时,它似乎不起作用。

Sysinternals Process Explorer 显示错误的图像。DisableAllPrivileges作为例外工作 -SE_PRIVILEGE_ENABLED从令牌中的所有权限中删除属性。但有些权限也可以有SE_PRIVILEGE_ENABLED_BY_DEFAULT属性。SeChangeNotifyPrivilege例如有这个属性。它保持不变,什么和显示你的形象。但无论如何,只有SE_PRIVILEGE_ENABLEDPrivilegeCheckSePrivilegeCheck api 中使用的属性。所以你真的有效地禁用了令牌中的所有权限,包括SeChangeNotifyPrivilege. 所有需要具体特权的调用,SE_PRIVILEGE_ENABLED在您的令牌中没有属性 - 失败,即使SE_PRIVILEGE_ENABLED_BY_DEFAULT属性存在。

测试代码

#ifndef RtlPointerToOffset
#define RtlPointerToOffset(B,P) ((ULONG)( ((PCHAR)(P)) - ((PCHAR)(B)) ))
#endif

inline ULONG BOOL_TO_ERROR(BOOL fOk)
{
    return fOk ? NOERROR : GetLastError();
}

volatile UCHAR guz = 0;

void DumpTokenPrivs(HANDLE hToken)
{
    union {
        PVOID buf;
        PTOKEN_PRIVILEGES ptp;
    };

    PVOID stack = alloca(guz);

    ULONG cb = 0, rcb = 0x40;

    ULONG dwError;
    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (NOERROR == (dwError = BOOL_TO_ERROR(
            GetTokenInformation(hToken, TokenPrivileges, buf, cb, &rcb))))
        {
            ULONG PrivilegeCount = ptp->PrivilegeCount;

            DbgPrint("PrivilegeCount = %u\n", PrivilegeCount);
            if (PrivilegeCount)
            {
                PLUID_AND_ATTRIBUTES Privileges = ptp->Privileges;
                do 
                {
                    WCHAR Name[64];
                    ULONG cch = RTL_NUMBER_OF(Name);
                    if (!LookupPrivilegeNameW(0, &Privileges->Luid, Name, &cch))
                    {
                        _swprintf(Name, L"{%u-%u}", 
                            Privileges->Luid.HighPart, Privileges->Luid.LowPart);
                    }

                    BOOL fResult;
                    PRIVILEGE_SET ps = { 
                        1, PRIVILEGE_SET_ALL_NECESSARY, { 
                            { Privileges->Luid.LowPart, Privileges->Luid.HighPart } 
                        } 
                    };

                    if (!PrivilegeCheck(hToken, &ps, &fResult))
                    {
                        DbgPrint("PrivilegeCheck=%u\n", GetLastError());
                    }

                    DbgPrint("%08x %x %S\n", Privileges->Attributes, fResult, Name);

                } while (Privileges++, --PrivilegeCount);
            }
        }

    } while (dwError == ERROR_INSUFFICIENT_BUFFER);
}

void PrivTest()
{
    HANDLE hToken;

    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken))
    {
        ULONG rcb;
        TOKEN_LINKED_TOKEN tlk;
        GetTokenInformation(hToken, TokenLinkedToken, &tlk, sizeof(tlk), &rcb);
        CloseHandle(hToken);
        hToken = tlk.LinkedToken;

        DumpTokenPrivs(hToken);

        if (AdjustTokenPrivileges(hToken, TRUE, 0, 0, 0, 0) && GetLastError() == NOERROR)
        {
            DumpTokenPrivs(hToken);
        }
    }

    CloseHandle(hToken);
}

和输出:

PrivilegeCount = 5
00000000 0 SeShutdownPrivilege
00000003 1 SeChangeNotifyPrivilege
00000000 0 SeUndockPrivilege
00000000 0 SeIncreaseWorkingSetPrivilege
00000000 0 SeTimeZonePrivilege
PrivilegeCount = 5
00000000 0 SeShutdownPrivilege
00000001 0 SeChangeNotifyPrivilege
00000000 0 SeUndockPrivilege
00000000 0 SeIncreaseWorkingSetPrivilege
00000000 0 SeTimeZonePrivilege

请注意,在通话之前是

00000003 1 SeChangeNotifyPrivilege

是平均SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED属性,并PrivilegeCheck说特权已启用。

通话后是

00000001 0 SeChangeNotifyPrivilege

是平均SE_PRIVILEGE_ENABLED_BY_DEFAULT属性,并PrivilegeCheck说特权被禁用。


推荐阅读