2

I'm currently trying to emulate the traffic sent to/from a HID device using libusb. The traffic is sniffed using wireshark and USBPcap. I emulated the first packets by requesting the descriptors and setting configuration etc. But at this point according to the log, the host sends a set idle request, get descriptor hid report and lastly a bunch of set reports. What functions in libusb corresponds to these packets? AFAIK the set report is basically the host transmitting some sort of settings to the device. I figured I could just copy the packet data and send my own reports exactly the same? Also is there a way to see exactly what the data does in the set report packets? I need to know how to properly set this up.

This is the packets i'm trying to emulate:

1   0.000000    host    2.41.0  USB 36  GET DESCRIPTOR Request DEVICE
2   0.000174    2.41.0  host    USB 46  GET DESCRIPTOR Response DEVICE
3   0.000208    host    2.41.0  USB 36  GET DESCRIPTOR Request CONFIGURATION
4   0.000291    2.41.0  host    USB 37  GET DESCRIPTOR Response CONFIGURATION
5   0.000304    host    2.41.0  USB 36  GET DESCRIPTOR Request CONFIGURATION
6   0.000395    2.41.0  host    USB 62  GET DESCRIPTOR Response CONFIGURATION
7   0.000411    host    2.41.0  USB 36  SET CONFIGURATION Request
8   0.001150    2.41.0  host    USB 28  SET CONFIGURATION Response
9   0.001167    host    2.41.0  USBHID  36  SET_IDLE Request
10  0.001239    2.41.0  host    USBHID  28  SET_IDLE Response
11  0.001386    host    2.41.0  USBHID  36  GET DESCRIPTOR Request HID Report
12  0.001462    2.41.0  host    USBHID  104 GET DESCRIPTOR Response HID Report
13  0.002620    host    2.41.1  USB 27  URB_INTERRUPT in
14  0.002645    host    2.41.1  USB 27  URB_INTERRUPT in
15  6.085037    2.41.1  host    USB 27  URB_INTERRUPT in
16  6.085090    2.41.1  host    USB 27  URB_INTERRUPT in
17  18.467828   host    2.41.0  USBHID  36  SET_IDLE Request
18  18.467993   2.41.0  host    USBHID  28  SET_IDLE Response
19  18.468086   host    2.41.1  USB 27  URB_INTERRUPT in
20  18.468114   host    2.41.1  USB 27  URB_INTERRUPT in
21  18.468385   host    2.41.0  USB 36  GET DESCRIPTOR Request STRING
22  18.468537   2.41.0  host    USB 86  GET DESCRIPTOR Response STRING
23  18.468595   host    2.41.0  USB 36  GET DESCRIPTOR Request STRING
24  18.468801   2.41.0  host    USB 60  GET DESCRIPTOR Response STRING
25  18.475044   host    2.41.0  USBHID  53  SET_REPORT Request
26  18.475273   2.41.0  host    USBHID  28  SET_REPORT Response
27  18.475834   host    2.41.0  USBHID  1061    SET_REPORT Request
28  18.476102   2.41.0  host    USBHID  28  SET_REPORT Response
29  18.476571   host    2.41.0  USBHID  1061    SET_REPORT Request
30  18.476849   2.41.0  host    USBHID  28  SET_REPORT Response
31  18.477280   host    2.41.0  USBHID  1061    SET_REPORT Request
32  18.477565   2.41.0  host    USBHID  28  SET_REPORT Response
33  18.478085   host    2.41.0  USBHID  1061    SET_REPORT Request
34  18.478329   2.41.0  host    USBHID  28  SET_REPORT Response
35  18.478700   host    2.41.0  USBHID  1061    SET_REPORT Request

I assume that I need to claim the interface and setup the endpoints. But I am having trouble understanding how to setup the system as hid class, setting the interrupts and polling correctly etc. At this point I have the config descriptor, the device descriptor and a device handle to work with.

#include <stdio.h>
#include "libusb.h"
#include <unistd.h>
#include <time.h>

