decode: add some python tools to decode SniffUSB dumps

decode.py will read SniffUSB logs of communication with
QMUX or WMC speaking devices.  It will dump the packets
in both hex and ASCII.  If you know something about the
device then you can tell it to decode the packets.  For
example, we know the Pantech UML290's WMC port speaks
WMC using Bulk Transfers, so we can:

decode.py --transfer=wmc <path to sniffusb logs>

or we know the UML290's "rmnet" port speaks raw IP in
the Bulk Transfers and QMUX in the Control Transfers, so:

decode.py --control=qmux <path to sniffusb logs>

qmiprotgen.py takes a path to an Entities.txt file and
dumps out the protocol entities and services in
Python code which is used by qmux.py.

xml2ascii.py and analyze.py dump out UsbSnoopy XML logs
but these are not as usable as the SniffUSB logs (they
do not provide good direction information).

http://www.wingmanteam.com/usbsnoopy/
http://www.pcausa.com/Utilities/UsbSnoop/
This commit is contained in:
Dan Williams
2011-12-30 20:36:01 -06:00
parent a2b578d755
commit c9d0dea5b0
9 changed files with 3788 additions and 0 deletions

211
decode/wmc.py Normal file
View File

@@ -0,0 +1,211 @@
#!/usr/bin/python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details:
#
# Copyright (C) 2011 Red Hat, Inc.
#
import binascii
import struct
import defs
def unpack(data, direction):
# unpack the data
if direction == defs.TO_MODEM:
if data[:14] == "41542a574d433d":
# remove the AT*WMC= bits, and the newline and CRC at the end
data = data[14:]
if data[len(data) - 2:] == "0d":
data = data[:len(data) - 6]
elif direction == defs.TO_HOST:
if data[len(data) - 2:] == "7e":
# remove HDLC terminator and CRC
data = data[:len(data) - 6]
else:
raise ValueError("No data direction")
data = binascii.unhexlify(data)
# PPP-unescape it
escape = False
new_data = ""
for i in data:
if ord(i) == 0x7D:
escape = True
elif escape == True:
new_data += chr(ord(i) ^ 0x20)
escape = False
else:
new_data += i
return new_data
def show_data(data, prefix):
line = ""
for i in data:
line += " %02x" % ord(i)
print prefix + " Data: %s" % line
def show_device_info(data, prefix, direction):
if direction != defs.TO_HOST:
return
fmt = "<"
fmt = fmt + "27s" # unknown1
fmt = fmt + "64s" # manf
fmt = fmt + "64s" # model
fmt = fmt + "64s" # fwrev
fmt = fmt + "64s" # hwrev
fmt = fmt + "64s" # unknown2
fmt = fmt + "64s" # unknown3
fmt = fmt + "10s" # min
fmt = fmt + "12s" # unknown4
fmt = fmt + "H" # home_sid
fmt = fmt + "6s" # unknown5
fmt = fmt + "H" # eri_ver?
fmt = fmt + "3s" # unknown6
fmt = fmt + "64s" # unknown7
fmt = fmt + "20s" # meid
fmt = fmt + "22s" # imei
fmt = fmt + "16s" # unknown9
fmt = fmt + "22s" # iccid
fmt = fmt + "4s" # unknown10
fmt = fmt + "16s" # MCC
fmt = fmt + "16s" # MNC
fmt = fmt + "4s" # unknown11
fmt = fmt + "4s" # unknown12
fmt = fmt + "4s" # unknown13
fmt = fmt + "1s"
expected = struct.calcsize(fmt)
if len(data) != expected:
raise ValueError("Unexpected Info command response len (got %d expected %d)" % (len(data), expected))
(u1, manf, model, fwrev, hwrev, u2, u3, cdmamin, u4, homesid, u5, eriver, \
u6, u7, meid, imei, u9, iccid, u10, mcc, mnc, u11, u12, u13, u14) = struct.unpack(fmt, data)
print prefix + " Manf: %s" % manf
print prefix + " Model: %s" % model
print prefix + " FW Rev: %s" % fwrev
print prefix + " HW Rev: %s" % hwrev
print prefix + " MIN: %s" % cdmamin
print prefix + " Home SID: %d" % homesid
print prefix + " ERI Ver: %d" % eriver
print prefix + " MEID: %s" % meid
print prefix + " IMEI: %s" % imei
print prefix + " Unk9: %s" % u9
print prefix + " ICCID: %s" % iccid
print prefix + " MCC: %s" % mcc
print prefix + " MNC: %s" % mnc
def show_ip_info(data, prefix, direction):
if direction != defs.TO_HOST:
return
fmt = "<"
fmt = fmt + "I" # rx_bytes
fmt = fmt + "I" # tx_bytes
fmt = fmt + "8s" # unknown3
fmt = fmt + "B" # unknown4
fmt = fmt + "7s" # unknown7
fmt = fmt + "16s" # ip4_address
fmt = fmt + "8s" # netmask?
fmt = fmt + "40s" # ip6_address
expected = struct.calcsize(fmt)
if len(data) != expected:
raise ValueError("Unexpected IP Info command response len (got %d expected %d)" % (len(data), expected))
(rxb, txb, u3, u4, u7, ip4addr, netmask, ip6addr) = struct.unpack(fmt, data)
print prefix + " RX Bytes: %d" % rxb
print prefix + " TX Bytes: %d" % txb
print prefix + " IP4 Addr: %s" % ip4addr
print prefix + " IP6 Addr: %s" % ip6addr
def get_signal(item):
if item == 0x7D:
return (item * -1, "(NO SIGNAL)")
else:
return (item * -1, "")
def show_status(data, prefix, direction):
if direction != defs.TO_HOST:
return
fmt = "<"
fmt = fmt + "B" # unknown1
fmt = fmt + "3s" # unknown2
fmt = fmt + "B" # unknown3
fmt = fmt + "B" # unknown4
fmt = fmt + "10s" # magic
fmt = fmt + "H" # counter1
fmt = fmt + "H" # counter2
fmt = fmt + "B" # unknown5
fmt = fmt + "3s" # unknown6
fmt = fmt + "B" # cdma1x_dbm
fmt = fmt + "3s" # unknown7
fmt = fmt + "16s" # cdma_opname
fmt = fmt + "18s" # unknown8
fmt = fmt + "B" # hdr_dbm
fmt = fmt + "3s" # unknown9
fmt = fmt + "B" # unknown10
fmt = fmt + "3s" # unknown11
fmt = fmt + "B" # unknown12
fmt = fmt + "8s" # lte_opname
fmt = fmt + "60s" # unknown13
fmt = fmt + "B" # lte_dbm
fmt = fmt + "3s" # unknown14
fmt = fmt + "4s" # unknown15
expected = struct.calcsize(fmt)
if len(data) != expected:
raise ValueError("Unexpected Status command response len (got %d expected %d)" % (len(data), expected))
(u1, u2, u3, u4, magic, counter1, counter2, u5, u6, cdma_dbm, u7, cdma_opname, \
u8, hdr_dbm, u9, u10, u11, u12, lte_opname, u13, lte_dbm, u14, u15) = struct.unpack(fmt, data)
print prefix + " Counter1: %s" % counter1
print prefix + " Counter2: %s" % counter2
print prefix + " CDMA dBm: %d dBm %s" % get_signal(cdma_dbm)
print prefix + " CDMA Op: %s" % cdma_opname
print prefix + " HDR dBm: %d dBm %s" % get_signal(hdr_dbm)
print prefix + " LTE Op: %s" % lte_opname
print prefix + " LTE dBm: %d dBm %s" % get_signal(lte_dbm)
def show_init(data, prefix, direction):
show_data(data, prefix)
def show_bearer_info(data, prefix, direction):
pass
cmds = { 0x06: ("DEVICE_INFO", show_device_info),
0x0A: ("IP_INFO", show_ip_info),
0x0B: ("STATUS", show_status),
0x0D: ("INIT", show_init),
0x4D: ("EPS_BEARER_INFO", show_bearer_info)
}
def show(data, prefix, direction):
data = data[1:] # skip 0xC8 header
cmdno = ord(data[:1])
try:
cmdinfo = cmds[cmdno]
except KeyError:
return
data = data[1:] # skip cmdno
print prefix + "WMC Packet:"
print prefix + " Cmd: 0x%02x (%s)" % (cmdno, cmdinfo[0])
cmdinfo[1](data, prefix, direction)
print ""
def get_funcs():
return (unpack, show)