From ac025acbee97dcc0db830f8d08c5cac7867bf640 Mon Sep 17 00:00:00 2001 From: JoshuaMK <60854312+JoshuaMKW@users.noreply.github.com> Date: Sat, 11 Apr 2020 22:12:27 -0500 Subject: [PATCH] Add files via upload --- codehandler.bin | Bin 0 -> 2232 bytes main.py | 314 ++++++++++++++++++++++++++++++++++++++++++++++++ sme-code.bin | Bin 0 -> 868 bytes 3 files changed, 314 insertions(+) create mode 100644 codehandler.bin create mode 100644 main.py create mode 100644 sme-code.bin diff --git a/codehandler.bin b/codehandler.bin new file mode 100644 index 0000000000000000000000000000000000000000..e5cbb7882b897e4e5f344cd2a42c7234959035fa GIT binary patch literal 2232 zcmd5-{ZCwF7Cv|80+%{*$IVSUZAiJm^n-SGr0K^p6mRd{ZIyOVA-*F@Y(hIW{eakF z-R#xed*^~fEOoXWD^?_xAX>6)8n%AyreeclmQC1=F{3etADX5=5L=Tb#l)nve7yU- zgBbsS{b47$dCq-5&Uwyr&bdRh^z%q-`^o&jgq||4T{S73m8c|j#5a`kXnkrJ_&J^% zH1v-Hq$IgUC;2^|x*>(9BpRP8qsb|ga=UJLqYao|0LpkhS(xz z>T~~4Y8cPiAGFjF|Bwf+SHQWtjBeDE6nO$7d&h}{KjEvrn52ihiDDWNJ67tlL%ZCU zT7$%r(xMx9)k18AeL;a}0a0WHN#+1~=Acv$+i!OAE5HKN^99U7xde8RIUw(@qk@f{ z_2B;Njr8~+Y1vD8|56=MmAkiPgn5O!P1*dO-F;vL>mhgV!6@_OU#usic5zFaP4XqX z`0%A=?oMWn8YvL5sow0M6GlJZ25yr1Aw}5fv~Hf`SK^$%8>=J{F93TOwr~4B&W!;+ zjdwYbp&GlZ!h*d&&KG~QyDKdFe1&E7`v&NR9c9}B!C^fLMv zC%nJ%*^c9Uo_#3m>@Qt9ySPD*c7em+`6K2hyv*nj`LslBIZLQj069i+f4iM-R-MYz zYMzV7bBJxRqeY9zC74iV-Q`-qm;9U4RM4m>wMIW#=AZm&k++$lfZ0P;$g9NY!5!q$ zfr%0CuxsCgZFg(4iORI@wANL#w5+Ed(2NtqdA&lBV)7wY2)dOReWVH9%{~eNgXTLF z1S)1PDF+mij57<@%$|iQ3u5l=wZiR8)Iiyj=G0mRKZ25L5;mWqK>UZ?eY9s z#qO)HU<)0C&ephPd_;=d)~B*Vhj*bbiw%z$eEq@hE*CxxySwaLV6_vjuz*!gSgQtZ zbi(E0UBkPmXUGYM1qSzrH65rp;q_Hn#EzrQ;CF@DF<(CpJ;$FSy6vMEg>JWf%BEa% z{!Eoq=Nn=d*ILfLP3kgdr_Mhl=G_>Z53-}Wd`V1sdY>+tJe`C${VujXXrP?uJuQ@l9~PI%%2bNg3Qil&E}q z6unjJY^Yn>`}fk`dzC~YKKRS5by_#P1y#(N^Us57;!CQ9?_oQw&5AyCHfz-`v_ZZz zLSvQ=Rig$PdN1JI%I8t$OuwRH28$AR2zGXpO}aIov}HsX*Xs( zqct>iNuv#iiWYIc9gkv+@vBb6YG_<1jpBWOtc_&nY`KblnRg=3EU)hYw;uQ}gjO5D z>A6HEtvBt)(~NIaKqJ$ezh(z=WO(!6#QFWpO?&v_5op%#7rKR@C6zR;`PJ3dX7XV# z-{-KUH=pG5Pt^%N_wC37LUU;w^bs>P0Tg{T4)hzH_qCtq{{s8tWj|*2l<851xrKV^ zb@H*dY3&QM9z{ZEGSuVX-6~?e-r7=~Y;Afk? zdWL|iy=DsW`L&w6BqQIPhZ$~3`Y8)McZbirGoOimDOp;V^6TQ;Ao|nJqDIdb>LqFP z0_qay_b!S53HJ7*I_sU#S-Mciw|V;Mdxcw^zND4<{nu(!Gu0r!kbAf2CHF4nN`Ff} z@RC!{<{BcagcejHc)Q>Ghu(h$>o5Pu+6n!BNBl=SG>JTU4`z58H4cdXN$^nF(L#>d oTXdBAs>CYHx#&%0lf}BI6#f)@XfteY$-XSU=l5h>{h$2)3($_JumAu6 literal 0 HcmV?d00001 diff --git a/main.py b/main.py new file mode 100644 index 0000000..e89232c --- /dev/null +++ b/main.py @@ -0,0 +1,314 @@ +import sys, os, time + +def resource_path(relative_path): + """ Get absolute path to resource, works for dev and for PyInstaller """ + base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) + return os.path.join(base_path, relative_path) + +def build(gct, dol, size): + with open(resource_path('sme-code.bin'), 'rb') as code, open(dol, 'rb+') as dol, open(gct, 'rb') as gecko, open(resource_path('codehandler.bin'), 'rb') as handler, open('tmp.bin', 'wb+') as tmp, open(os.path.join('BUILD', os.path.split(r'{}'.format(dol))[1][:-2]), 'wb+') as final: + '''Initialize the new DOL file''' + + final.write(dol.read()) + + '''Initialize the sme-code loader''' + + tmp.write(code.read()) + code.seek(0, 0) + tmp.seek(0, 0) + + '''Search for main entry of loader''' + + entryIndex = 0 + sample = tmp.read(4) + while sample: + if sample == ENTRY: + tmp.seek(-4, 1) + tmp.write(bytes.fromhex('7C0802A6')) + break + entryIndex += 4 + sample = tmp.read(4) + tmp.seek(0) + + '''Get BSS section for insert''' + + final.seek(int('D8', 16)) + BSS = int(final.read(4).hex(), 16) + BSS_length = int(final.read(4).hex(), 16) + dump_address = '{:08X}'.format(int(BSS + (BSS_length / 2)))[:-2] + '00' + _START = bytes.fromhex('{:08X}'.format(int(dump_address, 16) + entryIndex)) + cLoader = bytes.fromhex(dump_address) + + '''Get address split for later''' + + upperAddr, lowerAddr = dump_address[:int(len(dump_address)/2)], dump_address[int(len(dump_address)/2):] + + '''Get code initialize address''' + + final.seek(int('E0', 16)) + _init = final.read(4) + + '''Patch the values for the addresses and such''' + + hooked = False + heaped = False + sized = False + fsized = False + + initUpperAddr = bytes.fromhex(upperAddr) + geckoUpperAddr = bytes.fromhex(upperAddr) + gUpperAddr = bytes.fromhex(upperAddr) + + while hooked == False or heaped == False or sized == False or fsized == False: + try: + sample = tmp.read(4) + if sample == HOOK: #Found keyword "HOOK". Goes with the entry to the game + if not hooked: + tmp.seek(-4, 1) + + initInfo = tmp.tell() + if int(lowerAddr, 16) + initInfo > int('7FFF', 16): #Absolute addressing + initUpperAddr = bytes.fromhex('{:04X}'.format(int(upperAddr, 16) + 1)) + if int(lowerAddr, 16) + (initInfo + 4) > int('7FFF', 16): #Absolute addressing + geckoUpperAddr = bytes.fromhex('{:04X}'.format(int(upperAddr, 16) + 1)) + + tmp.write(_init) + hooked = True + elif sample == HEAP: #Found keyword "HEAP". Goes with the resize of the heap + if not heaped: + tmp.seek(-4, 1) + + gInfo = tmp.tell() + if int(lowerAddr, 16) + gInfo > int('7FFF', 16): #Absolute addressing + gUpperAddr = bytes.fromhex('{:04X}'.format(int(upperAddr, 16) + 1)) + + tmp.write(size) + heaped = True + elif sample == LOADERSIZE: #Found keyword "LSIZ". Goes with the size of the loader + if not sized: + tmp.seek(-4, 1) + tmp.write(get_size(code)) + sized = True + elif sample == FULLSIZE: #Found keyword "FSIZ". Goes with the size of the loader + codes + if not fsized: + tmp.seek(-4, 1) + code.seek(0, 2) + gecko.seek(0, 2) + tmp.write(get_size(code, gecko.tell())) + fsized = True + except TypeError as err: + print('Fatal error, (' + err + ') build failed to complete') + time.sleep(3) + sys.exit(1) + + '''Patch all load/store offsets to data''' + + tmp.seek(0) + sample = tmp.read(2) + while sample: + if sample == GH: + tmp.seek(-2, 1) + tmp.write(gUpperAddr) + elif sample == GL: + tmp.seek(-2, 1) + tmp.write(bytes.fromhex('{:04X}'.format(int(lowerAddr, 16) + gInfo))) + elif sample == CH: + tmp.seek(-2, 1) + tmp.write(geckoUpperAddr) + elif sample == CL: + tmp.seek(-2, 1) + tmp.write(bytes.fromhex('{:04X}'.format(int(lowerAddr, 16) + (initInfo + 4)))) + elif sample == IH: + tmp.seek(-2, 1) + tmp.write(initUpperAddr) + elif sample == IL: + tmp.seek(-2, 1) + tmp.write(bytes.fromhex('{:04X}'.format(int(lowerAddr, 16) + initInfo))) + elif sample == JH: + tmp.seek(-2, 1) + tmp.write(geckoUpperAddr) + elif sample == JL: + tmp.seek(-2, 1) + tmp.write(bytes.fromhex('{:04X}'.format(int(lowerAddr, 16) + (initInfo + 8)))) + sample = tmp.read(2) + + tmp.seek(0) + gecko.seek(0) + dol_handler_offset = get_size(final) + final.write(handler.read()) + time.sleep(0.01) + dol_sme_offset = get_size(final) + final.write(tmp.read()) + time.sleep(0.01) + final.write(gecko.read()) + final.seek(0, 0) + status = False + i = 0 + while i < 6: + size = int(final.read(4).hex(), 16) + if size == 0: + status = True + offset = i * 4 + final.seek(-4, 1) + final.write(dol_handler_offset) + final.write(dol_sme_offset) + + final.seek(int('48', 16) + offset) + final.write(bytes.fromhex('80001800')) + final.write(cLoader) + final.seek(int('E0', 16)) + final.write(_START) + handler_size = get_size(handler) + tmp.seek(0, 2) + gecko.seek(0, 2) + sme_code_size = get_size(tmp, gecko.tell()) + final.seek(int('90', 16) + offset) + final.write(handler_size) + final.write(sme_code_size) + break + else: + i += 1 + if status == False: + print('Not enough sections to patch the DOL file! Potentially due to previous mods?') + +def get_size(file, offset=0): + """ Return a file's size in bytes """ + file.seek(0, 2) + return(bytes.fromhex('{:08X}'.format(file.tell() + offset))) + + +if __name__ == "__main__": + if len(sys.argv) == 1: + while True: + gct = input('Name of the input GCT file? ') + if os.path.splitext(gct)[1] == '': + gct = gct + '.gct' + if os.path.splitext(gct)[1] != '.gct' and os.path.splitext(gct)[1] != '.GCT': + print('Invalid input!') + continue + if os.path.exists(gct): + gct = os.path.abspath(gct) + break + else: + print('File not found! Please try again.') + while True: + dol = input('Name of the input dol file? ') + if os.path.splitext(dol)[1] == '': + dol = dol + '.dol' + if os.path.splitext(dol)[1] != '.dol': + print('Invalid input!') + continue + if os.path.exists(dol): + dol = os.path.abspath(dol) + break + else: + print('File not found! Please try again.') + elif len(sys.argv) == 2: + if sys.argv[1].endswith('.gct') or sys.argv[1].endswith('.GCT'): + gct = sys.argv[1] + while True: + dol = input('Name of the input dol file? ') + if os.path.splitext(dol)[1] == '': + dol = dol + '.dol' + if os.path.splitext(dol)[1] != '.dol': + print('Invalid input!') + continue + if os.path.exists(dol): + dol = os.path.abspath(dol) + break + else: + print('File not found! Please try again.') + elif sys.argv[1].endswith('.dol'): + dol = sys.argv[1] + while True: + gct = input('Name of the input GCT file? ') + if os.path.splitext(gct)[1] == '': + gct = gct + '.gct' + if os.path.splitext(gct)[1] != '.gct' and os.path.splitext(gct)[1] != '.GCT': + print('Invalid input!') + continue + if os.path.exists(gct): + gct = os.path.abspath(gct) + break + else: + print('File not found! Please try again.') + else: + print('The given file is invalid! Please provide a valid dol file, a valid GCT file, or both.') + time.sleep(1) + sys.exit(1) + else: + if sys.argv[1].endswith('.gct') or sys.argv[1].endswith('.GCT'): + gct = sys.argv[1] + if sys.argv[2].endswith('.dol'): + dol = sys.argv[2] + else: + while True: + dol = input('Name of the input DOL file? ') + if os.path.splitext(dol)[1] == '': + dol = dol + '.dol' + if os.path.splitext(dol)[1] != '.dol': + print('Invalid input!') + continue + if os.path.exists(dol): + dol = os.path.abspath(dol) + break + else: + print('File not found! Please try again.') + elif sys.argv[1].endswith('.dol'): + dol = sys.argv[1] + if sys.argv[2].endswith('.gct') or sys.argv[2].endswith('.GCT'): + gct = sys.argv[2] + else: + while True: + gct = input('Name of the input GCT file? ') + if os.path.splitext(gct)[1] == '': + gct = gct + '.gct' + if os.path.splitext(gct)[1] != '.gct' and os.path.splitext(gct)[1] != '.GCT': + print('Invalid input!') + continue + if os.path.exists(gct): + gct = os.path.abspath(gct) + break + else: + print('File not found! Please try again.') + else: + print('The given files are invalid! Please provide a valid DOL file, a valid GCT file, or both.') + sys.exit(1) + + + while True: + size = input('Define desired code space. (Hex): ') + try: + int(size, 16) + break + except Exception: + print('Invalid input!') + time1 = time.time() + + HEAP = bytes.fromhex('48454150') + LOADERSIZE = bytes.fromhex('4C53495A') + FULLSIZE = bytes.fromhex('4653495A') + HOOK = bytes.fromhex('484F4F4B') + ENTRY = bytes.fromhex('454E5452') + GH = bytes.fromhex('4748') + GL = bytes.fromhex('474C') + CH = bytes.fromhex('4348') + CL = bytes.fromhex('434C') + IH = bytes.fromhex('4948') + IL = bytes.fromhex('494C') + JH = bytes.fromhex('4A48') + JL = bytes.fromhex('4A4C') + size = bytes.fromhex('{:08X}'.format(int(size, 16))) + + try: + if not os.path.isdir('BUILD'): + os.mkdir('BUILD') + build(gct, dol, size) + os.remove('tmp.bin') + print('Compiled in {:0.4f} seconds!'.format(time.time() - time1)) + time.sleep(4) + + except Exception as err: + print(err) + time.sleep(4) + sys.exit(1) diff --git a/sme-code.bin b/sme-code.bin new file mode 100644 index 0000000000000000000000000000000000000000..c173910a7ebbb2fd2ca8da0b16c2396e2a5a73f2 GIT binary patch literal 868 zcmaJ4{{*!!T}uLmP!mH940g0n>XM4-h5BI8VZDNyNmJ&sU$Yj0{%%+uvAjB|wuv`txo%k$`JRZmrVQbD0n3w!qEpOWZGq0@;M=@RgF? z5AY=g>MPC)q~+_qfVH5Lz8GPvhmDN-^YID|2aZg8te*DeDhAizBfkCxrmZ97J(O+w z-({+~1Vc8U+tF^^at_j-?A(pXpJ`w0Pb}6tNY)5b?Gf2QqL*i$gd}kkT;cE z0rmLZ;c0K`1NBkFAj>04vE5SpcTlST3h#G&bxlWRrL!TytFU;(+@ibd73#S{z0*I9 zkgqfYXTHv6b5H-xg2N?bp8kgPyXDXW;vh^hy~mvhW5m~R_>3p>Gro8o^60}3pCdeX zj>B2I!jq$LE;8!$^kR-TJH6;Xn|twymV|jMeoO^y4N0~M#`fV0jm{NVxmCjvrP25X VX%)rMxK+o)9Xfjp3mJO1^%rF)3P}I} literal 0 HcmV?d00001