Ошибка OpenProcessToken с отказом в доступе (5) В Windows XP

мой код прототипа отлично работает на каждой ОС Windows, которую я смог протестировать, кроме Windows XP.

когда я запускаю это в Windows XP как администратор, мне дают Доступ запрещен (5) при вызове OpenProcessToken.

есть ли какая-то разница, о которой я не знаю?

#include "stdafx.h"
#include <Windows.h>
#include <userenv.h>

#pragma comment(lib, "userenv")

void DisplayError(LPWSTR pszAPI)
{
    LPVOID lpvMessageBuffer;

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, GetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPWSTR)&lpvMessageBuffer, 0, NULL);

    wprintf(L"ERROR: API        = %s.n", pszAPI);
    wprintf(L"       error code = %d.n", GetLastError());
    wprintf(L"       message    = %s.n", (LPWSTR)lpvMessageBuffer);

    LocalFree(lpvMessageBuffer);

    ExitProcess(GetLastError());
}

void SetDebugPrivileges()
{
    void* tokenHandle;

    TOKEN_PRIVILEGES privilegeToken;
    LookupPrivilegeValue(0, SE_DEBUG_NAME, &privilegeToken.Privileges[0].Luid);
    privilegeToken.PrivilegeCount = 1;
    privilegeToken.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle);
    AdjustTokenPrivileges(tokenHandle, 0, &privilegeToken, sizeof(TOKEN_PRIVILEGES), 0, 0);
    CloseHandle(tokenHandle);
}

void wmain(int argc, WCHAR *argv[])
{
    DWORD     dwSize;
    HANDLE    hToken;
    LPVOID    lpvEnv;
    PROCESS_INFORMATION pi = { 0 };
    STARTUPINFO         si = { 0 };
    WCHAR               szUserProfile[256] = L"";

    si.cb = sizeof(STARTUPINFO);

    if (argc != 4)
    {
        wprintf(L"Usage: %s [user@domain] [password] [cmd]", argv[0]);
        wprintf(L"nn");
        return;
    }

    if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE,
        LOGON32_PROVIDER_DEFAULT, &hToken))
        DisplayError(L"LogonUser");

    if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
        DisplayError(L"CreateEnvironmentBlock");

    dwSize = sizeof(szUserProfile) / sizeof(WCHAR);

    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
        DisplayError(L"GetUserProfileDirectory");

    if (!CreateProcessWithLogonW(argv[1], NULL, argv[2],
        LOGON_WITH_PROFILE, NULL, argv[3],
        CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile,
        &si, &pi))
        DisplayError(L"CreateProcessWithLogonW");

    if (!DestroyEnvironmentBlock(lpvEnv))
        DisplayError(L"DestroyEnvironmentBlock");

    //Sleep(5000);

    SetDebugPrivileges();

    HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pi.dwProcessId);
    if(process == NULL)
        DisplayError(L"OpenProcess");

    // Not working on Windows XP
    HANDLE token;
    if(!OpenProcessToken(process, TOKEN_QUERY, &token))
        DisplayError(L"OpenProcessToken");

    CloseHandle(token);
    CloseHandle(process);
    CloseHandle(hToken);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

1 ответов


на XP процессы, которые работают под LocalSystem(S-1-5-18) имеют следующий список DACL на знак:

A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 00020008 S-1-5-32-544 'Administrators'
Owner: S-1-5-32-544 'Administrators' @ 'BUILTIN' [Alias]

это означает, что SYSTEM полный доступ TOKEN_ALL_ACCESS (000F01FF) и пользователи из группы Admin (S-1-5-32-544) у READ_DACL|TOKEN_QUERY(00020008) к

процессы, которые запускаются под любой другой учетной записью иметь следующее список DACL на знак:

A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF <UserSid>
Owner: <UserSid>

здесь Пользовательsid некоторые уникальные (не группа!) СИД. скажем, за услуги беги не под LocalSystem похоже S-1-5-80- - ... . для пользователей - S-1-5-21- - ... . это означает, что этот dacl предоставляет полный доступ к 'SYSTEM' и б пользователей. но не предоставлять доступ к группе администраторов (S-1-5-32-544). таким образом, вы можете открыть любой токен процесса, который работает под то же самое пользователей. но если вы попробуете открыть процесс toke, который работает под другим пользователем (другой Sid), у вас нет доступа к нему и Вам отказано в доступе. вы не можете даже прочитать его dacl (вы не владелец и не имеете READ_CONTROL).

в коде вы пытаетесь открыть токен из другого пользовательского процесса (LogonUser используется). в этом токене dacl-нет вашего SID пользователя или Sid администраторов. в результате и доступ запрещен

