Last active
May 30, 2020 20:36
-
-
Save larsenv/ea873c6b105316cfff8313b94e8ad06a to your computer and use it in GitHub Desktop.
wad.py - Python script to make a clean Wii WAD using another WAD or a ticket. (Not my script)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
from binascii import hexlify, unhexlify | |
from Crypto.Cipher import AES | |
from struct import pack, unpack | |
from sys import argv, exit | |
import requests | |
import re | |
def modu(dat): | |
wad.write(b'\x00' * ((0x40 - (len(dat) % 0x40)) % 0x40)) | |
tik = open(argv[1], 'rb') | |
temp = tik.read(0x8) | |
if temp == b'\x00\x00\x00\x20\x49\x73\x00\x00' or temp == b'\x00\x00\x00\x00\x00\x00\x00\x00': | |
certsize, = unpack('>I', tik.read(4)) | |
if certsize == 0: | |
certsize = 0xA00 | |
tik.seek(certsize + 0x40) | |
tik = tik.read(0x2A4) | |
# open('tik', 'wb').write(tik) | |
else: | |
tik.seek(0) | |
tik = tik.read() | |
tik = b'\x00\x01\x00\x01' + b'\x00' * 0x13C + tik[0x140:0x180] + b'\x00' * 0x3C + tik[0x1BC:0x1D0] + b'\x00' * 0xC + tik[0x1DC:0x2A4] | |
titid = tik[0x1DC:0x1E4].hex() | |
region = unhexlify(titid[-2:]) | |
titkey = tik[0x1BF:0x1CF] | |
hacked_titkeys = [b'OhCrapAnotheriNT', b'BFGRBeFreeeeeee!', b'DaLetterAisan00b', titkey[0:1]+b'kikekakikrules!'] #latter is "kikekakikrules!!" but positioned a byte later | |
if titkey in hacked_titkeys: | |
exit('Hacked title key') | |
# else: | |
# print(titkey) | |
if tik[0x1f1] == 0: # & 1 == 0: | |
# print('Using normal common key...') | |
ckey = unhexlify('EBE42A225E8593E448D9C5457381AAF7') # Standard common key | |
elif tik[0x1f1] == 1 and region == b'K': # & 1 == 1 and region == b'K': | |
# print('Using Korean common key...') | |
ckey = unhexlify('63B82BB4F4614E2E13F2FEFBBA4C9B7E') # Korean common key | |
else: | |
# print('Detected scene modified ticket (using normal common key)...') | |
# hack | |
tik = bytearray(tik) | |
tik[0x1f1:0x1f4] = b'\x00' * 3 | |
# / hack | |
ckey = unhexlify('EBE42A225E8593E448D9C5457381AAF7') | |
print(titid) | |
# print(hexlify(titkey).decode('ascii')) | |
iv = unhexlify(titid) + b'\x00' * 8 | |
cipher = AES.new(ckey, AES.MODE_CBC, iv) | |
titkey = cipher.decrypt(titkey) | |
baseurl = 'http://nus.cdn.shop.wii.com/ccs/download/'+titid+'/' | |
tmdurl = baseurl + 'tmd' | |
try: | |
if argv[2]: | |
tmdver = True | |
tmdurl += '.' + argv[2] | |
except IndexError: | |
tmdver = False | |
pass | |
if requests.head(tmdurl).status_code != 200: | |
if tmdver: | |
exit('Invalid revision.') | |
else: | |
open('debug.log', 'a').write(titid+'\n') | |
exit('Title not on CDN.') | |
tmd = requests.get(tmdurl).content | |
clist = {} | |
contents, = unpack('>H', tmd[0x1DE:0x1E0]) | |
off = 0x1e4 | |
for i in range(contents): | |
cid, = unpack('>I', tmd[off:off+4]) | |
cidx, = unpack('>H', tmd[off+4:off+6]) | |
clist[cidx] = '{:08x}'.format(cid) | |
off += 0x24 | |
print(clist) | |
tmd = tmd[:off] | |
rev, = unpack('>H', tmd[0x1DC:0x1DE]) | |
# print(argv[1], rev) | |
# exit() | |
appsize = 0 | |
for c in clist: | |
s = int(requests.head(baseurl+clist[c]).headers['Content-Length']) | |
appsize += s + (0x40 - (s % 0x40)) % 0x40 | |
temp = requests.get(baseurl + clist[0]).content | |
cipher = AES.new(titkey, AES.MODE_CBC, b'\x00'*16) | |
temp = cipher.decrypt(temp) | |
nameo = {b'J': 0, b'B': 1, b'D': 1, b'E': 1, b'F': 1, b'M':1, b'N': 1, b'L': 1, b'P': 1, b'A': 1, b'K': 9} | |
if titid[:8] != '00000001': | |
if temp[0x80:0x84] != b'IMET': | |
if temp[0x40:0x44] != b'WIBN': | |
exit('Incorrect title key.') | |
nameoff = 0x80 + 0x1c + 0x54 * nameo[region] | |
region = {b'J': 'Japan', b'B': 'USA', b'E': 'USA', b'F': 'France', b'D': 'Germany', b'N': 'USA', | |
b'P': 'Europe', b'L': 'Europe', b'M': 'Europe', b'A': 'System', b'K': 'Korea'}[region] | |
if titid[6:8] == '05': | |
nameoff = 0x60 | |
name = temp[nameoff:nameoff+0x54].decode('utf-16be').strip('\x00').replace('/', '-').replace('\x00', ' ').replace(': ', ' - ') | |
name = re.sub(' +', ' - ', name) | |
name = name + ' (' + region + ') (v' + str(rev) + ')' | |
print(name) | |
else: | |
if len(clist) > 1: | |
name = temp[:0x20].strip(b'\x00').decode('utf-8') | |
else: | |
name = 'System' | |
wad = open(name + '.wad', 'wb') | |
wad.write(b'\x00\x00\x00\x20\x49\x73\x00\x00') | |
wad.write(pack('>IIIIII', 0xA00, 0, len(tik), len(tmd), appsize, int(requests.head(baseurl+clist[0]).headers['Content-Length']))) | |
wad.write(b'\x00'*0x20) | |
wad.write(open('cert.sys', 'rb').read()) | |
wad.write(tik) | |
modu(tik) | |
wad.write(tmd) | |
modu(tmd) | |
for i in clist: | |
i = clist[i] | |
print('Downloading '+i) | |
fi = requests.get(baseurl + i).content | |
wad.write(fi) | |
modu(fi) | |
wad.write(temp) | |
modu(temp) | |
wad.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment