Skip to content

Commit

Permalink
Restore control transfer specific URB handling
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
desowin committed Jul 2, 2019
1 parent 8ee0a73 commit 296e4ef
Showing 1 changed file with 328 additions and 16 deletions.
344 changes: 328 additions & 16 deletions USBPcapDriver/USBPcapURB.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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);
}
}
}

Expand Down

0 comments on commit 296e4ef

Please sign in to comment.