PDA

Просмотр полной версии : USB flash: программирование универсального интерфейса


Marylin
20.04.2021, 15:16
..предыдущая часть (https://forum.antichat.xyz/threads/577263/)– теория (рекомендуется к прочтению).

Немного растолковав спецификацию USB на свой лад, перейдём к практике.

Для непросвещённых, программирование универсального интерфейса USB сулит много проблем и большинство энтузиастов бросают это дело ещё на взлёте. Инженеры Microsoft посчитали, что здесь не место проповедовать гуманность, и возложили всю рутину на плечи самих программистов. Так-что приготовьтесь к длительной осаде бастиона. Именно поэтому я уделил всю предыдущую часть на теоретическую муть, приняв которую можно будет чувствовать себя в этом направлении, немного уверенней.

В этой части:

1. Функции менеджера настройки: SetupDi**(), CM_Get**() ;
2. DeviceIoControl() – формат пакета Setup ;
3. Практика – сбор информации об USB-Flash накопителях, безопасное извлечение устройств ;
4. Назначение и состав библиотеки WinUsb.dll ;
5. Сниффинг пакетов USB ;
6. Заключение.
------------------------------------------

1. Системная поддержка

Поскольку прямого доступа к портам устройств в защищённом режиме у нас нет, все запросы придётся отправлять драйверу, посредством специально предназначенной для этих целей функцией DeviceIoControl(). Если с точки зрения подсистемы безопасности мы не замышляем ничего мутного, драйвер выполнит наш запрос, иначе облом. В большинстве случаях, чтению системных структур никто не препятствует, а вот на запись – юзеру могут наложить запрет.

Основным источником различного рода информации является системный реестр, куда диспетчер Plug-and-Play сохраняет свойства всех сконфигурированных девайсов для следующей загрузки ОС. Основная ветка находится по адресу

[HKLM\SYSTEM\CurrentControlSet\Enum\USB]

. Разбирать эту огромную базу вручную нереально, поскольку данные об одном устройстве могут быть размазаны тонким слоем по всему периметру реестра. Поэтому мы воспользуемся услугами системного менеджера конфигурации, функции которого сосредоточены в библиотеке setupapi.dll. Ознакомимся с основными из них..

1.1. Менеджер настройки устройств SetupDi**()

Пара функций SetupDiGetClassDevs() и SetupDiEnumDeviceInfo() позволяют организовать циклический поиск информации в реестре. Первая вернёт хэндл требуемого набора информации, а вторая – заполняет структуру SP_DEVINFO_DATA, которая служит проводником на конкретное устройство в этом наборе. Вот их прототипы:

C-подобный:



HDEVINFO SetupDiGetClassDevsA
ClassGuid dd
0
;
// указатель на GUID класса устройств
Enumerator dd
0
;
// 0
hwndParent dd
0
;
// 0
Flags dd
0
;
// DIGCF_PRESENT = искать только активные девайсы




Здесь, в первый аргумент мы должны положить указатель на идентификатор класса USB, а в последний – флаг, предписывающий искать реально имеющиеся на данный момент устройства (present). Поскольку сейчас нас интересует класс USB, то в первое поле кладём линк на 16-байтную константу GUID_DEVCLASS_USB. Если вы захотите собрать инфу о каких-либо иных классах устройств, то ознакомьтесь с полным списком из 46 возможных вариантов:

C-подобный:



BOOL SetupDiEnumDeviceInfo
DeviceInfoSet dd
0
;
// хэндл набора (возвращает предыдущая функция)
MemberIndex dd
0
;
// индекс устройства в наборе, начиная с нуля
DeviceInfoData dd
0
;
// указатель на структуру PSP_DEVINFO_DATA
struct SP_DEVINFO_DATA
cbSize dd sizeof
.
SP_DEVINFO_DATA
ClassGuid db
16
dup
(
0
)
;
// сюда получим GUID обнаруженного устройства
DevInst dd
0
;
// handle для fn.CM_GET**
Reserved dd
0
;
// резерв..
ends




Здесь уже интересней.. Индекс во-втором аргументе служит для организации циклического обхода всех устройств в данном наборе. При первом вызове, эта функция вернёт информацию не о Flash-накопителе, а о хост-контролёре, поскольку узел Node начинается именно с него и он тоже принадлежит к классу USB. Значит нужно будет увеличить индекс на 1 и повторно вызвать эту функцию. Тогда получим линк на сл.девайс в цепочке – корневой концентратор, и только на третий раз можем наткнуться на флеш. И то, если повезёт, т.к. контролёров у нас аж 5-штук, и у каждого своё древо устройств. Таким образом, индекс позволяет в цикле обходить всё древо, пока не найдём нужное устройство. Функция возвращает нуль, если в наборе больше нет устройств данного класса.

Отдельного внимания заслуживает и структура SP_DEVINFO_DATA. Она является ключевой для менеджера конфигурации СМ (config manager), а указатель на её содержимое, в виде аргумента ожидает почти весь состав библиотеки setupapi.dll. При каждом вызове с увеличением индекса, SetupDiEnumDeviceInfo() перезаписывает эту структуру новыми данными, где можно найти GUID очередного устройства, и что немаловажно – в члене "DevInst" хэндл девайса, для функций конфигуратора с префиксом CM_**().

По непонятной причине, в описании этой функции Microsoft не делает акцент на данном хэндле, лишь вскользь упоминая о нём. В результате, столкнувшись с диспетчером конфигурации вообще не ясно, от куда брать чёртов хэндл для CM_GET**(). Можно-же было обозвать это поле иначе, например прицепив к нему ярлык "бла-бла-бла Hndl", ан нет.. нужно, чтобы всё было через известное место.

Теперь, обнаружив хаб и порт нашей USB-Flash, мы можем послать по этому хэндлу команду на безопасное извлечение флеш, посредством функции CM_Request_Device_Eject(). Советую красным фломастером отметить структуру SP_DEVINFO_DATA и поле "DevInst" в ней!

1.2. Чтение свойств и характеристик устройств

Будем считать, что двойкой SetupDiGetClassDevs() и SetupDiEnumDeviceInfo() мы получили указатель на свой брелок в реестре. Следующие две функции позволяют вытягивать уже его свойства, в виде текстовых строк и hex-значений – это SetupDiGetDeviceRegistryProperty() и родственная ей SetupDiGetDevicePropertyW(). Учтите, что вторая возвращает строки в кодировке юникод (нет ansi версии), выводить на консоль которые можно при помощи printf() со-спецификатором %ls (long-string).

Самих-же свойств – как звёзд на небе, и я собрал их в отдельный инклуд (см.скрепку в конце статьи).

Для первой функции константы начинаются с префикса SPDRP_**, а для второй – DEVPKEY_Device_**. Вот их прототипы:

C-подобный:



BOOL SetupDiGetDeviceRegistryPropertyA
;
//
,
hubName
;
// вывод на консоль
;
//.....
;
//----- Вспомогательные процедуры --------------
proc Unicode2Ansi
xor ecx
,
ecx
;
// очистить ECX под размер строки
mov esi
,
buff
;
// источник
mov edi
,
esi
;
// ..он-же приёмник.
@@
:
lodsw
;
// берём из ESI по 2-байта юникоде
or ax
,
ax
;
// если нуль,
je @f
;
// ..выйти из цикла.
stosb
;
// записать 1-байт ansi в приёмник
inc ecx
;
// размер строки +1
jmp @b
;
// пройтись по всей строке..
@@
:
mov byte
[
edi
]
,
0
;
// вставить в хвост терминальный нуль
ret
;
// выход из процедуры – в ECX длина строки ansi
endp
proc ParseBuffString char
;
//
,
eax
,
ebx
,
ecx
,
edx




3. Практика – сбор информации об USB-Flash, безопасное извлечение устройств

В приведённом ниже примере я собрал всё сказанное под один капот, и постарался вывести на консоль наиболее значимую информацию о своей флешке. В коде присутствуют ещё парочка функций, которые являются вспомогательными, т.е. можно обойтись без них. Первая GetLogicalDriveStrings() возвращает имена всех томов, которые смонтированы на данный момент в системе. К примеру на своём узле я получил от этой функции буквы: C:, D:, E:, F:

Чтобы узнать, какая из них принадлежит USB-Flash, можно в цикле вскармливая эти литеры, запрашивать GetDriveType() проверяя её выхлоп на константу DRIVE_REMOVABLE=2 (съёмное устройство). Теперь у нас есть буква флеш-драйва, по которой функцией QueryDosDevice() можно узнать имя объекта, в системном пространстве имён типа: Device\HarddiskVolume2.

В таком формате его потребует CreateFile(), чтобы открыть флеш и через GetVolumeInformation() собрать информацию о файловой системе накопителя, его общим/свободном пространстве, метке и серийнике. Вот собственно и исходник:

C-подобный:



format pe console
include
'win32ax.inc'
entry start
;
//----------
section
'.inc'
data readable
include
'equates\setupapi.inc'
include
'equates\usbstor.inc'
;
//----------
.
data
ntName db
'\\?\GLOBALROOT'
dosName db
32
dup
(
0
)
hubName db '\\
?
\'
hubStr db
64
dup
(
0
)
hubGuid db
'#{f18a0e88-c30c-11d0-8815-00a0c906bed8}'
,
0
hubHndl dd
0
usbPort dd
0
epCount dd
0
volume dd
0
volTotal dd
0
,
0
volFree dd
0
,
0
volLabel db
16
dup
(
0
)
volFsys db
08
dup
(
0
)
volSn dd
0
maxLen dd
0
flags dd
0
sysTime SYSTEMTIME

gByte dd
1024
*
1024
*
1024
fResult1 dq
0
fResult2 dq
0
hndl dd
0
index dd
0
dpt dd
0
retSize dd
0
align
16
request USB_DESCRIPTOR_REQUEST
align
16
devData SP_DEVINFO_DATA
align
16
buff dd
0
;
//----------
.
code
start
:
invoke SetConsoleTitle
,

invoke GetLogicalDriveStringsA
,
64
,
buff
mov esi
,
buff
@@
:
push esi
invoke GetDriveType
,
esi
pop esi
cmp eax
,
DRIVE_REMOVABLE
;
// съёмный диск?
je @ok
;
// да!
add esi
,
4
cmp byte
[
esi
]
,
0
jne @b

cinvoke printf
,

jmp @exit

@ok
:
push esi
mov eax
,
[
esi
]
mov
[
volume
]
,
eax
cinvoke printf
,

,
esi
pop esi
mov byte
[
esi
+
2
]
,
0
invoke QueryDosDevice
,
esi
,
dosName
,
32
cinvoke printf
,

,
ntName
;
//**** Получаем хэндл набора USB ******************
invoke SetupDiGetClassDevs
,
GUID_DEVCLASS_USB
,
0
,
0
,
DIGCF_PRESENT
mov
[
hndl
]
,
eax
;
//**** Поиск USB-Flash в цикле ********************
@findNextDevice
:
invoke SetupDiEnumDeviceInfo
,
[
hndl
]
,
[
index
]
,
devData
or eax
,
eax
jz @exit

invoke SetupDiGetDeviceRegistryProperty
,
[
hndl
]
,
devData
,
SPDRP_SERVICE
,
\
0
,
buff
,
256
,
0
call @f
db
'USBSTOR'
@@
:
pop esi
mov edi
,
buff
mov ecx
,
7
repe cmpsb
or ecx
,
ecx
jnz @next
;
//**** Нашли! Выводим информацию из реестра **************
cinvoke printf
,

invoke SetupDiGetDeviceProperty
,
[
hndl
]
,
devData
,
\
DEVPKEY_Device_DriverProvider
,
dpt
,
buff
,
256
*
4
,
0
,
0
invoke CharToOem
,
buff
,
buff
cinvoke printf
,

,
buff

invoke SetupDiGetDeviceProperty
,
[
hndl
]
,
devData
,
\
DEVPKEY_Device_DriverInfPath
,
dpt
,
buff
,
256
*
4
,
0
,
0
cinvoke printf
,

,
buff

invoke SetupDiGetDeviceProperty
,
[
hndl
]
,
devData
,
\
DEVPKEY_Device_DriverVersion
,
dpt
,
buff
,
256
*
4
,
0
,
0
cinvoke printf
,

,
buff

invoke SetupDiGetDeviceProperty
,
[
hndl
]
,
devData
,
\
DEVPKEY_Device_DriverDate
,
dpt
,
buff
,
256
*
4
,
0
,
0
invoke FileTimeToSystemTime
,
buff
,
sysTime
movzx eax
,
[
sysTime
.
wDay
]
movzx ebx
,
[
sysTime
.
wMonth
]
movzx ecx
,
[
sysTime
.
wYear
]
cinvoke printf
,

,
eax
,
ebx
,
ecx

invoke SetupDiGetDeviceProperty
,
[
hndl
]
,
devData
,
\
DEVPKEY_Device_DriverRank
,
dpt
,
buff
,
256
*
4
,
0
,
0
cinvoke printf
,

,
[
buff
]
invoke SetupDiGetDeviceRegistryProperty
,
[
hndl
]
,
devData
,
\
SPDRP_SERVICE
,
0
,
buff
,
256
,
0
invoke CharToOem
,
buff
,
buff
cinvoke printf
,

,
buff
mov
[
buff
]
,
0
;
//**********************************
cinvoke printf
,

invoke SetupDiGetDeviceRegistryProperty
,
[
hndl
]
,
devData
,
\
SPDRP_LOCATION_PATHS
,
0
,
buff
,
256
,
0
mov eax
,
'# '
push eax
call ParseBuffString
cinvoke printf
,

,
buff

invoke SetupDiGetDeviceProperty
,
[
hndl
]
,
devData
,
\
DEVPKEY_Device_Parent
,
dpt
,
buff
,
256
*
4
,
0
,
0
call Unicode2Ansi
push ecx
mov eax
,
'\#'
push eax
call ParseBuffString
pop ecx
mov esi
,
buff
mov edi
,
hubStr
rep movsb
invoke lstrcat
,
hubName
,
hubGuid
cinvoke printf
,

,
hubName

invoke SetupDiGetDeviceRegistryProperty
,
[
hndl
]
,
devData
,
\
SPDRP_COMPATIBLEIDS
,
0
,
buff
,
256
,
0
mov eax
,
'& '
push eax
call ParseBuffString
cinvoke printf
,

,
buff
;
//*****************************
cinvoke printf
,

invoke SetupDiGetDeviceRegistryProperty
,
[
hndl
]
,
devData
,
\
SPDRP_LOCATION_INFORMATION
,
0
,
buff
,
256
,
0
invoke CharToOem
,
buff
,
buff
cinvoke printf
,

,
buff

invoke SetupDiGetDeviceRegistryProperty
,
[
hndl
]
,
devData
,
\
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME
,
\
0
,
buff
,
256
,
0
invoke CharToOem
,
buff
,
buff
cinvoke printf
,

,
buff

invoke SetupDiGetDeviceRegistryProperty
,
[
hndl
]
,
devData
,
\
SPDRP_ADDRESS
,
0
,
buff
,
256
,
0
mov eax
,
dword
[
buff
]
mov
[
usbPort
]
,
eax
;
//
,
[
buff
]
;
//*****************************
cinvoke printf
,

invoke SetupDiGetDeviceRegistryProperty
,
[
hndl
]
,
devData
,
\
SPDRP_DEVICEDESC
,
0
,
buff
,
256
,
0
invoke CharToOem
,
buff
,
buff
cinvoke printf
,

,
buff

invoke SetupDiGetDeviceProperty
,
[
hndl
]
,
devData
,
\
DEVPKEY_Device_BusReportedDeviceDesc
,
dpt
,
buff
,
256
*
4
,
0
,
0
invoke CharToOem
,
buff
,
buff
cinvoke printf
,

,
buff

invoke SetupDiGetDeviceProperty
,
[
hndl
]
,
devData
,
\
DEVPKEY_Device_InstanceId
,
dpt
,
buff
,
256
*
4
,
0
,
0
call Unicode2Ansi
mov edi
,
buff
mov al
,
'&'
repne scasb
mov byte
[
edi
-
1
]
,
' '
mov al
,
'\'
repne scasb
mov byte
[
edi
-
1
]
,
0
push edi
cinvoke printf
,

,
buff
pop edi
cinvoke printf
,

,
edi
;
//******************************************
cinvoke printf
,

invoke GetDiskFreeSpaceEx
,
volume
,
0
,
volTotal
,
volFree
invoke GetVolumeInformation
,
volume
,
volLabel
,
16
,
volSn
,
maxLen
,
flags
,
volFsys
,
8
finit
fild qword
[
volTotal
]
fidiv
[
gByte
]
fstp
[
fResult1
]
fild qword
[
volFree
]
fidiv
[
gByte
]
fstp
[
fResult2
]
cinvoke printf
,

,
\
dword
[
fResult1
]
,
dword
[
fResult1
+
4
]
,
\
dword
[
fResult2
]
,
dword
[
fResult2
+
4
]
mov eax
,
[
volSn
]
movzx ebx
,
ax
shr eax
,
16
cinvoke printf
,

,
\
volLabel
,
eax
,
ebx
,
volFsys
;
//######[ READ DESCRIPTORS ]##########################
cinvoke printf
,

invoke CreateFile
,
hubName
,
GENERIC_READ
+
GENERIC_WRITE
,
\
FILE_SHARE_READ
+
FILE_SHARE_WRITE
,
\
0
,
OPEN_EXISTING
,
0
,
0
mov
[
hubHndl
]
,
eax
;
// Запрос стандартных дескрипторов устройства
mov eax
,
[
usbPort
]
mov
[
request
.
ConnectionIndex
]
,
eax
mov
[
request
.
SetupPacket
.
bRequest
]
,
GET_DESCRIPTOR

mov
[
request
.
SetupPacket
.
wValueHigh
]
,
USB_DEVICE_DESCRIPTOR_TYPE
mov
[
request
.
SetupPacket
.
wValueLow
]
,
0
mov
[
request
.
SetupPacket
.
wIndex
]
,
0
mov
[
request
.
SetupPacket
.
wLenght
]
,
sizeof
.
USB_DEVICE_DESCRIPTOR

invoke DeviceIoControl
,
[
hubHndl
]
,
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
,
\
request
,
sizeof
.
USB_DESCRIPTOR_REQUEST
,
\
request
,
sizeof
.
USB_DESCRIPTOR_REQUEST
,
retSize
,
0
mov esi
,
request
.
Data
movzx eax
,
[
esi
+
USB_DEVICE_DESCRIPTOR
.
bcdUSB
]
movzx ebx
,
al
shr eax
,
8
movzx ecx
,
[
esi
+
USB_DEVICE_DESCRIPTOR
.
bNumConfigurations
]
movzx edx
,
[
esi
+
USB_DEVICE_DESCRIPTOR
.
bMaxPacketSize
]
cinvoke printf
,

,
eax
,
ebx
,
ecx
,
edx
;
// Запрос дескриптора "конфигурации" и сразу всех остальных
mov
[
request
.
SetupPacket
.
wValueHigh
]
,
USB_CONFIG_DESCRIPTOR_TYPE
mov
[
request
.
SetupPacket
.
wValueLow
]
,
0
;
// Номер конфигурации
mov
[
request
.
SetupPacket
.
wIndex
]
,
0
mov
[
request
.
SetupPacket
.
wLenght
]
,
sizeof
.
USB_CONFIGURATION_DESCRIPTOR
*
16
invoke DeviceIoControl
,
[
hubHndl
]
,
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
,
\
request
,
sizeof
.
USB_DESCRIPTOR_REQUEST
,
\
request
,
sizeof
.
USB_DESCRIPTOR_REQUEST
,
retSize
,
0
mov esi
,
request
.
Data
movzx eax
,
[
esi
+
USB_CONFIGURATION_DESCRIPTOR
.
MaxPower
]
shl eax
,
1
cinvoke printf
,

,
eax
;
// Читаем сразу дескриптор "интерфейса"
mov esi
,
request
.
Data
add esi
,
sizeof
.
USB_CONFIGURATION_DESCRIPTOR
push esi
movzx eax
,
[
esi
+
USB_INTERFACE_DESCRIPTOR
.
bNumEndpoints
]
mov
[
epCount
]
,
eax
dec
[
epCount
]
;
//
,
eax
,
ebx
;
// Читаем сразу дескрипторы "конечных точек EP"
jmp @f
bulk db
'Bulk'
,
0
iso db
'Isochronius'
,
0
input db
'In'
,
0
output db
'Out'
,
0
@@
:
pop esi
add esi
,
sizeof
.
USB_INTERFACE_DESCRIPTOR
push esi
movzx eax
,
[
esi
+
USB_ENDPOINT_DESCRIPTOR
.
bEndpointAddress
]
movzx ebx
,
[
esi
+
USB_ENDPOINT_DESCRIPTOR
.
wMaxPacketSize
]
movzx ecx
,
[
esi
+
USB_ENDPOINT_DESCRIPTOR
.
bmAttributes
]
movzx edi
,
[
esi
+
USB_ENDPOINT_DESCRIPTOR
.
bInterval
]
imul edi
,
125
mov edx
,
input
test al
,
10000000
b
;
//
,
eax
,
edi
,
ebx
,
ebp
,
edx

pop esi
;
//
,
eax
,
edi
,
ebx
,
ebp
,
edx

pop esi
dec
[
epCount
]
;
//
,
esi
;
//********* Безопасное извлечение устройства *************
cinvoke printf
,

cinvoke getch
cmp al
,
'y'
jne @f

cinvoke printf
,

mov eax
,
[
devData
.
DevInst
]
invoke CM_Request_Device_Eject
,
eax
,
0
,
0
,
0
,
0
@@
:
cinvoke printf
,

;
//**** Индексированный поиск устройств, пока не найдём.
@next
:
inc
[
index
]
jmp @findNextDevice

@exit
:
cinvoke getch
;
//#######################
proc Unicode2Ansi
xor ecx
,
ecx
mov esi
,
buff
mov edi
,
esi
@@
:
lodsw
or ax
,
ax
je @f
stosb
inc ecx
jmp @b
@@
:
mov byte
[
edi
]
,
0
ret
endp
proc ParseBuffString char
invoke lstrlen
,
buff
xchg ecx
,
eax
mov edi
,
buff
mov eax
,
[
char
]
@@
:
repne scasb
or ecx
,
ecx
je @f
mov byte
[
edi
-
1
]
,
ah
jmp @b
@@
:
ret
endp
;
//---------------
section
'.idata'
import data readable
library msvcrt
,
'msvcrt.dll'
,
setupapi
,
'setupapi.dll'
,
\
kernel32
,
'kernel32.dll'
,
user32
,
'user32.dll'
import msvcrt
,
printf
,
'printf'
,
fflush
,
'fflush'
,
getch
,
'_getch'
,
exit
,
'exit'
import setupapi
,
SetupDiGetClassDevs
,
'SetupDiGetClassDevsA'
,
\
SetupDiEnumDeviceInfo
,
'SetupDiEnumDeviceInfo'
,
\
SetupDiGetDeviceProperty
,
'SetupDiGetDevicePropertyW'
,
\
SetupDiGetDeviceRegistryProperty
,
'SetupDiGetDeviceRegistryPropertyA'
,
\
CM_Request_Device_Eject
,
'CM_Request_Device_EjectA'
include
'api\kernel32.inc'
include
'api\user32.inc'


https://forum.antichat.xyz/attachments/4905309/img_54e8e5005f.png



Здесь видно, что у моего устройства USB-2.0 всего две конечные точки: канал ЕР1 служит для записи(Out), а канал ЕР2 на чтение(In). Если у кого имеется флешка USB-3, просьба показать кол-во её конечных точек – программа должна определить их сама, для чего предусмотрен цикл. Интересует, два или четыре пайпа в устройствах USB-3.

4. Функции из библиотекиWinUsb.dll

В арсенале системы имеется библиотека winUsb.dll, которая ходит со-своим драйвером winUsb.sys. Она была включена в состав ОС для устройств, у которых нет класс-драйвера в системе. К числу таких девайсов можно отнести платы Arduino, сотовые телефоны, собранные "на коленке" разнообразные поделки на PIC-контролёрах, и прочие.

Библиотека выдаёт на экспорт всего 22 функции, но они предоставляют более гибкий и удобный интерфейс общения с устройствами. Либа прекрасно документирована на сайте MSDN, поэтому с прототипами функций проблем не возникает, а полный их список можно посмотреть в любом дизассемблере типа Win32Dasm:

Код:



+++++++++++++++++++ EXPORTED FUNCTIONS ++++++++++++++++++
Number of Functions = 0022 (decimal)

Addr:10002530 Ord: 1 (0001h) Name: WinUsb_AbortPipe
Addr:1000231C Ord: 2 (0002h) Name: WinUsb_ControlTransfer
Addr:100025F4 Ord: 3 (0003h) Name: WinUsb_FlushPipe
Addr:100016C0 Ord: 4 (0004h) Name: WinUsb_Free
Addr:1000172E Ord: 5 (0005h) Name: WinUsb_GetAssociatedInterface
Addr:10001B27 Ord: 6 (0006h) Name: WinUsb_GetCurrentAlternateSetting
Addr:10001984 Ord: 7 (0007h) Name: WinUsb_GetDescriptor
Addr:100026B8 Ord: 8 (0008h) Name: WinUsb_GetOverlappedResult
Addr:10001DCF Ord: 9 (0009h) Name: WinUsb_GetPipePolicy
Addr:10001FE4 Ord: 10 (000Ah) Name: WinUsb_GetPowerPolicy
Addr:100012A8 Ord: 11 (000Bh) Name: WinUsb_Initialize
Addr:1000120D Ord: 12 (000Ch) Name: WinUsb_ParseConfigurationDescriptor
Addr:100011C5 Ord: 13 (000Dh) Name: WinUsb_ParseDescriptors
Addr:100018C0 Ord: 14 (000Eh) Name: WinUsb_QueryDeviceInformation
Addr:1000185B Ord: 15 (000Fh) Name: WinUsb_QueryInterfaceSettings
Addr:10001BE4 Ord: 16 (0010h) Name: WinUsb_QueryPipe
Addr:100020BA Ord: 17 (0011h) Name: WinUsb_ReadPipe
Addr:1000246C Ord: 18 (0012h) Name: WinUsb_ResetPipe
Addr:10001A63 Ord: 19 (0013h) Name: WinUsb_SetCurrentAlternateSetting
Addr:10001C98 Ord: 20 (0014h) Name: WinUsb_SetPipePolicy
Addr:10001EAF Ord: 21 (0015h) Name: WinUsb_SetPowerPolicy
Addr:100021EB Ord: 22 (0016h) Name: WinUsb_WritePipe




Обратите внимание, что библиотека помимо чтения позволяет производить и запись в пайпы, причём с правами смертного юзера. Проблема в том, что например, на моей машине драйвер winUsb.sys не подгружается автоматически при запуске системы, и не факт, что он будет загружен на удалённом узле. Соответственно, чтобы использовать эти функции, нужно будет сначала подтянуть драйвер в оперативную память, а это не всегда удобно. Вывод – если для устройства в системе имеются класс-драйверы (типа HID, Storage, Audio, коммуникации CDC и прочие), то лучше не рисковать и использовать их, по приведённому выше алго. К winUsb.dll следует обращаться в крайних случаях, когда других вариантов уже нет.

5.Снифф пакетовUSB

Интересную информацию можно почерпнуть посредством снифферов USB. В природе, лично мне встречались несколько таких зверьков, но больше всех порадовал "USB-Lyzer". Во-первых, он уже в коробке идёт со-встроенным драйвером usbPcap.sys, так-что установив этот софт появляется возможность ловить USB-пакеты и в завоевавшем рынок Wireshark. Во-вторых, при запуске лузера сразу становится очевидно, что он был написан грамотно, с учётом всех мелочей. 30-дневную пробную версию софтины можно скачать с их сайта поэтому адресу– настоятельно рекомендую:

https://forum.antichat.xyz/attachments/4905309/img_5a13a0fd04.png



6. Заключение

Устройства USB поддерживают и интерфейс SCSI, который намного мощнее обычного. Но к сожалению ограниченный объём статьи не позволяет охватить всё сразу, так-что придётся отложить это дело до лучших времён. Если проснифать пакеты, то оказывается, что в своей массе, система поддерживает диалог с шиной USB исключительно по SCSI, периодически посылая ей пакеты CBW (Command Block Wrapper) и принимая CSW (Command Status Wrapper). Реализовать данный обмен можно посредством всё того-же DeviceIoControl() с управляющим кодом IOCTL_SCSI_PASS_THROUGH_DIRECT.

В скрепку кладу исполняемый файл представленного выше кода, и пару инклудов, с описанием необходимых структур. На этом тчк, всем удачи и до скорого.

rusrst
21.04.2021, 20:54
О, классно до сих пор помню Вашу статью по getEnumDevice() обходил по ней дерево com портов.
Можно попробовать хабы обойти через GUID_DEVINTERFACE_USB_HUB.
По поводу winUSB, она вроде же автоматом ставится на устройства, которые выдают спец значение при энумерации, абы куда ее вроде не поставить. И при работе драйвер не должен выгружаться из памяти, если устройство подключено, разве нет?

Marylin
22.04.2021, 04:30
rusrst сказал(а):

По поводу winUSB, она вроде же автоматом ставится на устройства, которые выдают спец значение при энумерации,


..да, но только начиная с Win8, о чём говорится на сайте Microsoft.



До Windows 8 для загрузки Winusb.sys в качестве функционального драйвера требовалось предоставить собственный INF. В Windows 8 входящий файл Winusb.inf был обновлен, чтобы позволить Windows автоматически сопоставлять INF с устройством WinUSB.



Здесь более развернутая инфа на эту тему: Архитектура и модули WinUSB и Установка winUsb.sys