SetTokenInformation 失败并返回 24,但长度正确

SetTokenInformation fails with 24, but the length is correct

我正在尝试创建提升的 SYSTEM 令牌,但下面的代码失败了:

#include <windows.h>
#include <stdio.h>

BOOL Elevate()
{
    PSID pSID = NULL;
    HANDLE hToken = NULL, hToken2 = NULL;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    {
        fprintf(stderr, "OpenProcessToken(): %d\n", GetLastError());
        goto done;
    }

    if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hToken2))
    {
        fprintf(stderr, "DuplicateTokenEx(): %d\n", GetLastError());
        goto done;
    }

    if (!AllocateAndInitializeSid(
        &NtAuthority,
        1,
        SECURITY_MANDATORY_SYSTEM_RID,
        0,
        0, 0, 0, 0, 0, 0,
        &pSID))
    {
        fprintf(stderr, "AllocateAndInitializeSid(): %d\n", GetLastError());
        goto done;
    }

    if (!SetTokenInformation(hToken2, TokenIntegrityLevel, &pSID, sizeof(pSID)))
    {
        fprintf(stderr, "SetTokenInformation(): %d\n", GetLastError());
        goto done;
    }

done:
    if (pSID)
    {
        FreeSid(pSID);
        pSID = NULL;
    }

    CloseHandle(hToken);
    CloseHandle(hToken2);

    return TRUE;
}

int main(int argc, char** argv)
{
    Elevate();
}

SetTokenInformation 失败,错误代码为 24:ERROR_BAD_LENGTH。有人知道怎么回事吗?

编辑

Remy Lebeau 是对的,我在这里找到了一个例子:https://wiki.sei.cmu.edu/confluence/display/c/WIN02-C.+Restrict+privileges+when+spawning+child+processes

根据 TOKEN_INFORMATION_CLASS 文档

TokenIntegrityLevel
The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level.

其中 TOKEN_MANDATORY_LABEL 定义为:

typedef struct _SID_AND_ATTRIBUTES {
#if ...
  PISID Sid;
#else
  PSID  Sid;
#endif
  DWORD Attributes;
} SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES;

typedef struct _TOKEN_MANDATORY_LABEL {
  SID_AND_ATTRIBUTES Label;
} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;

所以,你需要给 SetTokenInformation() 一个指向 TOKEN_MANDATORY_LABEL 的指针,而不是指向 SID 的指针,例如:

#include <windows.h>
#include <stdio.h>

BOOL Elevate()
{
    TOKEN_MANDATORY_LABEL tml = {};
    HANDLE hToken = NULL, hToken2 = NULL;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
    BOOL result = FALSE;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    {
        fprintf(stderr, "OpenProcessToken(): %ul\n", GetLastError());
        goto done;
    }

    if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hToken2))
    {
        fprintf(stderr, "DuplicateTokenEx(): %ul\n", GetLastError());
        goto done;
    }

    if (!AllocateAndInitializeSid(
        &NtAuthority,
        1,
        SECURITY_MANDATORY_SYSTEM_RID,
        0,
        0, 0, 0, 0, 0, 0,
        &(tml.Label.SID)))
    {
        fprintf(stderr, "AllocateAndInitializeSid(): %ul\n", GetLastError());
        goto done;
    }

    tml.Label.Attributes = ...; // desired integrity level

    if (!SetTokenInformation(hToken2, TokenIntegrityLevel, &tml, sizeof(tml)))
    {
        fprintf(stderr, "SetTokenInformation(): %ul\n", GetLastError());
        goto done;
    }

    result = TRUE;

done:
    if (tml.Label.SID) FreeSid(tml.Label.SID);
    if (hToken) CloseHandle(hToken);
    if (hToken2) CloseHandle(hToken2);

    return result;
}

int main(int argc, char** argv)
{
    Elevate();
}