AddNode() публичный Метод

public AddNode ( string name, XObjType objType ) : XNodeOut
name string
objType XObjType
Результат XNodeOut
Пример #1
0
        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));
        }
Пример #2
0
        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();
        }
Пример #3
0
        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();
        }
Пример #4
0
        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();
        }
Пример #5
0
        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 + "]");
                }
            }
        }