Skip to content

Commit dc3b948

Browse files
committed
decode_pcapng: Support all formats
Signed-off-by: Daniel Schaefer <[email protected]>
1 parent 2954da2 commit dc3b948

File tree

1 file changed

+84
-195
lines changed

1 file changed

+84
-195
lines changed

decode_pcapng.py

Lines changed: 84 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,47 @@
11
#!/usr/bin/env python3
22

3-
from pcapng import FileScanner, blocks
4-
import struct
3+
import argparse
54
from collections import namedtuple
5+
import struct
66
import sys
77

8+
from pcapng import FileScanner, blocks
9+
10+
FORMATS = [
11+
# Both binaries stitched right after another
12+
'binary',
13+
# Flashimage, like it's on the flash, with padded regions
14+
'flashimage',
15+
# Two CYACD files, like the CCG3 SDK outputs and FWUPD expects
16+
'cyacd'
17+
]
18+
19+
# CCG3 row size
20+
ROW_SIZE = 128
21+
# CCG3 has a maximum of 1024 rows
22+
MAX_ROWS = 1024
23+
24+
DEBUG = False
25+
VERBOSE = False
26+
27+
# Run the updater on Windows and capture the USB packets with Wireshark and USBPcap
28+
# Then you can use this script to extract the binary from it
29+
#
30+
# Sample files
31+
# -t dp -V 006 -b 1.7 dp-flash-006.pcapng
32+
# -t dp -V 008 -b 1.8 flash-100-to-8.pcapng
33+
# -t dp -V 100 -b 1.6 reflash100.pcapng
34+
# -t dp -V 101 -b 2.12 reflash101.pcapng
35+
# -t hdmi -V 005 -b 1.4 --second-first hdmi-flash-005.pcapng
36+
# -t hdmi -V 006 -b 1.29 hdmi-reflash-006.pcapng
37+
# -t hdmi -V 102 -b 2.8 --second-first hdmi-flash-102.pcapng
38+
# -t hdmi -V 103 -b 2.6 --second-first hdmi-flash-103.pcapng
39+
# -t hdmi -V 104 -b 2.4 --second-first hdmi-flash-104.pcapng
40+
# -t hdmi -V 105 -b 1.26 hdmi-flash-105.pcapng
41+
842
# From https://github.com/JohnDMcMaster/usbrply/blob/master/usbrply/win_pcap.py#L171
43+
# transfer_type=2 is URB_CONTROL
44+
# irp_info: 0 means from host, 1 means from device
945
usb_urb_win_nt = namedtuple(
1046
'usb_urb_win',
1147
(
@@ -54,180 +90,6 @@
5490
def usb_urb(s):
5591
return usb_urb_win_nt(*struct.unpack(usb_urb_win_fmt, bytes(s)))
5692

57-
# transfer_type=2 is URB_CONTROL
58-
# irp_info: 0 means from host, 1 means from device
59-
60-
# To find them, look at the pcap in wireguard and check the source/destination
61-
images = {
62-
'dp-6': {
63-
'type': 'DP',
64-
'version': '006',
65-
'filename': 'dp-flash-006.pcapng',
66-
'second_first': False,
67-
'devices': {
68-
1: {
69-
'busid': 1,
70-
'device': 7,
71-
},
72-
2: {
73-
'busid': 1,
74-
'device': 8,
75-
}
76-
}
77-
},
78-
'8': {
79-
'type': 'DP',
80-
'version': '008',
81-
'filename': 'flash-100-to-8.pcapng',
82-
'second_first': False,
83-
'devices': {
84-
1: {
85-
'busid': 1,
86-
'device': 8,
87-
},
88-
2: {
89-
'busid': 1,
90-
'device': 9,
91-
}
92-
}
93-
},
94-
'100': {
95-
'type': 'DP',
96-
'version': '100',
97-
'filename': 'reflash100.pcapng',
98-
'second_first': False,
99-
'devices': {
100-
1: {
101-
'busid': 1,
102-
'device': 6,
103-
},
104-
2: {
105-
'busid': 1,
106-
'device': 7,
107-
}
108-
}
109-
},
110-
'101': {
111-
'type': 'DP',
112-
'version': '101',
113-
'filename': 'reflash101.pcapng',
114-
'second_first': False,
115-
'devices': {
116-
1: {
117-
'busid': 2,
118-
'device': 12,
119-
},
120-
2: {
121-
'busid': 2,
122-
'device': 13,
123-
}
124-
}
125-
},
126-
# HDMI
127-
'5': {
128-
'type': 'HDMI',
129-
'version': '005',
130-
'filename': 'hdmi-flash-005.pcapng',
131-
'second_first': True,
132-
'devices': {
133-
1: {
134-
'busid': 1,
135-
'device': 4,
136-
},
137-
2: {
138-
'busid': 1,
139-
'device': 5,
140-
}
141-
}
142-
},
143-
'hdmi-6': {
144-
'type': 'HDMI',
145-
'version': '005',
146-
'filename': 'hdmi-reflash-006.pcapng',
147-
'second_first': False,
148-
'devices': {
149-
1: {
150-
'busid': 1,
151-
'device': 29,
152-
},
153-
2: {
154-
'busid': 1,
155-
'device': 30,
156-
}
157-
}
158-
},
159-
102: {
160-
'type': 'HDMI',
161-
'version': '102',
162-
'filename': 'hdmi-flash-102.pcapng',
163-
'second_first': True,
164-
'devices': {
165-
1: {
166-
'busid': 2,
167-
'device': 8,
168-
},
169-
2: {
170-
'busid': 2,
171-
'device': 9,
172-
}
173-
}
174-
},
175-
103: {
176-
'type': 'HDMI',
177-
'version': '103',
178-
'filename': 'hdmi-flash-103.pcapng',
179-
'second_first': True,
180-
'devices': {
181-
1: {
182-
'busid': 2,
183-
'device': 6,
184-
},
185-
2: {
186-
'busid': 2,
187-
'device': 7,
188-
}
189-
}
190-
},
191-
104: {
192-
'type': 'HDMI',
193-
'version': '104',
194-
'filename': 'hdmi-flash-104.pcapng',
195-
'second_first': True,
196-
'devices': {
197-
1: {
198-
'busid': 2,
199-
'device': 4,
200-
},
201-
2: {
202-
'busid': 2,
203-
'device': 5,
204-
}
205-
}
206-
},
207-
'105': {
208-
'type': 'HDMI',
209-
'version': '105',
210-
'filename': 'hdmi-flash-105.pcapng',
211-
'second_first': False,
212-
'devices': {
213-
1: {
214-
'busid': 1,
215-
'device': 26,
216-
},
217-
2: {
218-
'busid': 1,
219-
'device': 27,
220-
}
221-
}
222-
},
223-
}
224-
225-
ROW_SIZE = 128
226-
MAX_ROWS = 1024
227-
228-
DEBUG = False
229-
VERBOSE = False
230-
23193

23294
def format_hex(buf):
23395
return ''.join('{:02x} '.format(x) for x in buf)
@@ -285,9 +147,17 @@ def write_cyacd(path, binary1):
285147

286148
write_cyacd_row(f, binary1[-1][0], binary1[-1][1])
287149

150+
# Just concatenate both firmware binaries
151+
def write_bin(path, binary1, binary2):
152+
with open(path, "wb") as f:
153+
for (_, row) in binary1:
154+
f.write(row)
155+
156+
for (_, row) in binary2:
157+
f.write(row)
288158

289159
# Write the binary in the same layout with padding as on flash
290-
def write_bin(path, binary1, binary2):
160+
def write_flashimage(path, binary1, binary2):
291161
with open(path, "wb") as f:
292162
# Write fist padding
293163
# Verified
@@ -353,7 +223,7 @@ def check_assumptions(img1_binary, img2_binary):
353223
sys.exit(1)
354224

355225

356-
def decode_pcapng(path, info):
226+
def decode_pcapng(path, bus_id, dev, second_first):
357227
img1_binary = [] # [(addr, row)]
358228
img2_binary = [] # [(addr, row)]
359229
with open(path, "rb") as f:
@@ -369,11 +239,13 @@ def decode_pcapng(path, info):
369239
urb = usb_urb(packet[0:usb_urb_sz])
370240

371241
# Filter device
372-
if urb.bus_id == info['devices'][1]['busid'] and urb.device == info['devices'][1]['device']:
242+
if urb.bus_id == bus_id and urb.device == dev:
373243
img1 = True
374-
elif urb.bus_id == info['devices'][2]['busid'] and urb.device == info['devices'][2]['device']:
244+
elif urb.bus_id == bus_id and urb.device == dev+1:
375245
img2 = True
376246
else:
247+
#print(f"Other device bus_id: {urb.bus_id}, dev: {urb.device}")
248+
#print(f"bus_id: {bus_id}, dev_id: {dev}")
377249
continue
378250

379251
# Only consider outgoing packets
@@ -399,40 +271,57 @@ def decode_pcapng(path, info):
399271
print("{:4d} 0x{:08X} {}".format(block_no, addr, format_hex(payload)))
400272

401273
if img1:
402-
if info['second_first']:
274+
if second_first:
403275
img2_binary.append((addr, payload))
404276
else:
405277
img1_binary.append((addr, payload))
406278
elif img2:
407-
if info['second_first']:
279+
if second_first:
408280
img1_binary.append((addr, payload))
409281
else:
410282
img2_binary.append((addr, payload))
411283

412284
block_no += 1
413285
else:
414-
print(block)
286+
pass
287+
#print(block)
415288
return (img1_binary, img2_binary)
416289

417290

418-
def main():
419-
info = images[sys.argv[1]]
420-
FW_VERSION = info['version']
421-
path = '/home/zoid/framework/dp-card-fw-update/{}'.format(info['filename'])
422-
423-
(img1_binary, img2_binary) = decode_pcapng(path, info)
291+
def main(args):
292+
[bus_id, dev] = args.bus_dev.split('.')
293+
(img1_binary, img2_binary) = decode_pcapng(args.pcap, int(bus_id), int(dev), args.second_first)
424294

425295
check_assumptions(img1_binary, img2_binary)
426296

427-
print("Firmware version: {}".format(FW_VERSION))
297+
print("Firmware version: {}".format(args.version))
428298

429299
print_image_info(img1_binary, 1)
430300
print_image_info(img2_binary, 2)
431301

432-
# Write cyacd file, instead of binary because that's what FWUPD expects
433-
#write_bin("{}-{}.bin".format(info['type'], FW_VERSION), img1_binary, img2_binary)
434-
write_cyacd("{}-{}-1.cyacd".format(info['type'], FW_VERSION), img1_binary)
435-
write_cyacd("{}-{}-2.cyacd".format(info['type'], FW_VERSION), img2_binary)
302+
if args.format == 'binary':
303+
write_bin("{}-{}.bin".format(args.type, args.version), img1_binary, img2_binary)
304+
elif args.format == 'flashimage':
305+
write_flashimage("{}-{}.bin".format(args.type, args.version), img1_binary, img2_binary)
306+
elif args.format == 'cyacd':
307+
write_cyacd("{}-{}-1.cyacd".format(args.type, args.version), img1_binary)
308+
write_cyacd("{}-{}-2.cyacd".format(args.type, args.version), img2_binary)
309+
else:
310+
print(f"Invalid Format {args.format}")
311+
sys.exit(1)
436312

437313
if __name__ == "__main__":
438-
main()
314+
parser = argparse.ArgumentParser(description='Extract firmware from PCAPNG capture')
315+
parser.add_argument('-t', '--type', help='Which type of card', required=True, choices=['dp', 'hdmi'])
316+
parser.add_argument('-V', '--version', help='Which firmware version', required=True)
317+
parser.add_argument('-f', '--format', help='Which output format', required=True, choices=FORMATS)
318+
parser.add_argument('-v', '--verbose', help='Verbose', action='store_true')
319+
parser.add_argument('-b', '--bus-dev', help='Bus ID and Device of first time. Example: 1.23')
320+
parser.add_argument('--second-first', help='If the second image was update first', default=False, action='store_true')
321+
parser.add_argument('pcap', help='Path to the pcap file')
322+
args = parser.parse_args()
323+
324+
if args.verbose:
325+
VERBOSE = True
326+
327+
main(args)

0 commit comments

Comments
 (0)