确定用户是否可以使用 C++ 提升进程
Determine if User can elevate a process with c++
我的应用程序需要一个功能来检查是否允许当前用户提升进程(运行 作为管理员)。函数 IsUserAnAdmin()
只告诉我进程是否已经提升,但在我的情况下它不是。
是否有任何其他选项来确定用户是否能够提升流程(是管理员)?
借助@RbMm 的评论,我创建了以下函数来确定进程是否可以提升。 (无密码)
bool IsElevationPossible()
{
TOKEN_ELEVATION_TYPE tokenElevationType;
DWORD size;
if (!GetTokenInformation(
GetCurrentProcessToken(),
TokenElevationType,
&tokenElevationType,
sizeof(tokenElevationType),
&size))
{
// Log Error
return false;
}
return tokenElevationType == TokenElevationTypeLimited;
}
为了检查当前海拔状态,我们可以查询 TOKEN_ELEVATION_TYPE
of current process with TokenElevationType
:
TokenElevationTypeFull
- 我们已经 运行 提升了。
TokenElevationTypeLimited
- 我们 运行 令牌有限,但有
提升的链接令牌。这通常是具有交互功能的管理员帐户
登录。我们可以在相同用户下提升。
TokenElevationTypeDefault
- 我们没有链接令牌。这里存在 2
案例:
我们已经提升(用于检查此用途
TokenElevation
和
从 TOKEN_ELEVATION
中寻找 TokenIsElevated
)如果我们 运行 在内置管理员帐户下
(DOMAIN_ALIAS_RID_ADMINS
500 ) 未被过滤,或者 UAC 在系统中被禁用。
我们 运行 不在管理员帐户下。我们
在这种情况下也可以提升,但只能在 另一个 帐户下。
为此需要知道此帐户密码
演示代码:
inline ULONG BTE(BOOL f)
{
return f ? 0 : GetLastError();
}
void TryElevate()
{
WCHAR path[MAX_PATH];
if (GetModuleFileNameW(0, path, RTL_NUMBER_OF(path)))
{
SHELLEXECUTEINFOW sei = { sizeof(sei), 0, 0, L"runas", path };
ShellExecuteExW(&sei);
}
}
ULONG CheckElevation()
{
HANDLE hToken;
ULONG err = BTE(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
if (!err)
{
ULONG cb = 0, rcb = 0x20;
union {
PTOKEN_USER ptu;
PVOID buf;
};
static volatile UCHAR guz;
PVOID stack = alloca(guz);
PWSTR SzSid = 0;
//++ for display user sid only
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (!(err = BTE(GetTokenInformation(hToken, ::TokenUser, buf, cb, &rcb))))
{
ConvertSidToStringSidW(ptu->User.Sid, &SzSid);
break;
}
} while (err == ERROR_INSUFFICIENT_BUFFER);
// -- for display user sid only
union {
TOKEN_ELEVATION te;
TOKEN_ELEVATION_TYPE tet;
};
if (!(err = BTE(GetTokenInformation(hToken, ::TokenElevationType, &tet, sizeof(tet), &rcb))))
{
switch (tet)
{
case TokenElevationTypeDefault:
if (!(err = BTE(GetTokenInformation(hToken, ::TokenElevation, &te, sizeof(te), &rcb))))
{
if (te.TokenIsElevated)
{
// we are built-in admin or UAC is disabled in system
case TokenElevationTypeFull:
MessageBoxW(HWND_DESKTOP, L"we run elevated", SzSid, MB_ICONINFORMATION);
break;
}
// we can not elevate under same user, but still can elevate under another admin account
// non admin account
TryElevate();
MessageBoxW(HWND_DESKTOP, L"Default", SzSid, MB_ICONINFORMATION);
}
break;
case TokenElevationTypeLimited:
// this mean that we have linked token, which is elevated. we can elevate under same user
TryElevate();
MessageBoxW(HWND_DESKTOP, L"Limited", SzSid, MB_ICONINFORMATION);
break;
default:
MessageBoxW(HWND_DESKTOP, L"unknown elevation type", SzSid, MB_ICONWARNING);
err = ERROR_GEN_FAILURE;
}
}
if (SzSid) LocalFree(SzSid);
CloseHandle(hToken);
}
return err;
}
结果:
我的应用程序需要一个功能来检查是否允许当前用户提升进程(运行 作为管理员)。函数 IsUserAnAdmin()
只告诉我进程是否已经提升,但在我的情况下它不是。
是否有任何其他选项来确定用户是否能够提升流程(是管理员)?
借助@RbMm 的评论,我创建了以下函数来确定进程是否可以提升。 (无密码)
bool IsElevationPossible()
{
TOKEN_ELEVATION_TYPE tokenElevationType;
DWORD size;
if (!GetTokenInformation(
GetCurrentProcessToken(),
TokenElevationType,
&tokenElevationType,
sizeof(tokenElevationType),
&size))
{
// Log Error
return false;
}
return tokenElevationType == TokenElevationTypeLimited;
}
为了检查当前海拔状态,我们可以查询 TOKEN_ELEVATION_TYPE
of current process with TokenElevationType
:
TokenElevationTypeFull
- 我们已经 运行 提升了。TokenElevationTypeLimited
- 我们 运行 令牌有限,但有
提升的链接令牌。这通常是具有交互功能的管理员帐户 登录。我们可以在相同用户下提升。TokenElevationTypeDefault
- 我们没有链接令牌。这里存在 2
案例:我们已经提升(用于检查此用途
TokenElevation
和 从TOKEN_ELEVATION
中寻找TokenIsElevated
)如果我们 运行 在内置管理员帐户下
(DOMAIN_ALIAS_RID_ADMINS
500 ) 未被过滤,或者 UAC 在系统中被禁用。我们 运行 不在管理员帐户下。我们 在这种情况下也可以提升,但只能在 另一个 帐户下。 为此需要知道此帐户密码
演示代码:
inline ULONG BTE(BOOL f)
{
return f ? 0 : GetLastError();
}
void TryElevate()
{
WCHAR path[MAX_PATH];
if (GetModuleFileNameW(0, path, RTL_NUMBER_OF(path)))
{
SHELLEXECUTEINFOW sei = { sizeof(sei), 0, 0, L"runas", path };
ShellExecuteExW(&sei);
}
}
ULONG CheckElevation()
{
HANDLE hToken;
ULONG err = BTE(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
if (!err)
{
ULONG cb = 0, rcb = 0x20;
union {
PTOKEN_USER ptu;
PVOID buf;
};
static volatile UCHAR guz;
PVOID stack = alloca(guz);
PWSTR SzSid = 0;
//++ for display user sid only
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (!(err = BTE(GetTokenInformation(hToken, ::TokenUser, buf, cb, &rcb))))
{
ConvertSidToStringSidW(ptu->User.Sid, &SzSid);
break;
}
} while (err == ERROR_INSUFFICIENT_BUFFER);
// -- for display user sid only
union {
TOKEN_ELEVATION te;
TOKEN_ELEVATION_TYPE tet;
};
if (!(err = BTE(GetTokenInformation(hToken, ::TokenElevationType, &tet, sizeof(tet), &rcb))))
{
switch (tet)
{
case TokenElevationTypeDefault:
if (!(err = BTE(GetTokenInformation(hToken, ::TokenElevation, &te, sizeof(te), &rcb))))
{
if (te.TokenIsElevated)
{
// we are built-in admin or UAC is disabled in system
case TokenElevationTypeFull:
MessageBoxW(HWND_DESKTOP, L"we run elevated", SzSid, MB_ICONINFORMATION);
break;
}
// we can not elevate under same user, but still can elevate under another admin account
// non admin account
TryElevate();
MessageBoxW(HWND_DESKTOP, L"Default", SzSid, MB_ICONINFORMATION);
}
break;
case TokenElevationTypeLimited:
// this mean that we have linked token, which is elevated. we can elevate under same user
TryElevate();
MessageBoxW(HWND_DESKTOP, L"Limited", SzSid, MB_ICONINFORMATION);
break;
default:
MessageBoxW(HWND_DESKTOP, L"unknown elevation type", SzSid, MB_ICONWARNING);
err = ERROR_GEN_FAILURE;
}
}
if (SzSid) LocalFree(SzSid);
CloseHandle(hToken);
}
return err;
}
结果: