Почему OpenProcess () возвращает ERROR_ACCESS_DENIED только для некоторых процессов? - PullRequest
0 голосов
/ 04 августа 2020

OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid) успешно возвращается, например, для cmd.exe с правами администратора и cmd.exe без прав администратора. Однако когда я передаю pid для процесса node.exe, он терпит неудачу, и GetLastError() возвращает ERROR_ACCESS_DENIED. Может ли кто-нибудь сказать мне, как получить доступ к этому объекту процесса?

ОБНОВЛЕНИЕ: Я считаю, что сделал все, что @ErykSun предлагает в следующем коде. Я пошел дальше, но теперь AdjustTokenPrivileges() не работает с ERROR_ACCESS_DENIED (я убрал всю обработку ошибок, чтобы упростить понимание кода здесь). Более того, теперь моя программа не может отключать привилегии для более низких уровней целостности, например cmd.exe без прав администратора. (Два прототипа функций предназначены для вспомогательных функций, следующих за функцией disable_all_privileges(). Надеюсь, они верны.)

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;
}

1 Ответ

1 голос
/ 08 августа 2020

Наконец-то все заработало. Вот код маленькой программы, которая отключает все привилегии процесса. Pid передается в командной строке. Я бы не справился с этим без помощи Эрика Сан (спасибо!). (См. ОБНОВЛЕНИЕ внизу.)

#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;
}

ОБНОВЛЕНИЕ: Вот улучшенный reduce_privilege() с дальнейшими предложениями Эрика. Таким образом, мы включаем и используем привилегию олицетворения только в случае крайней необходимости.

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...