对于我正在开发的文件浏览器,我需要在 Windows 系统上生成打开文件的列表。
我已经开始使用成功生成进程 ID 列表的代码。有没有办法把它变成列出每个进程打开的所有文件的方法?
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <psapi.h>
using namespace std;
void PrintProcessNameAndID(DWORD processID) {
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
// Get a handle to the process.
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, processID);
// Get the process name.
if (NULL != hProcess) {
HMODULE hMod;
DWORD cbNeeded;
if (EnumProcessModules(hProcess, &hMod, sizeof (hMod),
&cbNeeded)) {
GetModuleBaseName(hProcess, hMod, szProcessName,
sizeof (szProcessName) / sizeof (TCHAR));
}
}
// Print the process name and identifier.
_tprintf(TEXT("%s (PID: %u)\n"), szProcessName, processID);
// Release the handle to the process.
CloseHandle(hProcess);
}
int startup(void) {
// Get the list of process identifiers.
DWORD aProcesses[1024], cbNeeded, cProcesses;
unsigned int i;
if (!EnumProcesses(aProcesses, sizeof (aProcesses), &cbNeeded)) {
return 1;
}
// Calculate how many process identifiers were returned.
cProcesses = cbNeeded / sizeof (DWORD);
// Print the name and process identifier for each process.
for (i = 0; i < cProcesses; i++) {
if (aProcesses[i] != 0) {
PrintProcessNameAndID(aProcesses[i]);
}
}
return 0;
}
int main(int argc, char** argv) {
startup();
return 0;
}
执行此操作的典型方法是使用 NtQueryInformationProcess 的“未记录”功能来枚举句柄。请注意,这将返回相对于设备的文件路径 - 您需要使用 GetVolumePathName 然后将其与驱动器号相关联。
#include <windows.h>
#include <memory>
#include <string>
#define NT_SUCCESS(status) (status >= 0)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
enum PROCESSINFOCLASS {
ProcessHandleInformation = 51
};
struct PROCESS_HANDLE_TABLE_ENTRY_INFO {
HANDLE HandleValue;
ULONG_PTR HandleCount;
ULONG_PTR PointerCount;
ULONG GrantedAccess;
ULONG ObjectTypeIndex;
ULONG HandleAttributes;
ULONG Reserved;
};
// private
struct PROCESS_HANDLE_SNAPSHOT_INFORMATION {
ULONG_PTR NumberOfHandles;
ULONG_PTR Reserved;
PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1];
};
typedef NTSTATUS(NTAPI* t_NtQueryInformationProcess)(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength);
t_NtQueryInformationProcess NtQueryInformationProcess()
{
static t_NtQueryInformationProcess f_NtQueryInformationProcess = NULL;
if (!f_NtQueryInformationProcess)
{
HMODULE h_NtDll = GetModuleHandle("Ntdll.dll"); // Ntdll is loaded into EVERY process!
f_NtQueryInformationProcess = (t_NtQueryInformationProcess)GetProcAddress(h_NtDll, "NtQueryInformationProcess");
}
return f_NtQueryInformationProcess;
}
struct ThreadData {
HANDLE hDup;
std::wstring name;
};
enum OBJECT_INFORMATION_CLASS
{
ObjectBasicInformation,
ObjectNameInformation,
ObjectTypeInformation,
ObjectAllInformation,
ObjectDataInformation
};
struct UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
};
struct OBJECT_NAME_INFORMATION
{
UNICODE_STRING Name; // defined in winternl.h
WCHAR NameBuffer;
};
struct OBJECT_TYPE_INFORMATION {
UNICODE_STRING TypeName;
ULONG TotalNumberOfObjects;
ULONG TotalNumberOfHandles;
};
typedef NTSTATUS(NTAPI* t_NtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS Info, PVOID Buffer, ULONG BufferSize, PULONG ReturnLength);
t_NtQueryObject NtQueryObject();
std::wstring GetFileHandleNameInformation_GetMappedFileName(HANDLE fileHandle);
/// <summary>
/// Loads/retrieves the NtQueryObject function from NtDll
/// </summary>
/// <returns>The functor for the NtQueryObject function</returns>
t_NtQueryObject NtQueryObject()
{
static t_NtQueryObject f_NtQueryObject = NULL;
if (!f_NtQueryObject)
{
HMODULE h_NtDll = GetModuleHandle("Ntdll.dll"); // Ntdll is loaded into EVERY process!
f_NtQueryObject = (t_NtQueryObject)GetProcAddress(h_NtDll, "NtQueryObject");
}
return f_NtQueryObject;
}
/// <summary>
/// Calls NtQueryObject to get the filename for the file handle
/// Remark: NtQueryObject uses Device name for the drives
/// </summary>
/// <param name="fileHandle">The file handle</param>
/// <returns>The filename.</returns>
std::wstring GetFileHandleNameInformation_NtQueryObject(HANDLE fileHandle)
{
ULONG szNeeded;
auto status = ::NtQueryObject()(fileHandle, ObjectNameInformation, NULL, 0, &szNeeded);
//Get handle name information
std::unique_ptr<BYTE[]> nameBuffer = std::make_unique<BYTE[]>(szNeeded);
OBJECT_NAME_INFORMATION* nameInfo = (OBJECT_NAME_INFORMATION*)nameBuffer.get();
status = NtQueryObject()(fileHandle, ObjectNameInformation, nameInfo, szNeeded, &szNeeded);
return std::wstring{ nameInfo->Name.Buffer, nameInfo->Name.Length / sizeof(WCHAR) };
}
std::vector<std::wstring> ProcessFileHandles(HANDLE hProcess)
{
//Get the concatenated list of handles for the process. This gets the buffer length first, then gets the actual buffer of information
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 {};
}
bool result = false;
//Look through the handles to find our target file path
std::vector<std::wstring> filePaths;
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
}
//Get size of buffer
ULONG szNeeded;
auto status = NtQueryObject()(hTarget, ObjectTypeInformation, NULL, 0, &szNeeded);
//Get handle type information
std::unique_ptr<BYTE[]> typeBuffer = std::make_unique<BYTE[]>(szNeeded);
OBJECT_TYPE_INFORMATION* typeInfo = (OBJECT_TYPE_INFORMATION*)typeBuffer.get();
status = NtQueryObject()(hTarget, ObjectTypeInformation, typeInfo, szNeeded, &szNeeded);
if (!NT_SUCCESS(status) || typeInfo == nullptr)
{
continue;
}
if (::_wcsnicmp(typeInfo->TypeName.Buffer, L"File", 4) == 0)
{
std::wstring handlePath = GetFileHandleNameInformation_NtQueryObject(hTarget);
filePaths.push_back(handlePath);
}
CloseHandle(hTarget);
}
return filePaths;
}