SysInternals的WinObj可以列出所有设备对象。
我想知道如何列出设备。
我们可以阅读任何开源吗?(或代码片段)
我应该知道的最重要的功能是什么?
答案 0 :(得分:6)
WinObj使用NT系统调用NtOpenDirectoryObject
和NtQueryDirectoryObject
。不需要驱动程序或内核代码。您不会看到导入,因为这些NT函数是通过LoadLibrary
/ GetProcAddress
加载的。
您不必枚举整个对象命名空间。如果您对设备对象感兴趣,请使用NtOpenDirectoryObject
致电"\Device"
,然后在返回的句柄上调用NtQueryDirectoryObject
。
答案 1 :(得分:1)
本机NT API提供例程 允许用户模式程序 浏览命名空间并查询 位于那里的对象的状态,但是 接口没有文档。
我试过看WinObj的导入表(dumpbin /imports winobj.exe
),但没有明显的嫌疑人: - (
答案 2 :(得分:0)
您可以使用NtOpenDirectoryObject和NtQueryDirectoryObject来控制给定目录中的对象列表。
答案 3 :(得分:0)
要获取对象命名空间的详细信息,必须使用Windows NT未记录的API。 WinObj也使用了它,因为它描述了here WinOBj如何获得所有结果......对于那些说我们需要驱动程序来执行此操作的人,请在给定页面上阅读这些行。
“一个明显的方法是使用驱动程序 - 在内核模式下一切都是可访问的 - 所以客户端应用程序可以通过与自己的驱动程序通信来获取所需的信息。但WinObj不使用驱动程序(这是它的一个原因)能够在没有管理员权限的情况下执行,尽管使用管理员权限它会显示所有对象而不是部分结果。“
答案 4 :(得分:0)
根据answer from user1575778,您可以使用NtOpenDirectoryObject
和NtQueryDirectoryObject
(来自用户模式,分别与ZwOpenDirectoryObject
和ZwQueryDirectoryObject
相同)列出对象在对象管理器命名空间内。
查看NT Objects aka ntobjx的objmgr.hpp
,尤其是班级NtObjMgr::Directory
(或DirectoryT
)。它提供了很好地包装到C ++类中的相同功能。整个实用程序在自由许可下是开源的(由于WTL使用而获得双重许可:MIT和MS-PL),因此只要您遵守许可条款,就可以重复使用零碎件。
但这是一个简单的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
以外的任何类型,它将会不解决符号链接,如果有的话。对于任何这些功能,请查看上述实用程序的源代码并根据需要进行调整。任何最新的Windows SDK都应该提供winternl.h
。
函数RtlInitUnicodeString_
和NtClose_
有一个尾随下划线,以避免与这些本机API函数冲突,这些函数在winternl.h
中声明,但使用__declspec(dllimport)
。
披露:我是ntobjx的作者。
答案 5 :(得分:-1)
您可以从SetupDiCreateDeviceInfoList开始,并使用其他相关函数枚举所有设备。这个东西很难用。