Skip to content

Instantly share code, notes, and snippets.

@NWPlayer123
Created March 24, 2017 06:36
Show Gist options
  • Save NWPlayer123/7e6233aee364796c55d85f143bba4bd1 to your computer and use it in GitHub Desktop.
Save NWPlayer123/7e6233aee364796c55d85f143bba4bd1 to your computer and use it in GitHub Desktop.
Script to get icon and metadata for any Wii U title, title ID is hardcoded
# only dependencies are pycrypto and requests, I had to rename pycrypto's thing
# in C:\Python27\Lib\site-packages to Crypto from pip cause it defaulted to lowercase
from StringIO import StringIO
from Crypto.Cipher import AES
from struct import unpack
from requests import get
from os.path import exists
from os import mkdir
import warnings, sys
warnings.filterwarnings("ignore")
data = [ #IV + 4 keys
"\xA4\x69\x87\xAE\x47\xD8\x2B\xB4\xFA\x8A\xBC\x04\x50\x28\x5F\xA4",
"\x4A\xB9\xA4\x0E\x14\x69\x75\xA8\x4B\xB1\xB4\xF3\xEC\xEF\xC4\x7B",
"\x90\xA0\xBB\x1E\x0E\x86\x4A\xE8\x7D\x13\xA6\xA0\x3D\x28\xC9\xB8",
"\xFF\xBB\x57\xC1\x4E\x98\xEC\x69\x75\xB3\x84\xFC\xF4\x07\x86\xB5",
"\x80\x92\x37\x99\xB4\x1F\x36\xA6\xA7\x5F\xB8\xB4\x8C\x95\xF6\x6F"]
title_id = "00050000101C5800"
cdn_url = "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/{}/".format(title_id)
url = "https://idbe-ctr.cdn.nintendo.net/icondata/%02X/%16s.idbe" % (0x10, title_id)
total_size = 0
def getstr(f):
char = f.read(2); ret = ""
while char != "\x00\x00":
ret += char
char = f.read(2)
return ret.decode("UTF-16-BE").encode("UTF-8")
if __name__ == "__main__":
if not exists("icons"):
mkdir("icons")
if not exists("icons/%s.idbe" % title_id):
with open("icons/%s.idbe" % title_id, "wb") as f:
r = get(url, verify="cert.pem")
for chunk in r.iter_content(1024):
if chunk: f.write(chunk)
with open("icons/%s.idbe" % title_id, "rb") as f:
assert ord(f.read(1)) == 0
key_index = ord(f.read(1)) + 1 #IV is 0
obj = AES.new(data[key_index], AES.MODE_CBC, IV=data[0])
idbe = StringIO(obj.decrypt(f.read()))
idbe.seek(0x30) #Region lockout
region = unpack(">I", idbe.read(4))[0]
idbe.seek(0x250)
short_desc = getstr(idbe)
idbe.seek(0x2D0)
long_desc = getstr(idbe)
idbe.seek(0x3D0)
publisher = getstr(idbe)
print("Title: %s (%s - %s)" % (long_desc, short_desc, publisher))
if not exists("icons/%s.tga" % title_id):
with open("icons/%s.tga" % title_id, "wb") as f:
with open("icons/%s.idbe" % title_id, "rb") as r:
r.seek(0x2050)
f.write(r.read())
print("Wrote TGA icon to icons/%s.tga" % title_id)
else:
print("TGA icon already exists (icons/%s.tga)" % title_id)
r = get(cdn_url + "tmd")
tmd = StringIO()
for chunk in r.iter_content(1024):
if chunk: tmd.write(chunk)
tmd.seek(0)
print("Parsing metadata...")
tmd.seek(0x1DE)
count = unpack(">H", tmd.read(2))[0]
tmd.seek(0xB04)
for i in range(count):
content_id = unpack(">I", tmd.read(4))[0]
tmd.seek(8, 1)
content_size = unpack(">I", tmd.read(4))[0]
tmd.seek(0x20, 1)
print("%08X: %08X bytes" % (content_id, content_size))
total_size += content_size
print("Total size: {:.2f} MB (about {:,} bytes)".format\
(total_size / 1024.0 / 1024.0, total_size))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment