为什么OpenProcess()只对某些进程返回ERROR\u ACCESS\u DENIED?
为什么OpenProcess()只对某些进程返回ERROR\u ACCESS\u DENIED?,c,windows,winapi,process,C,Windows,Winapi,Process,OpenProcess(PROCESS\u QUERY\u INFORMATION,TRUE,pid)为管理员cmd.exe和非管理员cmd.exe成功返回。但是,当我传入node.exe进程的pid时,它会失败,GetLastError()返回ERROR\u ACCESS\u DENIED。有人能告诉我如何访问这个进程对象吗 更新:我相信我已经完成了@ErykSun在下面代码中建议的所有操作。我已经做了进一步的说明,但是现在,AdjustTokenPrivileges()失败,出现了错误\u访
OpenProcess(PROCESS\u QUERY\u INFORMATION,TRUE,pid)
为管理员cmd.exe和非管理员cmd.exe成功返回。但是,当我传入node.exe进程的pid时,它会失败,GetLastError()
返回ERROR\u ACCESS\u DENIED
。有人能告诉我如何访问这个进程对象吗
更新:我相信我已经完成了@ErykSun在下面代码中建议的所有操作。我已经做了进一步的说明,但是现在,AdjustTokenPrivileges()
失败,出现了错误\u访问被拒绝的情况(我去掉了所有的错误处理,以便在这里更容易理解代码)。此外,现在我的程序无法禁用较低完整性级别的权限,例如,非管理员cmd.exe。(这两个函数原型是针对disable\u all\u privileges()
函数之后的助手函数。希望它们是正确的。)
我终于让它工作了。下面是禁用所有进程权限的小程序的代码。pid在命令行上传递。如果没有Erik Sun的帮助(谢谢!),我不可能做到这一点。(请参见底部的更新。)
请求PROCESS\u QUERY\u LIMITED\u信息
access如果足够的话。但是,即使在这种情况下,如果DACL不授予访问权限,您也需要启用SeDebugPrivilege。可用的访问权限取决于DACL,DACL隐式授予所有者读控制权
和写控制权
访问权限。无论DACL如何,流程对象的强制访问控制策略都会拒绝从较低完整性级别(例如,高完整性级别安全上下文无法读取系统完整性级别的流程)进行读取访问,但使用process\u QUERY\u limited\u information
访问的有限信息除外。SeDebugPrivilege会覆盖DACL和强制标签,但它不会覆盖受保护的进程保护级别(例如PsProtectedSignerWinTcb灯)。进程查询信息
允许访问内核中进程的令牌,但是打开令牌的句柄仍然需要令牌的自主访问控制列表(DACL)中的条目授予访问权限。此外,无论向用户授予何种自主访问权,令牌对象的强制访问控制都会在较低的完整性级别(例如,中、高或系统级别)拒绝对安全上下文的写入访问,其中包括“调整”权限,如令牌调整权限
和令牌调整组
。换句话说,如果令牌对象处于系统完整性级别,但您的安全上下文仅处于高完整性级别(即提升的管理员),然后您将无法使用TOKEN\u ADJUST\u特权
access直接打开它。相反,尝试使用TOKEN\u QUERY | TOKEN\u DUPLICATE
access打开;确保在当前令牌中启用了SeImpersonatePrivilege,并在打开的令牌上调用ImpersonateLoggedOnUser
。现在,在模拟时,您应该能够使用所需的“调整”权限(如TOKEN\u adjust\u PRIVILEGES
)调用OpenProcessToken
。您错过了一步。这些步骤的要点是,当令牌的DACL不授予您写访问权限或您被拒绝写访问时,尝试获取对令牌的写(调整)访问权限,因为您运行的完整性级别较低(例如,令牌处于系统级别,而您处于高级别)。假设您有权查询和复制令牌,并且您拥有SeImpersonatePrivilege,然后打开令牌,模拟它,然后使用所需的写访问权限再次打开它(从模拟的安全上下文)。您错过了最后一步。对于reduce\u privileges
中的注释,此处使用的方法需要提升登录才能使用超级权限SeDebugPrivilege和SeImpersonatePrivilege,因此当前安全上下文已处于高完整性级别。如果令牌处于系统级别,或者令牌的DACL未授予管理员写访问权限,则模拟允许获取写(调整)访问权限。标准用户没有权限这样做。我会首先尝试启用SeDebugPrivilege,无论是否成功,都尝试禁用所有特权。如果失败,请尝试启用SeImpersonatePrivilege。如果特权存在并已启用(即调用AdjustTokenPrivileges
后检查GetLastError()==ERROR\u SUCCESS
),则从目标进程模拟令牌,然后重试禁用所有特权。如果权限不存在(即GetLastError()==ERROR\u not\u ALL\u ASSIGNED
),那么就不用麻烦了,因为您只能在身份级别模拟,这在这里没有用处。再次感谢您,Eryk。我加入了一个新版本的reduce_privileges()
,作为对我上面“答案”的更新。看起来我总是需要对node.exe进行模拟,但这使代码更通用,并且只有在必要时才能获取该权限。
BOOL set_privilege(HANDLE hToken, const char* privilege, BOOL bEnablePrivilege);
BOOL get_self_token(HANDLE* phToken);
int disable_all_privileges(DWORD pid)
{
int ret = 1;
HANDLE hSelfToken;
if (get_self_token(&hSelfToken)) {
if (set_privilege(hSelfToken, "SeDebugPrivilege", TRUE)) {
if (set_privilege(hSelfToken, "SeImpersonatePrivilege", TRUE)) {
const HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (hProcess) {
HANDLE hToken;
if (OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) {
print_privileges(hToken);
if (ImpersonateLoggedOnUser(hToken))
if (AdjustTokenPrivileges(hToken, TRUE, NULL, 0, NULL, NULL) && GetLastError() == ERROR_SUCCESS) {
print_privileges(hToken);
ret = 0;
}
CloseHandle(hToken);
}
}
set_privilege(hSelfToken, "SeImpersonatePrivilege", FALSE);
}
set_privilege(hSelfToken, "SeDebugPrivilege", FALSE);
}
CloseHandle(hSelfToken);
}
return ret;
}
BOOL set_privilege(HANDLE hToken, const char* privilege, BOOL bEnablePrivilege)
{
BOOL ok = FALSE;
LUID luid;
if (LookupPrivilegeValueA(NULL, privilege, &luid)) {
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious = sizeof tpPrevious;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof tp, &tpPrevious, &cbPrevious);
if (GetLastError() == ERROR_SUCCESS) {
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tpPrevious.Privileges[0].Attributes |= SE_PRIVILEGE_ENABLED;
else
tpPrevious.Privileges[0].Attributes ^= SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes;
AdjustTokenPrivileges(hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL);
ok = GetLastError() == ERROR_SUCCESS;
}
}
return ok;
}
BOOL get_self_token(HANDLE* phToken)
{
BOOL ok = FALSE;
if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, phToken))
ok = TRUE;
else
if (GetLastError() == ERROR_NO_TOKEN)
if (ImpersonateSelf(SecurityImpersonation))
if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, phToken))
ok = TRUE;
return ok;
}
#include <windows.h>
#include <stdio.h>
#include <TlHelp32.h>
void print_privileges(HANDLE hToken)
{
DWORD size;
if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &size) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
PTOKEN_PRIVILEGES tp = malloc(size);
if (tp != NULL && GetTokenInformation(hToken, TokenPrivileges, tp, size, &size)) {
size_t i;
for (i = 0; i < tp->PrivilegeCount; ++i) {
char name[64];
DWORD NAME_SIZE = sizeof name;
LookupPrivilegeNameA(0, &tp->Privileges[i].Luid, name, &NAME_SIZE);
BOOL fResult;
PRIVILEGE_SET ps = {
1, PRIVILEGE_SET_ALL_NECESSARY, {
{ { tp->Privileges[i].Luid.LowPart, tp->Privileges[i].Luid.HighPart } }
}
};
PrivilegeCheck(hToken, &ps, &fResult);
printf("%-*s %s\n", 42, name, fResult ? "Enabled" : "Disabled");
}
}
free(tp);
}
}
BOOL set_privilege(HANDLE hToken, const char* privilege, BOOL bEnablePrivilege)
{
BOOL ok = FALSE;
LUID luid;
if (LookupPrivilegeValueA(NULL, privilege, &luid)) {
// first pass. get current privilege setting
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious = sizeof tpPrevious;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof tp, &tpPrevious, &cbPrevious);
if (GetLastError() == ERROR_SUCCESS) {
// second pass. set privilege based on previous setting
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tpPrevious.Privileges[0].Attributes |= SE_PRIVILEGE_ENABLED;
else
tpPrevious.Privileges[0].Attributes ^= SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes;
AdjustTokenPrivileges(hToken, FALSE, &tpPrevious, cbPrevious, NULL, NULL);
ok = GetLastError() == ERROR_SUCCESS;
}
}
return ok;
}
BOOL get_current_token(HANDLE* phToken)
{
BOOL ok = FALSE;
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, phToken)) {
if (GetLastError() == ERROR_NO_TOKEN)
if (ImpersonateSelf(SecurityImpersonation))
if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, phToken))
ok = TRUE;
} else
ok = TRUE;
return ok;
}
BOOL impersonate_process(HANDLE hProcess)
{
BOOL ok = FALSE;
HANDLE hToken;
if (OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) {
if (ImpersonateLoggedOnUser(hToken))
ok = TRUE;
CloseHandle(hToken);
}
return ok;
}
BOOL disable_all_privileges(HANDLE hProcess)
{
BOOL ok = FALSE;
HANDLE hToken;
if (OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
puts("\nBefore:");
print_privileges(hToken);
/* disable all privileges */
if (AdjustTokenPrivileges(hToken, TRUE, NULL, 0, NULL, NULL))
/* AdjustTokenPrivileges() could succeed but still not disable all privileges */
if (GetLastError() != ERROR_NOT_ALL_ASSIGNED) {
puts("\nAfter:");
print_privileges(hToken);
ok = TRUE;
}
CloseHandle(hToken);
}
return ok;
}
BOOL reduce_privileges(DWORD pid)
{
BOOL ok = FALSE;
/* in case target process has higher integrity level than this process, e.g., system versus
* high integrity, enable SeDebugPrivilege and impersonate target process */
HANDLE hCurrentToken;
if (get_current_token(&hCurrentToken)) {
if (set_privilege(hCurrentToken, "SeDebugPrivilege", TRUE)) {
if (set_privilege(hCurrentToken, "SeImpersonatePrivilege", TRUE)) {
/* get process handle with only the least access needed */
const HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (hProcess) {
if (impersonate_process(hProcess))
/* now we should be able to adjust the privileges of any target process */
if (disable_all_privileges(hProcess))
ok = TRUE;
CloseHandle(hProcess);
}
/* disable privileges we no longer need */
set_privilege(hCurrentToken, "SeImpersonatePrivilege", FALSE);
}
set_privilege(hCurrentToken, "SeDebugPrivilege", FALSE);
}
CloseHandle(hCurrentToken);
}
return ok;
}
int main(int argc, char* argv[])
{
DWORD pid = 0;
if (argc > 1)
sscanf_s(argv[1], "%u", &pid);
return pid && reduce_privileges(pid) ? 0 : 1;
}
int reduce_privileges(DWORD pid)
{
int ret = 1;
HANDLE hCurrentToken;
if (get_current_token(&hCurrentToken)) {
const BOOL debug_set = set_privilege(hCurrentToken, "SeDebugPrivilege", TRUE);
/* regardless of whether we got debug privilege, try to get process handle with the least access needed */
const HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (hProcess) {
/* see if we can disable privileges of target process without the impersonate privilege;
if we can't, enable that privilege, impersonate, and try again */
if (disable_all_privileges(hProcess))
ret = 0;
else
if (set_privilege(hCurrentToken, "SeImpersonatePrivilege", TRUE)) {
if (impersonate_process(hProcess))
/* now we should be able to adjust the privileges of any target process */
if (disable_all_privileges(hProcess))
ret = 0;
/* impersonate privilege no longer needed */
set_privilege(hCurrentToken, "SeImpersonatePrivilege", FALSE);
}
CloseHandle(hProcess);
}
/* debug privilege no longer needed */
if (debug_set)
set_privilege(hCurrentToken, "SeDebugPrivilege", FALSE);
CloseHandle(hCurrentToken);
}
return ret;
}