public AddNode ( string name, XObjType objType ) : |
||
name | string | |
objType | XObjType | |
리턴 |
XNodeOut GetClassRef(TypeReference declaringType) { //if(!declaringType.IsGenericParameter && !declaringType.IsFunctionPointer) // XDef.ParseAndCheck(declaringType.ToString()); if (declaringType.IsGenericParameter) { Debug.WriteLine("GetClassRef for Generic Param - " + declaringType.ToString()); } if (declaringType.IsFunctionPointer) { Debug.WriteLine("GetClassRef for Function Pointer - " + declaringType.ToString()); } var scope = declaringType.Scope; if (scope.MetadataScopeType == MetadataScopeType.ModuleReference) { // is this scope type internal or external, should it be tracked externally? Debug.WriteLine("Skipped GetClassRef for - " + declaringType.ToString()); Debug.Assert(false); return(null); } //string namespaces = (declaringType.DeclaringType != null) ? declaringType.DeclaringType.Namespace : declaringType.Namespace; //string className = declaringType.Name; XNodeOut fileNode = null; // if xrayed internal if (scope.MetadataScopeType == MetadataScopeType.ModuleDefinition) { fileNode = XFile.FileNode; } // xrayed, but in diff module else if (Build.Files.Any(f => f.AssemblyName == scope.Name)) { fileNode = Build.Files.First(f => f.AssemblyName == scope.Name).FileNode; } // if not xrayed - map to external root else { string moduleName = scope.Name; fileNode = ExtRoot.AddNode(moduleName, XObjType.File); } return(SignatureToClass(declaringType.ToString(), fileNode)); }
public void Recompile(bool test) { if (Files.Count == 0) return; BuildStatus = ""; BuildError = ""; BuildSuccess = false; BuildThread = new Thread(() => { string stepname = ""; long linesAdded = 0; long trackedObjects = 0; try { BuildStatus = "Checking"; if (XDecompile.CheckIfAlreadyXRayed(Files) && !TryRestoreBackups()) { return; } BuildStatus = "Preparing"; // copy XLibrary to final destination CopyLocalToOutputDir("XLibrary.dll", OutputDir); if (EnableLocalViewer) { CopyLocalToOutputDir("OpenTK.dll", OutputDir); CopyLocalToOutputDir("OpenTK.GLControl.dll", OutputDir); CopyLocalToOutputDir("QuickFont.dll", OutputDir); } string errorLog = ""; XNodeOut.NextID = 0; XNodeOut root = new XNodeOut(null, "root", XObjType.Root); XNodeOut extRoot = root.AddNode("Not XRayed", XObjType.External); XNodeOut intRoot = root.AddNode("XRayed", XObjType.Internal); // init root file nodes so links can be made for processed fields before they are directly xrayed foreach (var item in Files) item.FileNode = intRoot.AddNode(Path.GetFileName(item.FilePath), XObjType.File); var callMap = new Dictionary<int, FunctionCall>(); var initMap = new Dictionary<int, FunctionCall>(); foreach (var item in Files) { var decompile = new XDecompile(this, intRoot, extRoot, item, callMap, initMap); try { if (CompileWithMS) { BuildStatus = "Decompiling " + item.FileName; decompile.MsDecompile(); // used for debugging tricky ilasm errors //for (int i = 0; i < int.MaxValue; i++) // { decompile.AllowedAdds = int.MaxValue; // i; decompile.AddsDone = 0; BuildStatus = "Scanning " + item.FileName; decompile.ScanLines(test); BuildStatus = "Recompiling " + item.FileName; item.RecompiledPath = decompile.Compile(); // } } else { BuildStatus = "Recompiling " + item.FileName; decompile.MonoRecompile(); } // remove signature // files that arent signed are coming up as signed meaning this would probably corrupt a file // also not sure if checked anymore - http://msdn.microsoft.com/en-us/library/cc713694.aspx //var meta = new MetaInfo(item.RecompiledPath); //if (meta.Load()) // meta.RemoveSignature(); // decompile to check if (DecompileAgain) { string filename = Path.GetFileName(item.FilePath); string compiler = CompileWithMS ? "MS" : "Mono"; // create directories var dir = Path.Combine(Application.StartupPath, "recompile", filename, compiler + "_original"); var originalPath = decompile.BackupPath != null ? decompile.BackupPath : item.FilePath; decompile.Decompile(originalPath, dir); dir = Path.Combine(Application.StartupPath, "recompile", filename, compiler + "_new"); decompile.Decompile(item.RecompiledPath, dir); } } catch (CompileError ex) { errorLog += item.FileName + "\r\n" + ex.Summary + "\r\n--------------------------------------------------------\r\n"; } catch (Exception ex) { BuildError = "Error recompiling: " + ex.Message + "\r\n" + ex.StackTrace; BuildStatus = "Error on " + item.FileName; return; } linesAdded += decompile.LinesAdded; } // save node map before verifying because we dont want bogus verify // errors from preventing the dat file form being made BuildStatus = "Saving Map"; var settings = new Dictionary<string, string>(); settings["Version"] = XRay.BuilderVersion; if (Pro.Verified) settings["Pro"] = Pro.SignedFile; if (EnableLocalViewer) { settings["EnableLocalViewer"] = EnableLocalViewer.ToString(); settings["EnableIpcServer"] = EnableIpcServer.ToString(); settings["ShowViewerOnStart"] = ShowViewerOnStart.ToString(); } if (EnableTcpServer) { settings["EnableTcpServer"] = EnableTcpServer.ToString(); settings["TcpListenPort"] = TcpListenPort.ToString(); settings["EncryptionKey"] = EncryptionKey; } settings["FunctionCount"] = XNodeOut.NextID.ToString(); var writePath = Path.Combine(OutputDir, "XRay.dat"); trackedObjects = SaveDat(writePath, settings, root, callMap, initMap); if (errorLog.Length > 0) { string logPath = Path.Combine(Application.StartupPath, "errorlog.txt"); File.WriteAllText(logPath, errorLog); Process.Start(logPath); } } catch (Exception ex) { BuildError = "Error during " + stepname + ": " + ex.Message; } BuildStatus = String.Format("Success! {0:#,#} instructions added, {1:#,#} objects tracked", linesAdded, trackedObjects); BuildSuccess = true; }); BuildThread.Start(); }
private void ReCompile(bool test) { XRayedFile[] files = FileList.Items.Cast<XRayedFile>().ToArray(); if (files.Length == 0) return; OptionsPanel.Enabled = false; // have to extract out because thread cant access gui elements bool trackFlow = TrackFlowCheckBox.Checked; bool trackExternal = TrackExternalCheckBox.Checked; bool trackAnon = TrackAnonCheckBox.Checked; bool trackFields = TrackFieldsCheckBox.Checked; bool trackInstances = TrackInstancesCheckBox.Checked; bool replaceOriginal = ReplaceOriginalCheckBox.Checked; bool doVerify = RunVerifyCheckbox.Checked; bool compileWithMS = MsToolsCheckbox.Checked; bool decompileAgain = DecompileAgainCheckbox.Checked; bool showUiOnStart = ShowOnStartCheckBox.Checked; bool saveMsil = SaveMsilCheckBox.Checked; bool decompileCSharp = DecompileCSharpCheckBox.Checked; new Thread(() => { string stepname = ""; var status = new Action<string, string>((step, name) => { stepname = step; RunInGui(() => StatusLabel.Text = step + " " + name); }); long linesAdded = 0; long trackedObjects = 0; try { status("checking", ""); if (XDecompile.CheckIfAlreadyXRayed(files) && !TryRestoreBackups(files)) { RunInGui(() => OptionsPanel.Enabled = true); return; } status("Preparing", ""); XDecompile.PrepareOutputDir(SourceDir, OutputDir); string errorLog = ""; XNodeOut.NextID = 0; XNodeOut root = new XNodeOut(null, "root", XObjType.Root); XNodeOut extRoot = root.AddNode("Not XRayed", XObjType.External); XNodeOut intRoot = root.AddNode("XRayed", XObjType.Internal); // init root file nodes so links can be made for processed fields before they are directly xrayed foreach (XRayedFile item in files) item.FileNode = intRoot.AddNode(Path.GetFileName(item.FilePath), XObjType.File); foreach (XRayedFile item in files) { XDecompile decompile = new XDecompile(intRoot, extRoot, item, OutputDir, DatPath, files, !replaceOriginal) { TrackFlow = trackFlow, TrackExternal = trackExternal, TrackAnon = trackAnon, TrackFields = trackFields, TrackInstances = trackInstances, ShowUIonStart = showUiOnStart, SaveMsil = saveMsil, DecompileCSharp = decompileCSharp }; try { if (compileWithMS) { status("Decompiling", item.FileName); decompile.MsDecompile(); // used for debugging tricky ilasm errors //for (int i = 0; i < int.MaxValue; i++) // { decompile.AllowedAdds = int.MaxValue; // i; decompile.AddsDone = 0; status("Scanning", item.FileName); decompile.ScanLines(test); status("Recompiling", item.FileName); item.RecompiledPath = decompile.Compile(); // } } else { status("Recompiling", item.FileName); decompile.MonoRecompile(); } // remove signature // files that arent signed are coming up as signed meaning this would probably corrupt a file // also not sure if checked anymore - http://msdn.microsoft.com/en-us/library/cc713694.aspx //var meta = new MetaInfo(item.RecompiledPath); //if (meta.Load()) // meta.RemoveSignature(); // decompile to check if (decompileAgain) { string filename = Path.GetFileName(item.FilePath); string compiler = compileWithMS ? "MS" : "Mono"; // create directories var dir = Path.Combine(Application.StartupPath, "recompile", filename, compiler + "_original"); var originalPath = decompile.BackupPath != null ? decompile.BackupPath : item.FilePath; decompile.Decompile(originalPath, dir); dir = Path.Combine(Application.StartupPath, "recompile", filename, compiler + "_new"); decompile.Decompile(item.RecompiledPath, dir); } } catch (CompileError ex) { errorLog += item.FileName + "\r\n" + ex.Summary + "\r\n--------------------------------------------------------\r\n"; } catch (Exception ex) { RunInGui(() => { MessageBox.Show("Error recompiling: " + ex.Message + "\r\n" + ex.StackTrace); StatusLabel.Text = "Error on " + item.FileName; OptionsPanel.Enabled = true; }); return; } linesAdded += decompile.LinesAdded; } // save node map before verifying because we dont want bogus verify // errors from preventing the dat file form being made status("Saving Map", ""); var settings = new Dictionary<string, string>(); settings["Version"] = XRay.BuilderVersion; if (Pro.Verified) settings["Pro"] = Pro.SignedFile; trackedObjects = root.SaveTree(DatPath, settings); // verify last and aggregate errors' if (doVerify) foreach (XRayedFile item in files) { try { status("Verifying", item.FileName); XDecompile.Verify(item.RecompiledPath); } catch (CompileError ex) { errorLog += item.FileName + "\r\n" + ex.Summary + "\r\n--------------------------------------------------------\r\n"; } } if (errorLog.Length > 0) throw new CompileError(errorLog); } catch (CompileError ex) { string summary = ex.Summary; summary = summary.Replace("Unexpected type on the stack.", "Unexpected type on the stack. (Ignore)"); summary = summary.Replace("Unmanaged pointers are not a verifiable type.", "Unmanaged pointers are not a verifiable type. (Ignore)"); if (!replaceOriginal) summary = summary.Replace("Unable to resolve token.", "Unable to resolve token. (Try turning off side by side)"); //todo token error - turn off side by side string logPath = Path.Combine(Application.StartupPath, "errorlog.txt"); File.WriteAllText(logPath, summary); Process.Start(logPath); } catch (Exception ex) { RunInGui(() => MessageBox.Show("Error during " + stepname + ": " + ex.Message)); } status(String.Format("Ready to Launch - {0:#,#} instructions added, {1:#,#} objects tracked", linesAdded, trackedObjects), ""); RunInGui(() => { OptionsPanel.Enabled = true; }); }).Start(); }
public void Recompile(bool test) { if (Files.Count == 0) { return; } BuildStatus = ""; BuildError = ""; BuildSuccess = false; BuildThread = new Thread(() => { string stepname = ""; long linesAdded = 0; long trackedObjects = 0; try { BuildStatus = "Checking"; if (XDecompile.CheckIfAlreadyXRayed(Files) && !TryRestoreBackups()) { return; } BuildStatus = "Preparing"; // copy XLibrary to final destination CopyLocalToOutputDir("XLibrary.dll", OutputDir); if (EnableLocalViewer) { CopyLocalToOutputDir("OpenTK.dll", OutputDir); CopyLocalToOutputDir("OpenTK.GLControl.dll", OutputDir); CopyLocalToOutputDir("QuickFont.dll", OutputDir); } string errorLog = ""; XNodeOut.NextID = 0; XNodeOut root = new XNodeOut(null, "root", XObjType.Root); XNodeOut extRoot = root.AddNode("Not XRayed", XObjType.External); XNodeOut intRoot = root.AddNode("XRayed", XObjType.Internal); // init root file nodes so links can be made for processed fields before they are directly xrayed foreach (var item in Files) { item.FileNode = intRoot.AddNode(Path.GetFileName(item.FilePath), XObjType.File); } foreach (var item in Files) { var decompile = new XDecompile(intRoot, extRoot, item, this); try { if (CompileWithMS) { BuildStatus = "Decompiling " + item.FileName; decompile.MsDecompile(); // used for debugging tricky ilasm errors //for (int i = 0; i < int.MaxValue; i++) // { decompile.AllowedAdds = int.MaxValue; // i; decompile.AddsDone = 0; BuildStatus = "Scanning " + item.FileName; decompile.ScanLines(test); BuildStatus = "Recompiling " + item.FileName; item.RecompiledPath = decompile.Compile(); // } } else { BuildStatus = "Recompiling " + item.FileName; decompile.MonoRecompile(); } // remove signature // files that arent signed are coming up as signed meaning this would probably corrupt a file // also not sure if checked anymore - http://msdn.microsoft.com/en-us/library/cc713694.aspx //var meta = new MetaInfo(item.RecompiledPath); //if (meta.Load()) // meta.RemoveSignature(); // decompile to check if (DecompileAgain) { string filename = Path.GetFileName(item.FilePath); string compiler = CompileWithMS ? "MS" : "Mono"; // create directories var dir = Path.Combine(Application.StartupPath, "recompile", filename, compiler + "_original"); var originalPath = decompile.BackupPath != null ? decompile.BackupPath : item.FilePath; decompile.Decompile(originalPath, dir); dir = Path.Combine(Application.StartupPath, "recompile", filename, compiler + "_new"); decompile.Decompile(item.RecompiledPath, dir); } } catch (CompileError ex) { errorLog += item.FileName + "\r\n" + ex.Summary + "\r\n--------------------------------------------------------\r\n"; } catch (Exception ex) { BuildError = "Error recompiling: " + ex.Message + "\r\n" + ex.StackTrace; BuildStatus = "Error on " + item.FileName; return; } linesAdded += decompile.LinesAdded; } // save node map before verifying because we dont want bogus verify // errors from preventing the dat file form being made BuildStatus = "Saving Map"; var settings = new Dictionary <string, string>(); settings["Version"] = XRay.BuilderVersion; if (Pro.Verified) { settings["Pro"] = Pro.SignedFile; } if (EnableLocalViewer) { settings["EnableLocalViewer"] = EnableLocalViewer.ToString(); settings["EnableIpcServer"] = EnableIpcServer.ToString(); settings["ShowViewerOnStart"] = ShowViewerOnStart.ToString(); } if (EnableTcpServer) { settings["EnableTcpServer"] = EnableTcpServer.ToString(); settings["TcpListenPort"] = TcpListenPort.ToString(); settings["EncryptionKey"] = EncryptionKey; } var writePath = Path.Combine(OutputDir, "XRay.dat"); trackedObjects = root.SaveTree(writePath, settings); if (errorLog.Length > 0) { string logPath = Path.Combine(Application.StartupPath, "errorlog.txt"); File.WriteAllText(logPath, errorLog); Process.Start(logPath); } } catch (Exception ex) { BuildError = "Error during " + stepname + ": " + ex.Message; } BuildStatus = String.Format("Success! {0:#,#} instructions added, {1:#,#} objects tracked", linesAdded, trackedObjects); BuildSuccess = true; }); BuildThread.Start(); }
internal void ScanLines(bool test) { XIL.Length = 0; CurrentNode = XFile.FileNode; if (!test) { InjectLibrary("XLibrary", "1:0:0:0"); } bool stripSig = false; using (StreamReader reader = new StreamReader(ILPathOriginal)) { while (!reader.EndOfStream) { string[] line = reader.SplitNextLine(XIL); if (test || line.Length == 0) { continue; } else if (line[0] == ".assembly") { // get last element, if in assemblies, replace with xray version stripSig = false; string assembly = line.Last(); // assemblies are referenced externally by xray. prefix, internally namespace names are the same if (Build.Files.Any(f => f.AssemblyName == assembly)) { if (!Build.ReplaceOriginal) { line[line.Length - 1] = "XRay." + line.Last(); XIL.RemoveLine(); XIL.AppendLine(String.Join(" ", line)); } stripSig = true; } } // the result dll is changed so a strong sig links need to be removed else if (line[0] == ".publickeytoken") { if (stripSig) { XIL.RemoveLine(); } } else if (line[0] == ".file") { // embedded files have a .hash that we won't be messing with, they require a hash stripSig = false; } else if (line[0] == ".hash" && stripSig) { XIL.RemoveLine(); if (line[1] != "algorithm") { string nextLine = string.Join(" ", line).FilterComment(); while (!nextLine.Contains(")")) { nextLine = reader.ReadLine().FilterComment(); } } } // remove assembly's public key else if (line[0] == ".publickey") { XIL.RemoveLine(); string nextLine = string.Join(" ", line).FilterComment();; while (!nextLine.Contains(")")) { nextLine = reader.ReadLine().FilterComment(); } } else if (line[0] == ".class") { // read the whole class before the { while (!line.Contains("{")) { line = line.Concat(reader.SplitNextLine(XIL)).ToArray(); } // right before the class is extended that is the7 name string name = line.TakeWhile(s => s != "extends" && s != "implements" && s != "{").LastOrDefault(); // add namespaces, and class, set current app obj to string[] namespaces = name.Split('.'); if (!line.Contains("nested")) { CurrentNode = XFile.FileNode; for (int i = 0; i < namespaces.Length - 1; i++) { CurrentNode = CurrentNode.AddNode(namespaces[i], XObjType.Namespace); } } string className = namespaces.Last(); int pos = className.LastIndexOf('`'); if (pos != -1) { className = className.Substring(0, pos); } CurrentNode = CurrentNode.AddNode(className, XObjType.Class); // exclude if we dont track anon classes if (!Build.TrackAnon && className.StartsWith("'")) { CurrentNode.Exclude = true; } } else if (line[0] == ".method") { // read the whole method before the { while (!line.Contains("{")) { line = line.Concat(reader.SplitNextLine(XIL)).ToArray(); } // method is the name with the ( in it string name = line.Where(s => s.Contains('(')).LastOrDefault(); //pinvokes can have afdaf( before method name name = name.Substring(0, name.IndexOf('(')); CurrentNode = CurrentNode.AddNode(name, XObjType.Method); // dont inject tracking code under these conditions if (line.Contains("abstract") || line.Where(s => s.StartsWith("pinvokeimpl")).FirstOrDefault() != null || (line.Contains("runtime") && line.Contains("managed")) || // 'runtime managed' / 'managed internalcall' at end of function indicates the body should be empty (line.Contains("managed") && line.Contains("internalcall"))) { CurrentNode.Exclude = true; continue; } // exclude if we dont track anony methods, but dont continue cause entry point could still be inside if (!Build.TrackAnon && name.StartsWith("'")) { CurrentNode.Exclude = true; } // scan for entry, break on .maxstack or } // read the whole method before the { // order method, entry, custom, maxstack, IL_ bool entry = false; while (!line.Contains(".maxstack")) { line = reader.SplitNextLine(XIL); Debug.Assert(!line.Contains("}")); // inject gui after .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) // if not then thread state will not be set for app's gui if (line.Contains(".entrypoint")) { entry = true; } } if (line.Length > 1 && line[0] == ".maxstack") { XIL.RemoveLine(); int maxstack = int.Parse(line[1]); if (maxstack == 0) { maxstack = 1; // for method enter function } // if we need to increase stack further for other added functions, // this is how to do it, checksIndexOfAny above, and check above this if (entry && maxstack < 2) { maxstack = 2; } // needs to push 1 more item on stack above whats needed for return // elements so that MethodExit can run if (Build.TrackFlow) { maxstack++; } XIL.AppendLine(".maxstack " + maxstack); // increase stack enough for hit function - need room for thread, hit, constructor if (entry) { InjectGui(); entry = false; } } if (!CurrentNode.Exclude) { InjectMethodEnter(CurrentNode); } } else if (line[0] == ".property") // ignore for now { while (!line.Contains("}")) { line = reader.SplitNextLine(XIL); } } else if (line[0] == ".field") { //todo - add option to track fields //string name = line.LastOrDefault(); //XNodeOut fieldNode = CurrentNode.AddNode(name, XObjType.Field); //fieldNode.Lines = 1; } else if (CurrentNode.ObjType == XObjType.Method) { bool inCatch = false; if (line[0] == "catch") { line = reader.SplitNextLine(XIL); inCatch = true; // inject after indent set } else if (Build.TrackFlow && !CurrentNode.Exclude && line.Length > 1 && line[1] == "ret") { Debug.Assert(line.Length == 2); XIL.RemoveLine(); // remove ret call XIL.AppendLine(); AddLine(line[0] + " nop // XRay - Redirected return address"); // anything jumping to return, will jump here instead and allow us to log exit InjectMethodExit(CurrentNode); AddLine("ret"); // put ret call back in } else if (line.Length > 1 && (Build.TrackFlow || Build.TrackExternal) && line[1].EndsWith(".s")) { // when we insert code we add more instructions, br is the branch instruction // and br.s is the short version allowing a max jump of 255 places which may // not be valid after our injection. Strip the .s, and run ilasm with /optimize // to add them back in Debug.Assert(line.Length == 3); XIL.RemoveLine(); line[1] = line[1].Replace(".s", ""); AddLine(string.Join(" ", line) + " // XRay - removed .s"); } // external method call tracking if (Build.TrackExternal && Build.TrackFlow && !CurrentNode.Exclude && line.Length > 1 && (line[1].StartsWith("constrained.") || line[1].StartsWith("call") || line[1].StartsWith("callvirt") || line[1].StartsWith("calli"))) { Debug.Assert(!line[1].StartsWith("calli")); // whats the format of calli? // any line starting with a constrained prefix is immediately followed by a call virt string[] constrainedLine = null; if (line[1].StartsWith("constrained.")) { XIL.RemoveLine(); // save constrained line a inject after external method tracking constrainedLine = line; line = reader.SplitNextLine(XIL); // read in callvirt } string parse = string.Join(" ", line); // get function name if (!parse.Contains("::")) { continue; // if no :: then caller is accessing a global internal function that is already tracked } int pos = parse.LastIndexOf('('); Debug.Assert(pos != -1); int pos2 = parse.LastIndexOf("::") + 2; Debug.Assert(pos2 != 1 && pos2 < pos); string functionName = parse.Substring(pos2, pos - pos2); parse = parse.Substring(0, pos2 - 2); // cut out what we just parsed // strip template info, read forward mark if in template string withoutTemplate = ""; int inTemplate = 0; for (int i = 0; i < parse.Length; i++) { if (parse[i] == '<') { inTemplate++; } else if (parse[i] == '>') { inTemplate--; } else if (inTemplate == 0) { withoutTemplate += parse[i]; } } parse = withoutTemplate; // now should just be namespace and extern dec to space pos = parse.LastIndexOf(' '); parse = parse.Substring(pos + 1); // we only care if this function is external if (!parse.StartsWith("[")) { continue; } pos = parse.IndexOf("]"); string external = parse.Substring(1, pos - 1); string namespaces = parse.Substring(pos + 1); pos = namespaces.LastIndexOf('`'); if (pos != -1) { namespaces = namespaces.Substring(0, pos); } // if already tracked, skip if (Build.Files.Any(f => f.AssemblyName == external)) { continue; } // add external file to root XNodeOut node = ExtRoot.Nodes.FirstOrDefault(n => n.Name == external) as XNodeOut; if (node == null) { node = ExtRoot.AddNode(external, XObjType.File); } // traverse or add namespace to root string[] names = namespaces.Split('.'); for (int i = 0; i < names.Length; i++) { string name = names[i]; XNodeOut next = node.Nodes.FirstOrDefault(n => n.Name == name) as XNodeOut; XObjType objType = (i == names.Length - 1) ? XObjType.Class : XObjType.Namespace; node = next ?? node.AddNode(name, objType); } node = node.AddNode(functionName, XObjType.Method); node.Lines = 1; // add wrapping for external tracking // remove function XIL.RemoveLine(); // inject method enter - re-route IL address to function to ensure it is logged XIL.AppendLine(); string address = (constrainedLine != null) ? constrainedLine[0] : line[0]; AddLine(address + " nop // XRay - Redirect external method begin"); XIL.AppendLine(); InjectMethodEnter(node); // add function line - strip IL address if (constrainedLine != null) { XIL.AppendLine(string.Join(" ", constrainedLine.Skip(1).ToArray())); } string nextLine = string.Join(" ", line.Skip(1).ToArray()); XIL.AppendLine(nextLine); // read over rest of function until ')' while (!nextLine.Contains(")")) { nextLine = reader.ReadLine(); XIL.AppendLine(nextLine); } // inject exit InjectMethodExit(node); } if (line[0] == "{") // try, catch, finallys, inside one another { CurrentNode.Indent++; CurrentNode.IndentString += " "; if (inCatch && Build.TrackFlow && !CurrentNode.Exclude) { InjectMethodCatch(CurrentNode); } } else if (line[0] == "}") // try, catch, finallys, inside one another { if (CurrentNode.Indent == 0) { CurrentNode = CurrentNode.Parent as XNodeOut; } else { CurrentNode.Indent--; CurrentNode.IndentString = CurrentNode.IndentString.Substring(2); } } CurrentNode.Lines++; } else if (CurrentNode.ObjType == XObjType.Class) { if (line[0] == "}") // try, catch, finallys, inside one another { CurrentNode = CurrentNode.Parent as XNodeOut; } } } } // change method call refs from old assembly to new if (!Build.ReplaceOriginal) { foreach (string assembly in Build.Files.Select(f => f.AssemblyName)) { XIL.Replace("[" + assembly + "]", "[XRay." + assembly + "]"); } } }