Skip to content

Instantly share code, notes, and snippets.

@x0rloser
Created March 14, 2019 00:53
Show Gist options
  • Save x0rloser/a88b964d8c0195d879cf7ed7f77fee27 to your computer and use it in GitHub Desktop.
Save x0rloser/a88b964d8c0195d879cf7ed7f77fee27 to your computer and use it in GitHub Desktop.
python3 code to extract the Dell firmware update for SKHynix SSD.
#
# python3 code to extract the Dell firmware update for SKHynix SSD.
#
# hacked together over morning coffee by xorloser 14th march 2019
#
# STEPS TO USE THIS
# This is where to download the exe packed file.
# https://www.dell.com/support/home/il/he/bsd/drivers/driversdetails?driverid=6p63y&lwp=rt
# https://downloads.dell.com/FOLDER04062662M/6/20005A00%20A03_ZPE.exe
# Run the exe packed file "20005A00%20A03_ZPE.exe" to get it to self extract somewhere.
# One of the extracted files will be "SKhynix_NVMe_Toolbox_Dell_Win_v24_20005A00.exe".
# Open this in 7zip and extract to ".rsrc/FIRMWARE/156".
# This is the main firmware file collection.
# I renamed this to "firmware.bin".
# Run this script in python3 to extract the various parts of the firmware.
# INFO ABOUT VARIOUS PARTS OF THE FIRMWARE
# The main file appears to be a collection of 4 firmwares,
# but has space in its headers to handle at least 8 firmwares.
# Each firmware then contains multiple layers of entries within entries,
# like a russian doll. Each extracted firmware is treated as the outer most
# layer of entries.
# Each entry that has sub entries starts with a list of entry-info for its sub entries.
# The first entry-info appears to always be "DSSLREVF".
# So an easy way to tell if an entry contains sub entries is by looking for that.
import struct
import os
def makedir(dirname):
try:
os.mkdir(dirname)
except FileExistsError:
pass
def extract_entry_info(data):
# 0 8 name
# 8 4 size
# C 4 offset_or_size (what is this????)
# 10 4 offset
# 14 4 zero
# 18 4 size2
# 1C 4 crc
entry = struct.unpack("<8sIIIIII", data[:0x20])
# if entry[1] != entry[5]:
# print("sizes in hdr for %s do not match: 0x%X vs 0x%X" % (entry[0], entry[1], entry[5]))
# if entry[2] != entry[3]:
# print("offsets in hdr for %s do not match: 0x%X vs 0x%X" % (entry[0], entry[2], entry[3]))
return entry
# this entry is the first on most firmware blocks, except for the outermost block
# probably because the outermost bvlock is actually a collection of different firmware files
# for the various models of the device that the firmware is for.
def extract_revf_info(data):
# 0 8 name
# 8 4 crc
# C 8 some number string (ascii)
# 14 4 size
# 18 8 magic values "EC D7 14 76 54 20 11 00"
entry = struct.unpack("<8sI8sIII", data[:0x20])
return entry
def extract_entries(outputDirpath, data, level):
makedir(outputDirpath)
done_extracting = False
first_offset = -1
for off in range(0, len(data), 0x20):
if done_extracting or (first_offset > 0 and off >= first_offset):
print("done extracting at %X" % off)
break
entry = extract_entry_info(data[off:off+0x20])
if level>=2 and off==0 and entry[0] != b"DSSLREVF":
print("no DSSLREVF found, so must be leaf entry") # %s" % entry[0].decode("utf-8"))
break
# skip entries with 0 offset and size
size=entry[1]
offset=entry[3]
if size==0 and offset==0:
print("skipping zero entry")
continue
entry_name = entry[0].decode("utf-8")
# handle "DSSLREVF" entries specially
if entry_name[7]=="F":
revf_info = extract_revf_info
print("skipping DSSLREVF entry")
continue
# handle all other types of entries
if first_offset < 0:
first_offset = offset
print("setting first offset to %X" % first_offset)
if size + offset >= len(data):
done_extracting = True
print(entry)
entry_name = entry[0].decode("utf-8")
entry_dirname = os.path.join(outputDirpath, entry_name)
entry_filename = os.path.join(entry_dirname, entry_name)
makedir(entry_dirname)
entry_data = data[offset:offset+size]
with open(entry_filename, "wb") as entry_file:
entry_file.write(entry_data)
# extract all subentries
extract_entries(entry_dirname, entry_data, level+1)
# main entry point for this script
fw_filename = "firmware.bin"
extract_dir = "extracted"
fw_file_data = None
with open(fw_filename, "rb") as fw_file:
fw_file_data = fw_file.read()
extract_entries(extract_dir, fw_file_data, 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment