Skip to content

Instantly share code, notes, and snippets.

@tiliarou
Forked from CTCaer/tx_unpack.py
Created July 10, 2018 15:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tiliarou/9338e242262cab88db6c46ba87faf299 to your computer and use it in GitHub Desktop.
Save tiliarou/9338e242262cab88db6c46ba87faf299 to your computer and use it in GitHub Desktop.
###############################################
# TX SX OS unpacker - by hexkyz and naehrwert #
###############################################
from Crypto.Cipher import AES
from Crypto.Util import Counter
import os
import struct
"""
typedef struct boot_dat_hdr
{
unsigned char ident[0x10];
unsigned char sha2_s2[0x20];
unsigned int s2_dst;
unsigned int s2_size;
unsigned int s2_enc;
unsigned char pad[0x10];
unsigned int s3_size;
unsigned char pad2[0x90];
unsigned char sha2_hdr[0x20];
} boot_dat_hdr_t;
"""
def aes_ctr_dec(buf, key, iv):
ctr = Counter.new(128, initial_value=long(iv.encode('hex'), 16))
return AES.new(key, AES.MODE_CTR, counter=ctr).encrypt(buf)
f = open("boot.dat", "rb")
b = f.read()
f.close()
boot_ver = struct.unpack("I", b[0x0C:0x10])[0]
s2_base, s2_size = struct.unpack("II", b[0x30:0x38])
s2_key = "47E6BFB05965ABCD00E2EE4DDF540261".decode("hex")
s2_ctr = "8E4C7889CBAE4A3D64797DDA84BDB086".decode("hex")
if boot_ver == 0x302E3156: # TX BOOT V1.0
arm64_key = "35D8FFC4AA1BAB9514825EB0658FB493".decode("hex")
arm64_ctr = "C38EA26FF3CCE98FD8D5ED431D9D5B94".decode("hex")
arm64_off = 0x53BAB0
arm64_size = 0x36370
arm64_base = 0x80FFFE00
fb_key = "E2AC05206A701C9AA514D2B2B7C9F395".decode("hex")
fb_ctr = "46FAB59AF0E469EF116614DEC366D15F".decode("hex")
fb_off = 0x17BAB0
fb_size = 0x3C0000
fb_base = 0xF0000000
payload_key = "030D865B7E458B10AD5706F6E227F4EB".decode("hex")
payload_ctr = "AFFC93692EBD2E3D252339F01E03416B".decode("hex")
payload_off = 0x5F40
payload_size = 0x175B70
payload_base = 0x80000000
elif boot_ver == 0x312E3156: # TX BOOT V1.1
arm64_key = "51A39F0B46BAE4691AD39A698146E865".decode("hex")
arm64_ctr = "7A307ED7F1ECC792F0E821ECD6999853".decode("hex")
arm64_off = 0x53BAE0
arm64_size = 0x36370
arm64_base = 0x80FFFE00
fb_key = "27BABEE3DCFEF100C744A2388B57E957".decode("hex")
fb_ctr = "0B88AC25AFAF9B92D81372331AD66E24".decode("hex")
fb_off = 0x17BAE0
fb_size = 0x3C0000
fb_base = 0xF0000000
payload_key = "8D6FEABE0F3936145A474D3F05D33679".decode("hex")
payload_ctr = "2846EFA9DACB065C51C71C154F0E9EA2".decode("hex")
payload_off = 0x5F50
payload_size = 0x175B90
payload_base = 0x80000000
elif boot_ver == 0x322E3156: # TX BOOT V1.2
arm64_key = "22429923901AF74ED6944992C824ACFE".decode("hex")
arm64_ctr = "590BE04550CC6139921D1C95241F34AC".decode("hex")
arm64_off = 0x53BAD0
arm64_size = 0x36370
arm64_base = 0x80FFFE00
fb_key = "E483A884AB59D5D0014404C2EB698517".decode("hex")
fb_ctr = "55A60F59F29DD518B4CAA59D0E3D1629".decode("hex")
fb_off = 0x17BAD0
fb_size = 0x3C0000
fb_base = 0xF0000000
payload_key = "AF8F5811D075F5317924E5C1DD70A531".decode("hex")
payload_ctr = "78219A2BB518BF9E302AFF75CE5862E1".decode("hex")
payload_off = 0x5F50
payload_size = 0x175B80
payload_base = 0x80000000
elif boot_ver == 0x332E3156: # TX BOOT V1.3
arm64_key = "0DA0D677361625E81FD6DF236B9450D5".decode("hex")
arm64_ctr = "B368ECA0F8C078908F6B979613D0E52A".decode("hex")
arm64_off = 0x53BB00
arm64_size = 0x36370
arm64_base = 0x80FFFE00
fb_key = "1E76718F0BAF7D8BB72ECCE4F657DAF8".decode("hex")
fb_ctr = "4B0D81D9F44B8458F1EA93324C40BCD1".decode("hex")
fb_off = 0x17BB00
fb_size = 0x3C0000
fb_base = 0xF0000000
payload_key = "5B52BF7DED400C967FB0B2E013B55E68".decode("hex")
payload_ctr = "A1E038CE082F2C26052BE75F111CE3D1".decode("hex")
payload_off = 0x5F70
payload_size = 0x175B90
payload_base = 0x80000000
else:
exit()
# Create main folder
if not os.path.exists("./sxos/"):
os.mkdir("./sxos/")
os.chdir("./sxos/")
# Create folder for the initial boot files
if not os.path.exists("./init/"):
os.mkdir("./init/")
os.chdir("./init/")
# Decrypt Stage2 IRAM payload
f = open("stage2_{0:08X}.bin".format(s2_base), "wb")
f.write(aes_ctr_dec(b[0x100:0x100+s2_size], s2_key, s2_ctr))
f.close()
# Decrypt ARM64 memory training blob
f = open("arm64_{0:08X}.bin".format(arm64_base), "wb")
f.write(aes_ctr_dec(b[arm64_off:arm64_off+arm64_size], arm64_key, arm64_ctr))
f.close()
# Decrypt initial framebuffer binary
f = open("fb_{0:08X}.bin".format(fb_base), "wb")
f.write(aes_ctr_dec(b[fb_off:fb_off+fb_size], fb_key, fb_ctr))
f.close()
# Create folder for the obfuscation payloads
if not os.path.exists("../payloads/"):
os.mkdir("../payloads/")
os.chdir("../payloads/")
# Decrypt first layer's obfuscation payload
f = open("payload_{0:08X}.bin".format(payload_base), "wb")
f.write(aes_ctr_dec(b[payload_off:payload_off+payload_size], payload_key, payload_ctr))
f.close()
if boot_ver == 0x332E3156: # TX BOOT V1.3
payload_key = "36FC59BEBA2AABC77D124668E025350E".decode("hex")
payload_ctr = "E773714BD860B532A356F2C6A07B843E".decode("hex")
payload_off = 0xC0B920
payload_size = 0xF5B20
payload_base = 0x90000000
# Decrypt second layer's obfuscation payload
f = open("payload_{0:08X}.bin".format(payload_base), "wb")
f.write(aes_ctr_dec(b[payload_off:payload_off+payload_size], payload_key, payload_ctr))
f.close()
payload_key = "9334A1F1943C16B2506BB1D9EBF33F93".decode("hex")
payload_ctr = "7BE8A72FBA0943AE57E93E6F6D6FB46A".decode("hex")
payload_off = 0xD01440
payload_size = 0xBC290
payload_base = 0x98000000
# Decrypt third layer's obfuscation payload
f = open("payload_{0:08X}.bin".format(payload_base), "wb")
f.write(aes_ctr_dec(b[payload_off:payload_off+payload_size], payload_key, payload_ctr))
f.close()
payload_key = "F1AC8CB71383F07FAF34C12879025BEE".decode("hex")
payload_ctr = "86B9D01C6FFAAF157CE31AE1162A7C48".decode("hex")
payload_off = 0xDBD6D0
payload_size = 0x1312E0
payload_base = 0xA0000000
# Decrypt fourth layer's obfuscation payload
f = open("payload_{0:08X}.bin".format(payload_base), "wb")
f.write(aes_ctr_dec(b[payload_off:payload_off+payload_size], payload_key, payload_ctr))
f.close()
# Create folder for the bootloader
if not os.path.exists("../bootloader/"):
os.mkdir("../bootloader/")
os.chdir("../bootloader/")
bootloader_key = "C439958095F3AC5CA361E46481A778B4".decode("hex")
bootloader_ctr = "07E32283C45EC5215DEFDBB199AD2F5B".decode("hex")
bootloader_off = 0x571E70
bootloader_size = 0x20FC0
bootloader_base = 0x88000000
assets_key = "5E5C65FA5C93C43BD8BA5B7B93A59687".decode("hex")
assets_ctr = "45E156D62914D27529AA7A8B7EAC8A31".decode("hex")
assets_off = 0x592E30
assets_size = 0x4C0400
assets_base = 0x88020FC0
# Decrypt SX OS bootloader's code and assets
f = open("bootloader_{0:08X}.bin".format(bootloader_base), "wb")
f.write(aes_ctr_dec(b[bootloader_off:bootloader_off+bootloader_size], bootloader_key, bootloader_ctr))
f.write(aes_ctr_dec(b[assets_off:assets_off+assets_size], assets_key, assets_ctr))
f.close()
os.chdir("../payloads/")
# Open final firmware binary (encrypted)
f = open("payload_A0000000.bin", "rb")
b = f.read()
f.close()
key = "264AAE11C24A65AB99E021788BFE6E66".decode("hex")
ctr = "71C68F4C9CBB2203AC267B917BAC76B0".decode("hex")
off = 0
size = 0x1312E0
# Decrypt final firmware binary
f = open("payload_A0000000_dec.bin", "wb")
f.write(aes_ctr_dec(b[off:off+size], key, ctr))
f.close()
# Open final firmware binary (decrypted)
f = open("payload_A0000000_dec.bin", "rb")
b = f.read()
f.close()
# Create folder for the patcher binaries
if not os.path.exists("../patcher/"):
os.mkdir("../patcher/")
os.chdir("../patcher/")
patcher_size = struct.unpack("I", b[0x00:0x04])[0]
patcher_off = struct.unpack("I", b[0x04:0x08])[0]
patcher_base = struct.unpack("I", b[0x08:0x0C])[0]
patcher_crc = struct.unpack("I", b[0x0C:0x10])[0]
patcher_hash = struct.unpack("8I", b[0x10:0x30])
# Parse and store the PK11 patcher
f = open("patcher_{0:08X}.bin".format(patcher_base), "wb")
f.write(b[patcher_off:patcher_off+patcher_size])
f.close()
patcher_size = struct.unpack("I", b[0x30:0x34])[0]
patcher_off = struct.unpack("I", b[0x34:0x38])[0]
patcher_base = struct.unpack("I", b[0x38:0x3C])[0]
patcher_crc = struct.unpack("I", b[0x3C:0x40])[0]
patcher_hash = struct.unpack("8I", b[0x40:0x60])
# Parse and store the KIP1/INI1 patcher
f = open("patcher_{0:08X}.bin".format(patcher_base), "wb")
f.write(b[patcher_off:patcher_off+patcher_size])
f.close()
patcher_size = struct.unpack("I", b[0x60:0x64])[0]
patcher_off = struct.unpack("I", b[0x64:0x68])[0]
patcher_base = struct.unpack("I", b[0x68:0x6C])[0]
patcher_crc = struct.unpack("I", b[0x6C:0x70])[0]
patcher_hash = struct.unpack("8I", b[0x70:0x90])
# Parse and store the kernel patcher
f = open("patcher_{0:08X}.bin".format(patcher_base), "wb")
f.write(b[patcher_off:patcher_off+patcher_size])
f.close()
# Create folder for the actual firmware binaries
if not os.path.exists("../firmware/"):
os.mkdir("../firmware/")
os.chdir("../firmware/")
kip_size = struct.unpack("I", b[0x90:0x94])[0]
kip_off = struct.unpack("I", b[0x94:0x98])[0]
kip_base = struct.unpack("I", b[0x98:0x9C])[0]
kip_crc = struct.unpack("I", b[0x9C:0xA0])[0]
kip_hash = struct.unpack("8I", b[0xA0:0xC0])
# Parse and store the Loader KIP1
f = open("kip_{0:08X}.bin".format(kip_base), "wb")
f.write(b[kip_off:kip_off+kip_size])
f.close()
kip_size = struct.unpack("I", b[0xC0:0xC4])[0]
kip_off = struct.unpack("I", b[0xC4:0xC8])[0]
kip_base = struct.unpack("I", b[0xC8:0xCC])[0]
kip_crc = struct.unpack("I", b[0xCC:0xD0])[0]
kip_hash = struct.unpack("8I", b[0xD0:0xF0])
# Parse and store the sm KIP1
f = open("kip_{0:08X}.bin".format(kip_base), "wb")
f.write(b[kip_off:kip_off+kip_size])
f.close()
kip_size = struct.unpack("I", b[0xF0:0xF4])[0]
kip_off = struct.unpack("I", b[0xF4:0xF8])[0]
kip_base = struct.unpack("I", b[0xF8:0xFC])[0]
kip_crc = struct.unpack("I", b[0xFC:0x100])[0]
kip_hash = struct.unpack("8I", b[0x100:0x120])
# Parse and store the fs.mitm KIP1
f = open("kip_{0:08X}.bin".format(kip_base), "wb")
f.write(b[kip_off:kip_off+kip_size])
f.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment