CreateEvent
やCreateSemaphore
で作成したカーネルオブジェクトから情報を取得する方法のメモです。
以降で出現するhHandle
は、下記のように作成した前提です。
HANDLE hHandle = CreateEvent(NULL, FALSE, TRUE, L"sample");
なお、ファイルのパスを取得する場合はGetFinalPathNameByHandle
を使えば簡単に取得できます。
下準備
この後使うNtQueryObject
やNtQuerySystemInformation
は、MSDNによるとインポートライブラリがないので、動的にリンクします。
#include <winternl.h>
#include <ntstatus.h>
typedef
__kernel_entry NTSYSCALLAPI
NTSTATUS
(NTAPI
*NtQueryObject_t)(
_In_opt_ HANDLE Handle,
_In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,
_Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,
_In_ ULONG ObjectInformationLength,
_Out_opt_ PULONG ReturnLength
);
typedef
__kernel_entry NTSTATUS
(NTAPI
*NtQuerySystemInformation_t)(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
HMODULE hNtDll = GetModuleHandle(L"ntdll.dll");
NtQueryObject_t fpNtQueryObject = (NtQueryObject_t)GetProcAddress(hNtDll, "NtQueryObject");
NtQuerySystemInformation_t fpNtQuerySystemInformation = (NtQuerySystemInformation_t)GetProcAddress(hNtDll, "NtQuerySystemInformation");
タイプの取得
ここまではドキュメント化されている範囲でできます。
PUBLIC_OBJECT_TYPE_INFORMATION
とObjectTypeInformation
で種類(Event
とか)を取得できます。
ULONG size = 0;
fpNtQueryObject(hHandle, ObjectTypeInformation, NULL, 0, &size);
PPUBLIC_OBJECT_TYPE_INFORMATION buf = malloc(size);
NTSTATUS status = fpNtQueryObject(hHandle, ObjectTypeInformation, buf, size, &size);
if (NT_ERROR(status))
{
free(buf);
return;
}
printf("%ls\n", buf->TypeName.Buffer);
free(buf);
名前の取得
ここからはUndocumentedの範囲です。
インターネットで適当に調べながら試したので、当然ながら正しく取得できる保証はありません。
使用する構造体(OBJECT_NAME_INFORMATION
)とコード(ObjectNameInformation
)は自分で定義します。
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING Name;
WCHAR NameBuffer[0];
} OBJECT_NAME_INFORMATION, * POBJECT_NAME_INFORMATION;
static const OBJECT_INFORMATION_CLASS ObjectNameInformation = (OBJECT_INFORMATION_CLASS)1;
ULONG size = 0;
fpNtQueryObject(hHandle, ObjectNameInformation, NULL, 0, &size);
POBJECT_NAME_INFORMATION buf = malloc(size);
NTSTATUS status = fpNtQueryObject(hHandle, ObjectNameInformation, buf, size, &size);
if (NT_ERROR(status))
{
free(buf);
return;
}
printf("%ls\n", buf->Name.Buffer);
free(buf);
\Sessions\2\BaseNamedObjects\sample
のような文字列が取得できます。
Object Address
Process ExplorerでObject Address
として表示される値です。
当然ながら正しく取得できる保証はありません。
調べた限り、ハンドルから直接取得する方法は無く、SystemHandleInformation
で一旦システムのすべてのハンドルの情報を取得して、その中から検索するしかなさそうです。
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
USHORT UniqueProcessId;
USHORT CreatorBackTraceIndex;
UCHAR ObjectTypeIndex;
UCHAR HandleAttributes;
USHORT HandleValue;
PVOID Object;
ULONG GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG NumberOfHandles;
SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
static const SYSTEM_INFORMATION_CLASS SystemHandleInformation = 16;
DWORD dwPID = GetCurrentProcessId();
ULONG size = sizeof(SYSTEM_HANDLE_INFORMATION);
PSYSTEM_HANDLE_INFORMATION buf = NULL;
NTSTATUS status = STATUS_INFO_LENGTH_MISMATCH;
do
{
size += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO) * 0x10000;
void *newPtr = realloc(buf, size);
if (NULL == newPtr)
break;
buf = newPtr;
ULONG returnLength = 0;
status = fpNtQuerySystemInformation(SystemHandleInformation, buf, size, &returnLength);
} while (status == STATUS_INFO_LENGTH_MISMATCH);
if (NT_ERROR(status))
{
free(buf);
return;
}
for (ULONG i = 0; i < buf->NumberOfHandles;++i)
{
if (buf->Handles[i].UniqueProcessId == dwPID && buf->Handles[i].HandleValue == (UINT_PTR)hHandle)
{
printf("%p\n", buf->Handles[i].Object);
}
}
free(buf);
Object Address(新しいAPIを使用)
前述の方法は古いみたいで、新しいAPIがあるみたいです。
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
{
PVOID Object;
ULONG_PTR UniqueProcessId;
ULONG_PTR HandleValue;
ULONG GrantedAccess;
USHORT CreatorBackTraceIndex;
USHORT ObjectTypeIndex;
ULONG HandleAttributes;
ULONG Reserved;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
ULONG_PTR NumberOfHandles;
ULONG_PTR Reserved;
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX;
static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = 0x40;
DWORD dwPID = GetCurrentProcessId();
ULONG size = sizeof(SYSTEM_HANDLE_INFORMATION_EX);
PSYSTEM_HANDLE_INFORMATION_EX buf = NULL;
NTSTATUS status = STATUS_INFO_LENGTH_MISMATCH;
do
{
size += sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX) * 0x10000;
void* newPtr = realloc(buf, size);
if (NULL == newPtr)
break;
buf = newPtr;
ULONG returnLength = 0;
status = fpNtQuerySystemInformation(SystemExtendedHandleInformation, buf, size, &returnLength);
} while (status == STATUS_INFO_LENGTH_MISMATCH);
if (NT_ERROR(status))
{
free(buf);
return -1;
}
for (ULONG i = 0; i < buf->NumberOfHandles; ++i)
{
if (buf->Handles[i].UniqueProcessId == dwPID && buf->Handles[i].HandleValue == hHandle)
{
printf("%p\n", buf->Handles[i].Object);
}
}
free(buf);