fixes in U8.py - now actualyl makes U8 files, not garbage stupidity. also fixes to IMET and a few other things.

This commit is contained in:
icefire 2009-06-13 14:40:53 -07:00
parent 3512fb6535
commit 27f07bdb2e
3 changed files with 67 additions and 38 deletions

61
U8.py
View File

@ -38,7 +38,7 @@ class U8():
if(os.path.isdir(file)): if(os.path.isdir(file)):
node.type = 0x0100 node.type = 0x0100
self.data_offset = recursion node.data_offset = recursion - 1
recursion += 1 recursion += 1
files = sorted(os.listdir(file)) files = sorted(os.listdir(file))
#if(sorted(files) == ["banner.bin", "icon.bin", "sound.bin"]): #if(sorted(files) == ["banner.bin", "icon.bin", "sound.bin"]):
@ -60,10 +60,9 @@ class U8():
data = f.read() data = f.read()
f.close() f.close()
sz = len(data) sz = len(data)
while len(data) % 32 != 0: data += "\x00" * (align(sz, 64) - sz)
data += "\x00" node.data_offset = len(self.data)
self.data += data self.data += data
node.data_offset = len(data)
node.size = sz node.size = sz
node.type = 0x0000 node.type = 0x0000
if(is_root != 1): if(is_root != 1):
@ -74,11 +73,11 @@ class U8():
This creates valid U8 archives for all purposes.""" This creates valid U8 archives for all purposes."""
header = self.U8Header() header = self.U8Header()
self.rootnode = self.U8Node() rootnode = self.U8Node()
header.tag = "U\xAA8-" header.tag = "U\xAA8-"
header.rootnode_offset = 0x20 header.rootnode_offset = 0x20
header.zeroes = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" header.zeroes = "\x00" * 16
self.nodes = [] self.nodes = []
self.strings = "\x00" self.strings = "\x00"
@ -88,13 +87,16 @@ class U8():
self._pack(".", 0, 1) self._pack(".", 0, 1)
os.chdir(origdir) os.chdir(origdir)
header.header_size = (len(self.nodes) + 1) * len(self.rootnode) + len(self.strings) header.header_size = (len(self.nodes) + 1) * len(rootnode) + len(self.strings)
header.data_offset = align(header.header_size + header.rootnode_offset, 0x40) print "\nstff starts: " + str(align(header.header_size + header.rootnode_offset, 64))
self.rootnode.size = len(self.nodes) + 1 print header.header_size + header.rootnode_offset
self.rootnode.type = 0x0100 header.data_offset = align(header.header_size + header.rootnode_offset, 64)
rootnode.size = len(self.nodes) + 1
rootnode.type = 0x0100
for node in self.nodes: for i in range(len(self.nodes)):
node.data_offset += header.data_offset if(self.nodes[i].type == 0x0000):
self.nodes[i].data_offset += header.data_offset
if(fn == ""): if(fn == ""):
if(self.f[len(self.f) - 4:] == "_out"): if(self.f[len(self.f) - 4:] == "_out"):
@ -102,15 +104,16 @@ class U8():
else: else:
fn = self.f fn = self.f
f = open(fn, "wb") fd = open(fn, "wb")
f.write(header.pack()) fd.write(header.pack())
f.write(self.rootnode.pack()) fd.write(rootnode.pack())
for node in self.nodes: for node in self.nodes:
f.write(node.pack()) fd.write(node.pack())
f.write(self.strings) fd.write(self.strings)
f.write("\x00" * (header.data_offset - header.rootnode_offset - header.header_size)) fd.write("\x00" * (header.data_offset - header.rootnode_offset - header.header_size))
f.write(self.data) print (header.data_offset - header.rootnode_offset - header.header_size)
f.close() fd.write(self.data)
fd.close()
return fn return fn
@ -136,7 +139,7 @@ class U8():
offset += len(rootnode) offset += len(rootnode)
nodes = [] nodes = []
for i in xrange(rootnode.size - 1): for i in range(rootnode.size - 1):
node = self.U8Node() node = self.U8Node()
node.unpack(data[offset:offset + len(node)]) node.unpack(data[offset:offset + len(node)])
offset += len(node) offset += len(node)
@ -296,7 +299,7 @@ class IMET():
self.sizes = Struct.uint32[3] #icon, banner, sound self.sizes = Struct.uint32[3] #icon, banner, sound
self.unk2 = Struct.uint32 self.unk2 = Struct.uint32
self.names = Struct.string(84, encoding = "utf-16-be", stripNulls = True)[7] self.names = Struct.string(84, encoding = "utf-16-be", stripNulls = True)[7]
self.zeroes2 = Struct.uint8[904] self.zeroes2 = Struct.uint8[840]
self.hash = Struct.string(16) self.hash = Struct.string(16)
def __init__(self, f): def __init__(self, f):
self.f = f self.f = f
@ -365,4 +368,16 @@ class IMET():
return "" return ""
imet.unpack(data[:len(imet)]) imet.unpack(data[:len(imet)])
return imet.names[1] name = imet.names[1]
topop = []
for i in range(len(name)):
if(name[i] == "\x00"):
topop.append(i)
name = list(name)
popped = 0 #don't ask me why I did this
for pop in topop:
name.pop(pop - popped)
popped += 1
name = ''.join(name)
return name

