diff --git a/disc.py b/disc.py index 9b237f8..9483dd6 100644 --- a/disc.py +++ b/disc.py @@ -126,15 +126,14 @@ class WOD: #WiiOpticalDisc except: self.markedBlocks.append(blockStart + x) - print '%s (%i blocks marked)' % (self.markedBlocks, len(self.markedBlocks)) - + #print '%s (%i blocks marked)' % (self.markedBlocks, len(self.markedBlocks)) def decryptBlock(self, block): if len(block) != 0x8000: raise Exception('Block size too big/small') - blockIV = block[0x3d0:0x3dF + 1] - print 'IV %s (len %i)\n' % (hexdump(blockIV), len(blockIV)) - blockData = block[0x0400:0x7FFF] + blockIV = block[0x3d0:0x3e0] + #print 'IV %s (len %i)\n' % (hexdump(blockIV), len(blockIV)) + blockData = block[0x0400:0x8000] return Crypto().decryptData(self.partitionKey, blockIV, blockData, True) @@ -144,18 +143,16 @@ class WOD: #WiiOpticalDisc 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) + #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: + + for x in range(readLen + 1): blob += self.decryptBlock(self.fp.read(0x8000)) - else: - for x in range(readLen + 1): - blob += self.decryptBlock(self.fp.read(0x8000)) self.markContent(offset, size) - print 'Read from 0x%x to 0x%x' % (offset, offset + size) + #print 'Read from 0x%x to 0x%x' % (offset, offset + size) offset -= readStart * 0x7C00 return blob[offset:offset + size] @@ -166,60 +163,91 @@ class WOD: #WiiOpticalDisc # 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, fst, names, i, isLast): - - fileName = names[struct.unpack(">I", fst[12 * i:12 * i + 4])[0] & 0x00ffffff] - fileSize = struct.unpack(">I", fst[12 * i + 8:12 * i + 8 + 4])[0] - + class fstObject(object): + #TODO: add ability to extract file by path + def __init__(self, name, iso=None): + ''' do init stuff here ''' + self.parent = None + self.type = 1 #directory: 1, file:0 + self.name = name + self.nameOff = 0 + self.fileOffset = 0 + self.size = 0 + self.children = [] + self.iso = iso + def addChild(self, child): + if self.type == 0: + raise Exception('I am not a directory.') + child.parent = self + self.children.append(child) + def getISO(self): + if(self.parent == None): + return self.iso + return self.parent.getISO() + def getList(self, pad=0): + if self.type == 0: + return ("\t" * pad) + self.getPath() + "\n" + str = "%s[%s]\n" % ("\t" * (pad), self.getPath()) + for child in self.children: + str += child.getList(pad+1) + return str + def count(self): + if self.type == 0: + return 1 + i = 0 + for child in self.children: + i += child.count() + return i + def getPath(self): + if(self.parent == None): + return "/" + if(self.type == 1): + return self.parent.getPath() + self.name + "/" + return self.parent.getPath() + self.name + def write(self, cwd): + if(self.type==0): + print cwd + self.getPath() + #print self.nameOff + open(cwd + self.getPath(), 'w+b').write(self.getISO().readPartition(self.fileOffset, self.size)) + if(self.type==1): + if(self.parent != None): + try: + os.makedirs(cwd + self.getPath()) + except: + j = None + for child in self.children: + child.write(cwd) + def parseFst(self, fst, names, i, fstDir): + size = struct.unpack(">I", fst[12 * i + 8:12 * i + 8 + 4])[0] + nameOff = struct.unpack(">I", fst[12 * i:12 * i + 4])[0] & 0x00ffffff + fileName = names[nameOff:] + fileName = fileName[:fileName.find('\0')] + if i == 0: - for j in range(1, fileSize): - self.parseFst(fst, names, j, (j == fileSize - 1)) - return fileSize - - if fst[12 * i]: - parentDir = struct.unpack(">I", fst[12 * i + 4:12 * i + 4 + 4])[0] - isLast = struct.unpack(">I", fst[12 * parentDir + 8:12 * parentDir + 8 + 4] == fileSize)[0] - - for j in range(1, fileSize): - self.parseFst(fst, names, j, (j == fileSize - 1)) - - return fileSize + j = 1 + while(jI", fst[12 * i + 4, 12 * i + 4 + 4]) - markContent(fileOffset, fileSize) - open(fileName, 'w+b').write(self.readPartition(fileOffset, fileSize)) - - """def parseFst(self, buffer): - rootFiles = struct.unpack('>I', buffer[8:12])[0] - namesTable = buffer[12 * (rootFiles):] - - open('fst.bin', 'w+b').write(buffer) - - 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] & 0x00ffffff - fileName = namesTable[nameOffset:].split('\x00')[0] - #print '%s' % namesTable[nameOffset:] - #print '%s %s\n' % (namesTable[nameOffset:].split('\x00')[0], namesTable[nameOffset:].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('..')""" + fileOffset = 4 * struct.unpack(">I", fst[12 * i + 4: 12 * i + 4 + 4])[0] + newFile = self.fstObject(fileName) + newFile.type = 0 + newFile.fileOffset = fileOffset + newFile.size = size + newFile.nameOff = nameOff + fstDir.addChild(newFile) + #self.markContent(fileOffset, size) + return i+1 def openPartition(self, index): - if index > self.partitionCount: + if index+1 > self.partitionCount: raise ValueError('Partition index too big') self.partitionOpen = index @@ -258,8 +286,6 @@ class WOD: #WiiOpticalDisc def getFst(self): fstBuf = self.readPartition(self.fstOffset, self.fstSize) - fileNumber = 1000#struct.unpack(">I", fstBuf[0x8:0xc]) - self.parseFst(fstBuf, fstBuf[12 * fileNumber], 0, 0) return fstBuf def getIsoBootmode(self): diff --git a/tests/testDISC.py b/tests/testDISC.py new file mode 100644 index 0000000..8753683 --- /dev/null +++ b/tests/testDISC.py @@ -0,0 +1,25 @@ +from disc import * +from title import * +from Struct import Struct +import os + +iso = WOD('/enter/other/wii/SUPER_MARIO_GALAXY.iso') +iso.openPartition(1) +#print '%s' % iso +#iso.decryptAll() +#open('appldr.bin', 'w+b').write(iso.getPartitionApploader()) +fstBuf = iso.getFst() +open('fst.bin', 'w+b').write(fstBuf) + +fileNumber = struct.unpack(">I", fstBuf[0x8:0xc])[0] +fileObject = iso.fstObject("", iso) +iso.parseFst(fstBuf, fstBuf[12 * fileNumber:], 0, fileObject) +print fileObject.getList() +fileObject.write(os.getcwd() + "/" + iso.discHdr.discId + iso.discHdr.gameCode + iso.discHdr.region) + +#open('h3.bin', 'w+b').write(iso.getPartitionH3Table()) +#isoTik = Ticket('tik.bin') +#print '%s' % isoTik +#open('main.dol', 'w+b').write(iso.getPartitionMainDol()) +#isoTmd = TMD(iso.getPartitionTmd()) +#print isoTmd