-
-
Save chrisfu/c4d9906c28eab37e64d9 to your computer and use it in GitHub Desktop.
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
#!/usr/bin/python | |
# -*- coding: utf-8 -*- | |
import argparse | |
import os | |
import random | |
import string | |
import tempfile | |
import binascii | |
import sys | |
import subprocess | |
import hashlib | |
parser = argparse.ArgumentParser() | |
parser.add_argument('-rom', required=True, action='store', help='<your rom>') | |
parser.add_argument('-exheader', required=True, action='store', help='<origianl decrypted exheader>') | |
parser.add_argument('-sd', action='store_true', default=False, dest='sd', help='') | |
parser.add_argument('-fwspoof', action='store_true', default=False, dest='fwspoof', help='Spoof FW') | |
arguments = parser.parse_args() | |
class bcolors: | |
HEADER = '\033[95m' | |
OKBLUE = '\033[94m' | |
OKGREEN = '\033[92m' | |
WARNING = '\033[93m' | |
FAIL = '\033[91m' | |
ENDC = '\033[0m' | |
BOLD = '\033[1m' | |
UNDERLINE = '\033[4m' | |
def randomString(length): | |
return ''.join(random.choice(string.lowercase) for i in range(length)) | |
def binRead(rfile, length=0, offset=0): | |
data=bytes() | |
with open(rfile, 'rb') as f: | |
f.seek(offset) | |
data = f.read(length) | |
return {'rbytes':len(data), 'data':data} | |
def binWrite(wfile, data, length=0, offset=0): | |
wbytes=0 | |
mode='wb' | |
if os.path.isfile(wfile): | |
mode='rb+' | |
with open(wfile, mode) as f: | |
f.seek(offset) | |
for i in range(0, length): | |
f.write(data[i]) | |
wbytes = wbytes+1 | |
return {'wbytes': wbytes} | |
def xor(data, keystream): | |
result = bytes() | |
for i in range(len(data)): | |
result = result+chr( ord(data[i]) ^ ord(keystream[i]) ) | |
return result | |
romfilepath=os.path.abspath(arguments.rom) | |
exheaderfilepath=os.path.abspath(arguments.exheader) | |
useSD=arguments.sd | |
fwSpoof=arguments.fwspoof | |
ctrtoolPath=os.path.join(os.path.dirname(os.path.abspath(__file__)), 'ctrtool') | |
container="" | |
zerostring = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" | |
tempdir=tempfile.gettempdir() | |
exheadercopypath=os.path.join(tempdir, randomString(9)+'exhcopy') | |
xorpadfilepath=os.path.join(tempdir, randomString(9)+'xorpad') | |
result={} | |
def cleanup(errcode): | |
if os.path.isfile(exheadercopypath): | |
os.remove(exheadercopypath) | |
if os.path.isfile(xorpadfilepath): | |
os.remove(xorpadfilepath) | |
exit(errcode) | |
result = binRead(exheaderfilepath, 0x400, 0) | |
if result['rbytes'] != 0x400: | |
print bcolors.FAIL + "Could not read exheader file!" | |
cleanup(0) | |
exheader = binRead(exheaderfilepath, 0x800, 0) | |
if exheader['rbytes'] != 0x800: | |
print bcolors.FAIL + "Could not read exheader file!" | |
cleanup(0) | |
result = binWrite(exheadercopypath, exheader['data'], 0x800, 0) | |
if result['wbytes'] != 0x800: | |
print bcolors.FAIL + "Could not write exheader copy!" | |
cleanup(0) | |
magic = binRead(romfilepath, 0x4, 0x100) | |
if magic['data'] not in ("NCCH", "NCSD"): | |
print bcolors.FAIL + "Invalid file!" | |
exit(0) | |
container = magic['data'] | |
offset = {'NCCH': 0x18F, 'NCSD': 0x418F} | |
ncchflags = binRead(romfilepath, 0x1, offset[container]) | |
if ncchflags['rbytes'] != 0x1: | |
print bcolors.FAIL + "Could not read ncch flags!" | |
cleanup(0) | |
if not(ord(ncchflags['data']) & 0x4) and not(ord(ncchflags['data']) & 0x1): | |
print bcolors.FAIL + "This is a retail rom!`nYou need a repacked one." | |
cleanup(0) | |
if ord(ncchflags['data']) & 0x4: | |
syscontrolflags = binRead(exheadercopypath, 0x1,0x0D) | |
if syscontrolflags['rbytes'] != 0x1: | |
print bcolors.FAIL + "Could not read system control flags!" | |
if not(ord(syscontrolflags['data']) & 0x02) and not(arguments.fwspoof or arguments.sd): | |
print bcolors.WARNING + "Do you want to install this game to the SD card (y,n)? ", | |
userinput = sys.stdin.readline(1) | |
if userinput == 'y': | |
useSD = True | |
fw = binRead(exheadercopypath, 0x1, 0x39C) | |
if not(arguments.fwspoof or arguments.sd) and fw > 0x21: | |
print bcolors.WARNING + "This game requires a firmware version higher than 4.5.\nSpoof firmware version so it runs on the CFW?\n(May not work with all games) (y,n)? ", | |
userinput = sys.stdin.readline(1) | |
if userinput == 'y': | |
fwSpoof = True | |
if not(ord(syscontrolflags['data']) & 0x02) and useSD: | |
newflags = chr(ord(syscontrolflags['data']) ^ 0x02) | |
result = binWrite(exheadercopypath, newflags, 0x1, 0x0D) | |
if result['wbytes'] != 0x1: | |
print bcolors.FAIL + "Could not write system control flags!" | |
cleanup(0) | |
if fwSpoof: | |
result = binWrite(exheadercopypath, chr(0x21), 0x1, 0x39C) | |
if result['wbytes'] != 0x1: | |
print bcolors.FAIL + "Could not write kernel release version!" | |
cleanup(0) | |
result = binWrite(exheadercopypath, chr(0x21), 0x1, 0x79C) | |
if result['wbytes'] != 0x1: | |
print bcolors.FAIL + "Could not write kernel release version!" | |
cleanup(0) | |
if container == "NCSD": | |
result = binWrite(romfilepath, zerostring, 0x800, 0x4200) | |
elif container == "NCCH": | |
result = binWrite(romfilepath, zerostring, 0x800, 0x200) | |
subprocess.call([ctrtoolPath, "--exheader", xorpadfilepath, romfilepath], stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
xorpad = binRead(xorpadfilepath, 0x800,0x0) | |
exhcopy = binRead(exheadercopypath, 0x800,0x0) | |
vhex = binRead(exheadercopypath, 0x400,0x0) | |
newexheader = xor(exhcopy['data'], xorpad['data']) | |
if container == "NCSD": | |
result = binWrite(romfilepath, exhcopy['data'], 0x800, 0x4200) | |
elif container == "NCCH": | |
result = binWrite(romfilepath, exhcopy['data'], 0x800, 0x200) | |
vhash = hashlib.sha256(vhex['data']).digest() | |
if container == "NCSD": | |
result = binWrite(romfilepath, vhash, 0x20, 0x1160) | |
result = binWrite(romfilepath, vhash, 0x20, 0x4160) | |
elif container == "NCCH": | |
result = binWrite(romfilepath, vhash, 0x20, 0x160) | |
ctrtool = subprocess.call([ctrtoolPath, romfilepath], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
if ctrtool != 0: | |
print bcolors.FAIL + "Could not inject properly." | |
cleanup(0) | |
print bcolors.OKGREEN + "Extended header successfully injected!" | |
cleanup(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment