Windows驱动USBVideo的USB请求超时默认为5秒
2025-01-21
27
0
今天在调试HOOK一个USB设备驱动,在追踪返回HOOK之后配置描述符之后,上层驱动没有下发SET_CONFIGURATION请求。从设备管理器来看,设备直接返回的是启动失败,请求失败。
故为了分析该问题,需要进行调试追踪,不过意外发现了Windows中UVC驱动的默认超时。
在Windows系统中,兼容UVC驱动使用的驱动usbvideo.sys来驱动,由其配合KS最终实现的是USB相机的功能。故usbvideo.sys是一个承上启下的驱动,其关于USB的相关的操作都是位于该驱动中。
这个UAC驱动usbaudio.sys类似
首先在我们的HOOK驱动的请求设备描述符代码处加上断点,中断后进行栈回溯:
3: kd> k
# Child-SP RetAddr Call Site
00 ffffa580`15e36058 fffff801`c858470a nt!DbgBreakPointWithStatus
01 ffffa580`15e36060 fffff801`c841ae64 nt!vDbgPrintExWithPrefixInternal+0x169876
02 ffffa580`15e36160 fffff804`ac5d7970 nt!DbgPrint+0x3c
03 ffffa580`15e361a0 fffff804`ac5de48b MyCamera!HookDirectCamera+0x80 [F:\WorkCamera\MyCamera\camera.c @ 1901]
04 ffffa580`15e36210 fffff804`ac5de212 MyCamera!PDO_HandleInternalDeviceControl+0x4b [F:\WorkCamera\MyCamera\pdo.c @ 1199]
05 ffffa580`15e36250 fffff804`ac5db86a MyCamera!PDO_Dispatch+0xf2 [F:\WorkCamera\MyCamera\pdo.c @ 137]
06 ffffa580`15e362a0 fffff804`abef456f MyCamera!DispatchIrp+0x4a [F:\WorkCamera\MyCamera\dten.c @ 117]
07 ffffa580`15e362e0 fffff804`abef5164 usbvideo!USBVideoCallUSBD+0xd7
08 ffffa580`15e36380 fffff804`abef312b usbvideo!StartUSBVideoDevice+0x294
09 ffffa580`15e363f0 fffff804`aa77c290 usbvideo!USBVideoPnpStart+0x10b
0a ffffa580`15e36430 fffff804`aa772c94 ks!CKsDevice::PnpStart+0x86ec
0b ffffa580`15e36480 fffff804`acb114b1 ks!CKsDevice::DispatchPnp+0x104
0c ffffa580`15e364f0 fffff801`c88c9191 ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
0d ffffa580`15e36550 fffff801`c84d3486 nt!PnpAsynchronousCall+0xe5
0e ffffa580`15e36590 fffff801`c8459660 nt!PnpSendIrp+0x92
0f ffffa580`15e36600 fffff801`c88c86ab nt!PnpStartDevice+0x88
10 ffffa580`15e36690 fffff801`c87f2ca3 nt!PnpStartDeviceNode+0xdb
11 ffffa580`15e36720 fffff801`c88cb989 nt!PipProcessStartPhase1+0x53
12 ffffa580`15e36760 fffff801`c8a57826 nt!PipProcessDevNodeTree+0x401
13 ffffa580`15e369e0 fffff801`c858662e nt!PiRestartDevice+0xba
14 ffffa580`15e36a30 fffff801`c848f039 nt!PnpDeviceActionWorker+0x15b26e
15 ffffa580`15e36b00 fffff801`c8433005 nt!ExpWorkerThread+0xe9
16 ffffa580`15e36b90 fffff801`c8571e66 nt!PspSystemThreadStartup+0x41
17 ffffa580`15e36be0 00000000`00000000 nt!KiStartSystemThread+0x16
可以看到,该请求是由usbaduio.sys在其IRP_MJ_PNP的回调函数usbvideo!USBVideoPnpStart中调用usbvideo!StartUSBVideoDevice实现的。最终创建的URB通过调用usbvideo!USBVideoCallUSBD下发给下层区动,即我们的驱动。
通过IDA打开usbvideo.sys,找到相关的函数。这理进行了简单的整理,代码如下:
__int64 __fastcall USBVideoCallUSBD(__int64 a1, ULONG_PTR Urb, ULONG code, ULONG_PTR RequestUrb)
{
_DEVICE_OBJECT *DeviceObject; // r15
ULONG IoControlCode; // ecx
IRP *bIrp; // rax
IRP *Irp; // rbx
NTSTATUS status; // eax
struct _IO_STATUS_BLOCK IoStatusBlock; // [rsp+50h] [rbp-30h] BYREF
struct _KEVENT Event; // [rsp+60h] [rbp-20h] BYREF
union _LARGE_INTEGER Timeout; // [rsp+A0h] [rbp+20h] BYREF
DeviceObject = *(_DEVICE_OBJECT **)(a1 + 40);
*(_QWORD *)&Event.Header.Lock = 0i64;
Event.Header.WaitListHead.Flink = 0i64;
Event.Header.WaitListHead.Blink = 0i64;
IoStatusBlock.Pointer = 0i64;
IoStatusBlock.Information = 0i64;
KeInitializeEvent(&Event, NotificationEvent, 0);
IoControlCode = 0x220003; // IOCTL_INTERNAL_USB_SUBMIT_URB
if ( code )
IoControlCode = code;
bIrp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, 0i64, 0, 0i64, 0, 1u, &Event, &IoStatusBlock);
Irp = bIrp;
if ( !bIrp )
return 0xC000009Ai64; // STATUS_INSUFFICIENT_RESOURCES
status = IoSetCompletionRoutineEx(*(PDEVICE_OBJECT *)(a1 + 24), bIrp, USBVideoCompleteSynch, &Event, 1u, 1u, 1u);
if ( status < 0 )
goto LABEL_14;
if ( RequestUrb )
Urb = RequestUrb;
Irp->Tail.Overlay.CurrentStackLocation[-1].Parameters.Others.Argument1 = (PVOID)Urb;
status = IofCallDriver(DeviceObject, Irp);
if ( status == 0x103 ) // STATUS_PENDING
{
Timeout.QuadPart = -50000000i64;
if ( KeWaitForSingleObject(&Event, Executive, 0, 0, &Timeout) == 0x102 )
{
if ( WPP_GLOBAL_Control != (PDEVICE_OBJECT)&WPP_GLOBAL_Control && BYTE1(WPP_GLOBAL_Control->Timer) >= 5u )
WPP_SF_(WPP_GLOBAL_Control->AttachedDevice, 18i64, &WPP_b7038f1b2f3431bf9a8df6f91b35ef63_Traceguids);
IoCancelIrp(Irp);
KeWaitForSingleObject(&Event, Executive, 0, 0, 0i64);
IoStatusBlock.Status = 0x102; // STATUS_TIMEOUT
}
}
else
{
LABEL_14:
IoStatusBlock.Status = status;
}
IofCompleteRequest(Irp, 0);
return (unsigned int)IoStatusBlock.Status;
}
可见,下发IRP的超时是间为 -50000000百纳秒,即5秒。如果5秒内该请求超时无法完成,则取消该IRP,等待其完成例程调用和,即可获取到event事件。
__int64 __fastcall USBVideoCompleteSynch(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
if ( Irp->PendingReturned )
KeSetEvent((PRKEVENT)Context, 0, 0);
return 0xC00000
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936