Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import os, hashlib, struct, subprocess, fnmatch, shutil, urllib, array
- import wx
- import png
- from hashlib import md5
- from Crypto.Cipher import AES
- from Struct import Struct
- from common import *
- from title import *
- class Savegame():
- class savegameHeader(Struct):
- __endian__ = Struct.BE
- def __format__(self):
- self.savegameId = Struct.uint32[2]
- self.bannerSize = Struct.uint32
- self.permissions = Struct.uint8
- self.unknown1 = Struct.uint8
- self.md5hash = Struct.uint32[4]
- self.unknown2 = Struct.uint16
- class savegameBanner(Struct):
- __endian__ = Struct.BE
- def __format__(self):
- self.magic = Struct.string(4)
- self.reserved = Struct.uint8[4]
- self.flags = Struct.uint32
- self.reserved = Struct.uint32[5]
- self.gameTitle = Struct.string(64)
- self.gameSubTitle = Struct.string(64)
- self.banner = Struct.uint8[24576]
- self.icon0 = Struct.uint8[4608]
- self.icon1 = Struct.uint8[4608]
- self.icon2 = Struct.uint8[4608]
- self.icon3 = Struct.uint8[4608]
- self.icon4 = Struct.uint8[4608]
- self.icon5 = Struct.uint8[4608]
- self.icon6 = Struct.uint8[4608]
- self.icon7 = Struct.uint8[4608]
- class backupHeader(Struct):
- __endian__ = Struct.BE
- def __format__(self):
- self.hdrSize = Struct.uint32
- self.magic = Struct.string(2)
- self.version = Struct.uint16
- self.NGid = Struct.uint32
- self.filesCount = Struct.uint32
- self.filesSize = Struct.uint32
- self.unknown1 = Struct.uint32
- self.unknown2 = Struct.uint32
- self.totalSize = Struct.uint32
- self.unknown3 = Struct.uint8[64]
- self.unknown4 = Struct.uint32
- self.gameId = Struct.string(4)
- self.wiiMacAddr = Struct.uint8[6]
- self.unknown6 = Struct.uint16
- self.padding = Struct.uint32[4]
- class fileHeader(Struct):
- __endian__ = Struct.BE
- def __format__(self):
- self.magic = Struct.uint32
- self.size = Struct.uint32
- self.permissions = Struct.uint8
- self.attribute = Struct.uint8
- self.type = Struct.uint8
- self.name = Struct.string(12, stripNulls=True) #Need a way to stop this to the 1st null char
- self.fileIV = Struct.uint32[4]
- self.unknown = Struct.uint8[10]
- def __init__(self, f):
- self.f = f
- self.fd = open(f, 'r+b')
- self.sdKey = '\xab\x01\xb9\xd8\xe1\x62\x2b\x08\xaf\xba\xd8\x4d\xbf\xc2\xa5\x5d'
- self.sdIv = '\x21\x67\x12\xe6\xaa\x1f\x68\x9f\x95\xc5\xa2\x23\x24\xdc\x6a\x98'
- try:
- os.mkdir(self.f.replace(".", "_") + "_out")
- except:
- pass
- os.chdir(self.f.replace(".", "_") + "_out")
- self.iconCount = 1
- def __str__(self):
- ret = ''
- ret += '\nSavegame header \n'
- ret += 'Savegame ID : 0x%x%x\n' % (self.hdr.savegameId[0], self.hdr.savegameId[1])
- ret += 'Banner size : 0x%x\n' % self.hdr.bannerSize
- ret += 'Permissions : 0x%x\n' % self.hdr.permissions
- ret += 'Unknown : 0x%x\n' % self.hdr.unknown1
- ret += 'MD5 hash : 0x%x%x%x%x\n' % (self.hdr.md5hash[0], self.hdr.md5hash[1], self.hdr.md5hash[2], self.hdr.md5hash[3])
- ret += 'Unknown : 0x%x\n' % self.hdr.unknown2
- ret += '\nBanner header \n'
- ret += 'Flags : 0x%x\n' % self.bnr.flags
- ret += 'Game title : %s\n' % self.bnr.gameTitle
- ret += 'Game subtitle : %s\n' % self.bnr.gameSubTitle
- ret += '\nBackup header \n'
- ret += 'Header size : 0x%x (+ 0x10 of padding) version 0x%x\n' % (self.bkHdr.hdrSize, self.bkHdr.version)
- ret += 'Wii MAC address %02x:%02x:%02x:%02x:%02x:%02x\n' % (self.bkHdr.wiiMacAddr[0], self.bkHdr.wiiMacAddr[1], self.bkHdr.wiiMacAddr[2], self.bkHdr.wiiMacAddr[3], self.bkHdr.wiiMacAddr[4], self.bkHdr.wiiMacAddr[5])
- ret += 'Found %i files for %i bytes\n' % (self.bkHdr.filesCount, self.bkHdr.filesSize)
- ret += 'Total size : %i bytes\n' % self.bkHdr.totalSize
- if self.bkHdr.gameId[3] == 'P':
- ret += 'Region : PAL\n'
- elif self.bkHdr.gameId[3] == 'E':
- ret += 'Region : NTSC\n'
- elif self.bkHdr.gameId[3] == 'J':
- ret += 'Region : JAP\n'
- ret += 'Game ID : %s\n' % self.bkHdr.gameId
- ret += 'NG id : 0x%x\n' % self.bkHdr.NGid
- return ret
- def extractFile(self, index):
- if index > self.bkHdr.filesCount:
- raise ValueError
- self.fd.seek(self.fileStartOffset)
- for i in range(self.bkHdr.filesCount):
- fileHdr = self.fd.read(0x80)
- fileHdr = self.fileHeader().unpack(fileHdr)
- if fileHdr.magic != 0x03adf17e:
- raise ValueError('Wrong file magic')
- fileHdr.size = align(fileHdr.size, 64)
- print 'File name : %s (%ib)' % (fileHdr.name, fileHdr.size)
- print 'Type [%i] Attribute [%i] Permission [%i]' % (fileHdr.type, fileHdr.attribute, fileHdr.permissions)
- print 'File IV : 0x%x%x%x%x' % (fileHdr.fileIV[0], fileHdr.fileIV[1], fileHdr.fileIV[2], fileHdr.fileIV[3])
- if fileHdr.type == 1:
- fileBuffer = self.fd.read(fileHdr.size)
- fileBuffer = Crypto().DecryptData(self.sdKey, struct.pack('>IIII', *fileHdr.fileIV), fileBuffer, True)
- open(fileHdr.name.rstrip('\0'), 'r+b').write(fileBuffer)
- elif fileHdr.type == 2:
- try:
- os.mkdir(fileHdr.name.rstrip('\0'))
- except:
- pass
- def analyzeHeader(self):
- headerBuffer = self.fd.read(0xF0BF + 1)
- headerBuffer = Crypto().DecryptData(self.sdKey, self.sdIv, headerBuffer, True)
- self.hdr = self.savegameHeader().unpack(headerBuffer[:0x20])
- #MD5 check fail always ...
- #list(headerBuffer)[0x000E:0x001E] = '\x0e\x65\x37\x81\x99\xbe\x45\x17\xab\x06\xec\x22\x45\x1a\x57\x93'
- #print '0x%x%x%x%x %s' % (self.hdr.md5hash[0], self.hdr.md5hash[1], self.hdr.md5hash[2], self.hdr.md5hash[3], hashlib.md5(headerBuffer[:0x20]).hexdigest())
- self.bnr = self.savegameBanner().unpack(headerBuffer[0x20:])
- if self.bnr.magic != 'WIBN':
- raise ValueError ('Wrong magic, should be WIBN')
- if self.hdr.bannerSize == 0xF0C0:
- self.iconCount += 7
- bkHdrBuffer = self.fd.read(0x80)
- self.bkHdr = self.backupHeader().unpack(bkHdrBuffer)
- if self.bkHdr.magic != 'Bk' or self.bkHdr.hdrSize != 0x70:
- raise ValueError ('Bk header error')
- self.fileStartOffset = self.fd.tell()
- def getBanner(self):
- open('bnr.bin', 'w+b').write(struct.pack('24576I', *self.bnr.banner))
- def getIcon(self, index):
- if index < 0 or index > 7 or index > self.iconCount:
- return -1
- if index == 0:
- return self.bnr.icon0
- if index == 1:
- return self.bnr.icon1
- if index == 2:
- return self.bnr.icon2
- if index == 3:
- return self.bnr.icon3
- if index == 4:
- return self.bnr.icon4
- if index == 5:
- return self.bnr.icon5
- if index == 6:
- return self.bnr.icon6
- if index == 7:
- return self.bnr.icon7
- def getIconsCount(self):
- return self.iconCount
- def getSaveString(self, string):
- if string == 'GAMEID':
- return self.bkHdr.gameId
- elif string == 'GAMETITLE':
- return self.bnr.gameTitle
- elif string == 'GAMESUBTITLE':
- return self.bnr.gameSubTitle
- def getFilesCount(self):
- return self.bkHdr.filesCount
Add Comment
Please, Sign In to add comment