如果BUILTIN\Administrators ( S-1-5-32-544 ) 组(别名)的用户成员,则此 sid 存在于它的令牌组中。并且通常仅在这种情况下(当然可以为具有S-1-5-32-544的非管理员用户和没有它的管理员用户创建令牌)。如此简单而有效的检查 - 列出令牌组并查看 -此处存在S-1-5-32-544,具有任何属性。IsUserAdmin
不只是检查这个 sid,而是
即使令牌中存在
SID ,系统也可能不会在访问检查中使用SID 。SID可能被禁用或具有SE_GROUP_USE_FOR_DENY_ONLY属性。执行访问检查时,系统仅使用启用的 SID 来授予访问权限。
当管理员用户(S-1-5-32-544 Alias 的成员)交互式登录系统和UAC活动时 - 系统过滤它的令牌,并为S-1-5-32-544设置SE_GROUP_USE_FOR_DENY_ONLY属性(内置管理员除外- S-1-5-32-500 )
所以代码可以是下一个:
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
ULONG IsUserInAdminGroup(BOOLEAN* pb)
{
*pb = FALSE;
HANDLE hToken;
ULONG dwError = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
if (dwError == NOERROR)
{
// /RTCs must be disabled !
static volatile UCHAR guz = 0;
PVOID stack = alloca(guz);
ULONG cb = 0, rcb = 0x100;
union {
PVOID buf;
PTOKEN_GROUPS ptg;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
dwError = BOOL_TO_ERROR(GetTokenInformation(hToken, ::TokenGroups, buf, cb, &rcb));
} while (dwError == ERROR_INSUFFICIENT_BUFFER);
CloseHandle(hToken);
if (dwError == NOERROR)
{
if (ULONG GroupCount = ptg->GroupCount)
{
static const SID_IDENTIFIER_AUTHORITY NT_AUTHORITY = SECURITY_NT_AUTHORITY;
PSID_AND_ATTRIBUTES Groups = ptg->Groups;
do
{
PSID Sid = Groups++->Sid;
if (*GetSidSubAuthorityCount(Sid) == 2 &&
*GetSidSubAuthority(Sid, 0) == SECURITY_BUILTIN_DOMAIN_RID &&
*GetSidSubAuthority(Sid, 1) == DOMAIN_ALIAS_RID_ADMINS &&
!memcmp(&NT_AUTHORITY, GetSidIdentifierAuthority(Sid), sizeof(SID_IDENTIFIER_AUTHORITY)))
{
*pb = TRUE;
break;
}
} while (--GroupCount);
}
return NOERROR;
}
}
return dwError;
}
也可以从令牌直接检查用户 sid - 它是DOMAIN_ALIAS_RID_ADMINS
别名的成员。这里的问题 - 任务到底如何,为什么这有必要。代码示例(使用ntsam.h并与samlib.lib链接- 标准 windows SDK的一部分)
HRESULT IsUserInAdminGroup(PSID UserSid, BOOLEAN* pb)
{
SAM_HANDLE ServerHandle, DomainHandle;
NTSTATUS status = SamConnect(0, &ServerHandle, SAM_SERVER_LOOKUP_DOMAIN, 0);
if (0 <= status)
{
ULONG len = GetSidLengthRequired(1);
PSID BuiltIn = (PSID)alloca(len);
static const SID_IDENTIFIER_AUTHORITY NT_AUTHORITY = SECURITY_NT_AUTHORITY;
InitializeSid(BuiltIn, const_cast<SID_IDENTIFIER_AUTHORITY*>(&NT_AUTHORITY), 1);
*GetSidSubAuthority(BuiltIn, 0) = SECURITY_BUILTIN_DOMAIN_RID;
status = SamOpenDomain(ServerHandle, DOMAIN_READ, BuiltIn, &DomainHandle);
SamCloseHandle(ServerHandle);
if (0 <= status)
{
ULONG MembershipCount, *Aliases;
status = SamGetAliasMembership(DomainHandle, 1, &UserSid, &MembershipCount, &Aliases);
SamCloseHandle(DomainHandle);
if (0 <= status)
{
PVOID buf = Aliases;
if (MembershipCount)
{
do
{
if (*Aliases++ == DOMAIN_ALIAS_RID_ADMINS)
{
*pb = TRUE;
break;
}
} while (--MembershipCount);
}
SamFreeMemory(buf);
}
}
}
return HRESULT_FROM_NT(status);
}
HRESULT IsUserInAdminGroup(BOOLEAN* pb)
{
*pb = FALSE;
HANDLE hToken;
ULONG dwError = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
if (dwError == NOERROR)
{
// /RTCs must be disabled !
static volatile UCHAR guz = 0;
PVOID stack = alloca(guz);
ULONG cb = 0, rcb = 0x80;
union {
PVOID buf;
PTOKEN_USER ptu;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
dwError = BOOL_TO_ERROR(GetTokenInformation(hToken, ::TokenUser, buf, cb, &rcb));
} while (dwError == ERROR_INSUFFICIENT_BUFFER);
CloseHandle(hToken);
if (dwError == NOERROR)
{
return IsUserInAdminGroup(ptu->User.Sid, pb);
}
}
return HRESULT_FROM_WIN32(dwError);
}