Skip to content

Instantly share code, notes, and snippets.

@InvoxiPlayGames
Created October 13, 2021 14:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save InvoxiPlayGames/45e1dd092a9af07b7b7159b41acd3cee to your computer and use it in GitHub Desktop.
Save InvoxiPlayGames/45e1dd092a9af07b7b7159b41acd3cee to your computer and use it in GitHub Desktop.
string-gecko.py - generate Wii gecko/ocarina codes to replace ASCII strings in game executables
# string-gecko.py by github.com/InvoxiPlayGames
# command usage: python string-gecko.py [dol|dump] [filename] [oldstring] [newstring]
# code licensing: don't be a dick with it, credit for general usage would be nice but not required
# but if you use parts of this python script in your own project, credit is required
import struct
import sys
memorybase = 0x80000000
memorysize = 0x01800000 # size of Wii MEM1, i think
memory = [0] * memorysize
if sys.argv[1] == "dol":
dolfilename = sys.argv[2]
print("loading DOL file '%s'..." % (dolfilename))
f = open(dolfilename, "rb")
# read header
f.seek(0)
textoffsets = struct.unpack(">IIIIIII", f.read(7 * 4))
dataoffsets = struct.unpack(">IIIIIIIIIII", f.read(11 * 4))
textloadaddr = struct.unpack(">IIIIIII", f.read(7 * 4))
dataloadaddr = struct.unpack(">IIIIIIIIIII", f.read(11 * 4))
textsizes = struct.unpack(">IIIIIII", f.read(7 * 4))
datasizes = struct.unpack(">IIIIIIIIIII", f.read(11 * 4))
[bssaddr] = struct.unpack(">I", f.read(4))
[bsssize] = struct.unpack(">I", f.read(4))
[entrypoint] = struct.unpack(">I", f.read(4))
# read data
f.seek(0)
doldata = f.read()
# we don't need the file anymore
f.close()
print()
if entrypoint >= memorybase and entrypoint < memorybase + memorysize:
print("entrypoint:")
print(" address: 0x%08x" % (entrypoint))
else:
print("entrypoint unused or invalid")
print()
if bssaddr >= memorybase and bssaddr < memorybase + memorysize:
print("bss:")
print(" address: 0x%08x" % (bssaddr))
print(" length: 0x%x" % (bsssize))
else:
print("bss unused or invalid")
print()
for x in range(7):
if textloadaddr[x] >= memorybase and textloadaddr[x] < memorybase + memorysize - textsizes[x]:
print("text%i:" % (x+1))
print(" address: 0x%08x" % (textloadaddr[x]))
print(" length: 0x%x" % (textsizes[x]))
print(" offset: 0x%x" % (textoffsets[x]))
memory[textloadaddr[x]-memorybase:textloadaddr[x]+textsizes[x]-memorybase] = doldata[textoffsets[x]:textoffsets[x]+textsizes[x]]
else:
print("text%i unused or invalid" % (x+1))
print()
for x in range(11):
if dataloadaddr[x] >= memorybase and dataloadaddr[x] < memorybase + memorysize - datasizes[x]:
print("data%i:" % (x+1))
print(" address: 0x%08x" % (dataloadaddr[x]))
print(" length: 0x%x" % (datasizes[x]))
print(" offset: 0x%x" % (dataoffsets[x]))
memory[dataloadaddr[x]-memorybase:dataloadaddr[x]+datasizes[x]-memorybase] = doldata[dataoffsets[x]:dataoffsets[x]+datasizes[x]]
else:
print("data%i unused or invalid" % (x+1))
print("loaded '%s' successfully" % (dolfilename))
elif sys.argv[1] == "dump":
dumpfilename = sys.argv[2]
print("loading memory dump file '%s'..." % (dumpfilename))
f = open(dumpfilename, "rb")
memory = f.read()
f.close()
print("loaded '%s' successfully" % (dumpfilename))
memory = bytearray(memory)
oldstring = sys.argv[3]
newstring = sys.argv[4]
codelength = len(oldstring)
if len(newstring) > len(oldstring):
print("new string is larger than old string, you will overwrite memory!!")
codelength = len(newstring)
elif len(oldstring) > len(newstring):
# might add automatically replacing substrings later, but not right now
print("new string is shorter than old string, will fill in the blank with null bytes")
if len(newstring) % 8 != 0:
newstring = newstring + ('\0' * 0x8) # lazy padding to avoid problems
noinstance = False
lastinstance = 0
instances = []
print("searching for instances of %s" % (oldstring))
while not noinstance:
lastinstance = memory.find(bytearray(oldstring, "utf8"), lastinstance + len(oldstring), memorysize)
if lastinstance > 0:
print("found string at %08x" % (lastinstance))
instances.append(lastinstance)
else:
noinstance = True
print()
print("code:")
for instance in instances:
print("%08x %08x" % (instance | 0x06000000, codelength))
x = 0
while x < (codelength - 1):
print("%02x%02x%02x%02x %02x%02x%02x%02x" % ( ord(newstring[x]), ord(newstring[x+1]), ord(newstring[x+2]), ord(newstring[x+3]), ord(newstring[x+4]), ord(newstring[x+5]), ord(newstring[x+6]), ord(newstring[x+7]) ))
x += 8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment