Linux环境下USB端口流量重定向、直通及数据修改的技术咨询
Linux环境下USB端口流量重定向、直通及数据修改的技术咨询
当然可以实现!你的需求本质上是让Linux机器充当一个USB中间代理——一端作为USB Host连接目标设备,另一端以USB Gadget身份模拟该设备,同时在中间层拦截、修改传输的数据。下面我会从硬件要求、核心实现思路到具体操作步骤给你拆解清楚:
一、硬件前提检查
首先得确认你的Linux机器具备同时运行USB Host和USB Gadget的硬件条件:
- 你的机器需要至少两个独立的USB控制器:一个用于Host模式(连接外部USB设备),另一个支持Gadget模式(作为模拟设备对外连接)。可以用
lsusb -t或lspci命令查看控制器信息,比如树莓派4B的部分USB端口支持模式切换,x86机器通常有多个独立控制器。 - 确保内核已启用USB Gadget相关模块:一般需要
libcomposite、usb_f_generic等模块,可通过modprobe libcomposite加载,或者在/etc/modules中配置开机自动加载。
二、核心技术栈与实现思路
你的需求需要三个核心环节:
- Gadget端模拟Host设备:通过Linux USB Gadget子系统,完全镜像Host端设备的硬件描述符(包括vendor ID、product ID、设备类、接口描述符等),让下游设备误以为连接的是原USB设备。
- Host端流量捕获:通过
libusb或usbmon捕获Host端与目标设备之间的所有USB传输数据包(控制、批量、中断等类型)。 - 数据转发与修改:在中间层对捕获到的数据包进行修改(增删改),再将处理后的数据包转发到Gadget端,同时反向处理Gadget端的请求并转发回Host端。
三、具体操作步骤
1. 捕获Host端设备的硬件信息
先连接目标USB设备到Host端口,用usb-devices命令获取设备的关键信息:
usb-devices
找到目标设备的idVendor、idProduct、bcdDevice、设备类(bDeviceClass)等参数,这些是配置Gadget的核心依据。
2. 配置USB Gadget模拟原设备
以模拟一个通用USB设备为例,创建Gadget配置:
# 创建Gadget目录 mkdir -p /sys/kernel/config/usb_gadget/my_usb_proxy cd /sys/kernel/config/usb_gadget/my_usb_proxy # 设置设备ID(对应Host端设备的信息) echo 0x1234 > idVendor # 替换为实际的vendor ID echo 0x5678 > idProduct # 替换为实际的product ID echo 0x0100 > bcdDevice # 配置字符串描述符 mkdir -p strings/0x409 echo "My USB Proxy" > strings/0x409/manufacturer echo "Proxy Device" > strings/0x409/product # 配置功能函数(这里用通用函数,根据设备类型调整,比如HID、存储等) mkdir -p functions/generic.0 ln -s functions/generic.0 configs/c.1/ # 绑定到Gadget端口(替换为你的USB控制器,比如usb1) echo "usb1" > UDC
3. 编写流量拦截与修改程序
用libusb编写C程序(或Python的pyusb库)实现双向转发与修改,核心逻辑如下:
#include <libusb-1.0/libusb.h> // 全局变量:Host端设备句柄、Gadget端设备句柄 libusb_device_handle *host_dev = NULL; libusb_device_handle *gadget_dev = NULL; // 处理Host端数据包的回调函数 int host_transfer_cb(struct libusb_transfer *transfer) { // 这里可以修改transfer->buffer中的数据 if (transfer->endpoint == 0x01) { // 批量输出端点 modify_data(transfer->buffer, transfer->actual_length); } // 将修改后的数据发送到Gadget端对应端点 libusb_bulk_transfer(gadget_dev, transfer->endpoint, transfer->buffer, transfer->actual_length, NULL, 0); // 重新提交传输,持续监听 libusb_submit_transfer(transfer); return 0; } // 主函数:初始化设备、监听传输 int main() { libusb_init(NULL); // 打开Host端设备(替换为实际的VID/PID) host_dev = libusb_open_device_with_vid_pid(NULL, 0x1234, 0x5678); // 打开Gadget端设备(这里假设Gadget已配置为对应VID/PID) gadget_dev = libusb_open_device_with_vid_pid(NULL, 0x1234, 0x5678); // 配置Host端端点监听(以批量端点为例) struct libusb_transfer *host_xfer = libusb_alloc_transfer(0); unsigned char buffer[512]; libusb_fill_bulk_transfer(host_xfer, host_dev, 0x81, // 批量输入端点 buffer, sizeof(buffer), host_transfer_cb, NULL, 0); libusb_submit_transfer(host_xfer); // 事件循环,持续处理传输 while (1) { libusb_handle_events(NULL); } libusb_close(host_dev); libusb_close(gadget_dev); libusb_exit(NULL); return 0; }
(注:实际使用时需要根据设备的端点配置、传输类型调整代码,同时实现Gadget端到Host端的反向转发逻辑)
四、注意事项与兼容性问题
- 权限问题:操作USB设备需要root权限,或者通过udev规则给普通用户授予USB设备的访问权限。
- 复杂设备适配:对于加密狗、带自定义协议的工业外设等,可能需要更细致地处理控制传输的交互逻辑,确保设备枚举和正常工作。
- 内核版本:建议使用4.14以上的Linux内核,USB Gadget子系统在新版本中功能更完善,兼容性更好。
备注:内容来源于stack exchange,提问作者Dennis Solomon




