From 336fa401e6050a456cb74d0339ca6211ebc61afa Mon Sep 17 00:00:00 2001 From: "Giuseppe (LemonBoy)" Date: Fri, 19 Jun 2009 18:16:08 +0200 Subject: [PATCH] Now you can delete the wii mac from the savedata. Uploaded the newer (but bugged) dvd class with fst reading :3 --- disc.py | 136 +++++++++++++++++++++++++++++++++++----------------- savedata.py | 9 ++-- 2 files changed, 99 insertions(+), 46 deletions(-) diff --git a/disc.py b/disc.py index 9f72b84..e583336 100644 --- a/disc.py +++ b/disc.py @@ -13,9 +13,12 @@ from common import * class WOD: #WiiOpticalDisc class fsentry: name = "" + type = 0 parent = None + offset = 0 + lenght = 0 - def __init__(self, name, parent): + def __init__(self, name, type, parent, offset, len): self.name = "" if(parent != None): self.parent = parent @@ -46,7 +49,20 @@ class WOD: #WiiOpticalDisc self.title = Struct.string(64) self.hashVerify = Struct.uint8 self.h3verify = Struct.uint8 + def __str__(self): + ret = '' + ret += '%s [%s%s%s]\n' % (self.title, self.discId, self.gameCode, self.region) + if self.region == 'P': + ret += 'Region : PAL\n' + elif self.region == 'E': + ret += 'Region : NTSC\n' + elif self.region == 'J': + ret += 'Region : JPN\n' + ret += 'Version 0x%x Maker %i%i Audio streaming %x\n' % (self.version, self.makerCode[0], self.makerCode[1], self.audioStreaming) + ret += 'Hash verify flag 0x%x H3 verify flag : 0x%x\n' % (self.hashVerify, self.h3verify) + return ret + # Many many thanks to Wiipower class Apploader(Struct): __endian__ = Struct.BE @@ -56,26 +72,27 @@ class WOD: #WiiOpticalDisc self.size = Struct.uint32 self.trailingSize = Struct.uint32 self.padding = Struct.uint8[4] + def __str__(self): + ret = '' + ret += 'Apploader built on %s\n' % self.buildDate + ret += 'Entry point 0x%x\n' % self.entryPoint + ret += 'Size %i (%i of them are trailing)\n' % (self.size, self.trailingSize) + + return ret def __str__(self): ret = '' - ret += '%s [%s%s%s]\n' % (self.discHdr.title, self.discHdr.discId, self.discHdr.gameCode, self.discHdr.region) - if self.discHdr.region == 'P': - ret += 'Region : PAL\n' - elif self.discHdr.region == 'E': - ret += 'Region : NTSC\n' - elif self.discHdr.region == 'J': - ret += 'Region : JPN\n' - ret += 'Version 0x%x Maker %i%i Audio streaming %x\n' % (self.discHdr.version, self.discHdr.makerCode[0], self.discHdr.makerCode[1], self.discHdr.audioStreaming) - ret += 'Hash verify flag 0x%x H3 verify flag : 0x%x\n' % (self.discHdr.hashVerify, self.discHdr.h3verify) + ret += '%s\n' % self.discHdr ret += 'Found %i partitions (table at 0x%x)\n' % (self.partitionCount, self.partsTableOffset) ret += 'Found %i channels (table at 0x%x)\n' % (self.channelsCount, self.chansTableOffset) - ret += 'Partition %i opened (type 0x%x) at 0x%x)\n' % (self.partitionOpen, self.partitionType, self.partitionOffset) - ret += 'Partition title : %s\n' % self.partitionHdr.title + ret += '\n' + ret += 'Partition %i opened (type 0x%x) at 0x%x\n' % (self.partitionOpen, self.partitionType, self.partitionOffset) + ret += '%s' % self.partitionHdr ret += 'Partition key %s\n' % hexdump(self.partitionKey) - ret += 'Tmd at 0x%x\n' % self.tmdOffset - ret += 'main.dol at 0x%x fst at 0x%x (%xb)\n' % (self.dolOffset, self.fstSize, self.fstOffset) - ret += 'Apploader built on %s (%x bytes)\n' % (self.appLdr.buildDate, self.appLdr.size + self.appLdr.trailingSize) + ret += 'Tmd at 0x%x (%x)\n' % (self.tmdOffset, self.tmdSize) + ret += 'main.dol at 0x%x (%x)\n' % (self.dolOffset, self.dolSize) + ret += 'FST at 0x%x (%x)\n' % (self.fstSize, self.fstOffset) + ret += '%s\n' % (self.appLdr) return ret @@ -109,7 +126,60 @@ class WOD: #WiiOpticalDisc return Crypto().DecryptData(self.partitionKey, blockIV, blockData, True) + def readPartition(self, offset, size): + readStart = offset / 0x7C00 + readLen = (align(size, 0x7C00)) / 0x7C00 + blob = '' + + print 'Read at 0x%x (Start on %i block, ends at %i block) for %i bytes' % (offset, readStart, readStart + readLen, size) + + self.fp.seek(self.partitionOffset + 0x20000 + (0x8000 * readStart)) + if readLen == 0: + blob += self.decryptBlock(self.fp.read(0x8000)) + else: + for x in range(readLen + 1): + blob += self.decryptBlock(self.fp.read(0x8000)) + + print 'Read from 0x%x to 0x%x' % (offset, offset + size) + offset -= readStart * 0x7C00 + return blob[offset:offset + size] + + def readUnencrypted(self, offset, size): + if offset > 0x20000: + raise Exception('This read is on encrypted data') + + # FIXMII : Needs testing, extracting the tmd cause to have 10 null bytes in the end instead of 10 useful bytes at start :| + self.fp.seek(self.partitionOffset + 0x2A4 + offset) + return self.fp.read(size) + + def parseFst(self, buffer): + rootFiles = struct.unpack('>I', buffer[8:12])[0] + namesTable = buffer[12 * (rootFiles):] + + open('tbl.bin', 'w+b').write(str(buffer[12 * (rootFiles):].split('\x00'))) + + for i in range(1, rootFiles): + fstTableEntry = buffer[12 * i:12 * (i + 1)] + + if fstTableEntry[0] == '\x01': + fileType = 1 + else: + fileType = 0 + + temp = struct.unpack('>I', fstTableEntry[0x0:0x4])[0] + nameOffset = struct.unpack('>I', fstTableEntry[0x0:0x4])[0] & 0xffffff + fileName = namesTable[nameOffset:nameOffset + 256].split('\x00')[0] + print '%s %s\n' % (namesTable[nameOffset:nameOffset + 256].split('\x00')[0], namesTable[nameOffset:nameOffset + 256].split('\x00')[1]) + fileOffset = 4 * (struct.unpack('>I', fstTableEntry[0x4:0x8])[0]) + fileLenght = struct.unpack('>I', fstTableEntry[0x8:0x0c])[0] + if fileName == '': + time.sleep(5) + + print '%s [%i] [0x%X] [0x%X] [0x%X]' % (fileName, fileType, fileOffset, fileLenght, nameOffset) + + os.chdir('..') + def openPartition(self, index): if index > self.partitionCount: raise ValueError('Partition index too big') @@ -144,33 +214,16 @@ class WOD: #WiiOpticalDisc self.dataOffset = struct.unpack(">I", self.fp.read(4))[0] >> 2 self.dataSize = struct.unpack(">I", self.fp.read(4))[0] >> 2 - self.dolOffset = 4 * struct.unpack(">I", self.readPartition (0x420, 4))[0] - self.fstOffset = 4 * struct.unpack(">I", self.readPartition (0x424, 4))[0] self.fstSize = 4 * struct.unpack(">I", self.readPartition (0x428, 4))[0] - def readPartition(self, offset, size): - - readStart = offset / 0x7C00 - readLen = (align(size, 0x7C00)) / 0x7C00 - blob = '' - - print 'Read at 0x%x (Start on %i block, ends at %i block) for %i bytes' % (offset, readStart, readStart + readLen, size) - - self.fp.seek(self.partitionOffset + 0x20000 + (0x8000 * readStart)) - if readLen == 0: - blob += self.decryptBlock(self.fp.read(0x8000)) - else: - for x in range(readLen + 1): - blob += self.decryptBlock(self.fp.read(0x8000)) - - print 'Read from 0x%x to 0x%x' % (offset, offset + size) - offset -= readStart * 0x7C00 - return blob[offset:offset + size] + self.dolOffset = 4 * struct.unpack(">I", self.readPartition (0x420, 4))[0] + self.dolSize = self.fstOffset - self.dolOffset def getFst(self): - #print 'Fst dump : %s' % hexdump(self.readPartition(self.fstOffset, self.fstSize)) - return self.readPartition(self.fstOffset, self.fstSize) + fstBuf = self.readPartition(self.fstOffset, self.fstSize) + self.parseFst(fstBuf) + return fstBuf def getIsoBootmode(self): if self.discHdr.discId == 'R' or self.discHdr.discId == '_': @@ -194,16 +247,13 @@ class WOD: #WiiOpticalDisc return self.channelsCount def getPartitionCerts(self): - self.fp.seek(self.partitionOffset + self.certsOffset) - return self.fp.read(self.certsSize) + return self.readUnencrypted(self.certsOffset, self.certsSize) def getPartitionH3Table(self): - self.fp.seek(self.partitionOffset + self.H3TableOffset) - return self.fp.read(0x18000) + return self.readUnencrypted(self.H3TableOffset, 0x18000) def getPartitionTmd(self): - self.fp.seek(self.partitionOffset + self.tmdOffset) - return self.fp.read(self.tmdSize) + return self.readUnencrypted(self.tmdOffset, self.tmdSize) def getPartitionTik(self): self.fp.seek(self.partitionOffset) diff --git a/savedata.py b/savedata.py index 2d61402..bea24fd 100644 --- a/savedata.py +++ b/savedata.py @@ -113,7 +113,7 @@ class Savegame(): ret += 'Total size : %i bytes\n' % self.bkHdr.totalSize return ret - + def extractFiles(self): try: @@ -173,7 +173,7 @@ class Savegame(): print 'File IV : 0x%s' % hexdump(fileIV, '') os.chdir('..') - + def analyzeHeader(self): headerBuffer = self.fd.read(0xF0C0) headerBuffer = Crypto().DecryptData(self.sdKey, self.sdIv, headerBuffer, True) @@ -201,7 +201,7 @@ class Savegame(): self.fileStartOffset = self.fd.tell() def getBanner(self): - open('bnr.bin', 'w+b').write(struct.pack('24576I', *self.bnr.banner)) + return struct.pack('24576I', *self.bnr.banner) def getIcon(self, index): if index < 0 or index > 7 or index > self.iconCount: @@ -223,6 +223,9 @@ class Savegame(): if index == 7: return self.bnr.icon7 + def eraseWiiMac(self): + self.fd.seek(0xF128) + print self.fd.write('\x00' * 6) def getIconsCount(self): return self.iconCount