SysInternals の WinObj は、すべてのデバイス オブジェクトを一覧表示できます。
どのようにデバイスを一覧表示できるのだろうか。
私たちが読めるオープンソースはありますか?(またはコードスニペット)
知っておくべき最も重要な機能は何ですか?
SysInternals の WinObj は、すべてのデバイス オブジェクトを一覧表示できます。
どのようにデバイスを一覧表示できるのだろうか。
私たちが読めるオープンソースはありますか?(またはコードスニペット)
知っておくべき最も重要な機能は何ですか?
WinObj は、NT システム コールNtOpenDirectoryObject
とNtQueryDirectoryObject
. ドライバーやカーネル コードは必要ありません。LoadLibrary
これらの NT 関数は/経由で読み込まれるため、インポートは表示されませんGetProcAddress
。
オブジェクトの名前空間全体を列挙する必要はありません。を使用したデバイス オブジェクトの呼び出しに関心がある場合はNtOpenDirectoryObject
、返されたハンドルで"\Device"
呼び出します。NtQueryDirectoryObject
ネイティブ NT API は、ユーザー モード プログラムが名前空間を参照し、そこにあるオブジェクトの状態を照会できるようにするルーチンを提供しますが、インターフェイスは文書化されていません。
WinObj のインポート テーブル ( dumpbin /imports winobj.exe
) を調べてみましたが、明らかな疑いはありません :-(
user1575778 からの回答に従って、 NtOpenDirectoryObject
and NtQueryDirectoryObject
(ユーザーモードからはZwOpenDirectoryObject
and とそれぞれ同じ) を使用ZwQueryDirectoryObject
して、オブジェクトマネージャーの名前空間内のオブジェクトを一覧表示できます。
NT Objects aka ntobjx、objmgr.hpp
特にクラス(または) を見てください。これは、C++ クラスに適切にラップされた同じ機能を提供します。ユーティリティ全体はリベラル ライセンス (WTL 使用のため MIT と MS-PL の二重ライセンス) の下でオープン ソースであるため、ライセンス条項に準拠していれば、必要に応じてビットとピースを再利用できます。NtObjMgr::Directory
DirectoryT
しかし、ここにあなたのユースケースだけを提供する簡単な C++ コードの例があります:
#include <Windows.h>
#include <tchar.h>
#include <cstdio>
#include <winternl.h>
NTSTATUS (NTAPI* NtOpenDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
NTSTATUS (NTAPI* NtQueryDirectoryObject)(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
VOID (NTAPI* RtlInitUnicodeString_)(PUNICODE_STRING, PCWSTR);
NTSTATUS (NTAPI* NtClose_)(HANDLE);
#define DIRECTORY_QUERY (0x0001)
#define DIRECTORY_TRAVERSE (0x0002)
typedef struct _OBJECT_DIRECTORY_INFORMATION {
UNICODE_STRING Name;
UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
#endif // STATUS_SUCCESS
#ifndef STATUS_MORE_ENTRIES
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
#endif // STATUS_MORE_ENTRIES
#ifndef STATUS_NO_MORE_ENTRIES
#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL)
#endif // STATUS_NO_MORE_ENTRIES
int PrintDevices()
{
NTSTATUS ntStatus;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING objname;
HANDLE hDeviceDir = NULL;
RtlInitUnicodeString_(&objname, L"\\Device");
InitializeObjectAttributes(&oa, &objname, 0, NULL, NULL);
ntStatus = NtOpenDirectoryObject(&hDeviceDir, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, &oa);
if(NT_SUCCESS(ntStatus))
{
size_t const bufSize = 0x10000;
BYTE buf[bufSize] = {0};
ULONG start = 0, idx = 0, bytes;
BOOLEAN restart = TRUE;
for(;;)
{
ntStatus = NtQueryDirectoryObject(hDeviceDir, PBYTE(buf), bufSize, FALSE, restart, &idx, &bytes);
if(NT_SUCCESS(ntStatus))
{
POBJECT_DIRECTORY_INFORMATION const pdilist = reinterpret_cast<POBJECT_DIRECTORY_INFORMATION>(PBYTE(buf));
for(ULONG i = 0; i < idx - start; i++)
{
if(0 == wcsncmp(pdilist[i].TypeName.Buffer, L"Device", pdilist[i].TypeName.Length / sizeof(WCHAR)))
{
_tprintf(_T("%s\n"), pdilist[i].Name.Buffer);
}
}
}
if(STATUS_MORE_ENTRIES == ntStatus)
{
start = idx;
restart = FALSE;
continue;
}
if((STATUS_SUCCESS == ntStatus) || (STATUS_NO_MORE_ENTRIES == ntStatus))
{
break;
}
}
(void)NtClose_(hDeviceDir);
return 0;
}
_tprintf(_T("Failed NtOpenDirectoryObject with 0x%08X"), ntStatus);
return 1;
}
int _tmain(int /*argc*/, _TCHAR** /*argv*/)
{
HMODULE hNtDll = ::GetModuleHandle(_T("ntdll.dll"));
*(FARPROC*)&NtOpenDirectoryObject = ::GetProcAddress(hNtDll, "NtOpenDirectoryObject");
*(FARPROC*)&NtQueryDirectoryObject = ::GetProcAddress(hNtDll, "NtQueryDirectoryObject");
*(FARPROC*)&RtlInitUnicodeString_ = ::GetProcAddress(hNtDll, "RtlInitUnicodeString");
*(FARPROC*)&NtClose_ = ::GetProcAddress(hNtDll, "NtClose");
if (!NtOpenDirectoryObject || !NtQueryDirectoryObject || !RtlInitUnicodeString_ || !NtClose_)
{
_tprintf(_T("Failed to retrieve ntdll.dll function pointers\n"));
return 1;
}
return PrintDevices();
}
いくつかの注意事項:これはサブディレクトリを掘り下げず、以外のタイプを一覧表示せずDevice
、シンボリック リンクが存在する場合でも解決しません。これらの機能については、前述のユーティリティのソース コードを参照し、必要に応じて調整してください。winternl.h
最近の Windows SDK で利用できるはずです。
関数RtlInitUnicodeString_
とNtClose_
には、これらのネイティブ API 関数との衝突を避けるために、末尾にアンダースコアが付いています。これらの関数は で宣言されてwinternl.h
いますが、__declspec(dllimport)
.
開示:私は ntobjx の作成者です。
オブジェクトの名前空間の詳細を取得するには、Windows NT Undocumented API を使用する必要があります。これは、WinOBj がすべての結果を取得する方法がここで説明されているように、WinObj でも使用されます。これを行うにはドライバーが必要だと言っている人は、特定のページのこれらの行を読んでください。
「明らかな方法の 1 つは、ドライバーを使用することです。カーネル モードではすべてにアクセスできます。クライアント アプリは、独自のドライバーと通信することで必要な情報を取得できます。ただし、WinObj はドライバーを使用しません (これが、ドライバーを実行できる理由の 1 つです)。ただし、管理者権限がある場合は、部分的な結果ではなくすべてのオブジェクトが表示されます)。」
NtOpenDirectoryObject と NtQueryDirectoryObject を使用して、特定のディレクトリ内のオブジェクト リストを列挙できます。
SetupDiCreateDeviceInfoList から開始し、他の関連関数を使用してすべてのデバイスを列挙できます。このようなものは使用するのが苦痛です。