Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么OpenProcess()只对某些进程返回ERROR\u ACCESS\u DENIED?_C_Windows_Winapi_Process - Fatal编程技术网

为什么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;
}