LoginSignup
3
3

More than 3 years have passed since last update.

カーネルオブジェクトのハンドルから情報を取得する

Last updated at Posted at 2020-02-06

CreateEventCreateSemaphoreで作成したカーネルオブジェクトから情報を取得する方法のメモです。

以降で出現するhHandleは、下記のように作成した前提です。


HANDLE hHandle = CreateEvent(NULL, FALSE, TRUE, L"sample");

なお、ファイルのパスを取得する場合はGetFinalPathNameByHandleを使えば簡単に取得できます。

下準備

この後使うNtQueryObjectNtQuerySystemInformationは、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_INFORMATIONObjectTypeInformationで種類(Eventとか)を取得できます。

GetTypeInfoFromHandle.c
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;
GetNameInfoFromHandle.c
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;
GetObjectAddressFromHandle.c
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;
GetObjectAddressFromHandleEx.c
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);
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3