30
nand.py
View File

@ -6,7 +6,7 @@ from Crypto.Cipher import AES
from Struct import Struct from Struct import Struct
from common import * from common import *
from title import *
class NAND: class NAND:
@ -95,9 +95,9 @@ class NAND:
cmfp.write(value) cmfp.write(value)
cmfp.close() cmfp.close()
return cnt return cnt
def importTitle(self, prefix, tmd, tik): def importTitle(self, prefix, tmd, tik, is_decrypted = False, result_decrypted = False):
"""When passed a prefix (the directory to obtain the .app files from, sorted by content id), a TMD instance, and a Ticket instance, this will add that title to the NAND base folder specified in the constructor.""" """When passed a prefix (the directory to obtain the .app files from, sorted by content id), a TMD instance, and a Ticket instance, this will add that title to the NAND base folder specified in the constructor. Unless is_decrypted is set, the contents are assumed to be encrypted. If result_decrypted is True, then the contents will not end up decrypted."""
self.ES.AddTitleStart(tmd, None, None) self.ES.AddTitleStart(tmd, None, None, is_decrypted, result_decrypted, use_version = True)
self.ES.AddTitleTMD(tmd) self.ES.AddTitleTMD(tmd)
self.ES.AddTicket(tik) self.ES.AddTicket(tik)
contents = tmd.getContents() contents = tmd.getContents()
@ -167,7 +167,7 @@ class ESClass:
hashout += cmfp.read(20) hashout += cmfp.read(20)
cmfp.close() cmfp.close()
return hashout return hashout
def AddTitleStart(self, tmd, certs, crl): def AddTitleStart(self, tmd, certs, crl, is_decrypted = False, result_decrypted = True, use_version = False):
if(not os.path.isdir(self.f + "/title/%08x" % (tmd.tmd.titleid >> 32))): if(not os.path.isdir(self.f + "/title/%08x" % (tmd.tmd.titleid >> 32))):
os.mkdir(self.f + "/title/%08x" % (tmd.tmd.titleid >> 32)) os.mkdir(self.f + "/title/%08x" % (tmd.tmd.titleid >> 32))
if(not os.path.isdir(self.f + "/title/%08x/%08x" % (tmd.tmd.titleid >> 32, tmd.tmd.titleid & 0xFFFFFFFF))): if(not os.path.isdir(self.f + "/title/%08x/%08x" % (tmd.tmd.titleid >> 32, tmd.tmd.titleid & 0xFFFFFFFF))):
@ -180,6 +180,9 @@ class ESClass:
os.mkdir(self.f + "/ticket/%08x" % (tmd.tmd.titleid >> 32)) os.mkdir(self.f + "/ticket/%08x" % (tmd.tmd.titleid >> 32))
self.workingcids = array.array('L') self.workingcids = array.array('L')
self.wtitleid = tmd.tmd.titleid self.wtitleid = tmd.tmd.titleid
self.is_decrypted = is_decrypted
self.result_decrypted = result_decrypted
self.use_version = use_version
return return
def AddTicket(self, tik): def AddTicket(self, tik):
"""Adds ticket to the title being added.""" """Adds ticket to the title being added."""
@ -261,15 +264,26 @@ class ESClass:
outfp = open(filestr, "wb") outfp = open(filestr, "wb")
data = fp.read() data = fp.read()
titlekey = tik.getTitleKey() titlekey = tik.getTitleKey()
tmpdata = Crypto().DecryptContent(titlekey, contents[idx].index, data) if(self.is_decrypted):
if(Crypto().ValidateHash(tmpdata, contents[idx].hash) == 0): tmpdata = data
else:
tmpdata = Crypto().DecryptContent(titlekey, contents[idx].index, data)
if(Crypto().ValidateSHAHash(tmpdata, contents[idx].hash) == 0):
"Decryption failed! SHA1 mismatch." "Decryption failed! SHA1 mismatch."
return -44 return -44
if(self.result_decrypted != True):
if(self.is_decrypted):
tmpdata = Crypto().EncryptContent(titlekey, contents[idx].index, data)
else:
tmpdata = data
fp.close() fp.close()
outfp.write(tmpdata) outfp.write(tmpdata)
outfp.close() outfp.close()
if(self.tmdadded): if(self.tmdadded and self.use_version):
tmd.rawdump(self.f + "/title/%08x/%08x/content/title.tmd.%d" % (self.wtitleid >> 32, self.wtitleid & 0xFFFFFFFF, tmd.tmd.title_version)) tmd.rawdump(self.f + "/title/%08x/%08x/content/title.tmd.%d" % (self.wtitleid >> 32, self.wtitleid & 0xFFFFFFFF, tmd.tmd.title_version))
elif(self.tmdadded):
tmd.rawdump(self.f + "/title/%08x/%08x/content/title.tmd" % (self.wtitleid >> 32, self.wtitleid & 0xFFFFFFFF))
if(self.ticketadded): if(self.ticketadded):
tik.rawdump(self.f + "/ticket/%08x/%08x.tik" % (self.wtitleid >> 32, self.wtitleid & 0xFFFFFFFF)) tik.rawdump(self.f + "/ticket/%08x/%08x.tik" % (self.wtitleid >> 32, self.wtitleid & 0xFFFFFFFF))
self.AddTitleCancel() self.AddTitleCancel()

