【问题标题】:Enumerating process handles, weird issue枚举进程句柄,奇怪的问题
【发布时间】:2015-06-22 22:41:17
【问题描述】:

我扫描我的进程打开的句柄并在控制台中打印它们。

  1. 我开始我的进程
  2. 我附上了作弊引擎
  3. 我运行打开句柄的枚举
  4. 我看到哪个进程拥有我的进程的句柄

此时奇怪的问题如下,查看代码:

array<Accessor^>^ AntiCheat::ScanHandles()
{
    List<Accessor^>^ accessorList = gcnew List<Accessor^>();

    if (!EnableDebugPrivilege(true))
        printf("EnableDebugPrivilege failed: %d\n", GetLastError());

    tNtQuerySystemInformation oNtQuerySystemInformation = (tNtQuerySystemInformation)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");

    PSYSTEM_HANDLE_INFORMATION handleInfo = new SYSTEM_HANDLE_INFORMATION;
    SYSTEM_INFORMATION_CLASS infoClass = (SYSTEM_INFORMATION_CLASS)16; // SystemHandleInformation
    DWORD size = sizeof(SYSTEM_HANDLE_INFORMATION);
    DWORD needed = 0;
    NTSTATUS status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
    while (!NT_SUCCESS(status))
    {
        if (needed == 0)
            return nullptr;
        // The previously supplied buffer wasn't enough.
        delete handleInfo;
        size = needed + 1024;
        handleInfo = (PSYSTEM_HANDLE_INFORMATION)new BYTE[size];
        status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
    }

    HANDLE currentProcess = GetCurrentProcess();
    DWORD currentProcessId = GetProcessId(currentProcess);
    for (DWORD i = 0; i < handleInfo->dwCount; i++)
    {
        //printf(".");
        SYSTEM_HANDLE handle = handleInfo->Handles[i];

        HANDLE procHandle = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, handle.dwProcessId);
        if (GetLastError() == ERROR_ACCESS_DENIED)
            continue;

        HANDLE dupl = 0;
        if (!DuplicateHandle(procHandle, (HANDLE)handle.wValue, currentProcess, &dupl, 0, false, DUPLICATE_SAME_ACCESS))
            continue;

        DWORD procId = GetProcessId(dupl);
        if (procId == currentProcessId)
        {
            printf("accessing us\n");
            char processName[MAX_PATH];
            GetModuleFileNameEx((HMODULE)procHandle, NULL, processName, MAX_PATH);
            accessorList->Add(gcnew Accessor(gcnew String(processName), handle.GrantedAccess));
        }

        CloseHandle(dupl);
    }

    return accessorList->ToArray();
}

如果我用 printf("."); 取消注释该行,我会看到 3 个打开的进程句柄(作弊引擎)。如果它被注释(运行速度更快),则没有打开的句柄。但是我不知道为什么这会影响我的代码。我很惊讶,有人知道为什么会这样吗?或者如何在没有我的 printf("."); 的情况下找出如何找到句柄;行吗?

另一个问题是:每次我调用函数时,分配的字节数都会重复。我不知道为什么。

【问题讨论】:

  • 也许第一次调用 C IO 函数会导致它打开标准输入、输出和错误的句柄?
  • 您不会忽略handle.dwProcessId 等于currentProcessId 的数组项,因此您最终会为自己的进程打开一个新句柄。您只对handle.dwProcessId 不等于currentProcessId 的其他进程感兴趣。
  • @RemyLebeau 假设 Handle 是一个进程句柄,GetProcessId 获取句柄的 id,如果它等于我的进程,我看到它是我的进程的句柄,这就是我正在寻找的为了。无论如何,另一个问题是:分配的字节数重复每次调用(NtQuerySystemInformation 返回 ERROR_INFO_LENGTH_MISMATCH)。

标签: c++ process handle


【解决方案1】:

我发现您的代码存在逻辑问题。

您不会忽略handle.dwProcessId 等于currentProcessId 的数组项,因此您最终会打开自己进程的句柄。由于您只对寻找其他进程感兴趣,因此您应该忽略handle.dwProcessId 等于currentProcessId 的项目。

您没有检查OpenProcess() 是否因ERROR_ACCESS_DENIED 以外的任何原因而失败。不要调用GetLastError(),除非OpenProcess()实际上首先返回NULL。

如果DuplicateHandle() 失败,您不会关闭打开的句柄。为什么要复制每个源句柄只是为了调用 GetProcessId() 呢?您已经从数组中获得了它们的进程 ID,因此整个 DuplicateHandle()+GetProcessId() 完全没有必要。

