#!/usr/bin/env python # Silicon Labs Si2168 firmware extractor. # Copyright (C) 2015 Antti Palosaari # Usage: si2168_extract_firmware.py binary_driver_name.sys import sys import struct import md5 fread = file(sys.argv[1], 'rb') binary = fread.read() offset = 0 # Known firmware md5 and its version fw_ver_tab = { 'b2670d8ae5e3369fc71edbb98cdd8f6e' : '4.0.11', '8dfc2483d90282bbb05817fbbc282376' : '4.0.19', 'c8e089c351e9834060e962356f8697b8' : '4.0.25', } while True: # Match 17-byte firmware header # 04 01 00 00 00 00 9a 41 05 1b af 33 02 1b 3e 7d 2a | A20 (not supported) # 08 05 00 xx xx xx xx xx xx 00 00 00 00 00 00 00 00 | B40 offset = binary.find('\x08\x05\x00', offset) if offset == -1: print "Done" break if (binary[offset + 9:offset + 17] != '\x00\x00\x00\x00\x00\x00\x00\x00'): offset = offset + 1 continue print "17-byte firmware found at 0x%x" % (offset) fw_filename = 'dvb-demod-si2168-b40-01.fw_' + str(offset) fw_write = open(fw_filename, 'wb') fw_md5 = md5.new() while True: fields = struct.unpack("B", binary[offset]) fw_data_len = fields[0] # Firmware chunk first byte tells bytes to upload - 16 is max if fw_data_len > 16: print "Firmware upload len too large %d" % (fw_data_len) break # Check remaining (unused) bytes on firmware 17-byte chunk are all zero data_valid = True for x in range(offset + fw_data_len + 1, offset + 17): if (binary[x] != '\x00'): data_valid = False break if data_valid == False: break # Firmware chunk validated, write it to file fw_write.write(binary[offset + 0:offset + 17]) fw_md5.update(binary[offset + 0:offset + 17]) offset = offset + 17 fw_write.close() if fw_md5.hexdigest() in fw_ver_tab: fw_ver = fw_ver_tab[fw_md5.hexdigest()] else: fw_ver = '' print "Firmware md5 '%s'" % (fw_md5.hexdigest()) print "Firmware version '%s'" % (fw_ver) print "Firmware stored to file '%s'" % (fw_filename) offset = offset + 1 fread.close()