Механизм листинга устройства Winobj Sysinternal
-
27-09-2019 - |
Вопрос
Sysinternals's Winobj может перечислять все объекты устройства.
Интересно, как он может перечислить устройства.
Есть ли какой-нибудь открытый источник, который мы можем прочитать? (Или фрагмент кода)
Какова самая значительная функция, которую я должен знать?
Решение
Winobj использует системные вызовы NT NtOpenDirectoryObject
а также NtQueryDirectoryObject
. Отказ Там нет ни одного драйвера или кода ядра. Вы не увидите импорт, потому что эти функции NT загружаются через LoadLibrary
/GetProcAddress
.
Вам не нужно перечищать все пространство имен объекта. Если вы заинтересованы в объектах устройства NtOpenDirectoryObject
с участием "\Device"
, Затем позвоните NtQueryDirectoryObject
на возвращенной ручке.
Другие советы
Согласно с Веб-страница Sysinternals:
Нативные API NT предоставляют процедуры, которые позволяют программам режима пользователей просматривать пространство имен и запрашивать состояние объектов, расположенных там, но интерфейсы недокументированы.
Я пытался смотреть на таблицу импорта Winobj (dumpbin /imports winobj.exe
) Но нет очевидных подозреваемых :-(
Вы можете использовать ntopendirectoryObject и ntquerydirectoryObject для enumarate список объектов в данном каталоге.
Чтобы получить детали пространства имен объекта, вы должны использовать Windows NT недокументированные API. Это также используется Winobj, как оно описано здесь Что о том, как Winobj получают все результаты .. и для тех, кто говорит, что нам нужен водитель, чтобы сделать это, пожалуйста, прочитайте эти строки на данной странице.
«Один очевидный способ - использовать драйвер - в режиме ядра все доступно - поэтому клиентское приложение может получить необходимую информацию, сообщаю со своим собственным драйвером. Winobj не использует драйвер, однако (это одна из причин, что она способна выполнить Без привилегий администратора, хотя с привилегиями администратора он показывает все объекты в отличие от частичных результатов).
В соответствии с Ответ от user1575778. вы можете использовать NtOpenDirectoryObject
а также NtQueryDirectoryObject
(который из пользовательского режима идентичен ZwOpenDirectoryObject
а также ZwQueryDirectoryObject
Соответственно) Чтобы перечислить объекты внутри пространства имен менеджера объекта.
Посмотри на objmgr.hpp
из NT объекты aka ntobjx, в частности, в классе NtObjMgr::Directory
(или DirectoryT
). Он обеспечивает ту же функциональность, хорошо завернутая в класс C ++. Вся утилита является открытым исходным кодом под лишевой лицензией (двойное лицензированное из-за WTL-USE: 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.
Вы можете начать с setupdicreatedeviceInFolist и использовать другие связанные функции для перечисления всех устройств. Этот материал болезнен, чтобы использовать.