无论如何,您采取了错误的方法。看看这个讨论:

Enumerating the processes referencing an object

使用 NtQuerySystemInformation 并将 SystemInformationClass 设置为 SystemHandleInformation。这会填充一个 SYSTEM_HANDLE_INFORMATION 结构的数组,这些结构定义为:

typedef struct _SYSTEM_HANDLE_INFORMATION {
    ULONG ProcessId;
    UCHAR ObjectTypeNumber;
    UCHAR Flags;
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
 } SYSTEM_HANDLE_INFORMATION;

搜索与您打开的ProcessID等于GetCurrentProcessId()的句柄对应的条目,然后找到具有相同Object指针的所有条目。

尽管讨论显示SYSTEM_HANDLE_INFORMATION 的声明错误。以下文章显示了正确的:

HOWTO: Enumerate handles

#define SystemHandleInformation 16

typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
    ULONG SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
    );

/* The following structure is actually called SYSTEM_HANDLE_TABLE_ENTRY_INFO, but SYSTEM_HANDLE is shorter. */
typedef struct _SYSTEM_HANDLE
{
    ULONG ProcessId;
    BYTE ObjectTypeNumber;
    BYTE Flags;
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
 } SYSTEM_HANDLE, *PSYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
  ULONG HandleCount; /* Or NumberOfHandles if you prefer. */
  SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

话虽如此,请尝试更多类似的东西:

array<Accessor^>^ AntiCheat::ScanHandles()
{
    List<Accessor^>^ accessorList = gcnew List<Accessor^>();

    if (!EnableDebugPrivilege(true))
        printf("EnableDebugPrivilege failed: %d\n", GetLastError());

    tNtQuerySystemInformation oNtQuerySystemInformation = (tNtQuerySystemInformation) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");

    DWORD currentProcessId = GetCurrentProcessId();
    HANDLE currentProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, currentProcessId);
    PVOID currentProcessAddr = nullptr;

    DWORD size = sizeof(SYSTEM_HANDLE_INFORMATION);
    DWORD needed = 0;
    PSYSTEM_HANDLE_INFORMATION handleInfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[size];
    SYSTEM_INFORMATION_CLASS infoClass = (SYSTEM_INFORMATION_CLASS) 16; // SystemHandleInformation
    NTSTATUS status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
    while (status == STATUS_INFO_LENGTH_MISMATCH)
    {
        // The previously supplied buffer wasn't enough.
        delete[] handleInfo;
        size += 1024;
        handleInfo = (PSYSTEM_HANDLE_INFORMATION) new BYTE[size];
        status = oNtQuerySystemInformation(infoClass, handleInfo, size, &needed);
    }
    if (status != 0)
    {
        delete[] handleInfo;
        return nullptr;
    }    


    for (DWORD i = 0; i < handleInfo->dwCount; i++)
    {
        SYSTEM_HANDLE &handle = handleInfo->Handles[i];

        if ((handle.dwProcessId == currentProcessId) &&
            (currentProcess == (HANDLE)handle.wValue))
        {
            currentProcessAddr = handle.pAddress;
            break;
        }
    }

    for (DWORD i = 0; i < handleInfo->dwCount; i++)
    {
        SYSTEM_HANDLE &handle = handleInfo->Handles[i];

        if ((handle.dwProcessId != currentProcessId) &&
            (handle.pAddress == currentProcessAddr))
        {
            printf("accessing us\n");

            HANDLE procHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, handle.dwProcessId);
            if (procHandle != 0)
            {
                char processName[MAX_PATH+1];
                DWORD len = GetModuleFileNameEx((HMODULE)procHandle, NULL, processName, MAX_PATH);
                CloseHandle(procHandle);
                processName[len] = '\0';
                accessorList->Add(gcnew Accessor(gcnew String(processName), handle.GrantedAccess));
            }
            else
                accessorList->Add(gcnew Accessor(gcnew String("unknown"), handle.GrantedAccess));
        }
    }

    CloseHandle(currentProcess);

    delete[] handleInfo;
    return accessorList->ToArray();
}

【讨论】:

  • 您可能希望在调用 NTQuerySystemInformation 之前打开本地进程的句柄 :)
猜你喜欢
  • 1970-01-01
  • 2017-08-07
  • 1970-01-01
  • 1970-01-01
  • 2012-11-15
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多