однако, если у вас есть привилегия takeownership-вы можете сначала открыть токен с WRITE_OWNER и установите себя как владельца, после этого откройте его с WRITE_DAC (владелец имеет этот доступ) и измените dacl. или, если у вас есть debug provilege, вы можете олицетворите системный поток, используя NtImpersonateThread и иметь полный доступ к маркеру.

util код:

#ifdef __cplusplus
extern "C" {
#endif

NTSYSCALLAPI
NTSTATUS 
NTAPI 
NtOpenThread(
             _Out_ PHANDLE ThreadHandle, 
             _In_ ULONG DesiredAccess, 
             _In_ POBJECT_ATTRIBUTES ObjectAttributes, 
             _In_ PCLIENT_ID ClientId
             );

extern "C"
NTSYSCALLAPI
NTSTATUS
NTAPI
NtImpersonateThread(
                    _In_ HANDLE ServerThreadHandle,
                    _In_ HANDLE ClientThreadHandle,
                    _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos
                    );

#ifdef __cplusplus
}
#endif

ULONG gOsVersion;

volatile UCHAR guz;
OBJECT_ATTRIBUTES zoa = { sizeof(zoa) };

void GetVersionEx()
{
    RTL_OSVERSIONINFOW VersionInformation;
    RtlGetVersion(&VersionInformation);
    gOsVersion = (VersionInformation.dwMajorVersion << 8) + VersionInformation.dwMinorVersion;
}

PCSTR GetSidNameUseName(::SID_NAME_USE snu)
{
    switch (snu)
    {
    case SidTypeUser: return "User";
    case SidTypeGroup: return "Group";
    case SidTypeDomain: return "Domain";
    case SidTypeAlias: return "Alias";
    case SidTypeWellKnownGroup: return "WellKnownGroup";
    case SidTypeDeletedAccount: return "DeletedAccount";
    case SidTypeInvalid: return "Invalid";
    case SidTypeUnknown: return "Unknown";
    case SidTypeComputer: return "Computer";
    case SidTypeLabel: return "Label";
    case SidTypeLogonSession: return "LogonSession";
    }
    return "?";
}

#define MAX_DOMAIN_NAME_LEN 128 

void DumpAcl(PACL acl, PCSTR caption)
{
    DbgPrint(caption);

    if (!acl)
    {
        DbgPrint("NULL\n");
        return;
    }

    USHORT AceCount = acl->AceCount;

    if (!AceCount)
    {
        DbgPrint("empty\n");
        return;
    }

    DbgPrint("T FL AcessMsK Sid\n");

    union {
        PVOID pv;
        PBYTE pb;
        PACE_HEADER pah;
        PACCESS_ALLOWED_ACE paaa;
    };

    pv = acl + 1;

    char sz[16], sz2[16];

    do
    {
        switch (pah->AceType)
        {
        case ACCESS_ALLOWED_ACE_TYPE:
        case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
        case ACCESS_DENIED_ACE_TYPE:
        case ACCESS_DENIED_CALLBACK_ACE_TYPE:
        case SYSTEM_MANDATORY_LABEL_ACE_TYPE:
            break;
        default:
            DbgPrint("AceType=%u\n", pah->AceType);
            continue;
        }

        UNICODE_STRING us;
        if (0 <= RtlConvertSidToUnicodeString(&us, (PSID)&paaa->SidStart, TRUE))
        {
            WCHAR name[256], DomainName[MAX_DOMAIN_NAME_LEN];
            ULONG cch = RTL_NUMBER_OF(name);
            ::SID_NAME_USE snu;
            DWORD cchReferencedDomainName = MAX_DOMAIN_NAME_LEN;

            if (!LookupAccountSidW(0, (PSID)&paaa->SidStart, name, &cch, DomainName, &cchReferencedDomainName, &snu))
            {
                name[0]=0;
            }

            ACCESS_MASK Mask = paaa->Mask;
            sprintf(sz2, "%08X", Mask);

            switch (pah->AceType)
            {
            case ACCESS_ALLOWED_ACE_TYPE:
            case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
                sz[0] = 'A', sz[1] = 0;
                break;
            case ACCESS_DENIED_ACE_TYPE:
            case ACCESS_DENIED_CALLBACK_ACE_TYPE:
                sz[0] = 'D', sz[1] = 0;
                break;
            case SYSTEM_MANDATORY_LABEL_ACE_TYPE:
                sz[0] = 'L', sz[1] = 0;
                sz2[0] = Mask & SYSTEM_MANDATORY_LABEL_NO_READ_UP ? 'R' : ' ';
                sz2[1] = Mask & SYSTEM_MANDATORY_LABEL_NO_WRITE_UP ? 'W' : ' ';
                sz2[2] = Mask & SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP ? 'E' : ' ';
                sz2[3] = 0;
                break;
            default: __assume(false);
            }
            DbgPrint("%s %02X %s %wZ '%S'\n", sz, paaa->Header.AceFlags, sz2, &us, name);
            RtlFreeUnicodeString(&us);
        }

    } while (pb += pah->AceSize, --AceCount);
}

void Dump(HANDLE hToken)
{
    ULONG cb = 0, rcb = 128;

    PVOID stack = alloca(guz);

    union {
        PVOID buf;
        PSECURITY_DESCRIPTOR psd;
        PTOKEN_USER ptu;
    };

    UNICODE_STRING us;
    ::SID_NAME_USE snu;
    WCHAR name[256], DomainName[MAX_DOMAIN_NAME_LEN];
    ULONG cch, cchReferencedDomainName;

    NTSTATUS status;

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

        if (0 <= (status = NtQueryInformationToken(hToken, TokenUser, buf, cb, &rcb)))
        {
            if (0 <= RtlConvertSidToUnicodeString(&us, ptu->User.Sid, TRUE))
            {
                cch = RTL_NUMBER_OF(name);
                cchReferencedDomainName = RTL_NUMBER_OF(DomainName);

                if (!LookupAccountSidW(NULL, ptu->User.Sid, name, &cch, DomainName, &cchReferencedDomainName, &snu))
                {
                    *name = 0;
                    *DomainName = 0;
                }
                DbgPrint("User: %wZ '%S' @ '%S' [%s]\r\n", &us, name, DomainName, GetSidNameUseName(snu));
                RtlFreeUnicodeString(&us);
            }

            break;
        }

    } while (status == STATUS_BUFFER_TOO_SMALL);

    if (0 > status)
    {
        DbgPrint("TokenUser=%x\n", status);
    }

    SECURITY_INFORMATION SecurityInformation = gOsVersion < _WIN32_WINNT_VISTA 
        ? OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION 
        : OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION;

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

        if (0 <= (status = NtQuerySecurityObject(hToken, SecurityInformation, psd, cb, &rcb)))
        {
            PACL Acl;
            BOOLEAN bPresent, bDefault;

            if (0 <= RtlGetDaclSecurityDescriptor(psd, &bPresent, &Acl, &bDefault))
            {
                DumpAcl(bPresent ? Acl : 0, "DACL:\n");
            }

            if (0 <= RtlGetSaclSecurityDescriptor(psd, &bPresent, &Acl, &bDefault))
            {
                DumpAcl(bPresent ? Acl : 0, "LABEL:\n");
            }

            PSID Owner;
            if (0 <= RtlGetOwnerSecurityDescriptor(psd, &Owner, &bDefault) && Owner)
            {
                if (0 <= RtlConvertSidToUnicodeString(&us, Owner, TRUE))
                {
                    cch = RTL_NUMBER_OF(name);
                    cchReferencedDomainName = RTL_NUMBER_OF(DomainName);

                    if (!LookupAccountSidW(NULL, Owner, name, &cch, DomainName, &cchReferencedDomainName, &snu))
                    {
                        *name = 0;
                        *DomainName = 0;
                    }
                    DbgPrint("Owner: %wZ '%S' @ '%S' [%s]\r\n", &us, name, DomainName, GetSidNameUseName(snu));
                    RtlFreeUnicodeString(&us);
                }
            }
        }

    } while (status == STATUS_BUFFER_TOO_SMALL);

    if (0 > status)
    {
        DbgPrint("QuerySecurityObject=%x\n", status);
    }
}

void Dump(ACCESS_MASK DesiredAccess, PSYSTEM_PROCESS_INFORMATION pspi)
{
    HANDLE hProcess, hToken;

    CLIENT_ID cid = { pspi->UniqueProcessId };

    DbgPrint("==============\n%p %wZ\n", cid.UniqueProcess, &pspi->ImageName);

    NTSTATUS status = NtOpenProcess(&hProcess, DesiredAccess, &zoa, &cid);

    if (0 > status)
    {
        DbgPrint("OpenProcess=%x\n", status);
        return;
    }

    status = NtOpenProcessToken(hProcess, READ_CONTROL|TOKEN_QUERY, &hToken);

    NtClose(hProcess);

    if (0 > status)
    {
        DbgPrint("OpenProcessToken=%x\n", status);
    }
    else
    {
        Dump(hToken);
        NtClose(hToken);
    }
}

void DumpProcessAndTokens(PVOID buf)
{
    union {
        PVOID pv;
        PBYTE pb;
        PSYSTEM_PROCESS_INFORMATION pspi;
    };

    pv = buf;

    ULONG NextEntryOffset = 0;

    ACCESS_MASK DesiredAccess = gOsVersion < _WIN32_WINNT_VISTA 
        ? PROCESS_QUERY_INFORMATION : PROCESS_QUERY_LIMITED_INFORMATION;

    do 
    {
        pb += NextEntryOffset;

        if (pspi->UniqueProcessId)
        {           
            Dump(DesiredAccess, pspi);
        }

    } while (NextEntryOffset = pspi->NextEntryOffset);
}

NTSTATUS GetSystemToken(PCLIENT_ID ClientId)
{
    HANDLE hThread;

    NTSTATUS status = NtOpenThread(&hThread, THREAD_DIRECT_IMPERSONATION, &zoa, ClientId);

    if (0 <= status)
    {
        static SECURITY_QUALITY_OF_SERVICE sqos = {
            sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE
        };

        if (0 <= (status = NtImpersonateThread(NtCurrentThread(), hThread, &sqos)))
        {
            HANDLE hToken;
            if (0 <= (status = NtOpenThreadTokenEx(NtCurrentThread(), TOKEN_QUERY,FALSE, 0, &hToken)))
            {

                ULONG cb = 0, rcb = 32;
                PVOID stack = alloca(guz);

                union {
                    PVOID buf;
                    PTOKEN_USER ptu;

                };

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

                    if (0 <= (status = NtQueryInformationToken(hToken, TokenUser, buf, cb, &rcb)))
                    {
                        static _SID LocalSystem = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } };

                        if (!RtlEqualSid(&LocalSystem, ptu->User.Sid))
                        {
                            RevertToSelf();
                            status = STATUS_SERVER_SID_MISMATCH;
                        }

                        break;
                    }

                } while (status == STATUS_BUFFER_TOO_SMALL);

                NtClose(hToken);
            }
        }

        NtClose(hThread);
    }

    return status;
}

NTSTATUS ImpersonateLocalSystem(PVOID buf)
{
    union {
        PVOID pv;
        PBYTE pb;
        PSYSTEM_PROCESS_INFORMATION pspi;
    };

    pv = buf;

    ULONG NextEntryOffset = 0;

    do 
    {
        pb += NextEntryOffset;

        if (pspi->UniqueProcessId && pspi->NumberOfThreads)
        {           
            if (0 <= GetSystemToken(&pspi->TH->ClientId))
            {
                return STATUS_SUCCESS;
            }
        }

    } while (NextEntryOffset = pspi->NextEntryOffset);

    return STATUS_UNSUCCESSFUL;
}

void DumpProcessTokens()
{
    BOOLEAN b;
    NTSTATUS status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);

    if (0 > status)
    {
        return ;
    }

    ULONG cb = 0x8000;

    do 
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        if (PVOID buf = new UCHAR[cb])
        {
            if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
            {
                if (0 <= ImpersonateLocalSystem(buf))
                {
                    DumpProcessAndTokens(buf);
                    RevertToSelf();
                }
            }

            delete [] buf;
        }

    } while (status == STATUS_INFO_LENGTH_MISMATCH);
}

    GetVersionEx();
    DumpProcessTokens();

некоторый результат от xp:

00000004 System
User: S-1-5-18 'SYSTEM' @ 'NT AUTHORITY' [User]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
LABEL:
NULL
Owner: S-1-5-32-544 'Administrators' @ 'BUILTIN' [Alias]

==============
0000021C smss.exe
User: S-1-5-18 'SYSTEM' @ 'NT AUTHORITY' [User]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 00020008 S-1-5-32-544 'Administrators'
LABEL:
NULL
Owner: S-1-5-32-544 'Administrators' @ 'BUILTIN' [Alias]
==============
000003B0 svchost.exe
User: S-1-5-20 'NETWORK SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF S-1-5-80-979556362-403687129-3954533659-2335141334-1547273080 ''
LABEL:
NULL
Owner: S-1-5-80-979556362-403687129-3954533659-2335141334-1547273080 '' @ '' [WellKnownGroup]

==============
0000047C svchost.exe
User: S-1-5-20 'NETWORK SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF S-1-5-20 'NETWORK SERVICE'
LABEL:
NULL
Owner: S-1-5-20 'NETWORK SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]

==============
000004C4 svchost.exe
User: S-1-5-19 'LOCAL SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF S-1-5-19 'LOCAL SERVICE'
LABEL:
NULL
Owner: S-1-5-19 'LOCAL SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]

==============
000005EC explorer.exe
User: S-1-5-21-839522115-2025429265-725345543-500 'Administrator' @ '*' [User]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-21-839522115-2025429265-725345543-500 'Administrator'
A 00 000F01FF S-1-5-18 'SYSTEM'
LABEL:
NULL
Owner: S-1-5-21-839522115-2025429265-725345543-500 'Administrator' @ '*' [User]