在特定过程中关闭句柄的程序

问题描述 投票:0回答:0

我正在尝试了解手柄的工作原理。我找到了解释如何在另一个进程中关闭句柄的文章,作者是 Pavel Yosifovich。他给代码解释了它是如何工作的,但我遇到的问题很少。

第一个:

enum PROCESSINFOCLASS {
    ProcessHandleInformation = 51
};

这部分给我一个错误:

  1. Error C2371 "PROCESSINFOCLASS": change in definition; different basic types 
  2. Error C2065 "ProcessHandleInformation": undeclared identifier

所以我决定改成:

const PROCESSINFOCLASS ProcessHandleInformation = static_cast<PROCESSINFOCLASS>(51);

现在工作正常,但为什么原始代码返回错误?

第二题:

auto status = ::NtQueryObject(hTarget, ObjectNameInformation, nameBuffer, sizeof(nameBuffer), nullptr);

我有错误:

Error C2065 "ObjectNameInformation": undeclared identifier
我通过添加解决了这个问题:

const OBJECT_INFORMATION_CLASS ObjectNameInformation = static_cast<OBJECT_INFORMATION_CLASS>(1);

编译此代码的问题到此结束。但不是所有问题的结束:)所以这里是源代码:

#include <windows.h>
#include <TlHelp32.h>
#include <memory>
#include <winternl.h>

#pragma comment(lib, "ntdll")

#define NT_SUCCESS(status) (status >= 0)
#define STATUS_INFO_LENGTH_MISMATCH      ((NTSTATUS)0xC0000004L)

typedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO {
    HANDLE HandleValue;
    ULONG_PTR HandleCount;
    ULONG_PTR PointerCount;
    ULONG GrantedAccess;
    ULONG ObjectTypeIndex;
    ULONG HandleAttributes;
    ULONG Reserved;
} PROCESS_HANDLE_TABLE_ENTRY_INFO, * PPROCESS_HANDLE_TABLE_ENTRY_INFO;

// private
typedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION {
    ULONG_PTR NumberOfHandles;
    ULONG_PTR Reserved;
    PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1];
} PROCESS_HANDLE_SNAPSHOT_INFORMATION, * PPROCESS_HANDLE_SNAPSHOT_INFORMATION;

extern "C" NTSTATUS NTAPI NtQueryInformationProcess(
    _In_ HANDLE ProcessHandle,
    _In_ PROCESSINFOCLASS ProcessInformationClass,
    _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
    _In_ ULONG ProcessInformationLength,
    _Out_opt_ PULONG ReturnLength);

DWORD FindMediaPlayer(){
    HANDLE hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE)
        return 0;

    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(pe);

    // skip the idle process
    ::Process32First(hSnapshot, &pe);

    DWORD pid = 0;
    while (::Process32Next(hSnapshot, &pe)) {
        if (::_wcsicmp(pe.szExeFile, L"wmplayer.exe") == 0) {
            // found it!
            pid = pe.th32ProcessID;
            break;
        }
    }
    ::CloseHandle(hSnapshot);
    return pid;
}

int main() {
    const PROCESSINFOCLASS ProcessHandleInformation = static_cast<PROCESSINFOCLASS>(51); 
    const OBJECT_INFORMATION_CLASS ObjectNameInformation = static_cast<OBJECT_INFORMATION_CLASS>(1);

    DWORD pid = FindMediaPlayer();
    if (pid == 0) {
        printf("Failed to locate media player\n");
        return 1;
    }
    printf("Located media player: PID=%u\n", pid);

    HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE,
        FALSE, pid);
    if (!hProcess) {
        printf("Failed to open WMP process handle (error=%u)\n",
            ::GetLastError());
        return 1;
    }

    ULONG size = 1 << 10;
    std::unique_ptr<BYTE[]> buffer;
    for (;;) {
        buffer = std::make_unique<BYTE[]>(size);
        auto status = ::NtQueryInformationProcess(hProcess, ProcessHandleInformation,
            buffer.get(), size, &size);
        if (NT_SUCCESS(status))
            break;
        if (status == STATUS_INFO_LENGTH_MISMATCH) {
            size += 1 << 10;
            continue;
        }
        printf("Error enumerating handles\n");
        return 1;
    }

    auto info = reinterpret_cast<PROCESS_HANDLE_SNAPSHOT_INFORMATION*>(buffer.get());
    for (ULONG i = 0; i < info->NumberOfHandles; i++) {
        HANDLE h = info->Handles[i].HandleValue;
        HANDLE hTarget;
        if (!::DuplicateHandle(hProcess, h, ::GetCurrentProcess(), &hTarget,
            0, FALSE, DUPLICATE_SAME_ACCESS))
            continue;   // move to next handle
        BYTE nameBuffer[1 << 10];
        auto status = ::NtQueryObject(hTarget, ObjectNameInformation,
            nameBuffer, sizeof(nameBuffer), nullptr);
        ::CloseHandle(hTarget);
        if (!NT_SUCCESS(status))
            continue;
        WCHAR targetName[256];
        DWORD sessionId;
        ::ProcessIdToSessionId(pid, &sessionId);
        ::swprintf_s(targetName,
            L"\\Sessions\\%u\\BaseNamedObjects\\Microsoft_WMP_70_CheckForOtherInstanceMutex",
            sessionId);
        auto len = ::wcslen(targetName);
        auto name = reinterpret_cast<UNICODE_STRING*>(nameBuffer);
        if (name->Buffer &&
            ::_wcsnicmp(name->Buffer, targetName, len) == 0) {
            // found it!
        }
        // found it!
        ::DuplicateHandle(hProcess, h, ::GetCurrentProcess(), &hTarget,
            0, FALSE, DUPLICATE_CLOSE_SOURCE);
        ::CloseHandle(hTarget);
        printf("Found it! and closed it!\n");
        return 0;
    }
return 0;
}

这个程序不起作用,我的意思是它应该在这个例子中关闭句柄

\\Sessions\\%u\\BaseNamedObjects\\Microsoft_WMP_70_CheckForOtherInstanceMutex
。程序写
Found it! and closed it!
但我用 Process Explorer 检查了这个并且这个句柄仍然存在。当然,我以管理员权限启动这个程序。有人可以解释我为什么这不起作用吗?或者给我一些资源,我可以从中了解更多信息?

我也加了

#include <winternl.h>
但为什么文章的作者没有提到这是必要的? 我正在使用 visual studio 2022

c++ winapi handle
© www.soinside.com 2019 - 2024. All rights reserved.