#!/usr/bin/env python3 """Конвертер дампа USBPcap (pcapng) → лог control-трансферов SET/GET_REPORT. Использование: ./analyze_pcap.py [out.txt] """ import struct import sys # тип блока Enhanced Packet в pcapng BLOCK_ENHANCED_PACKET = 6 # тип transfer'а control в USBPcap XFER_CONTROL = 2 # биты направления в endpoint EP_DIR_IN = 0x80 # device → host; иначе host → device def read_packet_blocks(data: bytes) -> list[bytes]: """Извлечь данные всех Enhanced Packet-блоков из pcapng-файла.""" records = [] off = 0 while off + 12 <= len(data): block_type, block_len = struct.unpack_from(" len(data): break if block_type == BLOCK_ENHANCED_PACKET: caplen = struct.unpack_from(" list[tuple]: """Собрать события SET/GET_REPORT, склеивая setup+data GET-ов по irpid.""" events = [] pending_get = {} # irpid → (iface, request_type, report_id) for packet in records: irpid, endpoint, transfer, data = parse_usb_header(packet) if transfer != XFER_CONTROL or not data: continue if (not endpoint & EP_DIR_IN and len(data) >= 8 and data[0] == 0x21 and data[1] == 0x09): # merged SET_REPORT: setup(8 байт) + payload wValue = struct.unpack("> 8, wValue & 0xFF, data[8:])) elif (endpoint & EP_DIR_IN and len(data) == 8 and data[0] == 0xA1 and data[1] == 0x01): # setup-часть GET_REPORT: данные придут отдельным пакетом с тем же irpid wValue = struct.unpack("> 8, wValue & 0xFF) elif endpoint & EP_DIR_IN and irpid in pending_get: iface, request_type, report_id = pending_get.pop(irpid) events.append(("GET", iface, request_type, report_id, data)) return events def main(): if len(sys.argv) < 2: raise SystemExit(__doc__) src = sys.argv[1] dst = sys.argv[2] if len(sys.argv) > 2 else "/tmp/tx_log.txt" with open(src, "rb") as f: data = f.read() events = parse_events(read_packet_blocks(data)) with open(dst, "w") as f: for num, (kind, iface, rtype, rid, payload) in enumerate(events, 1): f.write(f"{kind} #{num:4d} if={iface} t={rtype} rid={rid:02x} " f"len={len(payload)}: {payload.hex(' ')}\n") print("events:", len(events)) if __name__ == "__main__": main()