Decryping, but encoding is borked

This commit is contained in:
Nichlas Severinsen 2018-06-23 18:58:38 +02:00
parent 730b54d6bf
commit cfa8b1ca66
3 changed files with 101 additions and 25 deletions

1
.gitignore vendored
View file

@ -1,6 +1,7 @@
# Custom # Custom
*.iso *.iso
*.ird *.ird
*.txt
ird ird
region_* region_*

View file

@ -21,11 +21,32 @@ import sys
import gzip import gzip
ORDER = 'big' ORDER = 'big'
IRD_ORDER = 'little'
SECTOR = 2048 SECTOR = 2048
def bytes_to_int(byte): def bytes_to_int(byte):
return int.from_bytes(byte, ORDER) return int.from_bytes(byte, ORDER)
def ird_bytes_to_int(byte):
return int.from_bytes(byte, IRD_ORDER)
def read_seven_bit_encoded_int(fileobj):
# Read out an Int32 7 bits at a time. The high bit
# of the byte when on means to continue reading more bytes
count = 0
shift = 0
byte = -1
while (byte & 0x80) != 0 or byte == -1:
# Check for a corrupted stream. Read a max of 5 bytes.
if shift == (5 * 7):
raise ValueError
byte = ird_bytes_to_int(fileobj.read(1))
count |= (byte & 0x7F) << shift
shift += 7
print(byte, count, shift)
return count
class IRD: class IRD:
def is_compressed(self, fileobj): def is_compressed(self, fileobj):
@ -38,28 +59,54 @@ class IRD:
outfile.write(gzfile.read()) outfile.write(gzfile.read())
def __init__(self, filename): def __init__(self, filename):
with open(filename, 'rb') as fileobj: with open(filename, 'rb') as fileobj:
if self.is_compressed(fileobj): if self.is_compressed(fileobj):
self.uncompress(filename) self.uncompress(filename)
self.size = os.stat('ird').st_size self.size = os.stat('ird').st_size
with open('ird', 'rb') as ird: with open('ird', 'rb') as ird:
self.magic_string = ird.read(4) self.magic_string = ird.read(4)
self.version = bytes_to_int(ird.read(1)) self.version = ird_bytes_to_int(ird.read(1))
self.game_id = ird.read(9) self.game_id = ird.read(9)
self.game_name = ird.read(12) length = read_seven_bit_encoded_int(ird)
self.game_name = ird.read(length)
self.update_version = ird.read(4) self.update_version = ird.read(4)
self.game_version = ird.read(5) self.game_version = ird.read(5)
self.app_version = ird.read(5)
if self.version == 7: if self.version == 7:
self.identifier = ird.read(4) self.identifier = ird.read(4)
self.header = ird.read(SECTOR*3) if self.version < 9:
self.footer = ird.read(SECTOR) back = ird.tell()
self.region_count = ird.read(1) length = read_seven_bit_encoded_int(ird)
if length:
self.header = ird.read(length)
else:
ird.seek(back)
back = ird.tell()
length = read_seven_bit_encoded_int(ird)
if length:
self.footer = ird.read(length)
else:
ird.seek(back)
self.region_count = ird_bytes_to_int(ird.read(1))
self.region_hash = []
for i in range(0, self.region_count):
self.region_hash.append(ird.read(16))
self.file_count = ird_bytes_to_int(ird.read(4))
print(vars(self) )
return
sys.exit()
back = ird.tell() back = ird.tell()
prefix = bytes_to_int(ird.read(1)) prefix = bytes_to_int(ird.read(1))
length = prefix >> 1 length = prefix >> 1
if prefix & 0b00000001: if prefix & 0b00000001:
ird.seek(back) ird.seek(back)
self.header = ird.read(length) self.header = ird.read(length)
back = ird.tell() back = ird.tell()
@ -68,8 +115,6 @@ class IRD:
ird.seek(back) ird.seek(back)
self.footer = ird.read(length) self.footer = ird.read(length)
self.region_count self.region_count
print()
sys.exit()
print(self.game_name, self.update_version, self.game_version, self.region_count) print(self.game_name, self.update_version, self.game_version, self.region_count)

View file

