public void insertCode(DirectoryInfo romdir, out string hookmap, out string replaces) { hookmap = ""; replaces = ""; try { if (!File.Exists(romdir.FullName + @"\bak_safe\main.bin")) { if (File.Exists(romdir.FullName + @"\bak\main.bin")) { if (!Directory.Exists(romdir.FullName + @"\bak_safe")) { Directory.CreateDirectory(romdir.FullName + @"\bak_safe"); } File.Copy(romdir.FullName + @"\bak\main.bin", romdir.FullName + @"\bak_safe\main.bin", true); } else { this.handler.makeBinBackup(-1, true); } } File.Copy(romdir.FullName + @"\bak_safe\main.bin", romdir.FullName + @"\bak\main.bin", true); } catch (Exception ex) { new ErrorMSGBox("", "", "", ex.ToString()).ShowDialog(); } FileInfo fileInfo1 = new FileInfo(romdir.FullName + "/codemap.x"); if (!fileInfo1.Exists) { return; } StreamReader streamReader1 = new StreamReader(fileInfo1.FullName, Encoding.UTF8); while (!streamReader1.EndOfStream) { string str1 = streamReader1.ReadLine(); string[] strArray = str1.Split(' '); if (strArray.Length != 2 && strArray.Length != 3) { new ErrorMSGBox("", "", "", "Error: Wrong Codemap line format (" + str1 + ")").ShowDialog(); } else { string str2 = strArray[0]; if (!Directory.Exists(romdir.FullName + "/" + str2)) { new ErrorMSGBox("", "", "", "Error: Directory \"" + str2 + "\" does not exist").ShowDialog(); } else { if (strArray[1].StartsWith("0x")) { strArray[1] = strArray[1].Substring(2); } if (strArray[2].StartsWith("0x")) { strArray[2] = strArray[2].Substring(2); } int hex = PatchMaker.parseHex(strArray[1]); if (hex < 33554432) { new ErrorMSGBox("", "", "", "Error: Destination address of " + strArray[0] + " is too small (0x" + hex.ToString("X8") + ")").ShowDialog(); } else if (hex > 50331647) { new ErrorMSGBox("", "", "", "Error: Destination address of " + strArray[0] + " is too big (0x" + hex.ToString("X8") + ")").ShowDialog(); } else { int num5 = -1; if (strArray.Length == 3) { num5 = PatchMaker.parseHex(strArray[2]); } PatchCompiler.runProcess("make clean", romdir.FullName + "/" + strArray[0]); if (PatchCompiler.runProcess("make CODEADDR=0x" + hex.ToString("X8"), romdir.FullName + "/" + strArray[0]) != 0) { new ErrorMSGBox("", "", "", "Error: Compilation of " + strArray[0] + " failed.").ShowDialog(); } else { string str3 = romdir.FullName + "/" + str2 + "/newcode.bin"; if (!File.Exists(str3)) { new ErrorMSGBox("", "", "", "Insert Code Binary \"" + str3 + "\" does not exist!").ShowDialog(); break; } long length1 = new FileInfo(str3).Length; if (length1 > (long)num5) { new ErrorMSGBox("", "", "", "Insert Code Binary \"" + str3 + "\" size (" + (object)length1 + ") exeeds given maximum size (" + (object)num5 + ")").ShowDialog(); break; } FileInfo fileInfo2 = new FileInfo(romdir.FullName + "/" + strArray[0] + "/replaces.x"); List <PatchMaker.Replace> replaceList = new List <PatchMaker.Replace>(); if (fileInfo2.Exists) { StreamReader streamReader2 = new StreamReader(fileInfo2.FullName, Encoding.UTF8); while (!streamReader2.EndOfStream) { string str4 = streamReader2.ReadLine().Replace("\n", "").Replace("\t", ""); if (str4.Contains("@")) { str4 = str4.Substring(0, str4.IndexOf("@")); } List <string> stringList = new List <string>((IEnumerable <string>)str4.Split(' ')); for (int index = stringList.Count - 1; index >= 0; --index) { if (stringList[index] == "") { stringList.RemoveAt(index); } } if (stringList.Count != 0) { if (stringList.Count != 2) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong format.\n\nInput line: \"" + str4 + "\"").ShowDialog(); } else { int num8 = 9; if (stringList[0].Contains("_ov_")) { num8 += 6; } if (stringList[0].Length != num8 || !stringList[0].EndsWith(":")) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong format.\n\nInput line: \"" + str4 + "\"").ShowDialog(); } else { PatchMaker.Replace replace; if (!int.TryParse(str4.Substring(0, 8), NumberStyles.HexNumber, (IFormatProvider)null, out replace.ramAddr)) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong address format.\n\nInput address: \"" + str4.Substring(0, 8) + "\"").ShowDialog(); } else { replace.ovId = -1; if (stringList[0].Contains("_ov_") && !int.TryParse(str4.Substring(str4.IndexOf("_ov_") + 4, 2), NumberStyles.HexNumber, (IFormatProvider)null, out replace.ovId)) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong overlay format.\n\nInput overlay: \"" + str4.Substring(str4.IndexOf("_ov_") + 4, 2) + "\"").ShowDialog(); } else { uint result; if (uint.TryParse(stringList[1].Replace("0x", ""), NumberStyles.HexNumber, (IFormatProvider)null, out result)) { replaces = replaces + str4 + "\n"; } else { replace.funcName = stringList[1]; replaceList.Add(replace); } } } } } } } streamReader2.Close(); } StreamReader streamReader3 = new StreamReader(romdir.FullName + "/" + strArray[0] + "/newcode.sym", Encoding.UTF8); while (!streamReader3.EndOfStream) { string str4 = streamReader3.ReadLine(); for (int index = replaceList.Count - 1; index >= 0; --index) { PatchMaker.Replace replace = replaceList[index]; if (str4.Contains(replace.funcName) && (str4.Contains(".text") || str4.Contains(".data"))) { uint result; if (!uint.TryParse(str4.Substring(0, 8), NumberStyles.HexNumber, (IFormatProvider)null, out result)) { new ErrorMSGBox("", "", "", "Failed parsing destination adress: Wrong adress format.\n\nInput adress: \"" + str4.Substring(0, 8) + "\"").ShowDialog(); } else { if (replace.ovId == -1) { replaces = replaces + replace.ramAddr.ToString("X8") + " 0x" + result.ToString("X8") + "\n"; } else { replaces = replaces + replace.ramAddr.ToString("X8") + "_ov_" + replace.ovId.ToString("X2") + " 0x" + result.ToString("X8") + "\n"; } replaceList.Remove(replace); } } } int startIndex = -1; if (str4.Contains("nsub_")) { startIndex = str4.IndexOf("nsub_"); } if (str4.Contains("hook_")) { startIndex = str4.IndexOf("hook_"); } if (str4.Contains("repl_")) { startIndex = str4.IndexOf("repl_"); } if (startIndex != -1) { string str5 = str4.Substring(startIndex); int length2 = 13; if (str5.Contains("_ov_")) { length2 += 6; } else if (str5.Contains("_main")) { length2 += 5; } string str6 = str5.Substring(0, length2); hookmap = hookmap + str6 + ": " + str4.Substring(0, 8) + "\n"; } } streamReader3.Close(); string str7 = ""; foreach (PatchMaker.Replace replace in replaceList) { str7 = str7 + "\n" + replace.funcName; } if (str7 != "") { new ErrorMSGBox("", "", "", "Some replaces were not found:\n" + str7).ShowDialog(); } string path = romdir.FullName + "/bak/main.bin"; if (!File.Exists(path)) { new ErrorMSGBox("", "", "", "ARM 9 Binary \"" + path + "\" does not exist!").ShowDialog(); break; } byte[] bytes = File.ReadAllBytes(romdir.ToString() + "/bak/main.bin"); byte[] numArray = File.ReadAllBytes(str3); Array.Copy((Array)numArray, 0, (Array)bytes, hex - 33554432, numArray.Length); File.WriteAllBytes(path, bytes); } } } } } }
public void generatePatch(string hookmap = "", string replaces = "") { int codeAddr = (int)getCodeAddr(); Console.Out.WriteLine(String.Format("New code address: {0:X8}", codeAddr)); FileInfo f = new FileInfo(romdir.FullName + "/newcode.bin"); if (!f.Exists) { return; } FileStream fs = f.OpenRead(); byte[] newdata = new byte[fs.Length]; fs.Read(newdata, 0, (int)fs.Length); fs.Close(); ByteArrayOutputStream extradata = new ByteArrayOutputStream(); extradata.write(newdata); extradata.align(4); int hookAddr = codeAddr + extradata.getPos(); #region Decompiled replaces.x code mess Console.WriteLine(replaces); string str1 = replaces; char[] chArray1 = new char[1] { '\n' }; foreach (string str2 in str1.Split(chArray1)) { char[] chArray2 = new char[1] { ' ' }; string[] strArray = str2.Split(chArray2); if (strArray.Length == 2) { strArray[1] = strArray[1].Replace("0x", ""); int ov = -1; if (strArray[0].Contains("_ov_")) { ov = int.Parse(strArray[0].Substring(strArray[0].IndexOf("_ov_") + 4, 2), NumberStyles.HexNumber); } uint uhex = PatchMaker.parseUHex(strArray[1]); this.handler.writeToRamAddr(PatchMaker.parseHex(strArray[0].Substring(0, 8)), uhex, ov); } } FileInfo fileInfo2 = new FileInfo(this.romdir.FullName + "/replaces.x"); List <PatchMaker.Replace> replaceList = new List <PatchMaker.Replace>(); if (fileInfo2.Exists) { StreamReader streamReader = new StreamReader(fileInfo2.FullName, Encoding.UTF8); while (!streamReader.EndOfStream) { string str2 = streamReader.ReadLine().Replace("\n", "").Replace("\t", ""); if (str2.Contains("@")) { str2 = str2.Substring(0, str2.IndexOf("@")); } List <string> stringList = new List <string>((IEnumerable <string>)str2.Split(' ')); for (int index = stringList.Count - 1; index >= 0; --index) { if (stringList[index] == "") { stringList.RemoveAt(index); } } if (stringList.Count != 0) { if (stringList.Count != 2) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong format.\n\nInput line: \"" + str2 + "\"").ShowDialog(); } else { int num2 = 9; if (stringList[0].Contains("_ov_")) { num2 += 6; } if (stringList[0].Length != num2 || !stringList[0].EndsWith(":")) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong format.\n\nInput line: \"" + str2 + "\"").ShowDialog(); } else { PatchMaker.Replace replace; if (!int.TryParse(str2.Substring(0, 8), NumberStyles.HexNumber, (IFormatProvider)null, out replace.ramAddr)) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong address format.\n\nInput address: \"" + str2.Substring(0, 8) + "\"").ShowDialog(); } else { replace.ovId = -1; if (stringList[0].Contains("_ov_") && !int.TryParse(str2.Substring(str2.IndexOf("_ov_") + 4, 2), NumberStyles.HexNumber, (IFormatProvider)null, out replace.ovId)) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong overlay format.\n\nInput overlay: \"" + str2.Substring(str2.IndexOf("_ov_") + 4, 2) + "\"").ShowDialog(); } else { uint result; if (uint.TryParse(stringList[1].Replace("0x", ""), NumberStyles.HexNumber, (IFormatProvider)null, out result)) { this.handler.writeToRamAddr(replace.ramAddr, result, replace.ovId); } else { replace.funcName = stringList[1]; replaceList.Add(replace); } } } } } } } streamReader.Close(); } #endregion f = new FileInfo(romdir.FullName + "/newcode.sym"); StreamReader s = f.OpenText(); while (!s.EndOfStream) { string l = s.ReadLine(); #region Decompiled replaces.x code mess for (int index = replaceList.Count - 1; index >= 0; --index) { PatchMaker.Replace replace = replaceList[index]; if (l.Contains(replace.funcName) && (l.Contains(".text") || l.Contains(".data"))) { uint result; if (!uint.TryParse(l.Substring(0, 8), NumberStyles.HexNumber, (IFormatProvider)null, out result)) { new ErrorMSGBox("", "", "", "Failed parsing destination adress: Wrong adress format.\n\nInput adress: \"" + l.Substring(0, 8) + "\"").ShowDialog(); } else { this.handler.writeToRamAddr(replace.ramAddr, result, replace.ovId); replaceList.Remove(replace); } } } #endregion int ind = -1; String[,] instructionNames = new String[2, 5] { { "ansub", "ahook", "arepl", "trepl", "tnsub" }, //MKDS instructions { "nsub", "hook", "repl", "xrpl", "lrpl" } //NSMB equivalents }; foreach (String instructionName in instructionNames) { if (l.Contains(instructionName + "_")) { ind = l.IndexOf(instructionName + "_"); break; } } if (ind != -1) { int destRamAddr = parseHex(l.Substring(0, 8)); //Redirect dest addr //Determining if the instruction is 4 or 5 characters long (repl vs arepl, ...) bool isFiveLetterInstruction = l[ind + 5] == '_'; int startingIndex = isFiveLetterInstruction ? ind + 6 : ind + 5; //Determining if the address is 7 or 8 characters long (200... vs 0200...) bool isEightCharactersAddress = l[startingIndex] == '0'; String ramAddress = l.Substring(startingIndex, isEightCharactersAddress ? 8 : 7); if (!isEightCharactersAddress) { ramAddress = "0" + ramAddress; } int ramAddr = parseHex(ramAddress); //Patched addr uint val = 0; int ovId = -1; if (l.Contains("_ov_")) { ovId = parseHex(l.Substring(l.IndexOf("_ov_") + 4, 2)); } String retAddress; if (l.Contains("_retAddr_")) { startingIndex = l.IndexOf("_retAddr_") + 9; isEightCharactersAddress = l[startingIndex] == '0'; retAddress = l.Substring(startingIndex, isEightCharactersAddress ? 8 : 7); if (!isEightCharactersAddress) { retAddress = "0" + retAddress; } } string cmd = l.Substring(ind, isFiveLetterInstruction ? 5 : 4); int thisHookAddr = 0; UInt16 pushLR = 0xB500; UInt16 popPC = 0xBD00; switch (cmd) { case "ansub": case "nsub": val = makeBranchOpcode(ramAddr, destRamAddr, Branch.WITHOUT_BRANCH); break; case "arepl": case "repl": val = makeBranchOpcode(ramAddr, destRamAddr, Branch.WITH_BRANCH); break; case "trepl": case "xrpl": val = makeBranchOpcode(ramAddr, destRamAddr, Branch.WITH_BRANCH, Mode.THUMB); break; case "tnsub": case "lrpl": /*https://www.ece.uvic.ca/~ece255/lab/docs/ARM7-TDMI-manual-pt3.pdf * Opcodes for Thumb Push and Pop * The goal of this instruction is to push LR/PC before * it gets overwritten, then run a custom instruction with a BLX (?) * and at the end of it return to the original position. * This is essentially an 8-byte tnsub with some extra tinkering around * * PUSH {R14 (LR/PC))} * BLX label * POP {R14 (LR/PC)} * */ handler.writeToRamAddr(ramAddr, pushLR, ovId); ramAddr += 2; handler.writeToRamAddr(ramAddr, makeBranchOpcode(ramAddr, destRamAddr, Branch.WITH_BRANCH, Mode.THUMB), ovId); ramAddr += 4; val = popPC; break; case "ahook": case "hook": //Jump to the hook addr thisHookAddr = hookAddr; val = makeBranchOpcode(ramAddr, hookAddr, 0); uint originalOpcode = handler.readFromRamAddr(ramAddr, ovId); //TODO: Parse and fix original opcode in case of BL instructions //so it's possible to hook over them too. extradata.writeUInt(originalOpcode); hookAddr += 4; extradata.writeUInt(0xE92D5FFF); //push {r0-r12, r14} hookAddr += 4; extradata.writeUInt(makeBranchOpcode(hookAddr, destRamAddr, Branch.WITH_BRANCH)); hookAddr += 4; extradata.writeUInt(0xE8BD5FFF); //pop {r0-r12, r14} hookAddr += 4; extradata.writeUInt(makeBranchOpcode(hookAddr, ramAddr + 4, Branch.WITHOUT_BRANCH)); hookAddr += 4; extradata.writeUInt(0x12345678); hookAddr += 4; break; default: continue; } Console.Out.WriteLine(String.Format(" {0:X8} {1:X8}", destRamAddr, thisHookAddr)); handler.writeToRamAddr(ramAddr, val, ovId); } } #region Decompiled replaces.x code mess string str4 = hookmap; char[] chArray3 = new char[1] { '\n' }; foreach (string str2 in str4.Split(chArray3)) { if (!(str2 == "")) { int hex1 = PatchMaker.parseHex(str2.Substring(str2.Length - 8, 8)); int hex2 = PatchMaker.parseHex(str2.Substring(5, 8)); int ov = -1; if (str2.Contains("_ov_")) { ov = PatchMaker.parseHex(str2.Substring(str2.IndexOf("_ov_") + 4, 2)); } string str3 = str2.Substring(0, 4); uint val; if (!(str3 == "nsub")) { if (!(str3 == "repl")) { if (str3 == "hook") { val = PatchMaker.makeBranchOpcode(hex2, hookAddr, 0); uint u = this.handler.readFromRamAddr(hex2, ov); extradata.writeUInt(u); int num1 = hookAddr + 4; extradata.writeUInt(3912065023U); int srcAddr1 = num1 + 4; extradata.writeUInt(PatchMaker.makeBranchOpcode(srcAddr1, hex1, Branch.WITH_BRANCH)); int num2 = srcAddr1 + 4; extradata.writeUInt(3904724991U); int srcAddr2 = num2 + 4; extradata.writeUInt(PatchMaker.makeBranchOpcode(srcAddr2, hex2 + 4, Branch.WITHOUT_BRANCH)); int num3 = srcAddr2 + 4; extradata.writeUInt(305419896U); hookAddr = num3 + 4; } else { continue; } } else { val = PatchMaker.makeBranchOpcode(hex2, hex1, Branch.WITH_BRANCH); } } else { val = PatchMaker.makeBranchOpcode(hex2, hex1, 0); } this.handler.writeToRamAddr(hex2, val, ov); } } string str5 = ""; foreach (PatchMaker.Replace replace in replaceList) { str5 = str5 + "\n" + replace.funcName; } if (str5 != "") { new ErrorMSGBox("", "", "", "Some replaces were not found:\n" + str5).ShowDialog(); } #endregion s.Close(); int newArenaOffs = codeAddr + extradata.getPos(); handler.writeToRamAddr(ArenaLoOffs, (uint)newArenaOffs, -1); handler.sections.Add(new Arm9BinSection(extradata.getArray(), codeAddr, 0)); handler.saveSections(); }
public void generatePatch(string hookmap = "", string replaces = "") { int codeAddr = (int)getCodeAddr(); Console.Out.WriteLine(String.Format("New code address: {0:X8}", codeAddr)); FileInfo f = new FileInfo(romdir.FullName + "/newcode.bin"); if (!f.Exists) { return; } FileStream fs = f.OpenRead(); byte[] newdata = new byte[fs.Length]; fs.Read(newdata, 0, (int)fs.Length); fs.Close(); ByteArrayOutputStream extradata = new ByteArrayOutputStream(); extradata.write(newdata); extradata.align(4); int hookAddr = codeAddr + extradata.getPos(); #region Decompiled replaces.x code mess Console.WriteLine(replaces); string str1 = replaces; char[] chArray1 = new char[1] { '\n' }; foreach (string str2 in str1.Split(chArray1)) { char[] chArray2 = new char[1] { ' ' }; string[] strArray = str2.Split(chArray2); if (strArray.Length == 2) { strArray[1] = strArray[1].Replace("0x", ""); int ov = -1; if (strArray[0].Contains("_ov_")) { ov = int.Parse(strArray[0].Substring(strArray[0].IndexOf("_ov_") + 4, 2), NumberStyles.HexNumber); } uint uhex = PatchMaker.parseUHex(strArray[1]); this.handler.writeToRamAddr(PatchMaker.parseHex(strArray[0].Substring(0, 8)), uhex, ov); } } FileInfo fileInfo2 = new FileInfo(this.romdir.FullName + "/replaces.x"); List <PatchMaker.Replace> replaceList = new List <PatchMaker.Replace>(); if (fileInfo2.Exists) { StreamReader streamReader = new StreamReader(fileInfo2.FullName, Encoding.UTF8); while (!streamReader.EndOfStream) { string str2 = streamReader.ReadLine().Replace("\n", "").Replace("\t", ""); if (str2.Contains("@")) { str2 = str2.Substring(0, str2.IndexOf("@")); } List <string> stringList = new List <string>((IEnumerable <string>)str2.Split(' ')); for (int index = stringList.Count - 1; index >= 0; --index) { if (stringList[index] == "") { stringList.RemoveAt(index); } } if (stringList.Count != 0) { if (stringList.Count != 2) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong format.\n\nInput line: \"" + str2 + "\"").ShowDialog(); } else { int num2 = 9; if (stringList[0].Contains("_ov_")) { num2 += 6; } if (stringList[0].Length != num2 || !stringList[0].EndsWith(":")) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong format.\n\nInput line: \"" + str2 + "\"").ShowDialog(); } else { PatchMaker.Replace replace; if (!int.TryParse(str2.Substring(0, 8), NumberStyles.HexNumber, (IFormatProvider)null, out replace.ramAddr)) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong address format.\n\nInput address: \"" + str2.Substring(0, 8) + "\"").ShowDialog(); } else { replace.ovId = -1; if (stringList[0].Contains("_ov_") && !int.TryParse(str2.Substring(str2.IndexOf("_ov_") + 4, 2), NumberStyles.HexNumber, (IFormatProvider)null, out replace.ovId)) { new ErrorMSGBox("", "", "", "Failed parsing replace: Wrong overlay format.\n\nInput overlay: \"" + str2.Substring(str2.IndexOf("_ov_") + 4, 2) + "\"").ShowDialog(); } else { uint result; if (uint.TryParse(stringList[1].Replace("0x", ""), NumberStyles.HexNumber, (IFormatProvider)null, out result)) { this.handler.writeToRamAddr(replace.ramAddr, result, replace.ovId); } else { replace.funcName = stringList[1]; replaceList.Add(replace); } } } } } } } streamReader.Close(); } #endregion f = new FileInfo(romdir.FullName + "/newcode.sym"); StreamReader s = f.OpenText(); while (!s.EndOfStream) { string l = s.ReadLine(); #region Decompiled replaces.x code mess for (int index = replaceList.Count - 1; index >= 0; --index) { PatchMaker.Replace replace = replaceList[index]; if (l.Contains(replace.funcName) && (l.Contains(".text") || l.Contains(".data"))) { uint result; if (!uint.TryParse(l.Substring(0, 8), NumberStyles.HexNumber, (IFormatProvider)null, out result)) { new ErrorMSGBox("", "", "", "Failed parsing destination adress: Wrong adress format.\n\nInput adress: \"" + l.Substring(0, 8) + "\"").ShowDialog(); } else { this.handler.writeToRamAddr(replace.ramAddr, result, replace.ovId); replaceList.Remove(replace); } } } #endregion int ind = -1; if (l.Contains("nsub_")) { ind = l.IndexOf("nsub_"); } if (l.Contains("hook_")) { ind = l.IndexOf("hook_"); } if (l.Contains("repl_")) { ind = l.IndexOf("repl_"); } if (l.Contains("xrpl_")) { ind = l.IndexOf("xrpl_"); } if (l.Contains("lrpl_")) { ind = l.IndexOf("lrpl_"); } if (ind != -1) { int destRamAddr = parseHex(l.Substring(0, 8)); //Redirect dest addr int ramAddr = parseHex(l.Substring(ind + 5, 8)); //Patched addr uint val = 0; int ovId = -1; if (l.Contains("_ov_")) { ovId = parseHex(l.Substring(l.IndexOf("_ov_") + 4, 2)); } int patchCategory = 0; string cmd = l.Substring(ind, 4); int thisHookAddr = 0; switch (cmd) { case "nsub": val = makeBranchOpcode(ramAddr, destRamAddr, 0); break; case "repl": val = makeBranchOpcode(ramAddr, destRamAddr, 1); break; case "xrpl": val = makeBranchOpcode(ramAddr, destRamAddr, 2); break; case "lrpl": UInt16 lrvalue = 0xB500; //push {r14} handler.writeToRamAddr(ramAddr, lrvalue, ovId); ramAddr += 2; val = makeBranchOpcode(ramAddr, destRamAddr, 2); break; case "hook": //Jump to the hook addr thisHookAddr = hookAddr; val = makeBranchOpcode(ramAddr, hookAddr, 0); uint originalOpcode = handler.readFromRamAddr(ramAddr, ovId); //TODO: Parse and fix original opcode in case of BL instructions //so it's possible to hook over them too. extradata.writeUInt(originalOpcode); hookAddr += 4; extradata.writeUInt(0xE92D5FFF); //push {r0-r12, r14} hookAddr += 4; extradata.writeUInt(makeBranchOpcode(hookAddr, destRamAddr, 1)); hookAddr += 4; extradata.writeUInt(0xE8BD5FFF); //pop {r0-r12, r14} hookAddr += 4; extradata.writeUInt(makeBranchOpcode(hookAddr, ramAddr + 4, 0)); hookAddr += 4; extradata.writeUInt(0x12345678); hookAddr += 4; break; default: continue; } //Console.Out.WriteLine(String.Format("{0:X8}:{1:X8} = {2:X8}", patchCategory, ramAddr, val)); Console.Out.WriteLine(String.Format(" {0:X8} {1:X8}", destRamAddr, thisHookAddr)); handler.writeToRamAddr(ramAddr, val, ovId); } } #region Decompiled replaces.x code mess string str4 = hookmap; char[] chArray3 = new char[1] { '\n' }; foreach (string str2 in str4.Split(chArray3)) { if (!(str2 == "")) { int hex1 = PatchMaker.parseHex(str2.Substring(str2.Length - 8, 8)); int hex2 = PatchMaker.parseHex(str2.Substring(5, 8)); int ov = -1; if (str2.Contains("_ov_")) { ov = PatchMaker.parseHex(str2.Substring(str2.IndexOf("_ov_") + 4, 2)); } string str3 = str2.Substring(0, 4); uint val; if (!(str3 == "nsub")) { if (!(str3 == "repl")) { if (str3 == "hook") { val = PatchMaker.makeBranchOpcode(hex2, hookAddr, 0); uint u = this.handler.readFromRamAddr(hex2, ov); extradata.writeUInt(u); int num1 = hookAddr + 4; extradata.writeUInt(3912065023U); int srcAddr1 = num1 + 4; extradata.writeUInt(PatchMaker.makeBranchOpcode(srcAddr1, hex1, 1)); int num2 = srcAddr1 + 4; extradata.writeUInt(3904724991U); int srcAddr2 = num2 + 4; extradata.writeUInt(PatchMaker.makeBranchOpcode(srcAddr2, hex2 + 4, 0)); int num3 = srcAddr2 + 4; extradata.writeUInt(305419896U); hookAddr = num3 + 4; } else { continue; } } else { val = PatchMaker.makeBranchOpcode(hex2, hex1, 1); } } else { val = PatchMaker.makeBranchOpcode(hex2, hex1, 0); } this.handler.writeToRamAddr(hex2, val, ov); } } string str5 = ""; foreach (PatchMaker.Replace replace in replaceList) { str5 = str5 + "\n" + replace.funcName; } if (str5 != "") { new ErrorMSGBox("", "", "", "Some replaces were not found:\n" + str5).ShowDialog(); } #endregion s.Close(); int newArenaOffs = codeAddr + extradata.getPos(); handler.writeToRamAddr(ArenaLoOffs, (uint)newArenaOffs, -1); handler.sections.Add(new Arm9BinSection(extradata.getArray(), codeAddr, 0)); handler.saveSections(); }