|
import binascii, struct, hashlib, sys |
|
import lz4.block as block |
|
|
|
|
|
if len(sys.argv) != 4: |
|
print "patchnso.py: simple script to patch the .text sections of nso files and reassemble them" |
|
print "by tesnos6921, thanks to switchbrew.org for docs and the atmosphere team for exefs patching so early" |
|
print "Usage: patchnso.py nso-file patch-file out-file" |
|
print "patch-file should contain lines formatted like so, with values in hex." |
|
print "location:codepatch, Example: 2E8:21008052" |
|
print "Empty lines or lines beginning with pound signs are ignored." |
|
|
|
def padding(padlength): |
|
pad = "" |
|
for i in range(padlength): |
|
pad += "\x00" |
|
return pad |
|
|
|
def patchtext(source, patchlist): |
|
patchedsource = source |
|
|
|
for patch in patchlist: |
|
if "#" in patch or patch.strip() == "": |
|
continue |
|
|
|
patchlocation, patchcode = patch.split(":") |
|
|
|
patchlocation = int(patchlocation, 16) |
|
patchcode = binascii.unhexlify(patchcode.strip()) |
|
|
|
patchedsource = patchedsource[:patchlocation] + patchcode + patchedsource[patchlocation+len(patchcode):] |
|
|
|
return patchedsource |
|
|
|
main_f = open(sys.argv[1], "rb") |
|
mainsource = main_f.read() |
|
main_f.close() |
|
|
|
header = mainsource[:0x100] |
|
|
|
textloc = struct.unpack("<I", header[0x10:0x14])[0] |
|
dectextsize = struct.unpack("<I", header[0x18:0x1C])[0] |
|
|
|
rodataloc = struct.unpack("<I", header[0x20:0x24])[0] |
|
dataloc = struct.unpack("<I", header[0x30:0x34])[0] |
|
oldtextsize = rodataloc - textloc |
|
rodatasize = dataloc - rodataloc |
|
|
|
textsource = mainsource[textloc:textloc+oldtextsize] |
|
textsource = block.decompress(textsource, uncompressed_size=dectextsize) |
|
|
|
patch_f = open(sys.argv[2], "r") |
|
patches = patch_f.readlines() |
|
patch_f.close() |
|
|
|
textsource = patchtext(textsource, patches) |
|
texthash = hashlib.sha256(textsource).digest() |
|
|
|
compressedtext = block.compress(textsource, mode='fast', acceleration=2) |
|
compressedtext = compressedtext[0x4:] |
|
compressedtextsize = len(compressedtext) |
|
|
|
rodata = mainsource[rodataloc:rodataloc+rodatasize] |
|
data = mainsource[dataloc:] |
|
|
|
newrodataloc = textloc + compressedtextsize |
|
|
|
header = header[:0x20] + struct.pack("<I", newrodataloc) + header[0x24:] |
|
newdataloc = newrodataloc + rodatasize |
|
header = header[:0x30] + struct.pack("<I", newdataloc) + header[0x34:] |
|
|
|
header = header[:0x60] + struct.pack("<I", compressedtextsize) + header[0x64:] |
|
header = header[:0xA0] + texthash + header[0xC0:] |
|
|
|
newmain = header + padding(textloc - len(header)) + compressedtext + rodata + data |
|
|
|
newmain_f = open(sys.argv[3], "wb") |
|
newmain_f.write(newmain) |
|
newmain_f.close() |