我的原型(prototype)代码在我测试过的所有 Windows 操作系统上都运行良好,Windows XP 除外。
当我在 Windows XP 上以管理员身份运行此程序时,在调用 OpenProcessToken 时,系统提示我访问被拒绝 (5)。
有什么我不知道的区别吗?
#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"\n\n");
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);
}
最佳答案
在 LocalSystem
(S-1-5-18) 下运行的 XP 进程在 token 上有下一个 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
) 和管理员组 (S-1-5- 32-544
) 具有 READ_DACL|TOKEN_QUERY
(00020008
) 访问权限
在任何其他帐户下运行的进程在 token 上有下一个 Dacl:
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF <UserSid>
Owner: <UserSid>
其中 UserSid 一些唯一的(不是组!)sid。对于不在 LocalSystem 下运行的服务,它看起来像 S-1-5-80-..,对于用户 - S-1-5-21-。 .
这意味着此 dacl 授予对 'SYSTEM'
和具体 用户的完全访问权限。但不授予对 Administrators 组的任何访问权限 (S-1-5-32-544
)。因此您可以打开在相同 用户下运行的任何进程 token 。但是如果您尝试打开在另一个用户(另一个 Sid)下运行的进程 token ,您将无法访问它并且访问被拒绝。你甚至无法阅读它 dacl(你不是所有者,也没有 READ_CONTROL
)。
在代码中,您尝试从另一个用户进程(LogonUser
使用)打开 token 。在此 token dacl 中 - 没有您的用户 sid 或管理员 sid。结果访问被拒绝
但是,如果您拥有所有权权限 - 您可以先使用 WRITE_OWNER
打开 token 并将自己设置为所有者,然后使用 WRITE_DAC
打开它(所有者具有此访问权限)并且更改 DACL。或者,如果您有调试权限,您可以使用 NtImpersonateThread
模拟系统线程,并拥有对 token 的完全访问权限。
实用代码:
#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]
关于windows - OpenProcessToken 在 Windows XP 上因访问被拒绝 (5) 而失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47426157/