static void print_devs(libusb_device **devs) //Taken from examples provided with libusb. Not used at this time
{
    libusb_device *dev;
    int i = 0, j = 0;
    uint8_t path[8]; 

    while ((dev = devs[i++]) != NULL) {
        struct libusb_device_descriptor desc;
        int r = libusb_get_device_descriptor(dev, &desc);
        if (r < 0) {
            fprintf(stderr, "failed to get device descriptor");
            return;
        }

        printf("%04x:%04x (bus %d, device %d)",
            desc.idVendor, desc.idProduct,
            libusb_get_bus_number(dev), libusb_get_device_address(dev));

        r = libusb_get_port_numbers(dev, path, sizeof(path));
        if (r > 0) {
            printf(" path: %d", path[0]);
            for (j = 1; j < r; j++)
                printf(".%d", path[j]);
        }
        printf("\n");
    }
}

int port_open (libusb_device* dev, libusb_device_handle** dev_handle){ //Homebrew func. Retries after failed libusb_open
    int count = 0;
    int err = 0;
    printf("Attempting to open port...\n");
    while (1){
        printf(".\n");
        err = libusb_open(dev, &dev_handle); //Attempts to open port
        if (err == 0){
            break;
        }
        if(count>TIMEOUT){      //5s without the port opening and it will throw error
            printf(libusb_error_name(err));
            return -1;
        }
        count++;
        delay(1);
    }
    return 0;

}


static int target_find(libusb_device *dev){ //Check for device. Libusb already had this but it was done before I saw it.
    struct libusb_device_descriptor my_dev;
    libusb_get_device_descriptor(dev,&my_dev);
    if ((my_dev.idVendor == VENDOR) && (my_dev.idProduct == PRODUCT)){
        return 1;
    }
    return 0;
}


int main(void)
{   
    
    int r;
    int err = 0;
    err = libusb_init(NULL);
    if (err != 0) {
        printf("LIBUSB ERROR: Could not initialize\n");                                                                                                                                                                                                                     
        return -1;
    }
    libusb_device **list;
    libusb_device *found = NULL;


    while(1){   //Finds device and opens port
        ssize_t cnt = libusb_get_device_list(NULL, &list);
        ssize_t i = 0;
        err = 0;
        if (cnt < 0){
            printf("USB ERROR: Could not fetch device list\n");
            return -1;
        }
        for (i = 0; i < cnt; i++) {
            libusb_device *device = list[i];
            if (target_find(device)) {
                found = device;
                break;
            }
        }
        
        if (found) {
            printf("Port found!\n");
            struct libusb_device_descriptor desc;
            struct libusb_config_descriptor config;
            err = libusb_get_device_descriptor(found,&desc);
            if (err){
                printf(libusb_error_name(err));
                return -1;
            }
            err = libusb_get_config_descriptor(found,0,&config);
            if (err){
                printf(libusb_error_name(err));
                return -1;
            }

            libusb_device_handle *handle;
            err = port_open(found, &handle);
            if (err){
                printf("\n Timeout ERROR: Could not open port\n");
                return -1;
            }
            break;
        }
        libusb_free_device_list(list, 1); //Free device list so I can refresh. Unclear if this is needed though.
    }
    
    err = libusb_set_configuration(found, 0x1); //Set config 1 for device, should contain 1 interface with two endpoints. I think.
        //The rest here I guess???
   
    return 0;
}
Quasi-modo
  • 23
  • 3
  • I have a general question related to this, that I'm hoping someone who stumbles across this would know the answer to. When trying to emulate USB traffic from wireshark, do you have to "implement" the packets that come from the target device _to_ the host? For example, if there's 4 transactions/packets/etc sent: H(host) -> T(target), T -> H, H->T, T->H, is my code going to have 4 libusb calls? Or only 2; the (Host -> Target) ones? – Raleigh L. Mar 17 '23 at 06:27

1 Answers1

0

To do the configuration portion, you'll have to use:

The URB interrupts are done via libusb_interrupt_transfer()

https://libusb.sourceforge.io/api-1.0/group__libusb__syncio.html#ga0f171a72904a552fc43e6e6564d108a3

Raleigh L.
  • 599
  • 2
  • 13
  • 18