mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-12-14 03:37:10 +08:00
198 lines
5.7 KiB
C++
198 lines
5.7 KiB
C++
#include "pch.h"
|
|
|
|
#include "NtdllExtensions.h"
|
|
|
|
#define STATUS_INFO_LENGTH_MISMATCH ((LONG)0xC0000004)
|
|
|
|
// Calls NtQuerySystemInformation and returns a buffer containing the result.
|
|
|
|
NtdllExtensions::MemoryLoopResult NtdllExtensions::NtQuerySystemInformationMemoryLoop(ULONG SystemInformationClass)
|
|
{
|
|
MemoryLoopResult result;
|
|
result.memory.resize(DefaultResultBufferSize);
|
|
|
|
while (result.memory.size() <= MaxResultBufferSize)
|
|
{
|
|
ULONG result_len;
|
|
result.status = NtQuerySystemInformation(SystemInformationClass, result.memory.data(), (ULONG)result.memory.size(), &result_len);
|
|
|
|
if (result.status == STATUS_INFO_LENGTH_MISMATCH)
|
|
{
|
|
result.memory.resize(result.memory.size() * 2);
|
|
continue;
|
|
}
|
|
|
|
if (NT_ERROR(result.status))
|
|
{
|
|
result.memory.clear();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
result.status = STATUS_INFO_LENGTH_MISMATCH;
|
|
result.memory.clear();
|
|
return result;
|
|
}
|
|
|
|
std::wstring NtdllExtensions::file_handle_to_kernel_name(HANDLE file_handle, std::vector<BYTE>& buffer)
|
|
{
|
|
if (GetFileType(file_handle) != FILE_TYPE_DISK)
|
|
{
|
|
return L"";
|
|
}
|
|
|
|
ULONG return_length;
|
|
auto status = NtQueryObject(file_handle, ObjectNameInformation, buffer.data(), (ULONG)buffer.size(), &return_length);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
auto object_name_info = (UNICODE_STRING*)buffer.data();
|
|
return unicode_to_str(*object_name_info);
|
|
}
|
|
|
|
return L"";
|
|
}
|
|
|
|
std::wstring NtdllExtensions::file_handle_to_kernel_name(HANDLE file_handle)
|
|
{
|
|
std::vector<BYTE> buffer(DefaultResultBufferSize);
|
|
return file_handle_to_kernel_name(file_handle, buffer);
|
|
}
|
|
|
|
std::wstring NtdllExtensions::path_to_kernel_name(LPCWSTR path)
|
|
{
|
|
HANDLE file_handle = CreateFileW(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
if (file_handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
auto kernel_name = file_handle_to_kernel_name(file_handle);
|
|
CloseHandle(file_handle);
|
|
return kernel_name;
|
|
}
|
|
|
|
std::wstring_view NtdllExtensions::unicode_to_view(UNICODE_STRING unicode_str)
|
|
{
|
|
return std::wstring_view(unicode_str.Buffer, unicode_str.Length / sizeof(WCHAR));
|
|
}
|
|
|
|
std::wstring NtdllExtensions::unicode_to_str(UNICODE_STRING unicode_str)
|
|
{
|
|
return std::wstring(unicode_str.Buffer, unicode_str.Length / sizeof(WCHAR));
|
|
}
|
|
|
|
std::vector<NtdllExtensions::HandleInfo> NtdllExtensions::handles() noexcept
|
|
{
|
|
auto get_info_result = NtQuerySystemInformationMemoryLoop(SystemHandleInformation);
|
|
if (NT_ERROR(get_info_result.status))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
auto info_ptr = (SYSTEM_HANDLE_INFORMATION*)get_info_result.memory.data();
|
|
|
|
std::map<DWORD, HANDLE> pid_to_handle;
|
|
std::vector<HandleInfo> result;
|
|
|
|
std::vector<BYTE> object_info_buffer(DefaultResultBufferSize);
|
|
|
|
for (ULONG i = 0; i < info_ptr->HandleCount; i++)
|
|
{
|
|
auto handle_info = info_ptr->Handles + i;
|
|
DWORD pid = handle_info->ProcessId;
|
|
|
|
HANDLE process_handle = NULL;
|
|
auto iter = pid_to_handle.find(pid);
|
|
if (iter != pid_to_handle.end())
|
|
{
|
|
process_handle = iter->second;
|
|
}
|
|
else
|
|
{
|
|
process_handle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
|
|
if (!process_handle)
|
|
{
|
|
continue;
|
|
}
|
|
pid_to_handle[pid] = process_handle;
|
|
}
|
|
|
|
// According to this:
|
|
// https://stackoverflow.com/questions/46384048/enumerate-handles
|
|
// NtQueryObject could hang
|
|
|
|
// TODO uncomment and investigate
|
|
// if (handle_info->GrantedAccess == 0x0012019f) {
|
|
// continue;
|
|
// }
|
|
|
|
HANDLE handle_copy;
|
|
|
|
auto dh_result = DuplicateHandle(process_handle, (HANDLE)handle_info->Handle, GetCurrentProcess(), &handle_copy, 0, 0, DUPLICATE_SAME_ACCESS);
|
|
if (dh_result == 0)
|
|
{
|
|
// Ignore this handle.
|
|
continue;
|
|
}
|
|
|
|
ULONG return_length;
|
|
auto status = NtQueryObject(handle_copy, ObjectTypeInformation, object_info_buffer.data(), (ULONG)object_info_buffer.size(), &return_length);
|
|
if (NT_ERROR(status))
|
|
{
|
|
// Ignore this handle.
|
|
CloseHandle(handle_copy);
|
|
continue;
|
|
}
|
|
|
|
auto object_type_info = (OBJECT_TYPE_INFORMATION*)object_info_buffer.data();
|
|
auto type_name = unicode_to_str(object_type_info->Name);
|
|
|
|
std::wstring file_name = file_handle_to_kernel_name(handle_copy, object_info_buffer);
|
|
|
|
if (type_name == L"File")
|
|
{
|
|
file_name = file_handle_to_kernel_name(handle_copy, object_info_buffer);
|
|
}
|
|
|
|
result.push_back(HandleInfo{ pid, handle_info->Handle, type_name, file_name });
|
|
CloseHandle(handle_copy);
|
|
}
|
|
|
|
for (auto [pid, handle] : pid_to_handle)
|
|
{
|
|
CloseHandle(handle);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Returns the list of all processes.
|
|
// On failure, returns an empty vector.
|
|
|
|
std::vector<NtdllExtensions::ProcessInfo> NtdllExtensions::processes() noexcept
|
|
{
|
|
auto get_info_result = NtQuerySystemInformationMemoryLoop(SystemProcessInformation);
|
|
|
|
if (NT_ERROR(get_info_result.status))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
std::vector<ProcessInfo> result;
|
|
auto info_ptr = (PSYSTEM_PROCESS_INFORMATION)get_info_result.memory.data();
|
|
|
|
while (info_ptr->NextEntryOffset)
|
|
{
|
|
info_ptr = decltype(info_ptr)((LPBYTE)info_ptr + info_ptr->NextEntryOffset);
|
|
|
|
ProcessInfo item;
|
|
item.name = unicode_to_str(info_ptr->ImageName);
|
|
item.pid = (DWORD)(uintptr_t)info_ptr->UniqueProcessId;
|
|
|
|
result.push_back(item);
|
|
}
|
|
|
|
return result;
|
|
}
|