Skip to content

Instantly share code, notes, and snippets.

@marcnewlin
Created December 11, 2023 04:33
Show Gist options
  • Save marcnewlin/c936d1530fb5e3648aca23d7c08c9628 to your computer and use it in GitHub Desktop.
Save marcnewlin/c936d1530fb5e3648aca23d7c08c9628 to your computer and use it in GitHub Desktop.
script to extract firmware images from Alienware AW920K update tools
#!/usr/bin/env python3
'''
Firmware updates for the Alienware AW920K keyboard (and dongle) are encrypted
using a key derived from the size of the update.
This tool extracts the unencrypted firmware images from the update packages.
Instructions:
1. Download the Alienware AW920K firmware updates (dongle and keyboard):
https://www.dell.com/support/home/en-us/drivers/driversdetails?driverid=py9mn
https://www.dell.com/support/home/en-us/drivers/driversdetails?driverid=xff5j
2. Place the update packages in the same directory as this script
> ls
AW920K_Dongle_v0051.exe AW920K_Keyboard_v0051.exe extract-firmware.py
3. Run the script
> ./extract-firmware.py
success! wrote 75876 bytes to dongle.bin
success! wrote 66400 bytes to keyboard.2G4.bin
success! wrote 109856 bytes to keyboard.BLE.bin
success! wrote 109952 bytes to keyboard.USB.bin
4. The decrypted firmware images will be saved in the current directory
> ls *.bin
dongle.bin keyboard.2G4.bin keyboard.BLE.bin keyboard.USB.bin
'''
import binascii
import crcmod
import re
import struct
from Crypto.Cipher import AES
def read_ini(raw, name):
m = re.search(b"%s=([a-fA-F0-9]+)" % name.encode(), raw)
if m is None: return m
return m.group(1)
def decrypt(blob, fw_len=None):
if fw_len is None:
fw_len = len(blob)
seed = struct.pack(">IIII", fw_len, fw_len, fw_len, fw_len)
ecb = AES.new(seed, AES.MODE_ECB)
key = ecb.encrypt(seed)
cbc = AES.new(key, AES.MODE_CBC, iv=key)
return cbc.decrypt(blob)
def pad(chunk):
if len(chunk) % 16 == 0:
return chunk
else:
chunk += b"\x00"*(16-(len(chunk)%16))
return chunk
def extract_AW920K_Dongle_v0051_exe():
# load the updater binary
with open("AW920K_Dongle_v0051.exe", "rb") as f:
data = f.read()
# read the firmware length
fw_len = int(read_ini(data, "INI_FW_LEN"))
fw_len_not_padded = fw_len
if fw_len % 16 != 0:
fw_len = fw_len - (fw_len % 16) + 16
# read the expected firmware crc
crc_given = read_ini(data, "INI_FW_CRC")
crc_given = struct.unpack(">I", binascii.unhexlify(crc_given))[0]
# extract and decrypt the firmware image
magic = b"\x00\x00\x00\x00IEND\xAE\x42\x60\x82"
ix = data.find(magic) + len(magic)
fw_enc = data[ix:ix+fw_len]
fw_dec = decrypt(fw_enc, fw_len)[:fw_len_not_padded]
# validate crc and save the image to disk
crc32 = crcmod.mkCrcFun(0x104C11DB7, 1, True, 0xffffffff)
crc = crc32(fw_dec)
if crc != crc_given:
print("CRC check failed (expected=0x%08x, actual=0x%08x)" % (crc_given, crc))
else:
with open("dongle.bin", "wb") as f:
f.write(fw_dec)
print("success! wrote %d bytes to %s" % (len(fw_dec), "dongle.bin"))
def extract_AW920K_Keyboard_v0051_exe():
# load the updater binary
with open("AW920K_Keyboard_v0051.exe", "rb") as f:
data = f.read()
names = ["2G4", "BLE", "USB"]
# read the firmware lengths
lengths = [int(read_ini(data, "INI_%s_FW_SIZE"%n)) for n in names]
for x in range(len(names)):
if lengths[x] % 16 != 0:
lengths[x] += (16 - (lengths[x] % 16))
# read the expected checksums
checksums = [int(read_ini(data, "INI_%s_FW_CHKSUM"%n), 16) for n in names]
# extract the encrypted firmware blobs
magic = b"\x00\x00\x00\x00IEND\xAE\x42\x60\x82"
ix = data.find(magic) + len(magic)
for x in range(len(names)):
chunk = data[ix+sum(lengths[:x]):ix+sum(lengths[:x+1])]
fw_dec = decrypt(chunk)
path = "keyboard.%s.bin" % names[x]
# validate checksum and save the image to disk
cksum = sum(fw_dec)
if cksum != checksums[x]:
print("bad checksum (expected=0x%08x, actual=0x%08x)" % (checksums[x], cksum))
else:
with open(path, "wb") as f:
f.write(fw_dec)
print("success! wrote %d bytes to %s" % (len(fw_dec), path))
if __name__ == "__main__":
extract_AW920K_Dongle_v0051_exe()
extract_AW920K_Keyboard_v0051_exe()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment