From 296e4efcf6f3a63e4e71211f946564759ebc0009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Tue, 2 Jul 2019 19:35:51 +0200 Subject: [PATCH] Restore control transfer specific URB handling THe official USB 3.0 stack, unlike USB 2.0 stack, does not necessarily change the URB function when the IRP is travelling back from PDO. USBPcap 1.4.1.0 introduced new mechanism for control transfer capture that relied on the (false) assumption that the IRP will have the URB function changed to URB_FUNCTION_CONTROL_TRANSFER when travelling back from PDO. This resulted in DEVICE and CONFIGURATION descriptors not being captured for USB 3.0 devices connected to USB 3.0 host on recent Windows versions. This change restores the old mechanism for control transfer capture if the IRP does not travel back with changed URB function code. As the Setup packet is now manually created it should be checked if it is still affected by the issue #83. --- USBPcapDriver/USBPcapURB.c | 344 +++++++++++++++++++++++++++++++++++-- 1 file changed, 328 insertions(+), 16 deletions(-) diff --git a/USBPcapDriver/USBPcapURB.c b/USBPcapDriver/USBPcapURB.c index 1932d11..ae9c531 100644 --- a/USBPcapDriver/USBPcapURB.c +++ b/USBPcapDriver/USBPcapURB.c @@ -341,6 +341,310 @@ USBPcapAnalyzeControlTransfer(struct _URB_CONTROL_TRANSFER* transfer, } } +/* Microsoft official USB 3.0 stack, unlike the USB 2.0 one, does not return + * some of the control transfer related functions as URB_FUNCTION_CONTROL_TRANSFER. + * Due to that we are essentially faking the _URB_CONTROL_TRANSFER structure based + * on the information that can be derived from the URB function code and corresponding + * data structure. + * + * Return TRUE if the IRP was handled (and captured) as CONTROL transfer. + * Return FALSE otherwise. + */ +BOOLEAN USBPcapTryAnalyzeControlTransfer(PIRP pIrp, PURB pUrb, BOOLEAN post, + PUSBPCAP_DEVICE_DATA pDeviceData, + PUSBPCAP_URB_IRP_INFO pUnknownURBSubmitInfo) +{ + struct _URB_HEADER *header; + + header = (struct _URB_HEADER*)pUrb; + switch (header->Function) + { + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: + case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: + case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: + case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: + { + struct _URB_CONTROL_TRANSFER wrapTransfer; + struct _URB_CONTROL_DESCRIPTOR_REQUEST* request; + + request = (struct _URB_CONTROL_DESCRIPTOR_REQUEST*)pUrb; + + DkDbgVal("URB_FUNCTION_XXX_DESCRIPTOR", header->Function); + + /* Set up wrapTransfer */ + wrapTransfer.PipeHandle = NULL; /* Default pipe handle */ + if (header->Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE) + { + wrapTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN; + /* D7: Data from Device to Host (1) + * D6-D5: Standard (0) + * D4-D0: Device (0) + */ + wrapTransfer.SetupPacket[0] = 0x80; + /* 0x06 - GET_DESCRIPTOR */ + wrapTransfer.SetupPacket[1] = 0x06; + } + else if (header->Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT) + { + wrapTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN; + /* D7: Data from Device to Host (1) + * D6-D5: Standard (0) + * D4-D0: Endpoint (2) + */ + wrapTransfer.SetupPacket[0] = 0x82; + /* 0x06 - GET_DESCRIPTOR */ + wrapTransfer.SetupPacket[1] = 0x06; + } + else if (header->Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE) + { + wrapTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN; + /* D7: Data from Device to Host (1) + * D6-D5: Standard (0) + * D4-D0: Interface (1) + */ + wrapTransfer.SetupPacket[0] = 0x81; + /* 0x06 - GET_DESCRIPTOR */ + wrapTransfer.SetupPacket[1] = 0x06; + } + else if (header->Function == URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE) + { + wrapTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT; + /* D7: Data from Host to Device (0) + * D6-D5: Standard (0) + * D4-D0: Device (0) + */ + wrapTransfer.SetupPacket[0] = 0x00; + /* 0x07 - SET_DESCRIPTOR */ + wrapTransfer.SetupPacket[1] = 0x07; + } + else if (header->Function == URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT) + { + wrapTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT; + /* D7: Data from Host to Device (0) + * D6-D5: Standard (0) + * D4-D0: Endpoint (2) + */ + wrapTransfer.SetupPacket[0] = 0x02; + /* 0x07 - SET_DESCRIPTOR */ + wrapTransfer.SetupPacket[1] = 0x07; + } + else if (header->Function == URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE) + { + wrapTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT; + /* D7: Data from Host to Device (0) + * D6-D5: Standard (0) + * D4-D0: Interface (1) + */ + wrapTransfer.SetupPacket[0] = 0x01; + /* 0x07 - SET_DESCRIPTOR */ + wrapTransfer.SetupPacket[1] = 0x07; + } + else + { + DkDbgVal("Invalid function", header->Function); + return FALSE; + } + wrapTransfer.SetupPacket[2] = request->Index; + wrapTransfer.SetupPacket[3] = request->DescriptorType; + wrapTransfer.SetupPacket[4] = (request->LanguageId & 0x00FF); + wrapTransfer.SetupPacket[5] = (request->LanguageId & 0xFF00) >> 8; + wrapTransfer.SetupPacket[6] = (request->TransferBufferLength & 0x00FF); + wrapTransfer.SetupPacket[7] = (request->TransferBufferLength & 0xFF00) >> 8; + + wrapTransfer.TransferBufferLength = request->TransferBufferLength; + wrapTransfer.TransferBuffer = request->TransferBuffer; + wrapTransfer.TransferBufferMDL = request->TransferBufferMDL; + + USBPcapAnalyzeControlTransfer(&wrapTransfer, header, pUnknownURBSubmitInfo, + pDeviceData, pIrp, post); + return TRUE; + } + + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: + case URB_FUNCTION_GET_STATUS_FROM_OTHER: + { + struct _URB_CONTROL_TRANSFER wrapTransfer; + struct _URB_CONTROL_GET_STATUS_REQUEST* request; + + request = (struct _URB_CONTROL_GET_STATUS_REQUEST*)pUrb; + + DkDbgVal("URB_FUNCTION_GET_STATUS_FROM_XXX", header->Function); + + /* Set up wrapTransfer */ + wrapTransfer.PipeHandle = NULL; /* Default pipe handle */ + wrapTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN; + + if (header->Function == URB_FUNCTION_GET_STATUS_FROM_DEVICE) + { + /* D7: Data from Device to Host (1) + * D6-D5: Standard (0) + * D4-D0: Device (0) + */ + wrapTransfer.SetupPacket[0] = 0x80; + } + else if (header->Function == URB_FUNCTION_GET_STATUS_FROM_INTERFACE) + { + /* D7: Data from Device to Host (1) + * D6-D5: Standard (0) + * D4-D0: Interface (1) + */ + wrapTransfer.SetupPacket[0] = 0x81; + } + else if (header->Function == URB_FUNCTION_GET_STATUS_FROM_ENDPOINT) + { + /* D7: Data from Device to Host (1) + * D6-D5: Standard (0) + * D4-D0: Endpoint (2) + */ + wrapTransfer.SetupPacket[0] = 0x82; + } + else if (header->Function == URB_FUNCTION_GET_STATUS_FROM_OTHER) + { + /* D7: Data from Device to Host (1) + * D6-D5: Standard (0) + * D4-D0: Other (3) + */ + wrapTransfer.SetupPacket[0] = 0x83; + } + else + { + DkDbgVal("Invalid function", header->Function); + return FALSE; + } + + /* 0x00 - GET_STATUS */ + wrapTransfer.SetupPacket[1] = 0x00; + /* wValue is Zero */ + wrapTransfer.SetupPacket[2] = 0; + wrapTransfer.SetupPacket[3] = 0; + /* wIndex */ + wrapTransfer.SetupPacket[4] = (request->Index & 0x00FF); + wrapTransfer.SetupPacket[5] = (request->Index & 0xFF00) >> 8; + /* wLength must be 2 */ + wrapTransfer.SetupPacket[6] = (request->TransferBufferLength & 0x00FF); + wrapTransfer.SetupPacket[7] = (request->TransferBufferLength & 0xFF00) >> 8; + + wrapTransfer.TransferBufferLength = request->TransferBufferLength; + wrapTransfer.TransferBuffer = request->TransferBuffer; + wrapTransfer.TransferBufferMDL = request->TransferBufferMDL; + + USBPcapAnalyzeControlTransfer(&wrapTransfer, header, pUnknownURBSubmitInfo, + pDeviceData, pIrp, post); + return TRUE; + } + + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + case URB_FUNCTION_VENDOR_OTHER: + case URB_FUNCTION_CLASS_DEVICE: + case URB_FUNCTION_CLASS_INTERFACE: + case URB_FUNCTION_CLASS_ENDPOINT: + case URB_FUNCTION_CLASS_OTHER: + { + struct _URB_CONTROL_TRANSFER wrapTransfer; + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST* request; + + request = (struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST*)pUrb; + + DkDbgVal("URB_FUNCTION_VENDOR_XXX/URB_FUNCTION_CLASS_XXX", + header->Function); + + wrapTransfer.PipeHandle = NULL; /* Default pipe handle */ + wrapTransfer.TransferFlags = request->TransferFlags; + wrapTransfer.TransferBufferLength = request->TransferBufferLength; + wrapTransfer.TransferBuffer = request->TransferBuffer; + wrapTransfer.TransferBufferMDL = request->TransferBufferMDL; + + /* Set up D6-D0 of Request Type based on Function + * D7 (Data Stage direction) will be set later + */ + switch (header->Function) + { + case URB_FUNCTION_VENDOR_DEVICE: + /* D4-D0: Device (0) + * D6-D5: Vendor (2) + */ + wrapTransfer.SetupPacket[0] = 0x40; + break; + case URB_FUNCTION_VENDOR_INTERFACE: + /* D4-D0: Interface (1) + * D6-D5: Vendor (2) + */ + wrapTransfer.SetupPacket[0] = 0x41; + break; + case URB_FUNCTION_VENDOR_ENDPOINT: + /* D4-D0: Endpoint (2) + * D6-D5: Vendor (2) + */ + wrapTransfer.SetupPacket[0] = 0x42; + break; + case URB_FUNCTION_VENDOR_OTHER: + /* D4-D0: Other (3) + * D6-D5: Vendor (2) + */ + wrapTransfer.SetupPacket[0] = 0x43; + break; + case URB_FUNCTION_CLASS_DEVICE: + /* D4-D0: Device (0) + * D6-D5: Class (1) + */ + wrapTransfer.SetupPacket[0] = 0x20; + break; + case URB_FUNCTION_CLASS_INTERFACE: + /* D4-D0: Interface (1) + * D6-D5: Class (1) + */ + wrapTransfer.SetupPacket[0] = 0x21; + break; + case URB_FUNCTION_CLASS_ENDPOINT: + /* D4-D0: Endpoint (2) + * D6-D5: Class (1) + */ + wrapTransfer.SetupPacket[0] = 0x22; + break; + case URB_FUNCTION_CLASS_OTHER: + /* D4-D0: Other (3) + * D6-D5: Class (1) + */ + wrapTransfer.SetupPacket[0] = 0x23; + break; + default: + DkDbgVal("Invalid function", header->Function); + return FALSE; + } + + if (request->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + /* Set D7: Request data from device */ + wrapTransfer.SetupPacket[0] |= 0x80; + } + + wrapTransfer.SetupPacket[1] = request->Request; + wrapTransfer.SetupPacket[2] = (request->Value & 0x00FF); + wrapTransfer.SetupPacket[3] = (request->Value & 0xFF00) >> 8; + wrapTransfer.SetupPacket[4] = (request->Index & 0x00FF); + wrapTransfer.SetupPacket[5] = (request->Index & 0xFF00) >> 8; + wrapTransfer.SetupPacket[6] = (request->TransferBufferLength & 0x00FF); + wrapTransfer.SetupPacket[7] = (request->TransferBufferLength & 0xFF00) >> 8; + + USBPcapAnalyzeControlTransfer(&wrapTransfer, header, pUnknownURBSubmitInfo, + pDeviceData, pIrp, post); + return TRUE; + } + + default: + { + /* This is not a control transfer, or we do not know how to transform it */ + return FALSE; + } + } +} + /* * Analyzes the URB * @@ -485,25 +789,33 @@ VOID USBPcapAnalyzeURB(PIRP pIrp, PURB pUrb, BOOLEAN post, #endif if (!isControlTransfer) { - /* This is not a control transfer, so log the unknown URB */ - USBPCAP_BUFFER_PACKET_HEADER packetHeader; + if (USBPcapTryAnalyzeControlTransfer(pIrp, pUrb, post, pDeviceData, &unknownURBSubmitInfo)) + { + /* URB has been recognized as control transfer and it is already captured at this point */ + return; + } + else + { + /* This is not a control transfer, so log the unknown URB */ + USBPCAP_BUFFER_PACKET_HEADER packetHeader; - DkDbgVal("Logging unknown URB from URB IRP table", unknownURBSubmitInfo.function); + DkDbgVal("Logging unknown URB from URB IRP table", unknownURBSubmitInfo.function); - packetHeader.headerLen = sizeof(USBPCAP_BUFFER_PACKET_HEADER); - packetHeader.irpId = (UINT64) pIrp; - packetHeader.status = unknownURBSubmitInfo.status; - packetHeader.function = unknownURBSubmitInfo.function; - packetHeader.info = unknownURBSubmitInfo.info; - packetHeader.bus = unknownURBSubmitInfo.bus; - packetHeader.device = unknownURBSubmitInfo.device; - packetHeader.endpoint = 0; - packetHeader.transfer = USBPCAP_TRANSFER_UNKNOWN; - packetHeader.dataLength = 0; + packetHeader.headerLen = sizeof(USBPCAP_BUFFER_PACKET_HEADER); + packetHeader.irpId = (UINT64) pIrp; + packetHeader.status = unknownURBSubmitInfo.status; + packetHeader.function = unknownURBSubmitInfo.function; + packetHeader.info = unknownURBSubmitInfo.info; + packetHeader.bus = unknownURBSubmitInfo.bus; + packetHeader.device = unknownURBSubmitInfo.device; + packetHeader.endpoint = 0; + packetHeader.transfer = USBPCAP_TRANSFER_UNKNOWN; + packetHeader.dataLength = 0; - USBPcapBufferWriteTimestampedPacket(pDeviceData->pRootData, - unknownURBSubmitInfo.timestamp, - &packetHeader, NULL); + USBPcapBufferWriteTimestampedPacket(pDeviceData->pRootData, + unknownURBSubmitInfo.timestamp, + &packetHeader, NULL); + } } }