1
1
#!/usr/bin/env python3
2
2
3
- from pcapng import FileScanner , blocks
4
- import struct
3
+ import argparse
5
4
from collections import namedtuple
5
+ import struct
6
6
import sys
7
7
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
+
8
42
# 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
9
45
usb_urb_win_nt = namedtuple (
10
46
'usb_urb_win' ,
11
47
(
54
90
def usb_urb (s ):
55
91
return usb_urb_win_nt (* struct .unpack (usb_urb_win_fmt , bytes (s )))
56
92
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
-
231
93
232
94
def format_hex (buf ):
233
95
return '' .join ('{:02x} ' .format (x ) for x in buf )
@@ -285,9 +147,17 @@ def write_cyacd(path, binary1):
285
147
286
148
write_cyacd_row (f , binary1 [- 1 ][0 ], binary1 [- 1 ][1 ])
287
149
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 )
288
158
289
159
# 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 ):
291
161
with open (path , "wb" ) as f :
292
162
# Write fist padding
293
163
# Verified
@@ -353,7 +223,7 @@ def check_assumptions(img1_binary, img2_binary):
353
223
sys .exit (1 )
354
224
355
225
356
- def decode_pcapng (path , info ):
226
+ def decode_pcapng (path , bus_id , dev , second_first ):
357
227
img1_binary = [] # [(addr, row)]
358
228
img2_binary = [] # [(addr, row)]
359
229
with open (path , "rb" ) as f :
@@ -369,11 +239,13 @@ def decode_pcapng(path, info):
369
239
urb = usb_urb (packet [0 :usb_urb_sz ])
370
240
371
241
# 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 :
373
243
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 :
375
245
img2 = True
376
246
else :
247
+ #print(f"Other device bus_id: {urb.bus_id}, dev: {urb.device}")
248
+ #print(f"bus_id: {bus_id}, dev_id: {dev}")
377
249
continue
378
250
379
251
# Only consider outgoing packets
@@ -399,40 +271,57 @@ def decode_pcapng(path, info):
399
271
print ("{:4d} 0x{:08X} {}" .format (block_no , addr , format_hex (payload )))
400
272
401
273
if img1 :
402
- if info [ ' second_first' ] :
274
+ if second_first :
403
275
img2_binary .append ((addr , payload ))
404
276
else :
405
277
img1_binary .append ((addr , payload ))
406
278
elif img2 :
407
- if info [ ' second_first' ] :
279
+ if second_first :
408
280
img1_binary .append ((addr , payload ))
409
281
else :
410
282
img2_binary .append ((addr , payload ))
411
283
412
284
block_no += 1
413
285
else :
414
- print (block )
286
+ pass
287
+ #print(block)
415
288
return (img1_binary , img2_binary )
416
289
417
290
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 )
424
294
425
295
check_assumptions (img1_binary , img2_binary )
426
296
427
- print ("Firmware version: {}" .format (FW_VERSION ))
297
+ print ("Firmware version: {}" .format (args . version ))
428
298
429
299
print_image_info (img1_binary , 1 )
430
300
print_image_info (img2_binary , 2 )
431
301
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 )
436
312
437
313
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