Пример #1
0
        internal bool LoadMsil()
        {
            if (MsilPos == 0 || MsilLines == 0)
            {
                return(false);
            }

            if (Msil != null)
            {
                return(true);
            }

            using (FileStream DatStream = new FileStream(XRay.DatPath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                DatStream.Position = MsilPos;

                Msil = new List <XInstruction>();
                var code = new StringBuilder();

                for (int i = 0; i < MsilLines; i++)
                {
                    var inst = new XInstruction();
                    inst.Offset = BitConverter.ToInt32(DatStream.Read(4), 0);
                    inst.OpCode = XNodeIn.ReadString(DatStream);
                    inst.Line   = XNodeIn.ReadString(DatStream);
                    inst.RefId  = BitConverter.ToInt32(DatStream.Read(4), 0);

                    if (inst.RefId != 0 && !inst.Line.StartsWith("goto "))
                    {
                        inst.Line = Utilities.GetMethodName(this, inst.RefId);
                    }

                    Msil.Add(inst);
                    code.Append(inst.Offset.ToString("X") + ": " + inst.OpCode + " " + inst.Line + "\r\n");
                }

                PlainMsil = code.ToString();
            }

            return(true);
        }
Пример #2
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);
                }
            }
        }
Пример #3
0
        internal bool LoadMsil()
        {
            if (MsilPos == 0 || MsilLines == 0)
                return false;

            if (Msil != null)
                return true;

            using (FileStream DatStream = new FileStream(XRay.DatPath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                DatStream.Position = MsilPos;

                Msil = new List<XInstruction>();
                var code = new StringBuilder();

                for (int i = 0; i < MsilLines; i++)
                {
                    var inst = new XInstruction();
                    inst.Offset = BitConverter.ToInt32(DatStream.Read(4), 0);
                    inst.OpCode = XNodeIn.ReadString(DatStream);
                    inst.Line = XNodeIn.ReadString(DatStream);
                    inst.RefId = BitConverter.ToInt32(DatStream.Read(4), 0);

                    if (inst.RefId != 0 && !inst.Line.StartsWith("goto "))
                        inst.Line = Utilities.GetMethodName(this, inst.RefId);

                    Msil.Add(inst);
                    code.Append(inst.Offset.ToString("X") + ": " + inst.OpCode + " " + inst.Line + "\r\n");
                }

                PlainMsil = code.ToString();
            }

            return true;
        }
Пример #4
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();
            }
        }