Skip to content

Instantly share code, notes, and snippets.

@userlandkernel
Created April 20, 2020 00:40
Show Gist options
  • Save userlandkernel/5a69d2f1f25a98f7b58a175af4322810 to your computer and use it in GitHub Desktop.
Save userlandkernel/5a69d2f1f25a98f7b58a175af4322810 to your computer and use it in GitHub Desktop.
Forensic USB utility
/**
* USB Forenic Analyzer
* Written by @userlandkernel
* Powered by the free and opensource libusb (https://libusb.org)
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <libusb-1.0/libusb.h>
libusb_context* ctx = NULL;
libusb_device **devices = NULL;
ssize_t count = 0;
const char* libusb_class_string(enum libusb_class_code code){
switch(code) {
case LIBUSB_CLASS_PER_INTERFACE:
return "Interface Specific";
case LIBUSB_CLASS_AUDIO:
return "Audio";
case LIBUSB_CLASS_COMM:
return "Communcation";
case LIBUSB_CLASS_HID:
return "Human Interface Device";
case LIBUSB_CLASS_PHYSICAL:
return "Physical";
case LIBUSB_CLASS_PRINTER:
return "Printer";
case LIBUSB_CLASS_PTP:
return "PTP";
case LIBUSB_CLASS_MASS_STORAGE:
return "Mass Storage";
case LIBUSB_CLASS_DATA:
return "Data";
case LIBUSB_CLASS_SMART_CARD:
return "Smart card";
case LIBUSB_CLASS_CONTENT_SECURITY:
return "Content Security";
case LIBUSB_CLASS_VIDEO:
return "Video";
case LIBUSB_CLASS_PERSONAL_HEALTHCARE:
return "Personal Healthcare";
case LIBUSB_CLASS_DIAGNOSTIC_DEVICE:
return "Diagnostic device";
case LIBUSB_CLASS_WIRELESS:
return "Wireless class";
case LIBUSB_CLASS_APPLICATION:
return "Application class";
case LIBUSB_CLASS_VENDOR_SPEC:
return "Vendor specific";
default:
return "Unknown class";
}
}
const char* libusb_desc_type_string(enum libusb_descriptor_type type) {
switch(type) {
case LIBUSB_DT_DEVICE:
return "Device";
case LIBUSB_DT_CONFIG:
return "Configuration";
case LIBUSB_DT_STRING:
return "String";
case LIBUSB_DT_INTERFACE:
return "Interface";
case LIBUSB_DT_ENDPOINT:
return "Endpoint";
case LIBUSB_DT_BOS:
return "BOS";
case LIBUSB_DT_DEVICE_CAPABILITY:
return "Device Capability";
case LIBUSB_DT_HID:
return "HID";
case LIBUSB_DT_REPORT:
return "HID report";
case LIBUSB_DT_PHYSICAL:
return "Physical";
case LIBUSB_DT_HUB:
return "Hub";
case LIBUSB_DT_SUPERSPEED_HUB:
return "SuperSpeed Hub";
case LIBUSB_DT_SS_ENDPOINT_COMPANION:
return "SuperSpeed Endpoint Companion";
default:
return "Unknown descriptor";
}
}
void init(void) {
// Initialize libusb
libusb_init(&ctx);
// Retrieve attached devices
count = libusb_get_device_list(ctx, &devices);
}
void terminate(void) {
if(devices)
libusb_free_device_list(devices, count);
libusb_exit(ctx);
}
void hr(void) {
for(int i = 0; i < 80; i++) {
putchar('-');
}
putchar('\n');
}
libusb_device* find(uint16_t vid, uint16_t pid) {
// Go over all devices
for(int i = 0; i < count; i++) {
libusb_device* dev = devices[i];
// Retrieve descriptor
struct libusb_device_descriptor desc = {0};
libusb_get_device_descriptor(dev, &desc);
if(desc.idVendor == vid && desc.idProduct == pid)
return dev;
}
return NULL;
}
int main(int argc, char *argv[]){
init();
if(argc <= 2) {
printf("Usage: %s [vid] [pid]\n\tTip: Consider running lsusb to find devices to analyze\n\n", argv[0]);
return 1;
}
uint16_t vid = strtol(argv[1], NULL, 16);
uint16_t pid = strtol(argv[2], NULL, 16);
libusb_device* iphone = find(vid, pid);
if(!iphone) {
printf(" Could not find the device, are you sure it's attached to the BUS?\n");
return 1;
}
uint64_t bus = libusb_get_bus_number(iphone);
uint64_t address = libusb_get_device_address(iphone);
printf("\n");
hr();
printf(" USB FORENISCS BY @userlandkernel. Compiled on %s %s\n", __DATE__, __TIME__);
hr();
printf("\n");
printf(" Bus: %#lx\n", bus);
printf(" Address: %#lx\n", address);
struct libusb_device_descriptor desc = {0};
libusb_get_device_descriptor(iphone, &desc);
printf("\n");
printf(" Descriptor size: %d bytes\n", desc.bLength);
printf(" Descriptor type: %s\n", libusb_desc_type_string(desc.bDescriptorType));
printf(" USB Release: %#x\n", desc.bcdUSB);
printf("\n");
printf(" VID / PID: %04x:%04x\n", desc.idVendor, desc.idProduct);
printf(" Device class: %s\n", libusb_class_string(desc.bDeviceClass));
printf(" Device sub-class: %s\n", libusb_class_string(desc.bDeviceSubClass));
printf(" Device protocol: %#x\n", desc.bDeviceProtocol);
printf(" Device Release: %#x\n", desc.bcdDevice);
printf(" Max packet size EP0: %d\n", desc.bMaxPacketSize0);
printf(" Number of configurations: %d\n", desc.bNumConfigurations);
printf("\n");
libusb_device_handle* handle = NULL;
if( libusb_open(iphone, &handle) != LIBUSB_SUCCESS ) {
perror("Failed to open device");
return 1;
}
unsigned char string[256];
if(libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string))) {
printf("\tManufacturer: %s\n", (char*)string);
}
if(libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string))) {
printf("\tProduct: %s\n", (char*)string);
}
if(libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string))) {
printf("\tSerial Number: %s\n", (char*)string);
}
printf("\n");
// Print Configurations
for(int i = 0; i < desc.bNumConfigurations; i++) {
struct libusb_config_descriptor* config = NULL;
if( libusb_get_config_descriptor(iphone, i, &config) != LIBUSB_SUCCESS) {
perror(" Couldn't retrieve configuration descriptor.\n");
continue;
}
printf(" Configuration #%d\n", i+1);
hr();
printf("\tTotal length: %u", config->wTotalLength);
printf("\tInterface count: %u\n", config->bNumInterfaces);
printf("\tConfiguration value: %u\n", config->bConfigurationValue);
printf("\tConfiguration index: %u\n", config->iConfiguration);
printf("\tAttributes: %02xh\n", config->bmAttributes);
printf("\tMax. power: %u\n\n", config->MaxPower);
// Print interfaces
for(int j = 0; j < config->bNumInterfaces; j++) {
const struct libusb_interface *iface = &config->interface[j];
printf("\tInterface #%d\n", j+1);
printf("\n");
// Print settings
for(int k = 0; k < iface->num_altsetting; k++) {
const struct libusb_interface_descriptor *ifdesc = &iface->altsetting[k];
printf("\t\tSetting #%d\n", k+1);
printf("\t\t\tInterface number: %u\n", ifdesc->bInterfaceNumber);
printf("\t\t\tAlternate setting: %u\n", ifdesc->bAlternateSetting);
printf("\t\t\tEndpoint count: %u\n", ifdesc->bNumEndpoints);
printf("\t\t\tInterface class: %s\n", libusb_class_string(ifdesc->bInterfaceClass));
printf("\t\t\tInterface sub-class: %s\n", libusb_class_string(ifdesc->bInterfaceSubClass));
printf("\t\t\tInterface protocol: %#x\n", ifdesc->bInterfaceProtocol);
printf("\t\t\tInterface index: %d\n\n", ifdesc->iInterface);
printf("\n");
// Print endpoints
for(int l = 0; l < ifdesc->bNumEndpoints; l++) {
const struct libusb_endpoint_descriptor* ep = &ifdesc->endpoint[l];
printf("\t\t\tEndpoint %#02x\n", l);
printf("\t\t\t\tEndpoint Address: %#02x\n", ep->bEndpointAddress);
printf("\t\t\t\tAttributes: %#02x\n", ep->bmAttributes);
printf("\t\t\t\tMax. packetsize: %u\n", ep->wMaxPacketSize);
printf("\t\t\t\tInterval: %u\n", ep->bInterval);
printf("\t\t\t\tRefresh: %u\n", ep->bRefresh);
printf("\t\t\t\tSync. Address: %u\n", ep->bSynchAddress);
for(int k = 0; k < ep->extra_length; k++){
if( ep->extra[i + 1] == LIBUSB_DT_SS_ENDPOINT_COMPANION ) {
printf("\t\t\t\tHAS_ENDPOINTCOMPANION!\n");
}
}
printf("\n");
}
}
printf("\n");
}
if(config)
libusb_free_config_descriptor(config);
}
terminate();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment