SysInternal的WinObj设备列表机制

发布于 2024-08-28 23:01:40 字数 114 浏览 7 评论 0原文

SysInternals的WinObj可以列出所有设备对象。

我想知道它如何列出设备。

有没有我们可以阅读的开源代码?(或代码片段)

我应该知道的最重要的功能是什么?

SysInternals's WinObj can list all device objects.

I wonder how it can list the devices.

Is there any open source we can read?(or a code snippet)

What is the most significant function I should know?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

昨迟人 2024-09-04 23:01:40

WinObj 使用 NT 系统调用 NtOpenDirectoryObjectNtQueryDirectoryObject。不需要驱动程序或内核代码。您不会看到导入,因为这些 NT 函数是通过 LoadLibrary/GetProcAddress 加载的。

您不必枚举整个对象名称空间。如果您对设备对象感兴趣,请使用 "\Device" 调用 NtOpenDirectoryObject,然后在返回的句柄上调用 NtQueryDirectoryObject

WinObj uses the NT system calls NtOpenDirectoryObject and NtQueryDirectoryObject. There is no driver or kernel code needed. You won't see the imports because these NT functions are loaded via LoadLibrary/GetProcAddress.

You don't have to enumerate the entire object namespace. If you're interested in the device objects call NtOpenDirectoryObject with "\Device", then call NtQueryDirectoryObject on the returned handle.

谜兔 2024-09-04 23:01:40

根据 user1575778 的回答,您可以使用 NtOpenDirectoryObjectNtQueryDirectoryObject (从用户模式分别与 ZwOpenDirectoryObjectZwQueryDirectoryObject 相同)列出对象管理器命名空间内的对象。

查看 NT 对象又名 ntobjxobjmgr.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 之外的任何类型,并且它不会解析符号链接(如果有)。对于任何这些功能,请查看上述实用程序的源代码并根据需要进行调整。 winternl.h 应该在任何最新的 Windows SDK 中可用。

函数 RtlInitUnicodeString_NtClose_ 后面有一个下划线,以避免与这些本机 API 函数发生冲突,这些函数在 winternl.h 中声明,但使用 <代码>__declspec(dllimport)。

披露:我是 ntobjx 的作者。

As per the answer from user1575778 you can use NtOpenDirectoryObject and NtQueryDirectoryObject (which from user mode are identical to ZwOpenDirectoryObject and ZwQueryDirectoryObject respectively) to list the objects inside the object manager namespace.

Have a look at objmgr.hpp of NT Objects aka ntobjx, in particular at the class NtObjMgr::Directory (or DirectoryT). It provides the same functionality nicely wrapped into a C++ class. The whole utility is open source under a liberal license (dual-licensed due to WTL-use: MIT and MS-PL), so bits and pieces can be reused however you please, provided you comply with the license terms.

But here's a simple C++ code example catering just your use case:

#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();
}

Some remarks: This will not delve into subdirectories, it will not list any types other than Device and it will not resolve symbolic links, if any. For any of those features, please look at the aforementioned utility's source code and adjust as needed. winternl.h should be available in any recent Windows SDK.

The functions RtlInitUnicodeString_ and NtClose_ have a trailing underscore to avoid clashes with these native API functions, which are declared in winternl.h, but use __declspec(dllimport).

Disclosure: I am the author of ntobjx.

你怎么这么可爱啊 2024-09-04 23:01:40

根据 SysInternals 网页

本机 NT API 提供例程
允许用户模式程序
浏览命名空间并查询
位于那里的物体的状态,但是
接口未记录。

我尝试查看 WinObj 的导入表 (dumpbin /imports winobj.exe),但没有明显的嫌疑:-(

According to SysInternals' web page:

The native NT API provides routines
that allow user-mode programs to
browse the namespace and query the
status of objects located there, but
the interfaces are undocumented.

I've tried looking at WinObj's import table (dumpbin /imports winobj.exe) but there are no obvious suspects :-(

听闻余生 2024-09-04 23:01:40

您可以使用 NtOpenDirectoryObject 和 NtQueryDirectoryObject 枚举给定目录中的对象列表。

You can use NtOpenDirectoryObject and NtQueryDirectoryObject to enumarate the objects list in a given directory.

呢古 2024-09-04 23:01:40

要获取对象命名空间的详细信息,必须使用 Windows NT 未记录的 API。正如它所描述的那样,WinObj 也使用它 此处说明了 WinOBj 如何获取所有结果。对于那些说我们需要驱动程序来执行此操作的人,请阅读给定页面上的这些行。

“一种明显的方法是使用驱动程序 - 在内核模式下,一切都可以访问 - 因此客户端应用程序可以通过与其自己的驱动程序通信来获取所需的信息。然而,WinObj 不使用驱动程序(这是它的原因之一)能够在没有管理员权限的情况下执行,尽管具有管理员权限它会显示所有对象而不是部分结果)。”

To get the details of the object namespace, you must use the Windows NT Undocumented API. That is also used by the WinObj as it is described here that how WinOBj getting the all results..and for those who are saying that we need a driver to do this please, read these lines on given page.

"One obvious way is to use a driver – in kernel mode everything is accessible – so the client app can get the required information by communicating with its own driver. WinObj does not use a driver, however (this is one reason it’s able to execute without admin privileges, although with admin privileges it shows all objects as opposed to partial results)."

仲春光 2024-09-04 23:01:40

您可以从SetupDiCreateDeviceInfoList开始并使用其他相关函数来枚举所有设备。这东西用起来很痛苦。

You can start with SetupDiCreateDeviceInfoList and use other related functions to enumerate all the devices. This stuff is painful to use.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文