如何向指定USB设备发送目标字节序列?(支持Python/Java/Bash无GUI)
解决USB设备字节序列发送问题
我来帮你搞定这个问题——直接往/dev/bus/usb/XXX/XXX写数据失败,本质是因为USB设备通信得遵循USB协议规范,不是像写普通文件那样丢字节流就行。你得先从Wireshark/usbmon的抓包结果里抠出关键参数(比如传输类型、端点地址、控制传输的请求参数),再用对应的工具或库来发送数据。下面分几种语言给你具体方案:
第一步:先确认核心参数(必须做)
从抓包结果里提取以下信息,这是所有方案的基础:
- 传输类型:是Control(控制传输,最常见的设备指令交互方式)还是Bulk(批量传输)?
- 如果是控制传输:需要
bmRequestType、bRequest、wValue、wIndex这四个参数,以及要发送的字节内容 - 如果是批量传输:需要目标输出端点地址(比如
0x01)
方案1:Bash 实现(适合快速测试)
先确保安装libusb相关工具(Debian/Ubuntu系):
sudo apt install libusb-1.0-0-dev usbutils
控制传输示例
假设你抓包得到的参数是:bmRequestType=0x21、bRequest=0x09、wValue=0x0001、wIndex=0x0000,字节序列是01 02 03,用usb-send命令发送:
sudo usb-send -b 1 -d 5 -t control -r 0x21 -R 0x09 -v 0x0001 -i 0x0000 -D "01 02 03"
-b是总线号,-d是设备号(对应你lsusb的Bus 001 Device 005)
批量传输示例
如果是批量传输,先找输出端点地址(比如0x01),可以用lsusb -v -d 04b4:0a0a查看端点信息,然后用pyusb的命令行工具(或者写个简单Python脚本)配合Bash调用:
# 先安装pyusb pip install pyusb # 然后写个简单脚本send_bulk.py,再用Bash调用 sudo python3 send_bulk.py
方案2:Python 实现(推荐,灵活易集成)
用pyusb库,这是Python操作USB设备的标准工具,灵活性拉满。
安装依赖
pip install pyusb
控制传输示例
把你抓包的参数填到下面的脚本里:
import usb.core import usb.util # 匹配你的设备ID VENDOR_ID = 0x04b4 PRODUCT_ID = 0x0a0a # 从抓包提取的控制传输参数 BM_REQUEST_TYPE = 0x21 B_REQUEST = 0x09 W_VALUE = 0x0001 W_INDEX = 0x0000 # 要发送的字节序列(替换成你的抓包内容) DATA = b'\x01\x02\x03\x04' # 查找设备 dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID) if not dev: raise ValueError("设备未找到,请检查lsusb输出") # 解除内核驱动绑定(如果设备被内核占用) if dev.is_kernel_driver_active(0): try: dev.detach_kernel_driver(0) except usb.core.USBError as e: raise RuntimeError(f"无法解除内核驱动绑定: {str(e)}") # 设置设备配置 dev.set_configuration() # 发送控制传输 try: dev.ctrl_transfer(BM_REQUEST_TYPE, B_REQUEST, W_VALUE, W_INDEX, DATA) print("字节序列发送成功") except usb.core.USBError as e: print(f"发送失败: {str(e)}") # 可选:恢复内核驱动绑定(如果需要设备正常使用) usb.util.dispose_resources(dev) if not dev.is_kernel_driver_active(0): dev.attach_kernel_driver(0)
批量传输示例
如果是批量传输,替换成下面的脚本:
import usb.core import usb.util VENDOR_ID = 0x04b4 PRODUCT_ID = 0x0a0a # 抓包得到的输出端点地址 OUT_ENDPOINT = 0x01 DATA = b'\x01\x02\x03\x04' dev = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID) if not dev: raise ValueError("设备未找到") if dev.is_kernel_driver_active(0): dev.detach_kernel_driver(0) dev.set_configuration() # 获取输出端点 endpoint = dev[0][(0, 0)][OUT_ENDPOINT] try: dev.write(endpoint.bEndpointAddress, DATA) print("批量传输发送成功") except usb.core.USBError as e: print(f"发送失败: {str(e)}") # 恢复驱动绑定 usb.util.dispose_resources(dev) if not dev.is_kernel_driver_active(0): dev.attach_kernel_driver(0)
注意:运行脚本需要sudo权限,或者通过udev规则给普通用户授权(见下文注意事项)。
方案3:Java 实现
用usb4java库,适合Java项目集成。
添加Maven依赖
<dependency> <groupId>org.usb4java</groupId> <artifactId>usb4java</artifactId> <version>1.3.0</version> </dependency>
控制传输示例代码
import org.usb4java.*; public class UsbLockSender { public static void main(String[] args) { // 初始化libusb Context context = new Context(); int result = LibUsb.init(context); if (result != LibUsb.SUCCESS) { throw new RuntimeException("初始化libusb失败: " + LibUsb.strError(result)); } // 打开设备 DeviceHandle handle = new DeviceHandle(); result = LibUsb.openDeviceWithVidPid(context, (short) 0x04b4, (short) 0x0a0a, handle); if (result != LibUsb.SUCCESS) { throw new RuntimeException("无法打开设备: " + LibUsb.strError(result)); } try { // 解除内核驱动绑定 if (LibUsb.kernelDriverActive(handle, 0)) { result = LibUsb.detachKernelDriver(handle, 0); if (result != LibUsb.SUCCESS) { throw new RuntimeException("无法解除内核驱动: " + LibUsb.strError(result)); } } // 声明接口 result = LibUsb.claimInterface(handle, 0); if (result != LibUsb.SUCCESS) { throw new RuntimeException("无法声明接口: " + LibUsb.strError(result)); } // 准备发送数据 byte[] data = {0x01, 0x02, 0x03, 0x04}; IntBuffer transferred = IntBuffer.allocate(1); // 发送控制传输 result = LibUsb.controlTransfer( handle, (byte) 0x21, // bmRequestType (byte) 0x09, // bRequest (short) 0x0001, // wValue (short) 0x0000, // wIndex data, transferred, 1000 // 超时时间(毫秒) ); if (result == LibUsb.SUCCESS) { System.out.println("发送成功,传输字节数: " + transferred.get(0)); } else { throw new RuntimeException("控制传输失败: " + LibUsb.strError(result)); } } finally { // 释放资源 LibUsb.releaseInterface(handle, 0); if (!LibUsb.kernelDriverActive(handle, 0)) { LibUsb.attachKernelDriver(handle, 0); } LibUsb.close(handle); LibUsb.exit(context); } } }
关键注意事项
- 权限问题:所有操作USB设备的程序都需要root权限,或者你可以创建udev规则给普通用户授权:
创建/etc/udev/rules.d/50-usb-lock.rules文件:
然后重新加载规则:SUBSYSTEM=="usb", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0a0a", MODE="0666"sudo udevadm control --reload-rules && sudo udevadm trigger - 内核驱动占用:如果设备被内核驱动(比如usbhid)占用,必须先解除绑定才能操作,否则会报错。
- 参数准确性:所有传输参数必须和抓包结果完全一致,差一个字节都可能无法触发解锁行为。
内容的提问来源于stack exchange,提问作者Salocin
相关产品推荐
相关产品推荐

