You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

获取进程完整Handle列表失败求助:已提权仍未解决

无法获取进程完整Handle列表的问题排查与解决

问题描述

已以管理员身份运行程序,目标为获取普通进程的完整Handle列表,但与Process Hacker的结果对比存在明显缺失。已按建议添加SE_DEBUG_NAME权限,但问题仍未解决。

提供的代码

void SetPrivilege()
{
    TOKEN_PRIVILEGES NewState;
    LUID luid;
    HANDLE hToken;

    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);

    NewState.PrivilegeCount = 1;
    NewState.Privileges[0].Luid = luid;
    NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges(hToken, FALSE, &NewState, sizeof(NewState), NULL, NULL);

    CloseHandle(hToken);
}

int main(int argc, WCHAR* argv[])
{
    SetPrivilege();
    _NtQuerySystemInformation NtQuerySystemInformation =
        (_NtQuerySystemInformation)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtQuerySystemInformation");
    _NtDuplicateObject NtDuplicateObject =
        (_NtDuplicateObject)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtDuplicateObject");
    _NtQueryObject NtQueryObject =
        (_NtQueryObject)GetLibraryProcAddress((PSTR)"ntdll.dll", (PSTR)"NtQueryObject");
    NTSTATUS status;
    PSYSTEM_HANDLE_INFORMATION handleInfo;
    ULONG handleInfoSize = 0x10000;
    HANDLE processHandle;
    ULONG i;

    unsigned __int16 pid = 0;
    std::cin >> pid;

    if (!(processHandle = OpenProcess(PROCESS_DUP_HANDLE, 0, pid)))
    {
        printf("Could not open PID %d! (Don't try to open a system process.)\n", pid);
        return 1;
    }

    handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);

    while ((status = NtQuerySystemInformation(
        SystemHandleInformation,
        handleInfo,
        handleInfoSize,
        NULL
    )) == STATUS_INFO_LENGTH_MISMATCH)
        handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);

    if (!NT_SUCCESS(status))
    {
        printf("NtQuerySystemInformation failed!\n");
        return 1;
    }

    for (i = 0; i < handleInfo->HandleCount; i++)
    {
        SYSTEM_HANDLE handle = handleInfo->Handles[i];
        HANDLE dupHandle = NULL;
        POBJECT_TYPE_INFORMATION objectTypeInfo;
        PVOID objectNameInfo;
        UNICODE_STRING objectName;
        ULONG returnLength;

        if (handle.ProcessId != pid)
            continue;

        if (!NT_SUCCESS(NtDuplicateObject(
            processHandle,
            (HANDLE)handle.Handle,
            GetCurrentProcess(),
            &dupHandle,
            0,
            0,
            0
        )))
        {
            printf("[%#x] Error!\n", handle.Handle);
            continue;
        }

        objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000);
        if (!NT_SUCCESS(NtQueryObject(
            dupHandle,
            ObjectTypeInformation,
            objectTypeInfo,
            0x1000,
            NULL
        )))
        {
            printf("[%#x] Error!\n", handle.Handle);
            CloseHandle(dupHandle);
            continue;
        }

        if (handle.GrantedAccess == 0x0012019f)
        {
            printf(
                "[%#x] %.*S: (did not get name)\n",
                handle.Handle,
                objectTypeInfo->Name.Length / 2,
                objectTypeInfo->Name.Buffer
            );
            free(objectTypeInfo);
            CloseHandle(dupHandle);
            continue;
        }

        objectNameInfo = malloc(0x1000);
        if (!NT_SUCCESS(NtQueryObject(
            dupHandle,
            ObjectNameInformation,
            objectNameInfo,
            0x1000,
            &returnLength
        )))
        {
            objectNameInfo = realloc(objectNameInfo, returnLength);
            if (!NT_SUCCESS(NtQueryObject(
                dupHandle,
                ObjectNameInformation,
                objectNameInfo,
                returnLength,
                NULL
            )))
            {
                printf(
                    "[%#x] %.*S: (could not get name)\n",
                    handle.Handle,
                    objectTypeInfo->Name.Length / 2,
                    objectTypeInfo->Name.Buffer
                );
                free(objectTypeInfo);
                free(objectNameInfo);
                CloseHandle(dupHandle);
                continue;
            }
        }

        objectName = *(PUNICODE_STRING)objectNameInfo;

        if (objectName.Length)
        {
            printf(
                "[%#x] %.*S: %.*S\n",
                handle.Handle,
                objectTypeInfo->Name.Length / 2,
                objectTypeInfo->Name.Buffer,
                objectName.Length / 2,
                objectName.Buffer
            );
        }
        else
        {
            printf(
                "[%#x] %.*S: (unnamed)\n",
                handle.Handle,
                objectTypeInfo->Name.Length / 2,
                objectTypeInfo->Name.Buffer
            );
        }

        free(objectTypeInfo);
        free(objectNameInfo);
        CloseHandle(dupHandle);
    }

    free(handleInfo);
    CloseHandle(processHandle);
    system("pause");

    return 0;
}

排查与修复方案

1. 完善权限设置的错误检查

原SetPrivilege函数未检查任何API返回值,可能权限并未成功启用。修改后添加完整错误校验:

BOOL SetPrivilege()
{
    TOKEN_PRIVILEGES NewState;
    LUID luid;
    HANDLE hToken = NULL;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        printf("OpenProcessToken failed: %lu\n", GetLastError());
        return FALSE;
    }

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
    {
        printf("LookupPrivilegeValue failed: %lu\n", GetLastError());
        CloseHandle(hToken);
        return FALSE;
    }

    NewState.PrivilegeCount = 1;
    NewState.Privileges[0].Luid = luid;
    NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &NewState, sizeof(NewState), NULL, NULL))
    {
        printf("AdjustTokenPrivileges failed: %lu\n", GetLastError());
        CloseHandle(hToken);
        return FALSE;
    }
    else if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
        printf("Privilege not assigned\n");
        CloseHandle(hToken);
        return FALSE;
    }

    CloseHandle(hToken);
    return TRUE;
}

2. 提升OpenProcess的权限

原调用仅传入PROCESS_DUP_HANDLE,部分对象复制需要更高权限,改为:

processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, FALSE, pid);

3. 使用扩展句柄信息接口

SystemHandleInformation在部分Windows版本返回信息不全,改用SystemExtendedHandleInformation获取完整数据:

while ((status = NtQuerySystemInformation(
    SystemExtendedHandleInformation,
    handleInfo,
    handleInfoSize,
    NULL
)) == STATUS_INFO_LENGTH_MISMATCH)
    handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);

需注意补充SYSTEM_HANDLE_INFORMATION_EX结构定义(参考Windows SDK文档)。

4. 优化句柄复制权限

调用NtDuplicateObject时传入DUPLICATE_SAME_ACCESS,确保复制的句柄拥有原句柄相同权限:

if (!NT_SUCCESS(NtDuplicateObject(
    processHandle,
    (HANDLE)handle.Handle,
    GetCurrentProcess(),
    &dupHandle,
    0,
    0,
    DUPLICATE_SAME_ACCESS
)))

5. 取消不必要的句柄过滤

原代码跳过了GrantedAccess == 0x0012019f的句柄,导致遗漏,可注释该判断:

// if (handle.GrantedAccess == 0x0012019f)
// {
//     printf("[%#x] %.*S: (did not get name)\n",
//         handle.Handle,
//         objectTypeInfo->Name.Length / 2,
//         objectTypeInfo->Name.Buffer);
//     free(objectTypeInfo);
//     CloseHandle(dupHandle);
//     continue;
// }

内容的提问来源于stack exchange,提问作者IvanM1999

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:54:26