Механизм вывода списка устройств WinSbj от SysInternal - PullRequest
1 голос
/ 15 апреля 2010

WinSbj SysInternals может перечислить все объекты устройства.

Интересно, как можно перечислить устройства.

Есть ли открытый код, который мы можем прочитать? (Или фрагмент кода)

Какую наиболее важную функцию я должен знать?

Ответы [ 6 ]

6 голосов
/ 04 августа 2012

WinObj использует системные вызовы NT NtOpenDirectoryObject и NtQueryDirectoryObject. Не требуется драйвер или код ядра. Вы не увидите импорт, потому что эти функции NT загружаются через LoadLibrary / GetProcAddress.

Вам не нужно перечислять все пространство имен объекта. Если вас интересуют объекты устройства, вызовите NtOpenDirectoryObject с "\Device", затем вызовите NtQueryDirectoryObject в возвращенном дескрипторе.

1 голос
/ 01 марта 2011

По данным веб-страницы SysInternals :

Собственный NT API предоставляет подпрограммы которые позволяют программам пользовательского режима просмотреть пространство имен и запросить статус объектов, расположенных там, но интерфейсы недокументированы.

Я пытался просмотреть таблицу импорта WinObj (dumpbin /imports winobj.exe), но очевидных подозреваемых нет: - (

0 голосов
/ 08 июня 2017

Согласно ответу от пользователя 1575778 , вы можете использовать NtOpenDirectoryObject и NtQueryDirectoryObject (которые в пользовательском режиме идентичны ZwOpenDirectoryObject и ZwQueryDirectoryObject соответственно) для перечисления объектов внутри диспетчера объектов Пространство имен.

Взгляните на objmgr.hpp из NT Objects aka ntobjx , в частности, на класс 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.

0 голосов
/ 26 сентября 2014

Чтобы получить подробную информацию о пространстве имен объекта, необходимо использовать недокументированный API-интерфейс Windows NT. Это также используется WinObj, как описано здесь , как WinOBj получает все результаты ... и для тех, кто говорит, что для этого нужен драйвер, пожалуйста, прочитайте эти строки на данной странице.

"Один очевидный способ - использовать драйвер - в режиме ядра все доступно - так что клиентское приложение может получать необходимую информацию, связываясь со своим собственным драйвером. Однако WinObj не использует драйвер (это одна из причин того, что может выполняться без прав администратора, хотя с правами администратора показывает все объекты, а не частичные результаты). "

0 голосов
/ 23 июля 2012

Вы можете использовать NtOpenDirectoryObject и NtQueryDirectoryObject, чтобы перечислить список объектов в данном каталоге.

0 голосов
/ 15 апреля 2010

Вы можете начать с SetupDiCreateDeviceInfoList и использовать другие связанные функции для перечисления всех устройств. Этот материал является болезненным для использования.

...