View File

@ -59,12 +59,12 @@ class Ticket:
out += " Title ID: %08x-%08x\n" % (self.getTitleID() >> 32, self.getTitleID() & 0xFFFFFFFF) out += " Title ID: %08x-%08x\n" % (self.getTitleID() >> 32, self.getTitleID() & 0xFFFFFFFF)
out += " Title key IV: " out += " Title key IV: "
out += hexdump(report, struct.pack(">Q", self.getTitleID()) + "\x00\x00\x00\x00\x00\x00\x00\x00") out += hexdump(struct.pack(">Q", self.getTitleID()) + "\x00\x00\x00\x00\x00\x00\x00\x00")
out += "\n" out += "\n"
out += " Title key (encrypted): " out += " Title key (encrypted): "
out += hexdump(self.tik.enctitlekey) out += hexdump(self.tik.enctitlekey)
report.write("\n") out += "\n"
out += " Title key (decrypted): " out += " Title key (decrypted): "
out += hexdump(self.getTitleKey()) out += hexdump(self.getTitleKey())
@ -153,11 +153,11 @@ class TMD:
out = "" out = ""
out += " TMD:\n" out += " TMD:\n"
out += " Versions: (todo) %u, CA CRL (todo) %u, Signer CRL (todo) %u, System %u-%u\n" % (0, 0, 0, self.getIOSVersion() >> 32, self.getIOSVersion() & 0xFFFFFFFF) out += " Versions: (todo) %u, CA CRL (todo) %u, Signer CRL (todo) %u, System %u-%u\n" % (0, 0, 0, self.getIOSVersion() >> 32, self.getIOSVersion() & 0xFFFFFFFF)
out += " Title ID: %08x-%08x\n" % (item.titleid >> 32, item.titleid & 0xFFFFFFFF) out += " Title ID: %08x-%08x\n" % (self.getTitleID() >> 32, self.getTitleID() & 0xFFFFFFFF)
out += " Title Type: %u\n" % tmd.tmd.title_type out += " Title Type: %u\n" % self.tmd.title_type
out += " Group ID: '%02u'\n" % tmd.tmd.group_id out += " Group ID: '%02u'\n" % self.tmd.group_id
out += " Access Rights: 0x%08x\n" % tmd.tmd.access_rights out += " Access Rights: 0x%08x\n" % self.tmd.access_rights
out += " Title Version: 0x%04x\n" % item.version out += " Title Version: 0x%04x\n" % self.tmd.title_version
out += " Boot Index: %u\n" % self.getBootIndex() out += " Boot Index: %u\n" % self.getBootIndex()
out += " Contents: \n" out += " Contents: \n"