상속: XLibrary.XNode
예제 #1
0
        public static XNodeOut SignatureToClass(string signature, XNodeOut fileNode)
        {
            // create syntax tree for signature
            XDef def = XDef.ParseAndCheck(signature);

            // iterate syntax tree and add to our node map
            XNodeOut currentNode = fileNode;

            while (def != null)
            {
                if (def.DefType == XDef.XDefType.Namespace)
                {
                    currentNode = currentNode.AddNode(def.Name, XObjType.Namespace);
                }

                else if (def.DefType == XDef.XDefType.Class)
                {
                    currentNode = currentNode.AddNode(def.GetShortName(), XObjType.Class);

                    /* Cant map generic params because the fileNode is not right
                     * if (def.Generics != null)
                     *  foreach (var genericSig in def.Generics)
                     *      SignatureToClass(genericSig.GetFullName(), fileNode);*/
                }

                def = def.SubDef;
            }

            Debug.Assert(currentNode.ObjType == XObjType.Class);

            return(currentNode);
        }
예제 #2
0
        public long SaveDat(string path, Dictionary <string, string> settings, XNodeOut root,
                            Dictionary <int, FunctionCall> callMap, Dictionary <int, FunctionCall> initMap)
        {
            long trackedObjects = 0;

            root.ComputeSums();

            byte[] temp = new byte[4096];

            using (FileStream stream = new FileStream(path, FileMode.Create))
            {
                // save settings
                foreach (var setting in settings)
                {
                    WriteSetting(stream, setting.Key, setting.Value);
                }

                // save nodes
                trackedObjects += root.WriteNode(stream);

                // save call map
                SaveCallMap(stream, XPacketType.CallMap, callMap);
                SaveCallMap(stream, XPacketType.InitMap, initMap);
            }

            return(trackedObjects);
        }
예제 #3
0
        private void InjectMethodEnter(XNodeOut node)
        {
            Debug.Assert(!node.Exclude);

            XIL.AppendLine();
            AddLine("ldc.i4  " + node.ID.ToString() + " // XRay - Method enter");
            AddLine("call    void [XLibrary]XLibrary.XRay::MethodEnter(int32)");
            LinesAdded += 2;

            if (Build.TrackInstances)
            {
                if (node.Name == ".ctor")
                {
                    AddLine("ldc.i4  " + node.Parent.ID.ToString());
                    AddLine("call    void [XLibrary]XLibrary.XRay::Constructed(int32)");
                    LinesAdded += 2;
                }
                else if (node.Name == "Finalize")
                {
                    AddLine("ldc.i4  " + node.Parent.ID.ToString());
                    AddLine("call    void [XLibrary]XLibrary.XRay::Deconstructed(int32)");
                    LinesAdded += 2;
                }
            }

            XIL.AppendLine();
        }
예제 #4
0
 public XDecompile(XNodeOut intRoot, XNodeOut extRoot, XRayedFile item, BuildModel build)
 {
     ExtRoot = extRoot;
     OriginalPath = item.FilePath;
     item.RecompiledPath = null; // reset
     XFile = item;
     Build = build;
 }
예제 #5
0
 public XDecompile(XNodeOut intRoot, XNodeOut extRoot, XRayedFile item, BuildModel build)
 {
     ExtRoot             = extRoot;
     OriginalPath        = item.FilePath;
     item.RecompiledPath = null; // reset
     XFile = item;
     Build = build;
 }
예제 #6
0
        void MarkNodeAsAnon(XNodeOut node)
        {
            node.IsAnon = true;

            foreach (XNodeOut subnode in node.Nodes)
            {
                MarkNodeAsAnon(subnode);
            }
        }
예제 #7
0
        public XNodeOut AddNode(string name, XObjType objType)
        {
            // used for namespaces
            XNodeOut existing = Nodes.Where(n => n.Name == name && n.ObjType == objType).FirstOrDefault() as XNodeOut;
            if (existing != null)
                return existing;

            XNodeOut node = new XNodeOut(this, name, objType);
            Nodes.Add(node);
            return node;
        }
예제 #8
0
        internal XNodeOut GetNotAnonParent()
        {
            XNodeOut next = Parent as XNodeOut;

            while (next != null && next.IsAnon)
            {
                next = next.Parent as XNodeOut;
            }

            return(next);
        }
예제 #9
0
        private void InjectMethodCatch(XNodeOut node)
        {
            Debug.Assert(!node.Exclude);
            Debug.Assert(Build.TrackFlow);

            XIL.AppendLine();
            AddLine("ldc.i4  " + node.ID.ToString() + " // XRay - Method Catch");
            AddLine("call    void [XLibrary]XLibrary.XRay::MethodCatch(int32)");
            XIL.AppendLine();

            LinesAdded += 2;
        }
예제 #10
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));
        }
예제 #11
0
        public XNodeOut AddMethod(MethodReference method)
        {
            // used for namespaces
            XNodeOut existing = Nodes.Cast<XNodeOut>().Where(n => n.MethodRef != null && n.MethodRef.FullName == method.FullName).FirstOrDefault();
            if (existing != null)
                return existing;

            XNodeOut node = new XNodeOut(this, method.Name, XObjType.Method);
            node.MethodRef = method;
            Nodes.Add(node);
            return node;
        }
예제 #12
0
        public XNodeOut AddNode(string name, XObjType objType)
        {
            // used for namespaces
            XNodeOut existing = Nodes.Where(n => n.Name == name && n.ObjType == objType).FirstOrDefault() as XNodeOut;

            if (existing != null)
            {
                return(existing);
            }

            XNodeOut node = new XNodeOut(this, name, objType);

            Nodes.Add(node);
            return(node);
        }
예제 #13
0
        public XNodeOut(XNodeOut parent, string name, XObjType objType)
        {
            Parent = parent;
            Name = name;
            ObjType = objType;

            if (objType == XObjType.External)
                External = true;

            else if (parent != null) // else important cause external objs parent is not tagged as external
                External = parent.External;

            ID = NextID++;

            //Debug.WriteLine(string.Format("Added {0}: {1}", objType, FullName()));
        }
예제 #14
0
        public XNodeOut AddMethod(MethodReference method)
        {
            // used for namespaces
            XNodeOut existing = Nodes.Cast <XNodeOut>().Where(n => n.MethodRef != null && n.MethodRef.FullName == method.FullName).FirstOrDefault();

            if (existing != null)
            {
                return(existing);
            }

            XNodeOut node = new XNodeOut(this, method.Name, XObjType.Method);

            node.MethodRef = method;
            Nodes.Add(node);
            return(node);
        }
예제 #15
0
        private void InjectMethodExit(XNodeOut node)
        {
            Debug.Assert(!node.Exclude);
            Debug.Assert(Build.TrackFlow);

            if (AddsDone >= AllowedAdds)
            {
                return;
            }

            XIL.AppendLine();
            AddLine("ldc.i4  " + node.ID.ToString() + " // XRay - Method Exit");
            AddLine("call    void [XLibrary]XLibrary.XRay::MethodExit(int32)");
            XIL.AppendLine();

            AddsDone++;
            LinesAdded += 2;
        }
예제 #16
0
        internal double ComputeFieldValues(XNodeOut node)
        {
            // give fields a value that makes them take up a total of %15 of the value of the class

            double total      = node.Lines;
            double fieldCount = 0;

            // compute sum of all dependents
            foreach (XNodeOut subnode in node.Nodes)
            {
                if (subnode.ObjType == XObjType.Field)
                {
                    fieldCount++;
                }
                else
                {
                    total += ComputeFieldValues(subnode);
                }
            }

            if (fieldCount > 0)
            {
                // inflate total 15% and fit fields in there
                double subTotal = total;
                total = total * 100.0 / 85.0;

                double fieldTotal = total - subTotal;

                int fieldValue = (int)(fieldTotal / fieldCount);
                if (fieldValue < 1)
                {
                    fieldValue = 1;
                }

                foreach (XNodeOut field in node.Nodes.Where(n => n.ObjType == XObjType.Field))
                {
                    field.Lines = fieldValue;
                }
            }

            return(total);
        }
예제 #17
0
        public XNodeOut(XNodeOut parent, string name, XObjType objType)
        {
            Parent  = parent;
            Name    = name;
            ObjType = objType;

            if (objType == XObjType.External)
            {
                External = true;
            }

            else if (parent != null) // else important cause external objs parent is not tagged as external
            {
                External = parent.External;
            }

            ID = NextID++;

            //Debug.WriteLine(string.Format("Added {0}: {1}", objType, FullName()));
        }
예제 #18
0
        XNodeOut SetClassDependency(XNodeOut dependentClass, TypeReference declaringType)
        {
            if (declaringType == null)
            {
                return(null);
            }

            var target = GetClassRef(declaringType);

            target = target.GetParentClass(true) as XNodeOut;

            dependentClass = dependentClass.GetParentClass(true) as XNodeOut;

            if (dependentClass.ClassDependencies == null)
            {
                dependentClass.ClassDependencies = new HashSet <int>();
            }

            dependentClass.ClassDependencies.Add(target.ID);

            return(target);
        }
예제 #19
0
        private void AddInstanceTracking(TypeDefinition classDef, XNodeOut classNode)
        {
            bool hasCtor = false;

            // add tracking to constructor
            foreach (var ctorMethod in classDef.Methods.Where(m => (m.Name == ".ctor" || m.Name == ".cctor") && m.Body != null))
            {
                ctorMethod.Body.SimplifyMacros();

                var processor = ctorMethod.Body.GetILProcessor();

                // to prevent warnings in verify, our code should be put after the base constructor call

                AddInstruction(ctorMethod, 0, processor.Create(OpCodes.Ldc_I4, classNode.ID));

                if (ctorMethod.Name == ".ctor")
                {
                    hasCtor = true;
                    AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldarg, 0));
                    AddInstruction(ctorMethod, 2, processor.Create(OpCodes.Call, ClassConstructedRef));
                }
                // else static constructor
                else
                {
                    // ldtoken    XTestLib.SmallStatic
                    // ldtoken    XTestLib.StaticTemplateClass`1<!T> (for generic static classes)
                    // call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)

                    if (classDef.HasGenericParameters)
                    {
                        // for some reason the GenericInstanceType does not carry over the parameters
                        var genericDef = new GenericInstanceType(classDef);
                        foreach (var p in classDef.GenericParameters)
                            genericDef.GenericArguments.Add(p);

                        AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldtoken, genericDef));
                    }
                    else
                        AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldtoken, classDef));

                    AddInstruction(ctorMethod, 2, processor.Create(OpCodes.Call, GetTypeFromHandleRef));
                    AddInstruction(ctorMethod, 3, processor.Create(OpCodes.Call, ClassConstructedRef));
                }
                ctorMethod.Body.OptimizeMacros();
            }

            // add tracking to desconstructor (only add if ctor tracking added)
            if (hasCtor)
            {
                var finMethod = classDef.Methods.FirstOrDefault(m => m.Name == "Finalize");
                bool callObjectFinalize = false;

                if (finMethod == null)
                {
                    finMethod = new MethodDefinition("Finalize", Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Virtual, VoidRef);
                    callObjectFinalize = true;
                    classDef.Methods.Add(finMethod);
                }

                finMethod.Body.SimplifyMacros();

                var processor = finMethod.Body.GetILProcessor();

                AddInstruction(finMethod, 0, processor.Create(OpCodes.Ldc_I4, classNode.ID));
                AddInstruction(finMethod, 1, processor.Create(OpCodes.Ldarg, 0));
                AddInstruction(finMethod, 2, processor.Create(OpCodes.Call, ClassDeconstructedRef));

                if (callObjectFinalize)
                {
                    AddInstruction(finMethod, 3, processor.Create(OpCodes.Ldarg, 0));
                    AddInstruction(finMethod, 4, processor.Create(OpCodes.Call, ObjectFinalizeRef));

                    AddInstruction(finMethod, 5, processor.Create(OpCodes.Ret));
                }

                finMethod.Body.OptimizeMacros();
            }
        }
