Created
March 24, 2017 06:36
-
-
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
This file contains hidden or 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
# 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