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); }
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); } } }
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; }
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(); } }