예제 #20
0
        private void AddStaticCall(XNodeOut source, XNodeOut dest)
        {
            if (!Build.StaticAnalysis)
                return;

            int hash = XRay.PairHash(source.ID, dest.ID);
            CallMap[hash] = new FunctionCall() { ID = hash, Source = source.ID, Destination = dest.ID };
        }
예제 #21
0
        private void RecompileMethod(XNodeOut classNode, TypeDefinition classDef, MethodDefinition method)
        {
            XNodeOut methodNode = classNode.AddMethod(method);

            // return
            if (method.ReturnType != null)
            {
                var returnNode = SetClassDependency(classNode, method.ReturnType);
                if (returnNode != null)
                    methodNode.ReturnID = returnNode.ID;
            }

            // params
            for (int i = 0; i < method.Parameters.Count; i++)
            {
                var p = method.Parameters[i];

                if (methodNode.ParamIDs == null)
                {
                    methodNode.ParamIDs = new int[method.Parameters.Count];
                    methodNode.ParamNames = new string[method.Parameters.Count];
                }

                var paramNode = SetClassDependency(classNode, p.ParameterType);
                methodNode.ParamIDs[i] = paramNode.ID;
                methodNode.ParamNames[i] = p.Name;
            }

            if (method.Body == null)
                return;

            // local vars
            foreach (var local in method.Body.Variables)
                SetClassDependency(classNode, local.VariableType);

            // expands branches/jumps to support adddresses > 255
            // possibly needed if injecting code into large functions
            // OptimizeMacros at end of the function re-optimizes
            method.Body.SimplifyMacros();

            methodNode.Lines = method.Body.Instructions.Count;

            var processor = method.Body.GetILProcessor();

            for (int i = 0; i < method.Body.Instructions.Count; i++)
            {
                var instruction = method.Body.Instructions[i];

                // record method exited
                if (Build.TrackFlow && instruction.OpCode == OpCodes.Ret)
                {
                    instruction.OpCode = OpCodes.Nop; // any 'goto return' will go to here so method exit gets logged first

                    i = TrackMethodExit(method, method, methodNode, processor, i);

                    AddInstruction(method, ++i, processor.Create(OpCodes.Ret));
                }

                // if we're tracking calls to non-xrayed assemblies
                else if (instruction.OpCode == OpCodes.Call ||
                          instruction.OpCode == OpCodes.Calli ||
                          instruction.OpCode == OpCodes.Callvirt)
                {
                    var call = instruction.Operand as MethodReference;

                    if (call == null)
                    {
                        Debug.WriteLine("Unable to track not xrayed: " + instruction.Operand.ToString());
                        continue;
                    }

                    SetClassDependency(classNode, call.ReturnType);
                    SetClassDependency(classNode, call.DeclaringType);
                    foreach (var p in call.Parameters)
                        SetClassDependency(classNode, p.ParameterType);

                    var calledRef = GetClassRef(call.DeclaringType);

                    var calledNode = calledRef.AddMethod(call);

                    /*if( TrackExternal &&
                        !(method.Name == "Finalize" && method.DeclaringType.Namespace == "System") &&
                        (instruction.Operand as MethodReference).DeclaringType.Namespace != EnterMethodRef.DeclaringType.Namespace )*/
                    if (Build.TrackExternal &&
                        calledNode.External &&
                        calledRef.Name != "XRay")
                    // !(method.Name == "Finalize" && method.DeclaringType.Namespace == "System"))
                    {
                        if (method.Name == ".cctor" && call.Name == "GetTypeFromHandle")
                            continue; // call added to cctor by xray

                        calledNode.Lines = 1;
                        bool isConstrained = false;

                        // in function is prefixed by .constrained, wrap enter/exit around those 2 lines
                        int offset = 0;
                        if (i > 0 && method.Body.Instructions[i - 1].OpCode == OpCodes.Constrained)
                        {
                            i -= 1;
                            offset = 1;
                            isConstrained = true;
                        }

                        // put stuff below in here so instructions dont get messed up
                        var oldPos = method.Body.Instructions[i];
                        int pos = i;

                        // if this is an external call and we want to track the parameters, then we have to wrap the function
                        if (Build.TrackParameters && call.HasParameters)
                        {
                            // wrap call in a new function with the same parameters and return type as the original call, we do this
                            // because it's maybe impossible to build the object[] of parameters from the current stack because it's unknown
                            // in a wrapped function we can access the arguments easily to build the object[] and pass to method enter
                            var wrappedName = string.Format("{0}_{1}_XRay{2}", call.DeclaringType.Name, call.Name, UniqueEnterSig++);

                            var resolvedCall = ResolveGenericMethod(call);

                            var wrapFunc = new MethodDefinition(wrappedName, new Mono.Cecil.MethodAttributes(), resolvedCall.ReturnType);

                            // the wrapper can be static because we pass the called function's declaring type into the wrapper
                            wrapFunc.IsPrivate = true;
                            wrapFunc.IsStatic = true;
                            wrapFunc.HasThis = false;
                            wrapFunc.IsHideBySig = true;

                            if (call.HasThis)
                            {
                                // calling functions against a value type is done by calling against its address eg DateTime.AddMinutes()
                                if (call.DeclaringType.IsValueType)
                                    wrapFunc.Parameters.Add(new ParameterDefinition(new ByReferenceType(call.DeclaringType)));
                                else
                                    wrapFunc.Parameters.Add(new ParameterDefinition(call.DeclaringType));
                            }

                            foreach (var p in resolvedCall.Parameters)
                                wrapFunc.Parameters.Add(p);

                            // write body of method
                            var wrapProcessor = wrapFunc.Body.GetILProcessor();

                            TrackMethodEnterParams(wrapFunc, calledNode.ID, wrapProcessor, call.HasThis);

                            // load 'this' and arguemnts
                            for(int x = 0; x < wrapFunc.Parameters.Count; x++)
                                 wrapFunc.Body.Instructions.Add(wrapProcessor.Create(OpCodes.Ldarg, x));

                            if (isConstrained)
                            {
                                // test with oldfashionedfun with 'no parameter' filter above turned off
                                var inst = method.Body.Instructions[pos];
                                wrapFunc.Body.Instructions.Add(wrapProcessor.Create(inst.OpCode, inst.Operand as TypeReference));
                            }

                            // call original function
                            wrapFunc.Body.Instructions.Add(wrapProcessor.Create(instruction.OpCode, call));

                            // return
                            wrapFunc.Body.Instructions.Add(wrapProcessor.Create(OpCodes.Ret));

                            classDef.Methods.Add(wrapFunc);

                            // replace current call instruction with call to copy method
                            var wrapRef = new MethodReference(wrapFunc.Name, wrapFunc.ReturnType);
                            foreach (var parameter in wrapFunc.Parameters)
                                wrapRef.Parameters.Add(parameter);

                            if (classDef.HasGenericParameters)
                            {
                                // have to add arguments to declaring type manually for some reason
                                var genericClassDef = new GenericInstanceType(classDef);
                                foreach (var parameter in classDef.GenericParameters)
                                    genericClassDef.GenericArguments.Add(parameter);
                                wrapRef.DeclaringType = genericClassDef;
                            }
                            else
                                wrapRef.DeclaringType = classDef;

                            method.Body.Instructions[pos++].OpCode = OpCodes.Nop;

                            if(isConstrained)
                                method.Body.Instructions[pos++].OpCode = OpCodes.Nop; // sets the actual call to nop

                            AddInstruction(method, pos, processor.Create(OpCodes.Call, wrapRef));
                            // not incrementing pos because enter function takes un-inc'd pos as a param
                            // really need to go back through and standardize pos setting
                        }
                        else
                        {
                            // wrap the call with enter and exit, because enter to an external method may cause
                            // an xrayed method to be called, we want to track the flow of that process
                            AddInstruction(method, pos++, processor.Create(OpCodes.Ldc_I4, calledNode.ID));
                            AddInstruction(method, pos++, processor.Create(OpCodes.Call, MethodEnterRef));

                            // method
                            pos += offset;
                        }

                        pos = TrackMethodExit(method, call, calledNode, processor, pos);

                        var newPos = method.Body.Instructions[i]; // get new instruction at original position, inserting stuff changed it

                        UpdateExceptionHandlerPositions(method, oldPos, newPos);

                        i = pos; // loop end will add 1 putting us right after last added function
                    }
                }

                else if (Build.TrackFields &&
                         (instruction.OpCode == OpCodes.Stfld ||
                          instruction.OpCode == OpCodes.Stsfld ||
                          instruction.OpCode == OpCodes.Ldfld ||
                          instruction.OpCode == OpCodes.Ldflda ||
                          instruction.OpCode == OpCodes.Ldsfld ||
                          instruction.OpCode == OpCodes.Ldsflda))
                {
                    var fieldDef = instruction.Operand as FieldReference;

                    var classRef = GetClassRef(fieldDef.DeclaringType);
                    var fieldRef = classRef.AddField(fieldDef);

                    // some times volitile prefixes set/get field
                    int offset = 0;
                    if (i > 0 && method.Body.Instructions[i - 1].OpCode == OpCodes.Volatile)
                    {
                        i--;
                        offset = 1;
                    }

                    AddInstruction(method, i, processor.Create(OpCodes.Ldc_I4, fieldRef.ID));

                    if (instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld)
                        AddInstruction(method, i + 1, processor.Create(OpCodes.Call, SetFieldRef));
                    else
                        AddInstruction(method, i + 1, processor.Create(OpCodes.Call, LoadFieldRef));

                    i = i + 2 + offset; // skip instuction added, and field itself, end of loop will iterate this again

                    // Debug.WriteLine("{0} in Module: {1}, Namespace: {2}, Class: {3}, Name: {4}, Type: {5}", instruction.OpCode, fieldDef.DeclaringType.Scope.Name, namespaces, className, fieldName, fieldType);
                }

                else if (instruction.OpCode == OpCodes.Newobj)
                {
                    var newObj = instruction.Operand as MethodReference;
                    SetClassDependency(classNode, newObj.DeclaringType);
                }

                /* Still not really working - goal - to get side by side wpf apps to work
                 * else if (instruction.OpCode == OpCodes.Ldstr && !Build.ReplaceOriginal)
                {
                    // rename Pack URIs in WPF so resources can be found with an XRay.. namespace
                    // ex:  "/MyApp;component/views/aboutview.xaml" ->  "/XRay.MyApp;component/views/aboutview.xaml"
                    var packUri = instruction.Operand as String;

                    foreach (var file in XRayedFiles)
                        packUri = packUri.Replace("/" + file.AssemblyName + ";", "/XRay." + file.AssemblyName + ";");
                        //packUri = packUri.Replace(file.AssemblyName, "XRay." + file.AssemblyName);

                    instruction.Operand = packUri;
                }*/

            } // end iterating through instructions

            // record function was entered
            if (Build.TrackFunctions)
            {
                if (Build.TrackParameters && method.HasParameters)
                    TrackMethodEnterParams(method, methodNode.ID, processor, false);

                else
                {
                    AddInstruction(method, 0, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                    AddInstruction(method, 1, processor.Create(OpCodes.Call, MethodEnterRef));
                }
            }

            // record catches
            if (Build.TrackFlow)
                foreach (var handler in method.Body.ExceptionHandlers)
                {
                    if (handler.HandlerType != ExceptionHandlerType.Catch)
                        continue;

                    int i = method.Body.Instructions.IndexOf(handler.HandlerStart);

                    AddInstruction(method, i, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                    AddInstruction(method, i + 1, processor.Create(OpCodes.Call, MethodCatchRef));

                    var oldPos = handler.HandlerStart;
                    var newPos = method.Body.Instructions[i];

                    UpdateExceptionHandlerPositions(method, oldPos, newPos);
                }

            method.Body.OptimizeMacros();
        }
예제 #22
0
        private void AddInstanceTracking(TypeDefinition classDef, XNodeOut classNode)
        {
            bool hasCtor = false;

            // add tracking to constructor
            foreach (var ctorMethod in classDef.Methods.Where(m => (m.Name == ".ctor" || m.Name == ".cctor") && m.Body != null))
            {
                ctorMethod.Body.SimplifyMacros();

                var processor = ctorMethod.Body.GetILProcessor();

                // to prevent warnings in verify, our code should be put after the base constructor call

                AddInstruction(ctorMethod, 0, processor.Create(OpCodes.Ldc_I4, classNode.ID));

                if (ctorMethod.Name == ".ctor")
                {
                    hasCtor = true;
                    AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldarg, 0));
                    AddInstruction(ctorMethod, 2, processor.Create(OpCodes.Call, ClassConstructedRef));
                }
                // else static constructor
                else
                {
                    // ldtoken    XTestLib.SmallStatic
                    // ldtoken    XTestLib.StaticTemplateClass`1<!T> (for generic static classes)
                    // call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)

                    if (classDef.HasGenericParameters)
                    {
                        // for some reason the GenericInstanceType does not carry over the parameters
                        var genericDef = new GenericInstanceType(classDef);
                        foreach (var p in classDef.GenericParameters)
                        {
                            genericDef.GenericArguments.Add(p);
                        }

                        AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldtoken, genericDef));
                    }
                    else
                    {
                        AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldtoken, classDef));
                    }

                    AddInstruction(ctorMethod, 2, processor.Create(OpCodes.Call, GetTypeFromHandleRef));
                    AddInstruction(ctorMethod, 3, processor.Create(OpCodes.Call, ClassConstructedRef));
                }
                ctorMethod.Body.OptimizeMacros();
            }

            // add tracking to desconstructor (only add if ctor tracking added)
            if (hasCtor)
            {
                var  finMethod          = classDef.Methods.FirstOrDefault(m => m.Name == "Finalize");
                bool callObjectFinalize = false;

                if (finMethod == null)
                {
                    finMethod          = new MethodDefinition("Finalize", Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Virtual, VoidRef);
                    callObjectFinalize = true;
                    classDef.Methods.Add(finMethod);
                }

                finMethod.Body.SimplifyMacros();

                var processor = finMethod.Body.GetILProcessor();

                AddInstruction(finMethod, 0, processor.Create(OpCodes.Ldc_I4, classNode.ID));
                AddInstruction(finMethod, 1, processor.Create(OpCodes.Ldarg, 0));
                AddInstruction(finMethod, 2, processor.Create(OpCodes.Call, ClassDeconstructedRef));

                if (callObjectFinalize)
                {
                    AddInstruction(finMethod, 3, processor.Create(OpCodes.Ldarg, 0));
                    AddInstruction(finMethod, 4, processor.Create(OpCodes.Call, ObjectFinalizeRef));

                    AddInstruction(finMethod, 5, processor.Create(OpCodes.Ret));
                }

                finMethod.Body.OptimizeMacros();
            }
        }
