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

当前进程句柄检测仅返回自身句柄,求代码修复方案

问题分析与解决方案

你的核心问题在于仅枚举了当前进程自身的句柄,而ProcessExplorer这类工具的原理是遍历系统中所有进程,再检查每个进程持有的句柄是否指向目标进程。以下是具体修改方案:

关键思路

  1. 启用Debug权限:必须正确启用SeDebugPrivilege,否则无法访问系统进程(如csrss、lsass)的句柄。
  2. 遍历系统所有句柄:通过Native APINtQuerySystemInformation的SystemHandleInformation类,获取系统中所有打开的句柄信息。
  3. 筛选目标句柄:对每个句柄,复制到当前进程后查询其对象类型,判断是否为进程句柄,再验证其指向的进程ID是否为目标进程。

修改后的完整代码

#include <windows.h>
#include <winternl.h>
#include <stdio.h>
#include <malloc.h>
#include <wchar.h>

// Native API 结构体定义
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
    USHORT UniqueProcessId;
    USHORT CreatorBackTraceIndex;
    UCHAR ObjectTypeIndex;
    UCHAR HandleAttributes;
    USHORT HandleValue;
    PVOID Object;
    ULONG GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;

typedef struct _SYSTEM_HANDLE_INFORMATION {
    ULONG NumberOfHandles;
    SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

typedef struct _OBJECT_TYPE_INFORMATION {
    UNICODE_STRING Name;
    ULONG TotalNumberOfObjects;
    ULONG TotalNumberOfHandles;
    ULONG TotalPagedPoolUsage;
    ULONG TotalNonPagedPoolUsage;
    ULONG TotalNamePoolUsage;
    ULONG TotalHandleTableUsage;
    ULONG HighWaterNumberOfObjects;
    ULONG HighWaterNumberOfHandles;
    ULONG HighWaterPagedPoolUsage;
    ULONG HighWaterNonPagedPoolUsage;
    ULONG HighWaterNamePoolUsage;
    ULONG HighWaterHandleTableUsage;
    ULONG InvalidAttributes;
    GENERIC_MAPPING GenericMapping;
    ULONG ValidAccess;
    BOOLEAN SecurityRequired;
    BOOLEAN MaintainHandleCount;
    USHORT MaintainTypeList;
    POOL_TYPE PoolType;
    ULONG PagedPoolUsage;
    ULONG NonPagedPoolUsage;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;

// Native API 函数指针
typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
);

typedef NTSTATUS(WINAPI* PNtQueryObject)(
    HANDLE Handle,
    OBJECT_INFORMATION_CLASS ObjectInformationClass,
    PVOID ObjectInformation,
    ULONG ObjectInformationLength,
    PULONG ReturnLength
);

// 启用SeDebugPrivilege权限
BOOL EnableDebugPrivilege() {
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        return FALSE;
    }

    if (!LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &luid)) {
        CloseHandle(hToken);
        return FALSE;
    }

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

    AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
    BOOL result = (GetLastError() == ERROR_SUCCESS);
    CloseHandle(hToken);
    return result;
}

// 枚举所有指向目标进程的句柄
void EnumTargetProcessHandles(DWORD targetPid) {
    PNtQuerySystemInformation NtQuerySystemInformation = (PNtQuerySystemInformation)GetProcAddress(
        GetModuleHandleW(L"ntdll.dll"), "NtQuerySystemInformation");
    PNtQueryObject NtQueryObject = (PNtQueryObject)GetProcAddress(
        GetModuleHandleW(L"ntdll.dll"), "NtQueryObject");

    if (!NtQuerySystemInformation || !NtQueryObject) {
        printf("Failed to load native APIs\n");
        return;
    }

    // 动态分配缓冲区以容纳所有句柄信息
    ULONG bufferSize = 0x10000;
    PSYSTEM_HANDLE_INFORMATION handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(bufferSize);
    NTSTATUS status;

    while ((status = NtQuerySystemInformation(SystemHandleInformation, handleInfo, bufferSize, &bufferSize)) == STATUS_INFO_LENGTH_MISMATCH) {
        free(handleInfo);
        handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(bufferSize);
    }

    if (!NT_SUCCESS(status)) {
        printf("NtQuerySystemInformation failed: 0x%X\n", status);
        free(handleInfo);
        return;
    }

    printf("Found %lu handles pointing to PID %lu:\n", handleInfo->NumberOfHandles, targetPid);

    for (ULONG i = 0; i < handleInfo->NumberOfHandles; i++) {
        SYSTEM_HANDLE_TABLE_ENTRY_INFO& entry = handleInfo->Handles[i];

        // 打开句柄所属的进程
        HANDLE hOwnerProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, entry.UniqueProcessId);
        if (!hOwnerProcess) continue;

        // 将句柄复制到当前进程,否则无法查询其信息
        HANDLE hDupHandle = NULL;
        if (!DuplicateHandle(hOwnerProcess, (HANDLE)entry.HandleValue, GetCurrentProcess(), &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
            CloseHandle(hOwnerProcess);
            continue;
        }

        // 查询句柄对应的对象类型
        ULONG objInfoSize = 0x1000;
        POBJECT_TYPE_INFORMATION objTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(objInfoSize);
        status = NtQueryObject(hDupHandle, ObjectTypeInformation, objTypeInfo, objInfoSize, &objInfoSize);
        
        if (NT_SUCCESS(status) && wcscmp(objTypeInfo->Name.Buffer, L"Process") == 0) {
            // 验证该进程句柄是否指向目标进程
            DWORD pid = GetProcessId(hDupHandle);
            if (pid == targetPid) {
                printf("Process PID %d holds handle 0x%X to target process\n", entry.UniqueProcessId, entry.HandleValue);
            }
        }

        free(objTypeInfo);
        CloseHandle(hDupHandle);
        CloseHandle(hOwnerProcess);
    }

    free(handleInfo);
}

int main() {
    if (!EnableDebugPrivilege()) {
        printf("Failed to enable debug privilege\n");
        return 1;
    }

    DWORD targetPid = GetCurrentProcessId();
    EnumTargetProcessHandles(targetPid);

    return 0;
}

核心修改点说明

  1. Native API 使用:NtQuerySystemInformation是获取系统全局句柄的唯一途径,Win32 API没有提供直接接口。
  2. 句柄复制:其他进程的句柄无法被当前进程直接访问,必须通过DuplicateHandle复制到当前进程空间后才能查询其对象信息。
  3. 权限处理:EnableDebugPrivilege函数确保当前进程拥有访问系统进程的权限,这是枚举csrss、lsass等进程句柄的必要条件。
  4. 动态缓冲区:系统中句柄数量可能很大,初始缓冲区不足时需要重新分配,避免枚举不完整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 23:40:49