@ -21,8 +21,10 @@
import os import os
import sys import sys
import core import core
import base64
import struct import struct
import shutil import shutil
import binascii
from Crypto.Cipher import AES from Crypto.Cipher import AES
def bytes_to_int(byte): def bytes_to_int(byte):
@ -34,16 +36,35 @@ def int_to_hexstr(integer):
def int_to_bytes(integer): def int_to_bytes(integer):
return bytes(bytearray.fromhex(int_to_hexstr(integer))) return bytes(bytearray.fromhex(int_to_hexstr(integer)))
def hexstr_to_bytes(hexstr):
return bytes(bytearray.fromhex(hexstr))
def bprint(byte): def bprint(byte):
byteint = bytes_to_int(byte) byteint = bytes_to_int(byte)
print(byte, '\t->', byteint, '\t->', byteint*8, '\t->', byteint*2048 ) print(byte, '\t->', byteint, '\t->', byteint*8, '\t->', byteint*2048 )
def decode(self, text):
'''
Remove the PKCS#7 padding from a text string
'''
nl = len(text)
val = int(binascii.hexlify(text[-1]), 16)
if val > self.k:
raise ValueError('Input is not padded or padding is corrupt')
l = nl - val
return text[:l]
BS = 32
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[:-ord(s[len(s)-1:])]
if __name__ == '__main__': if __name__ == '__main__':
core.IRD('ird') #core.IRD('BCAS20001-CA107E13820801F29488EBEB7D82A2C4.ird')
#core.IRD('BLES00048-1AA29AD85F7770BDCED0B7030067D59A.ird')
sys.exit() #sys.exit()
bprint(b'\x00\x00\x00\x00') bprint(b'\x00\x00\x00\x00')
bprint(b'\x00\x00\x0c\xbf') bprint(b'\x00\x00\x0c\xbf')
@ -51,21 +72,29 @@ if __name__ == '__main__':
bprint(b'\x00\x00s\xc2\x7f') bprint(b'\x00\x00s\xc2\x7f')
bprint(b'\x00\x00s\xc2\x80') bprint(b'\x00\x00s\xc2\x80')
data = bytes(bytearray.fromhex("02EE0CE9E4C7CC1AD739ACC0DB6A3AA1")) data = hexstr_to_bytes("11089487d46ec9c1ec71205c2a6e8adc")
key = bytes(bytearray.fromhex("380bcf0b53455b3c7817ab4fa3ba90ed")) key = hexstr_to_bytes("380bcf0b53455b3c7817ab4fa3ba90ed")
iv = bytes(bytearray.fromhex("69474772af6fdab342743aefaa186287")) iv = hexstr_to_bytes("69474772af6fdab342743aefaa186287")
cipher = AES.new(key, AES.MODE_CBC, iv) cipher = AES.new(key, AES.MODE_CBC, iv)
disc_key = cipher.encrypt(data) disc_key = cipher.encrypt(data)
print(disc_key)
print(disc_key.hex())
disc_key = hexstr_to_bytes("01AD4F9DFED22E37998BDDC57E135935")
print(disc_key.hex())
print(unpad(disc_key.hex()))
disc_key = hexstr_to_bytes("DCD55A55B033905C58E7FE2A7F969F27")
regions = [ regions = [
{'start': 0, 'end': 6682624, 'enc': False}, {'start': 0, 'end': 6682624, 'enc': False},
{'start': 6682624, 'end': 59641856, 'enc': True}, {'start': 6682624, 'end': 59641856, 'enc': True},
{'start': 59641856, 'end': 15537010688, 'enc': False}, {'start': 59641856, 'end': 15537010688, 'enc': False},
{'start': 15537010688, 'end': 15537012736, 'enc': True }
# There's also a last sector between 15537010688 and 15537012736, but seems like it's not used # There's also a last sector between 15537010688 and 15537012736, but seems like it's not used
] ]
files = [] files = []
test = hexstr_to_bytes("70c2a1")
with open(sys.argv[1], 'rb') as iso: with open(sys.argv[1], 'rb') as iso:
for i, region in enumerate(regions): for i, region in enumerate(regions):
files.append('region_' + str(i)) files.append('region_' + str(i))
@ -81,16 +110,20 @@ if __name__ == '__main__':
while iso.tell() < region['end']: while iso.tell() < region['end']:
data = iso.read(core.SECTOR) data = iso.read(core.SECTOR)
num = iso.tell() num = iso.tell()
iv = ['' for i in range(0,16)] iv = bytearray([0 for i in range(0,16)])
for j in range(0,16): for j in range(0,16):
iv[16 - j - 1] = hex(ord(struct.pack("B", num & 0xFF))).replace('0x','') iv[16 - j - 1] = (num & 0xFF)
num >>= 8 num >>= 8
iv = "".join(iv)[-16:]
#print(iv)
cipher = AES.new(disc_key, AES.MODE_CBC, iv) cipher = AES.new(disc_key, AES.MODE_CBC, bytes(iv))
output.write(cipher.decrypt(data)) decrypted = cipher.decrypt(data)
if test in decrypted:
print(iv.hex())
print(data.hex())
print(decrypted.hex())
output.write(decrypted)
print(iso.tell()) print(iso.tell())
@ -164,6 +197,3 @@ if __name__ == '__main__':