예제 #23
0
        private void RecompileMethod(XNodeOut classNode, MethodDefinition method)
        {
            XNodeOut methodNode = classNode.AddMethod(method);

            // return
            if (method.ReturnType != null)
            {
                var returnNode = SetClassDependency(classNode, method.ReturnType);
                if (returnNode != null)
                    methodNode.ReturnID = returnNode.ID;
            }

            // params
            for (int i = 0; i < method.Parameters.Count; i++)
            {
                var p = method.Parameters[i];

                if (methodNode.ParamIDs == null)
                {
                    methodNode.ParamIDs = new int[method.Parameters.Count];
                    methodNode.ParamNames = new string[method.Parameters.Count];
                }

                var paramNode = SetClassDependency(classNode, p.ParameterType);
                methodNode.ParamIDs[i] = paramNode.ID;
                methodNode.ParamNames[i] = p.Name;
            }

            if (method.Body == null)
                return;

            // local vars
            foreach (var local in method.Body.Variables)
                SetClassDependency(classNode, local.VariableType);

            // expands branches/jumps to support adddresses > 255
            // possibly needed if injecting code into large functions
            // OptimizeMacros at end of the function re-optimizes
            method.Body.SimplifyMacros();

            methodNode.Lines = method.Body.Instructions.Count;

            var processor = method.Body.GetILProcessor();

            for (int i = 0; i < method.Body.Instructions.Count; i++)
            {
                var instruction = method.Body.Instructions[i];

                // record method exited
                if (Build.TrackFlow && instruction.OpCode == OpCodes.Ret)
                {
                    instruction.OpCode = OpCodes.Nop; // any 'goto return' will go to here so method exit gets logged first
                    AddInstruction(method, i + 1, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                    AddInstruction(method, i + 2, processor.Create(OpCodes.Call, ExitMethodRef));
                    AddInstruction(method, i + 3, processor.Create(OpCodes.Ret));

                    i += 3;
                }

                // if we're tracking calls to non-xrayed assemblies
                else if (instruction.OpCode == OpCodes.Call ||
                          instruction.OpCode == OpCodes.Calli ||
                          instruction.OpCode == OpCodes.Callvirt)
                {
                    var call = instruction.Operand as MethodReference;

                    if (call == null)
                    {
                        Debug.WriteLine("Unable to track not xrayed: " + instruction.Operand.ToString());
                        continue;
                    }

                    SetClassDependency(classNode, call.ReturnType);
                    SetClassDependency(classNode, call.DeclaringType);
                    foreach (var p in call.Parameters)
                        SetClassDependency(classNode, p.ParameterType);

                    var calledRef = GetClassRef(call.DeclaringType);

                    var calledNode = calledRef.AddMethod(call);

                    /*if( TrackExternal &&
                        !(method.Name == "Finalize" && method.DeclaringType.Namespace == "System") &&
                        (instruction.Operand as MethodReference).DeclaringType.Namespace != EnterMethodRef.DeclaringType.Namespace )*/
                    if (Build.TrackExternal &&
                        calledNode.External &&
                        calledRef.Name != "XRay")
                    // !(method.Name == "Finalize" && method.DeclaringType.Namespace == "System"))
                    {
                        if (method.Name == ".cctor" && call.Name == "GetTypeFromHandle")
                            continue; // call added to cctor by xray

                        calledNode.Lines = 1;

                        // in function is prefixed by .constrained, wrap enter/exit around those 2 lines
                        int offset = 0;
                        if (i > 0 && method.Body.Instructions[i - 1].OpCode == OpCodes.Constrained)
                        {
                            i -= 1;
                            offset = 1;
                        }

                        var oldPos = method.Body.Instructions[i];

                        // wrap the call with enter and exit, because enter to an external method may cause
                        // an xrayed method to be called, we want to track the flow of that process
                        int pos = i;
                        AddInstruction(method, pos++, processor.Create(OpCodes.Ldc_I4, calledNode.ID));
                        AddInstruction(method, pos++, processor.Create(OpCodes.Call, EnterMethodRef));

                        // method
                        pos += 1 + offset;

                        AddInstruction(method, pos++, processor.Create(OpCodes.Ldc_I4, calledNode.ID));
                        AddInstruction(method, pos, processor.Create(OpCodes.Call, ExitMethodRef));

                        var newPos = method.Body.Instructions[i];
                        UpdateExceptionHandlerPositions(method, oldPos, newPos);

                        i = pos; // loop end will add 1 putting us right after last added function
                    }
                }

                else if (Build.TrackFields &&
                         (instruction.OpCode == OpCodes.Stfld ||
                          instruction.OpCode == OpCodes.Stsfld ||
                          instruction.OpCode == OpCodes.Ldfld ||
                          instruction.OpCode == OpCodes.Ldflda ||
                          instruction.OpCode == OpCodes.Ldsfld ||
                          instruction.OpCode == OpCodes.Ldsflda))
                {
                    var fieldDef = instruction.Operand as FieldReference;

                    var classRef = GetClassRef(fieldDef.DeclaringType);
                    var fieldRef = classRef.AddField(fieldDef);

                    // some times volitile prefixes set/get field
                    int offset = 0;
                    if (i > 0 && method.Body.Instructions[i - 1].OpCode == OpCodes.Volatile)
                    {
                        i--;
                        offset = 1;
                    }

                    AddInstruction(method, i, processor.Create(OpCodes.Ldc_I4, fieldRef.ID));

                    if (instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld)
                        AddInstruction(method, i + 1, processor.Create(OpCodes.Call, SetFieldRef));
                    else
                        AddInstruction(method, i + 1, processor.Create(OpCodes.Call, LoadFieldRef));

                    i = i + 2 + offset; // skip instuction added, and field itself, end of loop will iterate this again

                    // Debug.WriteLine("{0} in Module: {1}, Namespace: {2}, Class: {3}, Name: {4}, Type: {5}", instruction.OpCode, fieldDef.DeclaringType.Scope.Name, namespaces, className, fieldName, fieldType);
                }

                else if (instruction.OpCode == OpCodes.Newobj)
                {
                    var newObj = instruction.Operand as MethodReference;
                    SetClassDependency(classNode, newObj.DeclaringType);
                }

                /* Still not really working - goal - to get side by side wpf apps to work
                 * else if (instruction.OpCode == OpCodes.Ldstr && !Build.ReplaceOriginal)
                {
                    // rename Pack URIs in WPF so resources can be found with an XRay.. namespace
                    // ex:  "/MyApp;component/views/aboutview.xaml" ->  "/XRay.MyApp;component/views/aboutview.xaml"
                    var packUri = instruction.Operand as String;

                    foreach (var file in XRayedFiles)
                        packUri = packUri.Replace("/" + file.AssemblyName + ";", "/XRay." + file.AssemblyName + ";");
                        //packUri = packUri.Replace(file.AssemblyName, "XRay." + file.AssemblyName);

                    instruction.Operand = packUri;
                }*/

            } // end iterating through instructions

            // record function was entered
            if (Build.TrackFunctions)
            {
                AddInstruction(method, 0, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                AddInstruction(method, 1, processor.Create(OpCodes.Call, EnterMethodRef));
            }

            // record catches
            if (Build.TrackFlow)
                foreach (var handler in method.Body.ExceptionHandlers)
                {
                    if (handler.HandlerType != ExceptionHandlerType.Catch)
                        continue;

                    int i = method.Body.Instructions.IndexOf(handler.HandlerStart);

                    AddInstruction(method, i, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                    AddInstruction(method, i + 1, processor.Create(OpCodes.Call, CatchMethodRef));

                    var oldPos = handler.HandlerStart;
                    var newPos = method.Body.Instructions[i];

                    UpdateExceptionHandlerPositions(method, oldPos, newPos);
                }

            method.Body.OptimizeMacros();
        }
예제 #24
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();
        }
예제 #25
0
        private void InjectMethodCatch(XNodeOut node)
        {
            Debug.Assert(!node.Exclude);
            Debug.Assert(TrackFlow);

            XIL.AppendLine();
            AddLine("ldc.i4  " + node.ID.ToString() + " // XRay - Method Catch");
            AddLine("call    void [XLibrary]XLibrary.XRay::MethodCatch(int32)");
            XIL.AppendLine();

            LinesAdded += 2;
        }
예제 #26
0
        XNodeOut SetClassDependency(XNodeOut dependentClass, TypeReference declaringType)
        {
            if (declaringType == null)
                return null;

            var target = GetClassRef(declaringType);
            target = target.GetParentClass(true) as XNodeOut;

            dependentClass = dependentClass.GetParentClass(true) as XNodeOut;

            if (dependentClass.ClassDependencies == null)
                dependentClass.ClassDependencies = new HashSet<int>();

            dependentClass.ClassDependencies.Add(target.ID);

            return target;
        }
예제 #27
0
        internal void ProcessClassNames(XNodeOut node)
        {
            // if class move anonymous objects into their non-anon counterparts
            if (node.ObjType == XObjType.Class)
            {
                // class under a namespace could be anon
                if (node.Name.StartsWith("<>"))
                {
                    MarkNodeAsAnon(node);
                }

                // put anonymous classes in the functions that they were generated from
                // ex -. Nested Class: <>c__DisplayClass15, has method: <FilterTextBox_TextChanged>b__11
                var anonClasses = node.Nodes.Where(n => n.ObjType == XObjType.Class && n.Name.StartsWith("<>")).ToArray();

                foreach (XNodeOut anonClass in anonClasses)
                {
                    // mark as anon
                    MarkNodeAsAnon(anonClass);

                    // if parent is not anon
                    if (!anonClass.Parent.IsAnon)
                    {
                        // iterate anon methods to find association
                        var anonMethod = anonClass.Nodes.FirstOrDefault(n => !n.Name.StartsWith("<>") && n.Name.StartsWith("<") && n.Name.Contains(">"));
                        if (anonMethod == null)
                        {
                            continue;
                        }

                        string anonMethodName = anonMethod.Name.Substring(1, anonMethod.Name.IndexOf(">") - 1);

                        // iterate parent class methods to find match
                        var parentMethod = node.Nodes.FirstOrDefault(n => n.Name == anonMethodName) as XNodeOut;
                        if (parentMethod == null)
                        {
                            continue;
                        }

                        // move node under that method
                        node.Nodes.Remove(anonClass);
                        parentMethod.Nodes.Add(anonClass);
                        anonClass.Parent = parentMethod;

                        // will be renamed when class is iterated below
                    }
                }

                // iterate anon methods, move into parent methods
                var anonMethods = node.Nodes.Where(n => n.ObjType == XObjType.Method && n.Name.StartsWith("<")).ToArray();

                foreach (XNodeOut anonMethod in anonMethods)
                {
                    MarkNodeAsAnon(anonMethod);

                    string parentName = anonMethod.Name.Substring(1, anonMethod.Name.IndexOf(">") - 1);

                    var parentMethod = node.Nodes.FirstOrDefault(n => n.Name == parentName) as XNodeOut;
                    if (parentMethod == null)
                    {
                        continue;
                    }

                    // move node under that method
                    node.Nodes.Remove(anonMethod);
                    parentMethod.Nodes.Add(anonMethod);
                    anonMethod.Parent = parentMethod;
                }

                // if current class is anon, rename class parentNodeName.classX
                if (node.IsAnon)
                {
                    XNodeOut parent = node.GetNotAnonParent();
                    node.Name = parent.Name + ".class" + parent.AnonClasses.ToString();
                    parent.AnonClasses++;
                }
            }

            // if method
            if (node.ObjType == XObjType.Method)
            {
                XNodeOut parent = node.GetNotAnonParent();

                // if method is ctor/cctor rename
                if (node.Name == ".ctor" || node.Name == ".cctor")
                {
                    node.Name = parent.Name + ((node.Name == ".ctor") ? ".ctor" : ".static_ctor");
                    if (parent.InitCount > 1)
                    {
                        node.Name += parent.InitCount.ToString();
                    }

                    parent.InitCount++;
                }

                else if (node.IsAnon ||      // simple anon method
                         node.Parent.IsAnon) // method of an anon class
                {
                    if (node.Name.StartsWith("<"))
                    {
                        node.Name = parent.Name + ".func" + parent.AnonFuncs.ToString();
                        parent.AnonFuncs++;
                    }
                }
            }

            // iterate sub elements
            foreach (XNodeOut subnode in node.Nodes)
            {
                ProcessClassNames(subnode);
            }
        }
예제 #28
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();
        }
예제 #29
0
        private void RecompileMethods(TypeDefinition classDef, XNodeOut classNode)
        {
            ILProcessor processor = null;

            // add fields
            if (TrackFields && classDef.HasFields)
                foreach (var fieldDef in classDef.Fields)
                {
                    var fieldNode = classNode.AddField(fieldDef);

                    SetClassDependency(classNode, fieldDef.DeclaringType);

                    if (fieldDef.FieldType.IsGenericParameter)
                        Debug.WriteLine("Generic parameter ignored - " + fieldDef.FieldType.ToString());
                    else
                        fieldNode.ReturnID = GetClassRef(fieldDef.FieldType).ID;
                }

            if(TrackCode)
                foreach (var method in classDef.Methods)
                {
                    XNodeOut methodNode = classNode.AddMethod(method);

                    if(DecompileCSharp)
                        methodNode.CSharp = DecompileMethod(method);

                    if (method.Body == null)
                        continue;

                    // record MSIL
                    if (SaveMsil)
                    {
                        methodNode.Msil = new List<XInstruction>();
                        foreach (var inst in method.Body.Instructions)
                        {
                            var xInst = new XInstruction();
                            xInst.Offset = inst.Offset;
                            xInst.OpCode = inst.OpCode.Name;
                            xInst.Line = (inst.Operand != null) ? inst.Operand.ToString() : "";

                            if (inst.OpCode == OpCodes.Call ||
                                inst.OpCode == OpCodes.Calli ||
                                inst.OpCode == OpCodes.Callvirt ||
                                inst.OpCode == OpCodes.Newobj ||
                                inst.OpCode == OpCodes.Ldftn) // pushes a function pointer to the stack
                            {
                                var call = inst.Operand as MethodReference;
                                if (call != null)
                                {
                                    var classRef = GetClassRef(call.DeclaringType);
                                    var methodRef = classRef.AddMethod(call);

                                    xInst.RefId = methodRef.ID;
                                }
                                else
                                    Debug.WriteLine("Unable to track: " + inst.Operand.ToString());
                            }
                            else if (inst.OpCode == OpCodes.Stfld ||
                                      inst.OpCode == OpCodes.Stsfld ||
                                      inst.OpCode == OpCodes.Ldfld ||
                                      inst.OpCode == OpCodes.Ldflda ||
                                      inst.OpCode == OpCodes.Ldsfld ||
                                      inst.OpCode == OpCodes.Ldsflda)
                            {
                                var fieldDef = inst.Operand as FieldReference;
                                var classRef = GetClassRef(fieldDef.DeclaringType);
                                var fieldRef = classRef.AddField(fieldDef);
                                xInst.RefId = fieldRef.ID;
                            }
                            else if (inst.OpCode.FlowControl == FlowControl.Branch ||
                                     inst.OpCode.FlowControl == FlowControl.Cond_Branch)
                            {
                                var op = inst.Operand as Instruction;
                                if (op != null)
                                {
                                    int offset = op.Offset;
                                    xInst.Line = "goto " + offset.ToString("X");
                                    xInst.RefId = offset;
                                }
                            }

                            methodNode.Msil.Add(xInst);
                        }
                    }
                }

            if (TrackInstances && !classDef.IsValueType)
            {
                bool hasCtor = false;

                // add tracking to constructor
                foreach(var ctorMethod in classDef.Methods.Where(m =>  (m.Name == ".ctor" || m.Name == ".cctor") && m.Body != null))
                {
                    ctorMethod.Body.SimplifyMacros();

                    processor = ctorMethod.Body.GetILProcessor();

                    // to prevent warnings in verify, our code should be put after the base constructor call

                    AddInstruction(ctorMethod, 0, processor.Create(OpCodes.Ldc_I4, classNode.ID));

                    if (ctorMethod.Name == ".ctor")
                    {
                        hasCtor = true;
                        AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldarg, 0));
                        AddInstruction(ctorMethod, 2, processor.Create(OpCodes.Call, ClassConstructedRef));
                    }
                    // else static constructor
                    else
                    {
                        // ldtoken    XTestLib.SmallStatic
                        // ldtoken    XTestLib.StaticTemplateClass`1<!T> (for generic static classes)
                        // call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)

                        if (classDef.HasGenericParameters)
                        {
                            // for some reason the GenericInstanceType does not carry over the parameters
                            var genericDef = new GenericInstanceType(classDef);
                            foreach (var p in classDef.GenericParameters)
                                genericDef.GenericArguments.Add(p);

                            AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldtoken, genericDef));
                        }
                        else
                            AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldtoken, classDef));

                        AddInstruction(ctorMethod, 2, processor.Create(OpCodes.Call, GetTypeFromHandleRef));
                        AddInstruction(ctorMethod, 3, processor.Create(OpCodes.Call, ClassConstructedRef));
                    }
                    ctorMethod.Body.OptimizeMacros();
                }

                // add tracking to desconstructor (only add if ctor tracking added)
                if (hasCtor)
                {
                     var finMethod = classDef.Methods.FirstOrDefault(m => m.Name == "Finalize");
                     bool callObjectFinalize = false;

                     if (finMethod == null)
                     {
                         finMethod = new MethodDefinition("Finalize", Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Virtual, VoidRef);
                         callObjectFinalize = true;
                         classDef.Methods.Add(finMethod);
                     }

                     finMethod.Body.SimplifyMacros();

                     processor = finMethod.Body.GetILProcessor();

                     AddInstruction(finMethod, 0, processor.Create(OpCodes.Ldc_I4, classNode.ID));
                     AddInstruction(finMethod, 1, processor.Create(OpCodes.Ldarg, 0));
                     AddInstruction(finMethod, 2, processor.Create(OpCodes.Call, ClassDeconstructedRef));

                     if (callObjectFinalize)
                     {
                         AddInstruction(finMethod, 3, processor.Create(OpCodes.Ldarg, 0));
                         AddInstruction(finMethod, 4, processor.Create(OpCodes.Call, ObjectFinalizeRef));

                         AddInstruction(finMethod, 5, processor.Create(OpCodes.Ret));
                     }

                     finMethod.Body.OptimizeMacros();
                }
            }

            // iterate method nodes
            foreach (var method in classDef.Methods)
            {
                XNodeOut methodNode = classNode.AddMethod(method);

                // return
                if(method.ReturnType != null)
                {
                    var returnNode = SetClassDependency(classNode, method.ReturnType);
                    if(returnNode != null)
                        methodNode.ReturnID = returnNode.ID;
                }
                // params
                for(int i = 0; i < method.Parameters.Count; i++)
                {
                    var p = method.Parameters[i];

                    if (methodNode.ParamIDs == null)
                    {
                        methodNode.ParamIDs = new int[method.Parameters.Count];
                        methodNode.ParamNames = new string[method.Parameters.Count];
                    }

                    var paramNode = SetClassDependency(classNode, p.ParameterType);
                    methodNode.ParamIDs[i] = paramNode.ID;
                    methodNode.ParamNames[i] = p.Name;
                }

                if (method.Body == null)
                    continue;

                // local vars
                foreach (var local in method.Body.Variables)
                    SetClassDependency(classNode, local.VariableType);

                // expands branches/jumps to support adddresses > 255
                // possibly needed if injecting code into large functions
                // OptimizeMacros at end of the function re-optimizes
                method.Body.SimplifyMacros();

                methodNode.Lines = method.Body.Instructions.Count;

                processor = method.Body.GetILProcessor();

                for (int i = 0; i < method.Body.Instructions.Count; i++)
                {
                    var instruction = method.Body.Instructions[i];

                    // record method exited
                    if (TrackFlow && instruction.OpCode == OpCodes.Ret)
                    {
                        instruction.OpCode = OpCodes.Nop; // any 'goto return' will go to here so method exit gets logged first
                        AddInstruction(method, i + 1, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                        AddInstruction(method, i + 2, processor.Create(OpCodes.Call, ExitMethodRef));
                        AddInstruction(method, i + 3, processor.Create(OpCodes.Ret));

                        i += 3;
                    }

                    // if we're tracking calls to non-xrayed assemblies
                    else if ( instruction.OpCode == OpCodes.Call ||
                              instruction.OpCode == OpCodes.Calli ||
                              instruction.OpCode == OpCodes.Callvirt)
                    {
                        var call = instruction.Operand as MethodReference;

                        if (call == null)
                        {
                            Debug.WriteLine("Unable to track not xrayed: " + instruction.Operand.ToString());
                            continue;
                        }

                        SetClassDependency(classNode, call.ReturnType);
                        SetClassDependency(classNode, call.DeclaringType);
                        foreach(var p in call.Parameters)
                            SetClassDependency(classNode, p.ParameterType);

                        var calledRef = GetClassRef(call.DeclaringType);

                        var calledNode = calledRef.AddMethod(call);

                        /*if( TrackExternal &&
                            !(method.Name == "Finalize" && method.DeclaringType.Namespace == "System") &&
                            (instruction.Operand as MethodReference).DeclaringType.Namespace != EnterMethodRef.DeclaringType.Namespace )*/
                        if (TrackExternal &&
                            calledNode.External &&
                            calledRef.Name != "XRay")
                           // !(method.Name == "Finalize" && method.DeclaringType.Namespace == "System"))
                        {
                            if (method.Name == ".cctor" && call.Name == "GetTypeFromHandle")
                                continue; // call added to cctor by xray

                            calledNode.Lines = 1;

                            // in function is prefixed by .constrained, wrap enter/exit around those 2 lines
                            int offset = 0;
                            if (i > 0 && method.Body.Instructions[i - 1].OpCode == OpCodes.Constrained)
                            {
                                i -= 1;
                                offset = 1;
                            }

                            var oldPos = method.Body.Instructions[i];

                            // wrap the call with enter and exit, because enter to an external method may cause
                            // an xrayed method to be called, we want to track the flow of that process
                            int pos = i;
                            AddInstruction(method, pos++, processor.Create(OpCodes.Ldc_I4, calledNode.ID));
                            AddInstruction(method, pos++, processor.Create(OpCodes.Call, EnterMethodRef));

                            // method
                            pos += 1 + offset;

                            AddInstruction(method, pos++, processor.Create(OpCodes.Ldc_I4, calledNode.ID));
                            AddInstruction(method, pos, processor.Create(OpCodes.Call, ExitMethodRef));

                            var newPos = method.Body.Instructions[i];
                            UpdateExceptionHandlerPositions(method, oldPos, newPos);

                            i = pos; // loop end will add 1 putting us right after last added function
                        }
                    }

                    else if (TrackFields &&
                             (instruction.OpCode == OpCodes.Stfld ||
                              instruction.OpCode == OpCodes.Stsfld ||
                              instruction.OpCode == OpCodes.Ldfld ||
                              instruction.OpCode == OpCodes.Ldflda ||
                              instruction.OpCode == OpCodes.Ldsfld ||
                              instruction.OpCode == OpCodes.Ldsflda))
                    {
                        var fieldDef = instruction.Operand as FieldReference;

                        var classRef = GetClassRef(fieldDef.DeclaringType);
                        var fieldRef = classRef.AddField(fieldDef);

                        // some times volitile prefixes set/get field
                        int offset = 0;
                        if (i > 0 && method.Body.Instructions[i - 1].OpCode == OpCodes.Volatile)
                        {
                            i--;
                            offset = 1;
                        }

                        AddInstruction(method, i, processor.Create(OpCodes.Ldc_I4, fieldRef.ID));

                        if (instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld)
                            AddInstruction(method, i + 1, processor.Create(OpCodes.Call, SetFieldRef));
                        else
                            AddInstruction(method, i + 1, processor.Create(OpCodes.Call, LoadFieldRef));

                        i = i + 2 + offset; // skip instuction added, and field itself, end of loop will iterate this again

                        // Debug.WriteLine("{0} in Module: {1}, Namespace: {2}, Class: {3}, Name: {4}, Type: {5}", instruction.OpCode, fieldDef.DeclaringType.Scope.Name, namespaces, className, fieldName, fieldType);
                    }

                    else if (instruction.OpCode == OpCodes.Newobj)
                    {
                        var newObj = instruction.Operand as MethodReference;
                        SetClassDependency(classNode, newObj.DeclaringType);
                    }

                    /* Still not really working - goal - to get side by side wpf apps to work
                     * else if (instruction.OpCode == OpCodes.Ldstr && SideBySide)
                    {
                        // rename Pack URIs in WPF so resources can be found with an XRay.. namespace
                        // ex:  "/MyApp;component/views/aboutview.xaml" ->  "/XRay.MyApp;component/views/aboutview.xaml"
                        var packUri = instruction.Operand as String;

                        foreach (var file in XRayedFiles)
                            packUri = packUri.Replace("/" + file.AssemblyName + ";", "/XRay." + file.AssemblyName + ";");
                            //packUri = packUri.Replace(file.AssemblyName, "XRay." + file.AssemblyName);

                        instruction.Operand = packUri;
                    }*/

                } // end iterating through instructions

                // record function was entered
                AddInstruction(method, 0, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                AddInstruction(method, 1, processor.Create(OpCodes.Call, EnterMethodRef));

                // record catches
                if (TrackFlow)
                    foreach (var handler in method.Body.ExceptionHandlers)
                    {
                        if (handler.HandlerType != ExceptionHandlerType.Catch)
                            continue;

                        int i = method.Body.Instructions.IndexOf(handler.HandlerStart);

                        AddInstruction(method, i, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                        AddInstruction(method, i + 1, processor.Create(OpCodes.Call, CatchMethodRef));

                        var oldPos = handler.HandlerStart;
                        var newPos = method.Body.Instructions[i];

                        UpdateExceptionHandlerPositions(method, oldPos, newPos);
                    }

                method.Body.OptimizeMacros();
            }
        }
예제 #30
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();
        }
예제 #31
0
        private void InjectMethodExit(XNodeOut node)
        {
            Debug.Assert(!node.Exclude);
            Debug.Assert(TrackFlow);

            if (AddsDone >= AllowedAdds)
                return;

            XIL.AppendLine();
            AddLine("ldc.i4  " + node.ID.ToString() + " // XRay - Method Exit");
            AddLine("call    void [XLibrary]XLibrary.XRay::MethodExit(int32)");
            XIL.AppendLine();

            AddsDone++;
            LinesAdded += 2;
        }
예제 #32
0
        private void InjectMethodEnter(XNodeOut node)
        {
            Debug.Assert(!node.Exclude);

            XIL.AppendLine();
            AddLine("ldc.i4  " + node.ID.ToString() + " // XRay - Method enter");
            AddLine("call    void [XLibrary]XLibrary.XRay::MethodEnter(int32)");
            LinesAdded += 2;

            if (TrackInstances)
                if (node.Name == ".ctor")
                {
                    AddLine("ldc.i4  " + node.Parent.ID.ToString());
                    AddLine("call    void [XLibrary]XLibrary.XRay::Constructed(int32)");
                    LinesAdded += 2;
                }
                else if (node.Name == "Finalize")
                {
                    AddLine("ldc.i4  " + node.Parent.ID.ToString());
                    AddLine("call    void [XLibrary]XLibrary.XRay::Deconstructed(int32)");
                    LinesAdded += 2;
                }

            XIL.AppendLine();
        }
예제 #33
0
        public static XNodeOut SignatureToClass(string signature, XNodeOut fileNode)
        {
            // create syntax tree for signature
            XDef def = XDef.ParseAndCheck(signature);

            // iterate syntax tree and add to our node map
            XNodeOut currentNode = fileNode;

            while (def != null)
            {
                if (def.DefType == XDef.XDefType.Namespace)
                    currentNode = currentNode.AddNode(def.Name, XObjType.Namespace);

                else if (def.DefType == XDef.XDefType.Class)
                {
                    currentNode = currentNode.AddNode(def.GetShortName(), XObjType.Class);

                    /* Cant map generic params because the fileNode is not right
                    if (def.Generics != null)
                        foreach (var genericSig in def.Generics)
                            SignatureToClass(genericSig.GetFullName(), fileNode);*/
                }

                def = def.SubDef;
            }

            Debug.Assert(currentNode.ObjType == XObjType.Class);

            return currentNode;
        }
예제 #34
0
        private XNodeOut RecompileClass(TypeDefinition classDef, XNodeOut fileNode)
        {
            if (!Build.TrackAnon && classDef.Name.StartsWith("<>"))
            {
                return(null);
            }

            var classNode = SignatureToClass(classDef.ToString(), fileNode);

            if (classDef.BaseType != null)
            {
                SetClassDependency(classNode, classDef.BaseType);
            }


            // add fields
            if (Build.TrackFields && classDef.HasFields)
            {
                foreach (var fieldDef in classDef.Fields)
                {
                    var fieldNode = classNode.AddField(fieldDef);

                    SetClassDependency(classNode, fieldDef.DeclaringType);

                    if (fieldDef.FieldType.IsGenericParameter)
                    {
                        Debug.WriteLine("Generic parameter ignored - " + fieldDef.FieldType.ToString());
                    }
                    else
                    {
                        fieldNode.ReturnID = GetClassRef(fieldDef.FieldType).ID;
                    }
                }
            }
            // save source code for methods
            foreach (var method in classDef.Methods)
            {
                SaveCode(classNode, method);
            }

            // track method creation/destruction
            if (Build.TrackInstances && !classDef.IsValueType)
            {
                AddInstanceTracking(classDef, classNode);
            }

            // add enter/exit info to method and call tracking
            foreach (var method in classDef.Methods)
            {
                RecompileMethod(classNode, method);
            }

            // recompile sub classes
            foreach (var nestedDef in classDef.NestedTypes)
            {
                if (nestedDef.MetadataType == MetadataType.Class || nestedDef.MetadataType == MetadataType.ValueType)
                {
                    RecompileClass(nestedDef, fileNode);
                }
                else
                {
                    Debug.WriteLine("Ignored nested type - " + nestedDef.ToString());
                }
            }

            return(classNode);
        }
예제 #35
0
        public long SaveDat(string path, Dictionary<string, string> settings, XNodeOut root, 
                            Dictionary<int, FunctionCall> callMap, Dictionary<int, FunctionCall> initMap)
        {
            long trackedObjects = 0;

            root.ComputeSums();

            byte[] temp = new byte[4096];

            using (FileStream stream = new FileStream(path, FileMode.Create))
            {
                // save settings
                foreach (var setting in settings)
                    WriteSetting(stream, setting.Key, setting.Value);

                // save nodes
                trackedObjects += root.WriteNode(stream);

                // save call map
                SaveCallMap(stream, XPacketType.CallMap, callMap);
                SaveCallMap(stream, XPacketType.InitMap, initMap);
            }

            return trackedObjects;
        }
예제 #36
0
        private XNodeOut RecompileClass(TypeDefinition classDef, XNodeOut fileNode)
        {
            if ( !TrackAnon && classDef.Name.StartsWith("<>") )
                return null;

            var classNode = SignatureToClass(classDef.ToString(), fileNode);

            if(classDef.BaseType != null)
                SetClassDependency(classNode, classDef.BaseType);

            RecompileMethods(classDef, classNode);

            foreach (var nestedDef in classDef.NestedTypes)
                if (nestedDef.MetadataType == MetadataType.Class || nestedDef.MetadataType == MetadataType.ValueType)
                    RecompileClass(nestedDef, fileNode);
                else
                    Debug.WriteLine("Ignored nested type - " + nestedDef.ToString());

            return classNode;
        }
예제 #37
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 + "]");
                }
            }
        }
예제 #38
0
        public XDecompile(BuildModel build, XNodeOut intRoot, XNodeOut extRoot, XRayedFile item, 
                          Dictionary<int, FunctionCall> callMap, Dictionary<int, FunctionCall> initMap)
        {
            Build = build;
            ExtRoot = extRoot;
            OriginalPath = item.FilePath;
            item.RecompiledPath = null; // reset
            XFile = item;

            CallMap = callMap;
            InitMap = initMap;
        }
예제 #39
0
        private void RecompileMethod(XNodeOut classNode, MethodDefinition method)
        {
            XNodeOut methodNode = classNode.AddMethod(method);

            // return
            if (method.ReturnType != null)
            {
                var returnNode = SetClassDependency(classNode, method.ReturnType);
                if (returnNode != null)
                {
                    methodNode.ReturnID = returnNode.ID;
                }
            }

            // params
            for (int i = 0; i < method.Parameters.Count; i++)
            {
                var p = method.Parameters[i];

                if (methodNode.ParamIDs == null)
                {
                    methodNode.ParamIDs   = new int[method.Parameters.Count];
                    methodNode.ParamNames = new string[method.Parameters.Count];
                }

                var paramNode = SetClassDependency(classNode, p.ParameterType);
                methodNode.ParamIDs[i]   = paramNode.ID;
                methodNode.ParamNames[i] = p.Name;
            }

            if (method.Body == null)
            {
                return;
            }

            // local vars
            foreach (var local in method.Body.Variables)
            {
                SetClassDependency(classNode, local.VariableType);
            }

            // expands branches/jumps to support adddresses > 255
            // possibly needed if injecting code into large functions
            // OptimizeMacros at end of the function re-optimizes
            method.Body.SimplifyMacros();

            methodNode.Lines = method.Body.Instructions.Count;

            var processor = method.Body.GetILProcessor();

            for (int i = 0; i < method.Body.Instructions.Count; i++)
            {
                var instruction = method.Body.Instructions[i];

                // record method exited
                if (Build.TrackFlow && instruction.OpCode == OpCodes.Ret)
                {
                    instruction.OpCode = OpCodes.Nop; // any 'goto return' will go to here so method exit gets logged first
                    AddInstruction(method, i + 1, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                    AddInstruction(method, i + 2, processor.Create(OpCodes.Call, ExitMethodRef));
                    AddInstruction(method, i + 3, processor.Create(OpCodes.Ret));

                    i += 3;
                }

                // if we're tracking calls to non-xrayed assemblies
                else if (instruction.OpCode == OpCodes.Call ||
                         instruction.OpCode == OpCodes.Calli ||
                         instruction.OpCode == OpCodes.Callvirt)
                {
                    var call = instruction.Operand as MethodReference;

                    if (call == null)
                    {
                        Debug.WriteLine("Unable to track not xrayed: " + instruction.Operand.ToString());
                        continue;
                    }

                    SetClassDependency(classNode, call.ReturnType);
                    SetClassDependency(classNode, call.DeclaringType);
                    foreach (var p in call.Parameters)
                    {
                        SetClassDependency(classNode, p.ParameterType);
                    }

                    var calledRef = GetClassRef(call.DeclaringType);

                    var calledNode = calledRef.AddMethod(call);


                    /*if( TrackExternal &&
                     *  !(method.Name == "Finalize" && method.DeclaringType.Namespace == "System") &&
                     *  (instruction.Operand as MethodReference).DeclaringType.Namespace != EnterMethodRef.DeclaringType.Namespace )*/
                    if (Build.TrackExternal &&
                        calledNode.External &&
                        calledRef.Name != "XRay")
                    // !(method.Name == "Finalize" && method.DeclaringType.Namespace == "System"))
                    {
                        if (method.Name == ".cctor" && call.Name == "GetTypeFromHandle")
                        {
                            continue; // call added to cctor by xray
                        }
                        calledNode.Lines = 1;

                        // in function is prefixed by .constrained, wrap enter/exit around those 2 lines
                        int offset = 0;
                        if (i > 0 && method.Body.Instructions[i - 1].OpCode == OpCodes.Constrained)
                        {
                            i     -= 1;
                            offset = 1;
                        }

                        var oldPos = method.Body.Instructions[i];

                        // wrap the call with enter and exit, because enter to an external method may cause
                        // an xrayed method to be called, we want to track the flow of that process
                        int pos = i;
                        AddInstruction(method, pos++, processor.Create(OpCodes.Ldc_I4, calledNode.ID));
                        AddInstruction(method, pos++, processor.Create(OpCodes.Call, EnterMethodRef));

                        // method
                        pos += 1 + offset;

                        AddInstruction(method, pos++, processor.Create(OpCodes.Ldc_I4, calledNode.ID));
                        AddInstruction(method, pos, processor.Create(OpCodes.Call, ExitMethodRef));

                        var newPos = method.Body.Instructions[i];
                        UpdateExceptionHandlerPositions(method, oldPos, newPos);

                        i = pos; // loop end will add 1 putting us right after last added function
                    }
                }

                else if (Build.TrackFields &&
                         (instruction.OpCode == OpCodes.Stfld ||
                          instruction.OpCode == OpCodes.Stsfld ||
                          instruction.OpCode == OpCodes.Ldfld ||
                          instruction.OpCode == OpCodes.Ldflda ||
                          instruction.OpCode == OpCodes.Ldsfld ||
                          instruction.OpCode == OpCodes.Ldsflda))
                {
                    var fieldDef = instruction.Operand as FieldReference;

                    var classRef = GetClassRef(fieldDef.DeclaringType);
                    var fieldRef = classRef.AddField(fieldDef);

                    // some times volitile prefixes set/get field
                    int offset = 0;
                    if (i > 0 && method.Body.Instructions[i - 1].OpCode == OpCodes.Volatile)
                    {
                        i--;
                        offset = 1;
                    }

                    AddInstruction(method, i, processor.Create(OpCodes.Ldc_I4, fieldRef.ID));

                    if (instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld)
                    {
                        AddInstruction(method, i + 1, processor.Create(OpCodes.Call, SetFieldRef));
                    }
                    else
                    {
                        AddInstruction(method, i + 1, processor.Create(OpCodes.Call, LoadFieldRef));
                    }

                    i = i + 2 + offset; // skip instuction added, and field itself, end of loop will iterate this again

                    // Debug.WriteLine("{0} in Module: {1}, Namespace: {2}, Class: {3}, Name: {4}, Type: {5}", instruction.OpCode, fieldDef.DeclaringType.Scope.Name, namespaces, className, fieldName, fieldType);
                }

                else if (instruction.OpCode == OpCodes.Newobj)
                {
                    var newObj = instruction.Operand as MethodReference;
                    SetClassDependency(classNode, newObj.DeclaringType);
                }

                /* Still not really working - goal - to get side by side wpf apps to work
                 * else if (instruction.OpCode == OpCodes.Ldstr && !Build.ReplaceOriginal)
                 * {
                 *  // rename Pack URIs in WPF so resources can be found with an XRay.. namespace
                 *  // ex:  "/MyApp;component/views/aboutview.xaml" ->  "/XRay.MyApp;component/views/aboutview.xaml"
                 *  var packUri = instruction.Operand as String;
                 *
                 *  foreach (var file in XRayedFiles)
                 *      packUri = packUri.Replace("/" + file.AssemblyName + ";", "/XRay." + file.AssemblyName + ";");
                 *      //packUri = packUri.Replace(file.AssemblyName, "XRay." + file.AssemblyName);
                 *
                 *  instruction.Operand = packUri;
                 * }*/
            } // end iterating through instructions


            // record function was entered
            if (Build.TrackFunctions)
            {
                AddInstruction(method, 0, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                AddInstruction(method, 1, processor.Create(OpCodes.Call, EnterMethodRef));
            }

            // record catches
            if (Build.TrackFlow)
            {
                foreach (var handler in method.Body.ExceptionHandlers)
                {
                    if (handler.HandlerType != ExceptionHandlerType.Catch)
                    {
                        continue;
                    }

                    int i = method.Body.Instructions.IndexOf(handler.HandlerStart);

                    AddInstruction(method, i, processor.Create(OpCodes.Ldc_I4, methodNode.ID));
                    AddInstruction(method, i + 1, processor.Create(OpCodes.Call, CatchMethodRef));

                    var oldPos = handler.HandlerStart;
                    var newPos = method.Body.Instructions[i];

                    UpdateExceptionHandlerPositions(method, oldPos, newPos);
                }
            }

            method.Body.OptimizeMacros();
        }
예제 #40
0
        internal void ProcessClassNames(XNodeOut node)
        {
            // if class move anonymous objects into their non-anon counterparts
            if(node.ObjType == XObjType.Class)
            {
                // class under a namespace could be anon
                if(node.Name.StartsWith("<>"))
                    MarkNodeAsAnon(node);

                // put anonymous classes in the functions that they were generated from
                // ex -. Nested Class: <>c__DisplayClass15, has method: <FilterTextBox_TextChanged>b__11
                var anonClasses = node.Nodes.Where(n => n.ObjType == XObjType.Class && n.Name.StartsWith("<>")).ToArray();

                foreach(XNodeOut anonClass in anonClasses)
                {
                    // mark as anon
                    MarkNodeAsAnon(anonClass);

                    // if parent is not anon
                    if( !anonClass.Parent.IsAnon )
                    {
                        // iterate anon methods to find association
                        var anonMethod = anonClass.Nodes.FirstOrDefault(n => !n.Name.StartsWith("<>") && n.Name.StartsWith("<") && n.Name.Contains(">"));
                        if (anonMethod == null)
                            continue;

                        string anonMethodName = anonMethod.Name.Substring(1, anonMethod.Name.IndexOf(">") - 1);

                        // iterate parent class methods to find match
                        var parentMethod = node.Nodes.FirstOrDefault(n => n.Name == anonMethodName) as XNodeOut;
                        if (parentMethod == null)
                            continue;

                        // move node under that method
                        node.Nodes.Remove(anonClass);
                        parentMethod.Nodes.Add(anonClass);
                        anonClass.Parent = parentMethod;

                        // will be renamed when class is iterated below
                    }
                }

                // iterate anon methods, move into parent methods
                var anonMethods = node.Nodes.Where(n => n.ObjType == XObjType.Method && n.Name.StartsWith("<")).ToArray();

                foreach(XNodeOut anonMethod in anonMethods)
                {
                    MarkNodeAsAnon(anonMethod);

                    string parentName = anonMethod.Name.Substring(1, anonMethod.Name.IndexOf(">") - 1);

                    var parentMethod = node.Nodes.FirstOrDefault(n => n.Name == parentName) as XNodeOut;
                    if (parentMethod == null)
                        continue;

                    // move node under that method
                    node.Nodes.Remove(anonMethod);
                    parentMethod.Nodes.Add(anonMethod);
                    anonMethod.Parent = parentMethod;
                }

                // if current class is anon, rename class parentNodeName.classX
                if (node.IsAnon)
                {
                    XNodeOut parent = node.GetNotAnonParent();
                    node.Name = parent.Name + ".class" + parent.AnonClasses.ToString();
                    parent.AnonClasses++;
                }
            }

            // if method
            if(node.ObjType == XObjType.Method)
            {
                XNodeOut parent = node.GetNotAnonParent();

                // if method is ctor/cctor rename
                if (node.Name == ".ctor" || node.Name == ".cctor")
                {
                    node.Name = parent.Name + ((node.Name == ".ctor") ? ".ctor" : ".static_ctor");
                    if (parent.InitCount > 1)
                        node.Name += parent.InitCount.ToString();

                    parent.InitCount++;
                }

                else if (node.IsAnon || // simple anon method
                         node.Parent.IsAnon) // method of an anon class
                {
                    if (node.Name.StartsWith("<"))
                    {
                        node.Name = parent.Name + ".func" + parent.AnonFuncs.ToString();
                        parent.AnonFuncs++;
                    }
                }
            }

            // iterate sub elements
            foreach (XNodeOut subnode in node.Nodes)
                ProcessClassNames(subnode);
        }
예제 #41
0
        private void SaveCode(XNodeOut classNode, MethodDefinition method)
        {
            XNodeOut methodNode = classNode.AddMethod(method);

            if (Build.DecompileCSharp)
            {
                methodNode.CSharp = DecompileMethod(method);
            }

            if (method.Body == null)
            {
                return;
            }

            // record MSIL
            if (Build.SaveMsil)
            {
                methodNode.Msil = new List <XInstruction>();
                foreach (var inst in method.Body.Instructions)
                {
                    var xInst = new XInstruction();
                    xInst.Offset = inst.Offset;
                    xInst.OpCode = inst.OpCode.Name;
                    xInst.Line   = (inst.Operand != null) ? inst.Operand.ToString() : "";

                    if (inst.OpCode == OpCodes.Call ||
                        inst.OpCode == OpCodes.Calli ||
                        inst.OpCode == OpCodes.Callvirt ||
                        inst.OpCode == OpCodes.Newobj ||
                        inst.OpCode == OpCodes.Ldftn) // pushes a function pointer to the stack
                    {
                        var call = inst.Operand as MethodReference;
                        if (call != null)
                        {
                            var classRef  = GetClassRef(call.DeclaringType);
                            var methodRef = classRef.AddMethod(call);

                            xInst.RefId = methodRef.ID;
                        }
                        else
                        {
                            Debug.WriteLine("Unable to track: " + inst.Operand.ToString());
                        }
                    }
                    else if (inst.OpCode == OpCodes.Stfld ||
                             inst.OpCode == OpCodes.Stsfld ||
                             inst.OpCode == OpCodes.Ldfld ||
                             inst.OpCode == OpCodes.Ldflda ||
                             inst.OpCode == OpCodes.Ldsfld ||
                             inst.OpCode == OpCodes.Ldsflda)
                    {
                        var fieldDef = inst.Operand as FieldReference;
                        var classRef = GetClassRef(fieldDef.DeclaringType);
                        var fieldRef = classRef.AddField(fieldDef);
                        xInst.RefId = fieldRef.ID;
                    }
                    else if (inst.OpCode.FlowControl == FlowControl.Branch ||
                             inst.OpCode.FlowControl == FlowControl.Cond_Branch)
                    {
                        var op = inst.Operand as Instruction;
                        if (op != null)
                        {
                            int offset = op.Offset;
                            xInst.Line  = "goto " + offset.ToString("X");
                            xInst.RefId = offset;
                        }
                    }

                    methodNode.Msil.Add(xInst);
                }
            }
        }
예제 #42
0
        private void AddInstanceTracking(TypeDefinition classDef, XNodeOut classNode)
        {
            bool hasCtor = false;

            // add tracking to constructor
            foreach (var ctorMethod in classDef.Methods.Where(m => (m.Name == ".ctor" || m.Name == ".cctor") && m.Body != null))
            {
                ctorMethod.Body.SimplifyMacros();

                var processor = ctorMethod.Body.GetILProcessor();

                if (ctorMethod.Name == ".ctor")
                {
                    // enter Constructed logging after System.Object::.ctor() is called, because passing the 'this' parameter before
                    // that causes PEVerify to complain about using an uninitialized variable

                    for (int i = 0; i < processor.Body.Instructions.Count; i++)
                    {
                        var instruction = processor.Body.Instructions[i];

                        if (instruction.OpCode == OpCodes.Call && instruction.Operand is MethodReference)
                        {
                            var callRef = instruction.Operand as MethodReference;

                            if (callRef.DeclaringType != null &&
                                classDef.BaseType.FullName == callRef.DeclaringType.FullName &&
                                callRef.Name == ".ctor")
                            {
                                hasCtor = true;
                                AddInstruction(ctorMethod, ++i, processor.Create(OpCodes.Ldc_I4, classNode.ID));
                                AddInstruction(ctorMethod, ++i, processor.Create(OpCodes.Ldarg, 0));
                                AddInstruction(ctorMethod, ++i, processor.Create(OpCodes.Call, ClassConstructedRef));
                                break;
                            }
                        }
                    }
                }
                // else static constructor
                else
                {
                    // ldtoken    XTestLib.SmallStatic
                    // ldtoken    XTestLib.StaticTemplateClass`1<!T> (for generic static classes)
                    // call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
                    AddInstruction(ctorMethod, 0, processor.Create(OpCodes.Ldc_I4, classNode.ID));

                    if (classDef.HasGenericParameters)
                    {
                        // for some reason the GenericInstanceType does not carry over the parameters
                        var genericDef = new GenericInstanceType(classDef);
                        foreach (var p in classDef.GenericParameters)
                            genericDef.GenericArguments.Add(p);

                        AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldtoken, genericDef));
                    }
                    else
                        AddInstruction(ctorMethod, 1, processor.Create(OpCodes.Ldtoken, classDef));

                    AddInstruction(ctorMethod, 2, processor.Create(OpCodes.Call, GetTypeFromHandleRef));
                    AddInstruction(ctorMethod, 3, processor.Create(OpCodes.Call, ClassConstructedRef));
                }
                ctorMethod.Body.OptimizeMacros();
            }

            // add tracking to desconstructor (only add if ctor tracking added)
            if (hasCtor)
            {
                var finMethod = classDef.Methods.FirstOrDefault(m => m.Name == "Finalize");
                bool callObjectFinalize = false;

                if (finMethod == null)
                {
                    finMethod = new MethodDefinition("Finalize", Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Virtual, VoidRef);
                    callObjectFinalize = true;
                    classDef.Methods.Add(finMethod);
                }

                finMethod.Body.SimplifyMacros();

                var processor = finMethod.Body.GetILProcessor();

                AddInstruction(finMethod, 0, processor.Create(OpCodes.Ldc_I4, classNode.ID));
                AddInstruction(finMethod, 1, processor.Create(OpCodes.Ldarg, 0));
                AddInstruction(finMethod, 2, processor.Create(OpCodes.Call, ClassDeconstructedRef));

                if (callObjectFinalize)
                {
                    AddInstruction(finMethod, 3, processor.Create(OpCodes.Ldarg, 0));
                    AddInstruction(finMethod, 4, processor.Create(OpCodes.Call, ObjectFinalizeRef));

                    AddInstruction(finMethod, 5, processor.Create(OpCodes.Ret));
                }

                finMethod.Body.OptimizeMacros();
            }
        }
