我正在尝试了解手柄的工作原理。我找到了解释如何在另一个进程中关闭句柄的文章,作者是 Pavel Yosifovich。他给代码解释了它是如何工作的,但我遇到的问题很少。
第一个:
enum PROCESSINFOCLASS {
ProcessHandleInformation = 51
};
这部分给我一个错误:
Error C2371 "PROCESSINFOCLASS": change in definition; different basic types
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