【问题标题】:Trying to understand process privilege attributes试图理解进程特权属性
【发布时间】:2015-04-05 01:27:12
【问题描述】:

我正在编写一个日志服务,它可能会收集进程的权限,并且我正在尝试了解每个进程权限的属性。让我用这段代码解释一下:

HANDLE hToken;
if(OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
    DWORD dwSize = 0;
    if(!GetTokenInformation(hToken, TokenPrivileges, NULL, dwSize, &dwSize) &&
        ::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        BYTE* pb = new (std::nothrow) BYTE[dwSize];
        if(pb)
        {
            TOKEN_PRIVILEGES* pTPs = (TOKEN_PRIVILEGES*)pb;
            DWORD dwSize2;
            if(GetTokenInformation(hToken, TokenPrivileges, pTPs, dwSize, &dwSize2) &&
                dwSize2 <= dwSize)
            {
                for(UINT i = 0; i < pTPs->PrivilegeCount; i++)
                {
                    //Analyze privilege attributes to understand if it's enabled or disabled?
                    DWORD dwPrivAttr = pTPs->Privileges[i].Attributes;

                    //...
                }
            }

            delete[] pb;
        }
    }

    CloseHandle(hToken);
}

那么让我们特别看一下TOKEN_PRIVILEGESLUID_AND_ATTRIBUTES的结构:

#define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L)
#define SE_PRIVILEGE_ENABLED            (0x00000002L)
#define SE_PRIVILEGE_REMOVED            (0X00000004L)
#define SE_PRIVILEGE_USED_FOR_ACCESS    (0x80000000L)

看起来它被定义为位掩码,但这带来了以下解释这些标志的问题:

  1. ENABLEDENABLED_BY_DEFAULT有什么区别?

  2. 什么是SE_PRIVILEGE_USED_FOR_ACCESS,如何使用?

  3. 如果SE_PRIVILEGE_ENABLEDSE_PRIVILEGE_REMOVED 都设置了怎么办?或者,重置?

  4. 我刚刚运行了一个简单的测试,对于我的进程,SeShutdownPrivilege 权限将这些属性设置为0。那是什么意思呢?

我对这个结构比较困惑,但我暂时只讨论这些问题。

谢谢!

【问题讨论】:

  • 默认启用意味着它在创建令牌时启用,而不是稍后通过AdjustTokenPrivileges。如果它从令牌中删除,那么您应该无法启用它。
  • 某些 API 会为您切换所需的权限,如果它存在于令牌中,但通常您必须手动启用它。 ExitWindowsExSeShutdownPrivilege 就是这种情况。
  • @eryksun:所以当属性设置为0时,这意味着权限关闭,对吗?在那种情况下,GetTokenInformation API 让我 SeShutdownPrivilege 和 attr 0 而不给我其余的特权有什么意义?我的意思是,SeTcbPrivilege 可能也与其他 20 个人一起关闭,但它不会返回它。抱歉,我只是想理解这里的逻辑。
  • @eryksun:还要检查权限是打开还是关闭,我需要做bool bEnabled = !!(dwAtt &amp; SE_PRIVILEGE_ENABLED);bool bEnabled = !(dwAtt &amp; SE_PRIVILEGE_REMOVED); 还是什么?
  • SeTcbPrivilege 不只是关闭。除非您作为系统服务运行,否则它根本不应该出现在令牌中。您不能添加权限;您只能启用、禁用或删除它们。最好仅在需要时启用特权,特别是因为特权的状态会被子进程继承。

标签: c++ windows winapi windows-kernel


【解决方案1】:

按顺序回答您的问题:

  1. ENABLED_BY_DEFAULT 表示该权限是进程启动时启用的权限之一。如果您有ENABLED 但没有ENABLED_BY_DEFAULT,则该进程已显式启用该权限。如果您有ENABLED_BY_DEFAULT 但没有ENABLED,则该进程已明确禁用该权限。

  2. 根据文档,SE_PRIVILEGE_USED_FOR_ACCESS 在实际使用权限时设置。您可以将其用于故障排除,例如,检测您正在设置您实际未使用的权限,或通过实验确定特定系统调用需要哪些权限。 (我从来没有检查过这是否真的像记录的那样,尽管我没有理由不这么认为。)

  3. 如果SE_PRIVILEGE_ENABLEDSE_PRIVILEGE_REMOVED 都已设置,则您在Windows 中发现了一个错误。 :-)

    如果SE_PRIVILEGE_ENABLEDSE_PRIVILEGE_REMOVED 均未设置,则该权限存在于令牌中,并且尚未删除,但当前未启用。您可以使用AdjustTokenPrivileges() 启用(或删除)它。

  4. 如果该属性为零,则该权限存在于令牌中,但当前未启用,尚未删除,默认情况下未启用,并且从未被进程使用。

【讨论】:

  • 谢谢。澄清一下,如果一个特权只有ENABLED_BY_DEFAULT,那么它是off没有为该进程启用,对吗?
  • 技术上默认启用仅适用于创建令牌时,对吗?即LogonUser。这让您知道手动启用了哪些权限,而不是创建令牌时默认启用的权限。
  • @eryksun:好的。但这意味着特权是on,这与哈利在第 1 项中所说的相反。我读错了吗?
  • @c00000fd,我不认为我与答案相矛盾。我只是补充说它不是进程创建的功能,而是令牌创建的功能。使用重复令牌创建进程,该令牌可能继承用户登录时未默认启用的启用权限。
  • @c00000fd, 引用:“如果您有 ENABLED_BY_DEFAULT 但没有 ENABLED,则该进程已明确禁用该权限。” 我只想补充一点澄清一下,它可能是一个禁用特权的祖先进程。
【解决方案2】:

我们中的一些人可能需要明确告知的是特权具有三种可能的状态,而不仅仅是两种。当我开始研究这些东西时,我认为一个进程要么有特权,要么没有特权。但事实证明,即使进程有特权,它也可以处于禁用状态。换句话说, disabled != 没有它。

其余的顺理成章。如果进程的访问令牌中不存在特权,则该进程没有该特权。反之亦然,如果进程没有特权,则该特权将不会出现在令牌中。

如果进程有权限,进程可以随意启用或禁用它,对吧?为什么这很有用?好吧,我猜想这允许你在不完全知道它们做什么的情况下调用库函数,如果它们做的比你想象的多,它们就会失败......不过很奇怪。

【讨论】: