Beispiel #1
0
        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();
        }
Beispiel #2
0
        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();
        }