fix: option versions are different; fix header metadat, formatting

This commit is contained in:
beerpsi 2024-07-18 03:31:34 +07:00
parent 8ca3bc37ba
commit 5c40c357c6

View File

@ -9,7 +9,16 @@ import zlib
from Crypto.Cipher import AES, PKCS1_OAEP from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Hash import HMAC, SHA1 from Crypto.Hash import HMAC, SHA1
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from construct import Bytes, Const, Int16ul, Int32ul, Int64ul, Int8ul, Struct from construct import (
Bytes,
Const,
IfThenElse,
Int16ul,
Int32ul,
Int64ul,
Int8ul,
Struct,
)
# ---- Configuration # ---- Configuration
ENCRYPTION_KEY = bytes.fromhex("") ENCRYPTION_KEY = bytes.fromhex("")
@ -28,11 +37,7 @@ BOOTID = {
"second": 43, "second": 43,
"milli": 0, "milli": 0,
}, },
"game_version": { "game_version": b"A041",
"release": 0,
"minor": 30,
"major": 1,
},
"block_size": 0x40000, "block_size": 0x40000,
"header_block_count": 8, "header_block_count": 8,
"unk1": 0, "unk1": 0,
@ -57,7 +62,8 @@ BOOTID = {
"minor": 54, "minor": 54,
"major": 80, "major": 80,
}, },
"strings": b"\x00" * 0x27AC, # Depending on the app/opt/pack, this might have some text in it. "strings": b"\x00"
* 0x27AC, # Depending on the app/opt/pack, this might have some text in it.
} }
# ---- # ----
@ -65,7 +71,9 @@ BOOTID = {
# The BootID (app/opt/pack header) encryption key and IV. # The BootID (app/opt/pack header) encryption key and IV.
BTKEY = bytes.fromhex("09ca5efd30c9aaef3804d0a7e3fa7120") BTKEY = bytes.fromhex("09ca5efd30c9aaef3804d0a7e3fa7120")
BTIV = bytes.fromhex("b155c22c2e7f0491fa7f0fdc217aff90") BTIV = bytes.fromhex("b155c22c2e7f0491fa7f0fdc217aff90")
SIGKEY = bytes.fromhex("e1bdcb2d5e9ed3b5de234364dfa4d126849edff769fc6c28fba5f43bc482bd7479d676afce8188e1d3a6852f4ebce45cde46bd15e8ee5fe84d197f945a54518f") SIGKEY = bytes.fromhex(
"e1bdcb2d5e9ed3b5de234364dfa4d126849edff769fc6c28fba5f43bc482bd7479d676afce8188e1d3a6852f4ebce45cde46bd15e8ee5fe84d197f945a54518f"
)
HEADER_META_PUBKEY = RSA.import_key("""-----BEGIN PUBLIC KEY----- HEADER_META_PUBKEY = RSA.import_key("""-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsRMLnJuczNpfoqPpHQ3o MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsRMLnJuczNpfoqPpHQ3o
5XNkjKXO6P3ToV/45Az5dNaHVL7uEu9vPI7a2KYFQnNYgD3UUHFahfTcljzLOkcH 5XNkjKXO6P3ToV/45Az5dNaHVL7uEu9vPI7a2KYFQnNYgD3UUHFahfTcljzLOkcH
@ -107,7 +115,7 @@ BootID = Struct(
"sequence_number" / Int16ul, "sequence_number" / Int16ul,
"game_id" / Bytes(4), "game_id" / Bytes(4),
"game_timestamp" / Timestamp, "game_timestamp" / Timestamp,
"game_version" / Version, "game_version" / IfThenElse(lambda ctx: ctx.type == 0x0201, Bytes(4), Version),
"block_count" / Int64ul, "block_count" / Int64ul,
"block_size" / Int64ul, "block_size" / Int64ul,
"header_block_count" / Int64ul, "header_block_count" / Int64ul,
@ -120,6 +128,7 @@ BootID = Struct(
"strings" / Bytes(0x27AC), "strings" / Bytes(0x27AC),
) )
def get_page_iv(iv: bytes, offset: int): def get_page_iv(iv: bytes, offset: int):
return bytes(x ^ (offset >> (8 * (i % 8))) & 0xFF for (i, x) in enumerate(iv)) return bytes(x ^ (offset >> (8 * (i % 8))) & 0xFF for (i, x) in enumerate(iv))
@ -134,11 +143,27 @@ print(f"Generated IV: {iv.hex()}")
filesize = os.stat(INPUT_FILE).st_size filesize = os.stat(INPUT_FILE).st_size
BOOTID["block_count"] = ceil(filesize / BOOTID["block_size"]) + 8 BOOTID["block_count"] = ceil(filesize / BOOTID["block_size"]) + 8
header_meta = struct.pack("<Q", time.time()) + os.path.abspath(INPUT_FILE).encode("utf-8") key = secrets.token_bytes(16)
header_meta += secrets.token_bytes(BOOTID["block_size"] - len(header_meta)) iv = secrets.token_bytes(16)
header_meta = PKCS1_OAEP.new(HEADER_META_PUBKEY).encrypt(header_meta) encrypted_keypair = PKCS1_OAEP.new(HEADER_META_PUBKEY).encrypt(key + iv)
header_meta = struct.pack("<Q", int(time.time())) + os.path.abspath(INPUT_FILE).encode(
"utf-8"
)
header_meta += secrets.token_bytes(
BOOTID["block_size"] - len(header_meta) - len(encrypted_keypair)
)
header_meta = encrypted_keypair + AES.new(key, AES.MODE_CBC, iv).encrypt(header_meta)
header_meta_crc32 = zlib.crc32(header_meta) header_meta_crc32 = zlib.crc32(header_meta)
block_crc32s = [0, header_meta_crc32, header_meta_crc32, header_meta_crc32, header_meta_crc32, header_meta_crc32, header_meta_crc32, header_meta_crc32] block_crc32s = [
0,
header_meta_crc32,
header_meta_crc32,
header_meta_crc32,
header_meta_crc32,
header_meta_crc32,
header_meta_crc32,
header_meta_crc32,
]
with open(INPUT_FILE, "rb") as fin, open(OUTPUT_FILE, "w+b") as fout: with open(INPUT_FILE, "rb") as fin, open(OUTPUT_FILE, "w+b") as fout:
# Write the bootID. # Write the bootID.
@ -207,7 +232,9 @@ with open(INPUT_FILE, "rb") as fin, open(OUTPUT_FILE, "w+b") as fout:
# Skip the HMAC signature and the first CRC32, which we're trying to calculate. # Skip the HMAC signature and the first CRC32, which we're trying to calculate.
_ = fout.seek(0x204, os.SEEK_CUR) _ = fout.seek(0x204, os.SEEK_CUR)
block_0_crc32 = zlib.crc32(fout.read(BOOTID["block_size"] - 0x2800 - 0x204), block_0_crc32) block_0_crc32 = zlib.crc32(
fout.read(BOOTID["block_size"] - 0x2800 - 0x204), block_0_crc32
)
_ = fout.seek(0x2A00) _ = fout.seek(0x2A00)
_ = fout.write(struct.pack("<I", block_0_crc32)) _ = fout.write(struct.pack("<I", block_0_crc32))
@ -227,4 +254,3 @@ with open(INPUT_FILE, "rb") as fin, open(OUTPUT_FILE, "w+b") as fout:
_ = fout.seek(0x2800) _ = fout.seek(0x2800)
_ = fout.write(hmac.digest()) _ = fout.write(hmac.digest())