예제 #43
0
        void MarkNodeAsAnon(XNodeOut node)
        {
            node.IsAnon = true;

            foreach (XNodeOut subnode in node.Nodes)
                MarkNodeAsAnon(subnode);
        }
예제 #44
0
        private XNodeOut RecompileClass(TypeDefinition classDef, XNodeOut fileNode)
        {
            if (!Build.TrackAnon && classDef.Name.StartsWith("<>"))
                return null;

            var classNode = SignatureToClass(classDef.ToString(), fileNode);

            if(classDef.BaseType != null)
                SetClassDependency(classNode, classDef.BaseType);

            // add fields
            if (Build.TrackFields && classDef.HasFields)
                foreach (var fieldDef in classDef.Fields)
                {
                    var fieldNode = classNode.AddField(fieldDef);

                    SetClassDependency(classNode, fieldDef.DeclaringType);

                    if (fieldDef.FieldType.IsGenericParameter)
                        Debug.WriteLine("Generic parameter ignored - " + fieldDef.FieldType.ToString());
                    else
                        fieldNode.ReturnID = GetClassRef(fieldDef.FieldType).ID;
                }
            // save source code for methods
            foreach (var method in classDef.Methods)
                SaveCode(classNode, method);

            // track method creation/destruction
            if (Build.TrackInstances && !classDef.IsValueType)
                AddInstanceTracking(classDef, classNode);

            // add enter/exit info to method and call tracking
            List<MethodDefinition> addMethods = new List<MethodDefinition>();

            foreach (var method in classDef.Methods.ToArray()) // toarray because recompile method may add new methods
                RecompileMethod(classNode, classDef, method);

            // recompile sub classes
            foreach (var nestedDef in classDef.NestedTypes)
                if (nestedDef.MetadataType == MetadataType.Class || nestedDef.MetadataType == MetadataType.ValueType)
                    RecompileClass(nestedDef, fileNode);
                else
                    Debug.WriteLine("Ignored nested type - " + nestedDef.ToString());

            return classNode;
        }
예제 #45
0
        private int TrackMethodExit(MethodDefinition method, MethodReference target, XNodeOut node, ILProcessor processor, int pos)
        {
            // really annoying, we need to box value type that are returned by the target method to pass to xray exit method
            // if the return type is generic msil returns something like !0, but we can't box !0, we have to resolve it from the function declaration
            // hence all the code below

            var resolved = ResolveGenericMethod(target);
            var returnType = resolved.ReturnType;

            if (Build.TrackReturnValue && returnType.FullName != VoidRef.FullName)
            {
                // this is key, duplicate the head of the stack, and we'll pass this to the xray method exit function to be recorded
                AddInstruction(method, ++pos, processor.Create(OpCodes.Dup));

                // if it's a value type or generic param then box because method exit takes an object as a param
                if (returnType.IsValueType || returnType.IsGenericParameter)
                    AddInstruction(method, ++pos, processor.Create(OpCodes.Box, returnType));

                AddInstruction(method, ++pos, processor.Create(OpCodes.Ldc_I4, node.ID)); // push id
                AddInstruction(method, ++pos, processor.Create(OpCodes.Call, MethodExitWithValueRef)); // call exit with object and id
            }
            // else not tracking return value
            else
            {
                AddInstruction(method, ++pos, processor.Create(OpCodes.Ldc_I4, node.ID));
                AddInstruction(method, ++pos, processor.Create(OpCodes.Call, MethodExitRef));
            }

            return pos;
        }
예제 #46
0
        public XDecompile(XNodeOut intRoot, XNodeOut extRoot, XRayedFile item, string outDir, string datPath, XRayedFile[] files, bool sxs)
        {
            ExtRoot = extRoot;
            OriginalPath = item.FilePath;
            OutputDir = outDir;
            DatPath = datPath;
            SideBySide = sxs;
            item.RecompiledPath = null; // reset
            XFile = item;

            XRayedFiles = files;
        }
예제 #47
0
        private void SaveCode(XNodeOut classNode, MethodDefinition method)
        {
            XNodeOut methodNode = classNode.AddMethod(method);

            if (Build.DecompileCSharp)
                methodNode.CSharp = DecompileMethod(method);

            if (method.Body == null)
                return;

            // record MSIL
            if (Build.SaveMsil)
            {
                methodNode.Msil = new List<XInstruction>();
                foreach (var inst in method.Body.Instructions)
                {
                    var xInst = new XInstruction();
                    xInst.Offset = inst.Offset;
                    xInst.OpCode = inst.OpCode.Name;
                    xInst.Line = (inst.Operand != null) ? inst.Operand.ToString() : "";

                    if (inst.OpCode == OpCodes.Call ||
                        inst.OpCode == OpCodes.Calli ||
                        inst.OpCode == OpCodes.Callvirt ||
                        inst.OpCode == OpCodes.Newobj ||
                        inst.OpCode == OpCodes.Ldftn) // pushes a function pointer to the stack
                    {
                        var call = inst.Operand as MethodReference;
                        if (call != null)
                        {
                            var classRef = GetClassRef(call.DeclaringType);
                            var methodRef = classRef.AddMethod(call);

                            xInst.RefId = methodRef.ID;
                        }
                        else
                            Debug.WriteLine("Unable to track: " + inst.Operand.ToString());
                    }
                    else if (inst.OpCode == OpCodes.Stfld ||
                              inst.OpCode == OpCodes.Stsfld ||
                              inst.OpCode == OpCodes.Ldfld ||
                              inst.OpCode == OpCodes.Ldflda ||
                              inst.OpCode == OpCodes.Ldsfld ||
                              inst.OpCode == OpCodes.Ldsflda)
                    {
                        var fieldDef = inst.Operand as FieldReference;
                        var classRef = GetClassRef(fieldDef.DeclaringType);
                        var fieldRef = classRef.AddField(fieldDef);
                        xInst.RefId = fieldRef.ID;
                    }
                    else if (inst.OpCode.FlowControl == FlowControl.Branch ||
                             inst.OpCode.FlowControl == FlowControl.Cond_Branch)
                    {
                        var op = inst.Operand as Instruction;
                        if (op != null)
                        {
                            int offset = op.Offset;
                            xInst.Line = "goto " + offset.ToString("X");
                            xInst.RefId = offset;
                        }
                    }

                    methodNode.Msil.Add(xInst);
                }
            }
        }
예제 #48
0
        internal double ComputeFieldValues(XNodeOut node)
        {
            // give fields a value that makes them take up a total of %15 of the value of the class

            double total = node.Lines;
            double fieldCount = 0;

            // compute sum of all dependents
            foreach (XNodeOut subnode in node.Nodes)
                if(subnode.ObjType == XObjType.Field)
                    fieldCount++;
                else
                    total += ComputeFieldValues(subnode);

            if(fieldCount > 0)
            {
                // inflate total 15% and fit fields in there
                double subTotal = total;
                total = total * 100.0 / 85.0;

                double fieldTotal = total - subTotal;

                int fieldValue = (int) (fieldTotal / fieldCount);
                if (fieldValue < 1)
                    fieldValue = 1;

                foreach (XNodeOut field in node.Nodes.Where(n => n.ObjType == XObjType.Field))
                    field.Lines = fieldValue;
            }

            return total;
        }