void CreateScopes (MethodBody body, ScopeCollection scopes, SymbolToken localVarToken) { foreach (Scope s in scopes) { int startOffset = s.Start.Offset; int endOffset = s.End == body.Instructions.Outside ? body.Instructions[body.Instructions.Count - 1].Offset + 1 : s.End.Offset; m_writer.OpenScope (startOffset); m_writer.UsingNamespace (body.Method.DeclaringType.Namespace); m_writer.OpenNamespace (body.Method.DeclaringType.Namespace); int start = body.Instructions.IndexOf (s.Start); int end = s.End == body.Instructions.Outside ? body.Instructions.Count - 1 : body.Instructions.IndexOf (s.End); ArrayList instructions = CollectSequencePoints (body, start, end); DefineSequencePoints (instructions); CreateLocalVariable (s, startOffset, endOffset, localVarToken); CreateScopes (body, s.Scopes, localVarToken); m_writer.CloseNamespace (); m_writer.CloseScope (endOffset); } }
public override void VisitMethodBody (MethodBody body) { MethodDefinition meth = body.Method; MethodBody methBody = body; BinaryReader br = m_reflectReader.Module.ImageReader.MetadataReader.GetDataReader (meth.RVA); // lets read the method int flags = br.ReadByte (); switch (flags & 0x3) { case (int) MethodHeader.TinyFormat : methBody.CodeSize = flags >> 2; methBody.MaxStack = 8; ReadCilBody (methBody, br); break; case (int) MethodHeader.FatFormat : br.BaseStream.Position--; int fatflags = br.ReadUInt16 (); //int headersize = (fatflags >> 12) & 0xf; methBody.MaxStack = br.ReadUInt16 (); methBody.CodeSize = br.ReadInt32 (); methBody.LocalVarToken = br.ReadInt32 (); body.InitLocals = (fatflags & (int) MethodHeader.InitLocals) != 0; if (methBody.LocalVarToken != 0) VisitVariableDefinitionCollection (methBody.Variables); ReadCilBody (methBody, br); if ((fatflags & (int) MethodHeader.MoreSects) != 0) ReadSection (methBody, br); break; } }
private void WeaveDependencyProperty(MethodBody staticCtorBody, FieldReference field, PropertyDefinition property) { var assembly = property.DeclaringType.Module.Assembly; var propertyType = assembly.ImportType(Type.GetType(property.PropertyType.FullName)); var getTypeFromHandle = assembly.ImportMethod(typeof(Type).GetMethod("GetTypeFromHandle")); var register = assembly.ImportMethod(typeof(DependencyProperty).GetMethod("Register", new[] { typeof(string), typeof(Type), typeof(Type) })); // ignore previously weaved DPs if (staticCtorBody.Instructions.Any(i => i.Operand != null && i.Operand.ToString() == field.ToString())) { return; } var ret = staticCtorBody.Instructions.Last(); if (ret.OpCode != OpCodes.Ret) throw new InvalidOperationException("The last instruction should be OpCode.Ret"); HasChanges = true; var proc = staticCtorBody.GetILProcessor(); proc.InsertBefore(ret, proc.Create(OpCodes.Ldstr, property.Name)); proc.InsertBefore(ret, proc.Create(OpCodes.Ldtoken, propertyType)); proc.InsertBefore(ret, proc.Create(OpCodes.Call, getTypeFromHandle)); proc.InsertBefore(ret, proc.Create(OpCodes.Ldtoken, property.DeclaringType)); proc.InsertBefore(ret, proc.Create(OpCodes.Call, getTypeFromHandle)); proc.InsertBefore(ret, proc.Create(OpCodes.Call, register)); proc.InsertBefore(ret, proc.Create(OpCodes.Stsfld, field)); }
private static void SwapMethods(MethodBody body, IEnumerable<Instruction> oldInstructions, IDictionary<MethodReference, MethodReference> methodMap, TypeDefinition targetDependency) { var IL = body.CilWorker; foreach (var instruction in oldInstructions) { var opCode = instruction.OpCode; if (opCode != OpCodes.Call && opCode != OpCodes.Callvirt) { IL.Append(instruction); continue; } var currentMethod = instruction.Operand as MethodReference; if (currentMethod == null || !methodMap.ContainsKey(currentMethod)) { IL.Append(instruction); continue; } if (currentMethod.DeclaringType != targetDependency) { IL.Append(instruction); continue; } var interfaceMethod = methodMap[currentMethod]; instruction.Operand = interfaceMethod; instruction.OpCode = OpCodes.Callvirt; IL.Append(instruction); } }
public void Write(MethodBody body, /*Telerik Authorship*/ MetadataToken methodToken, /*Telerik Authorship*/ MetadataToken localVarToken) { var method = new SourceMethod (body.Method); var instructions = GetInstructions (body); int count = instructions.Count; if (count == 0) return; var offsets = new int [count]; var start_rows = new int [count]; var start_cols = new int [count]; SourceFile file; Populate (instructions, offsets, start_rows, start_cols, out file); var builder = writer.OpenMethod (file.CompilationUnit, 0, method); for (int i = 0; i < count; i++) builder.MarkSequencePoint ( offsets [i], file.CompilationUnit.SourceFile, start_rows [i], start_cols [i], false); if (body.HasVariables) AddVariables (body.Variables); writer.CloseMethod (); }
public void Write(MethodBody body) { var method_token = body.Method.MetadataToken; var sym_token = new SymbolToken (method_token.ToInt32 ()); var instructions = CollectInstructions (body); if (instructions.Count == 0 && !body.HasVariables) return; writer.OpenMethod (sym_token); DefineSequencePoints (instructions); if (body.Scope != null) WriteScope (body, body.Scope); else if (body.HasVariables) { var start_offset = 0; var end_offset = body.CodeSize; writer.OpenScope (start_offset); DefineVariables (body, body.Variables, start_offset, end_offset); writer.CloseScope (end_offset); } if (body.IteratorType != null) DefineIteratorType (sym_token, body.IteratorType.Name); if (body.iterator_scopes != null) DefineIteratorScopes (sym_token, body.IteratorScopes, body.CodeSize); writer.CloseMethod (); }
public void Write (MethodBody body) { CreateDocuments (body); m_writer.OpenMethod (new SymbolToken ((int) body.Method.MetadataToken.ToUInt ())); CreateScopes (body, body.Scopes, new SymbolToken (body.LocalVarToken)); m_writer.CloseMethod (); }
public void VisitMethodBody(MethodBody body) { this.MethodBody = body; //VisitVariableDefinitionCollection(body.Variables); //VisitInstructionCollection(body.Instructions); //VisitExceptionHandlerCollection(body.ExceptionHandlers); }
private static void EmitArchsInit(MethodBody body, FieldReference archRef, Action<Instruction> emit) { var module = body.Method.Module; GenericInstanceType dictStrStrRef = (GenericInstanceType)archRef.FieldType; TypeReference dictOpenRef = dictStrStrRef.ElementType; GenericInstanceType iEqCompStrRef = new GenericInstanceType(module.Import(typeof(IEqualityComparer<>))); iEqCompStrRef.GenericArguments.Add(dictOpenRef.GenericParameters[0]); MethodReference dictStrStrCtor = CecilUtils.ImportInstanceMethodRef(module, dictStrStrRef, ".ctor", null, iEqCompStrRef); MethodReference dictAddRef = CecilUtils.ImportInstanceMethodRef(module, dictStrStrRef, "Add", null, dictOpenRef.GenericParameters[0], dictOpenRef.GenericParameters[1]); // Variables body.Variables.Add(new VariableDefinition(dictStrStrRef)); int varIdx = body.Variables.Count - 1; Instruction varSt = CecilUtils.ShortestStloc(varIdx); Instruction varLd = CecilUtils.ShortestLdloc(varIdx); emit(Instruction.Create(OpCodes.Ldnull)); emit(Instruction.Create(OpCodes.Newobj, dictStrStrCtor)); emit(varSt.Clone()); emit(varLd.Clone()); emit(Instruction.Create(OpCodes.Stsfld, archRef)); Action<string, string> emitAddPair = (k, v) => { emit(varLd.Clone()); emit(Instruction.Create(OpCodes.Ldstr, k)); emit(Instruction.Create(OpCodes.Ldstr, v)); emit(Instruction.Create(OpCodes.Callvirt, dictAddRef)); }; emitAddPair("x86", "Win32"); emitAddPair("AMD64", "x64"); emitAddPair("IA64", "Itanium"); emitAddPair("ARM", "WinCE"); }
public void Write(MethodBody body, byte [][] variables) { CreateDocuments (body); m_writer.OpenMethod (new SymbolToken ((int) body.Method.MetadataToken.ToUInt ())); CreateScopes (body, body.Scopes, variables); m_writer.CloseMethod (); }
public override void TerminateMethodBody(MethodBody body) { long pos = m_binaryWriter.BaseStream.Position; if (body.Variables.Count > 0 || body.ExceptionHandlers.Count > 0 || m_codeWriter.BaseStream.Length >= 64 || body.MaxStack > 8) { MethodHeader header = MethodHeader.FatFormat; if (body.InitLocals) header |= MethodHeader.InitLocals; if (body.ExceptionHandlers.Count > 0) header |= MethodHeader.MoreSects; m_binaryWriter.Write ((byte) header); m_binaryWriter.Write ((byte) 0x30); // (header size / 4) << 4 m_binaryWriter.Write ((short) body.MaxStack); m_binaryWriter.Write ((int) m_codeWriter.BaseStream.Length); m_binaryWriter.Write (((int) TokenType.Signature | body.LocalVarToken)); WriteExceptionHandlerCollection (body.ExceptionHandlers); } else m_binaryWriter.Write ((byte) ((byte) MethodHeader.TinyFormat | m_codeWriter.BaseStream.Length << 2)); m_binaryWriter.Write (m_codeWriter); m_binaryWriter.QuadAlign (); m_reflectWriter.MetadataWriter.AddData ( (int) (m_binaryWriter.BaseStream.Position - pos)); }
/// <summary> /// Create a new method in the declaring type of the given implicit implementation with the given name. /// This method will call the implicit implementation. /// </summary> internal static MethodDefinition CreateExplicitStub(MethodDefinition implicitImpl, string name, MethodDefinition iMethod, bool avoidGenericParam) { // Create method var newMethod = new MethodDefinition(name, implicitImpl.Attributes, implicitImpl.ReturnType); newMethod.IsVirtual = false; newMethod.IsAbstract = false; newMethod.IsFinal = true; // Clone generic parameters foreach (var gp in implicitImpl.GenericParameters) { newMethod.GenericParameters.Add(new GenericParameter(gp.Name, newMethod)); } // Update according to new context var cloner = new TypeCloner(avoidGenericParam, implicitImpl.Module.TypeSystem); newMethod.ReturnType = cloner.Get(implicitImpl.ReturnType, newMethod); // Clone parameters foreach (var p in iMethod.Parameters) { newMethod.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, cloner.Get(p.ParameterType, newMethod))); } // Add the method var targetType = implicitImpl.DeclaringType; targetType.Methods.Add(newMethod); // Add override newMethod.Overrides.Add(iMethod); // Create method body var body = new MethodBody(newMethod); newMethod.Body = body; var worker = body.GetILProcessor(); // Push this worker.Emit(OpCodes.Ldarg, body.ThisParameter); for (var i = 0; i < implicitImpl.Parameters.Count; i++) { var p = iMethod.Parameters[i]; var newMethodParam = newMethod.Parameters[i]; worker.Emit(OpCodes.Ldarg, newMethodParam); if (/*avoidGenericParam &&*/ p.ParameterType.ContainsGenericParameter) { worker.Emit(OpCodes.Box, implicitImpl.Parameters[i].ParameterType); } } worker.Emit(implicitImpl.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, implicitImpl); worker.Emit(OpCodes.Ret); // Mark method reachable if (implicitImpl.IsReachable) { newMethod.SetReachable(null); } return newMethod; }
protected BlockStatement RunInternal(MethodBody body, BlockStatement block, ILanguage language) { try { if (body.Instructions.Count != 0 || body.Method.IsJustDecompileGenerated) { foreach (IDecompilationStep step in steps) { if (language != null && language.IsStopped) { break; } block = step.Process(Context, block); } } } finally { if (Context.MethodContext.IsMethodBodyChanged) { body.Method.RefreshBody(); } } return block; }
public void Replace(MethodBody currentBody, ICollection<MethodReference> modifiedItems) { var invalidCalls = _callFilter.GetInvalidCalls(currentBody, modifiedItems); if (invalidCalls.Count == 0) return; var currentInstructions = currentBody.Instructions.Cast<Instruction>().ToArray(); var stackCtor = _targetModule.ImportConstructor<Stack<object>>(new Type[0]); var IL = currentBody.CilWorker; var targetMethod = currentBody.Method; var currentArgument = targetMethod.AddLocal<object>(); var currentArguments = targetMethod.AddLocal<Stack<object>>(); currentBody.Instructions.Clear(); // Create the stack that will hold the method arguments IL.Emit(OpCodes.Newobj, stackCtor); IL.Emit(OpCodes.Stloc, currentArguments); foreach (var currentInstruction in currentInstructions) { var currentMethod = currentInstruction.Operand as MethodReference; // Ignore any instructions that weren't affected by the // interface extraction if (currentMethod != null && invalidCalls.ContainsKey(currentMethod)) { var context = new MethodContext(IL, currentArguments, currentMethod, currentArgument); _replaceMethodCall.Replace(context, _targetModule); } IL.Append(currentInstruction); } }
public static bool ContainsCallTo(MethodBody m, string methodFullName) { return m.Instructions.Any(i => (i.OpCode == OpCodes.Call || i.OpCode == OpCodes.Callvirt) && ((MethodReference)i.Operand).FullName == methodFullName); }
public void Analyze(MethodBody body, NodeBase analyzedNode) { if (analyzedNode is MethodNode) ((MethodNode)analyzedNode).CyclomaticComplexity = 0; if (body == null) return; foreach (var instruction in body.Instructions) { // IL cyclomatic complexity if (instruction.OpCode.FlowControl == FlowControl.Cond_Branch && analyzedNode is MethodNode) ((MethodNode)analyzedNode).CyclomaticComplexity++; var operand = ReadOperand(instruction); if (operand is MethodReference) { var md = ((MethodReference)operand).Resolve(); if (md != null && assemblies.Contains(md.DeclaringType.Module.Assembly) && mappings.cecilMappings.ContainsKey(md)) { if (md.IsGetter || md.IsSetter) { var propertyNode = mappings.propertyMappings[(IProperty)mappings.cecilMappings[md]]; analyzedNode.AddRelationship(propertyNode); } else { var methodNode = mappings.methodMappings[(IMethod)mappings.cecilMappings[md]]; analyzedNode.AddRelationship(methodNode); } } } else if (operand is FieldReference) { var fd = ((FieldReference)operand).Resolve(); if (fd != null && assemblies.Contains(fd.DeclaringType.Module.Assembly) && mappings.cecilMappings.ContainsKey(fd)) { var fieldNode = mappings.fieldMappings[(IField)mappings.cecilMappings[fd]]; analyzedNode.AddRelationship(fieldNode); } } } }
public CecilVisitor(AssemblyDefinition assembly, ModuleDefinition module) { _assembly = assembly; _module = module; var program = _module.Types.First(t => t.Name == "Program"); _main = program.Methods.First(m => m.Name == "Main"); _body = _main.Body; _instructions = _body.Instructions; _instructions.Clear(); _objCtor = _module.Import(typeof(object).GetConstructor(new System.Type[0])); var systemFunctions = _module.Types.First(t => t.Name == "SystemFunctions"); // Math methods _fact = systemFunctions.Methods.First(m => m.Name == "Fact"); _max = systemFunctions.Methods.First(m => m.Name == "Max"); _min = systemFunctions.Methods.First(m => m.Name == "Min"); _pow = systemFunctions.Methods.First(m => m.Name == "Pow"); // Console methods _printBool = systemFunctions.Methods.First(m => m.Name == "PrintBool"); _printInt = systemFunctions.Methods.First(m => m.Name == "PrintInt"); _userFunctions = _module.Types.First(t => t.Name == "UserFunctions"); }
internal ControlFlowGraphBuilder (MethodDefinition method) { body = method.Body; if (body.ExceptionHandlers.Count > 0) exception_objects_offsets = new HashSet<int> (); }
protected override void ProxyMethod(MethodBody body, MethodReference proceedTargetMethod) { // Create base call if (!Method.IsAbstract) { callBaseMethod = new MethodDefinition(Name + "$Base", MethodAttributes.Private, Method.ReturnType); Method.CopyParameters(callBaseMethod); Method.CopyGenericParameters(callBaseMethod); callBaseMethod.Body.Emit(il => { il.Emit(OpCodes.Ldarg_0); for (var i = 0; i < Method.Parameters.Count; i++) { il.Emit(OpCodes.Ldarg, (short)i + 1); } var methodReference = GetProceedMethodTarget(); if (Method.GenericParameters.Count > 0) methodReference = methodReference.MakeGenericMethod(callBaseMethod.GenericParameters.ToArray()); il.Emit(OpCodes.Call, methodReference); il.Emit(OpCodes.Ret); }); ClassWeaver.ProxyType.Methods.Add(callBaseMethod); } base.ProxyMethod(body, proceedTargetMethod); }
public override Widget GetView() { if (scrolled_tree != null) { return(scrolled_tree); } // Create ui store = new ListStore(typeof(string), typeof(string), typeof(string)); tree = new TreeView(); tree.Model = store; tree.AppendColumn("Offset", new CellRendererText(), "text", 0); tree.AppendColumn("Instruction", new CellRendererText(), "text", 1); tree.AppendColumn("Operand", new CellRendererText(), "text", 2); tree.HeadersVisible = true; scrolled_tree = new ScrolledWindow(); scrolled_tree.Add(tree); Mono.Cecil.Cil.MethodBody body = method.Body; Mono.Cecil.Cil.Instruction instr; if (body != null) { for (int i = 0; i < body.Instructions.Count; i++) { instr = body.Instructions [i]; store.AppendValues("IL_" + instr.Offset.ToString("0000"), instr.OpCode.ToString(), FormatOperand(instr.Operand)); } } return(scrolled_tree); }
/// <summary> /// Create the Ctor /// </summary> private static void CreateDefaultCtor(ReachableContext reachableContext, TypeDefinition type) { var typeSystem = type.Module.TypeSystem; var ctor = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, typeSystem.Void); ctor.DeclaringType = type; var body = new MethodBody(ctor); body.InitLocals = true; ctor.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add ctor type.Methods.Add(ctor); ctor.SetReachable(reachableContext); }
internal DecompilationContext (MethodBody body, ControlFlowGraph cfg) { this.body = body; this.method = body.Method; this.variables = CloneCollection (body.Variables); this.cfg = cfg; }
/// <summary> /// Create a CopyFrom method. /// </summary> private static MethodDefinition CreateCopyFromMethod(ReachableContext reachableContext, TypeDefinition type) { var typeSystem = type.Module.TypeSystem; var method = new MethodDefinition(NameConstants.Struct.CopyFromMethodName, MethodAttributes.Public, type); var sourceParam = new ParameterDefinition(type); method.Parameters.Add(sourceParam); method.DeclaringType = type; var body = new MethodBody(method); body.InitLocals = true; method.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); // Call base CopyFrom var baseType = (type.BaseType != null) ? type.BaseType.GetElementType().Resolve() : null; if ((baseType != null) && baseType.IsValueType && (baseType.FullName != "System.ValueType")) { var baseMethod = new MethodReference(NameConstants.Struct.CopyFromMethodName, baseType, baseType) { HasThis = true }; baseMethod.Parameters.Add(new ParameterDefinition(baseType)); seq.Emit(OpCodes.Ldarg, sourceParam); seq.Emit(OpCodes.Call, baseMethod); } // Copy all fields foreach (var field in type.Fields.Where(x => !x.IsStatic)) { // Not need to bother with cloning struct-type fields here, // as this will be done automatically by one of the Converters. // Prepare for stfld seq.Emit(OpCodes.Ldarg, body.ThisParameter); // Load from source seq.Emit(OpCodes.Ldarg, sourceParam); seq.Emit(OpCodes.Ldfld, field); // Save in this seq.Emit(OpCodes.Stfld, field); } // Return this seq.Emit(OpCodes.Ldarg, body.ThisParameter); seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add method type.Methods.Add(method); method.SetReachable(reachableContext); return method; }
private void UpdateCallsToGetCurrentClassLogger(MethodBody ctorBody) { // Convert this: // // call class [Catel.Core]Catel.Logging.ILog [Catel.Core]Catel.Logging.LogManager::GetCurrentClassLogger() // stsfld class [Catel.Core]Catel.Logging.ILog Catel.Fody.TestAssembly.LoggingClass::AutoLog // // into this: // // ldtoken Catel.Fody.TestAssembly.LoggingClass // call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) // call class [Catel.Core]Catel.Logging.ILog [Catel.Core]Catel.Logging.LogManager::GetLogger(class [mscorlib]System.Type) // stsfld class [Catel.Core]Catel.Logging.ILog Catel.Fody.TestAssembly.LoggingClass::ManualLog var type = ctorBody.Method.DeclaringType; var instructions = ctorBody.Instructions; for (var i = 0; i < instructions.Count; i++) { var instruction = instructions[i]; var methodReference = instruction.Operand as MethodReference; if (methodReference != null) { FodyEnvironment.LogDebug($"Weaving auto log to specific log for '{type.FullName}'"); if (string.Equals(methodReference.Name, "GetCurrentClassLogger")) { // We have a possible match var getLoggerMethod = GetGetLoggerMethod(methodReference.DeclaringType); if (getLoggerMethod == null) { var point = instruction.SequencePoint; var message = $"Cannot change method call for log '{type.FullName}', the GetLogger(type) method does not exist on the calling type (try to use LogManager.GetCurrentClassLogger())"; if (point != null) { FodyEnvironment.LogWarningPoint(message, point); } else { FodyEnvironment.LogWarning(message); } continue; } var getTypeFromHandle = type.Module.GetMethodAndImport("GetTypeFromHandle"); instructions.RemoveAt(i); instructions.Insert(i, Instruction.Create(OpCodes.Ldtoken, type), Instruction.Create(OpCodes.Call, getTypeFromHandle), Instruction.Create(OpCodes.Call, type.Module.Import(getLoggerMethod))); } } } }
public ControlFlowGraph(Mono.Cecil.Cil.MethodBody body, InstructionBlock[] blocks, Dictionary<int, InstructionData> instructionData, List<ExceptionHandlerData> exception_data, HashSet<int> exception_objects_offsets) { this.body = body; this.blocks = blocks; this.data = instructionData; this.exception_data = exception_data; this.exception_objects_offsets = exception_objects_offsets; }
Instruction GetInstruction (MethodBody body, IDictionary instructions, int offset) { Instruction instr = (Instruction) instructions [offset]; if (instr != null) return instr; return body.Instructions.Outside; }
public void InjectInstructions(MethodBody body, int line, params Instruction[] instructions) { foreach (Instruction instr in instructions) { body.Instructions.Insert(line, instr); line++; } }
public ILBlock(MethodBody body) : this(ILBlockType.Root, 0, body.CodeSize) { AddExceptionHandlerBlocks(body); List<InstructionPair> allBranches = FindAllBranches(body); AddBlocks(allBranches); SortChildren(); }
static void AssertOpCodeSequence (OpCode [] expected, MethodBody body) { var opcodes = body.Instructions.Select (i => i.OpCode).ToArray (); Assert.AreEqual (expected.Length, opcodes.Length); for (int i = 0; i < opcodes.Length; i++) Assert.AreEqual (expected [i], opcodes [i]); }
string GetFileForMethodBody(MethodBody body) { if(body == null) return null; SequencePoint sp = body.Instructions[0].SequencePoint; return sp.Document.Url; }
static string GetVariableName(VariableDefinition variable, MethodBody body) { string name; if (body.Method.DebugInformation.TryGetName (variable, out name)) return name; return variable.ToString (); }
internal static MethodBody Clone(MethodBody body, MethodDefinition parent, ImportContext context) { MethodBody nb = new MethodBody(parent); nb.MaxStack = body.MaxStack; nb.InitLocals = body.InitLocals; nb.CodeSize = body.CodeSize; CilWorker worker = nb.CilWorker; if (body.HasVariables) { foreach (VariableDefinition var in body.Variables) { nb.Variables.Add(new VariableDefinition( var.Name, var.Index, parent, context.Import(var.VariableType))); } } foreach (Instruction instr in body.Instructions) { Instruction ni = new Instruction(instr.OpCode); switch (instr.OpCode.OperandType) { case OperandType.InlineParam: case OperandType.ShortInlineParam: if (instr.Operand == body.Method.This) { ni.Operand = nb.Method.This; } else { int param = body.Method.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = parent.Parameters [param]; } break; case OperandType.InlineVar: case OperandType.ShortInlineVar: int var = body.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = nb.Variables [var]; break; case OperandType.InlineField: ni.Operand = context.Import((FieldReference)instr.Operand); break; case OperandType.InlineMethod: ni.Operand = context.Import((MethodReference)instr.Operand); break; case OperandType.InlineType: ni.Operand = context.Import((TypeReference)instr.Operand); break; case OperandType.InlineTok: if (instr.Operand is TypeReference) { ni.Operand = context.Import((TypeReference)instr.Operand); } else if (instr.Operand is FieldReference) { ni.Operand = context.Import((FieldReference)instr.Operand); } else if (instr.Operand is MethodReference) { ni.Operand = context.Import((MethodReference)instr.Operand); } break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: case OperandType.InlineSwitch: break; default: ni.Operand = instr.Operand; break; } worker.Append(ni); } for (int i = 0; i < body.Instructions.Count; i++) { Instruction instr = nb.Instructions [i]; Instruction oldi = body.Instructions [i]; if (instr.OpCode.OperandType == OperandType.InlineSwitch) { Instruction [] olds = (Instruction [])oldi.Operand; Instruction [] targets = new Instruction [olds.Length]; for (int j = 0; j < targets.Length; j++) { targets [j] = GetInstruction(body, nb, olds [j]); } instr.Operand = targets; } else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget) { instr.Operand = GetInstruction(body, nb, (Instruction)oldi.Operand); } } if (!body.HasExceptionHandlers) { return(nb); } foreach (ExceptionHandler eh in body.ExceptionHandlers) { ExceptionHandler neh = new ExceptionHandler(eh.Type); neh.TryStart = GetInstruction(body, nb, eh.TryStart); neh.TryEnd = GetInstruction(body, nb, eh.TryEnd); neh.HandlerStart = GetInstruction(body, nb, eh.HandlerStart); neh.HandlerEnd = GetInstruction(body, nb, eh.HandlerEnd); switch (eh.Type) { case ExceptionHandlerType.Catch: neh.CatchType = context.Import(eh.CatchType); break; case ExceptionHandlerType.Filter: neh.FilterStart = GetInstruction(body, nb, eh.FilterStart); neh.FilterEnd = GetInstruction(body, nb, eh.FilterEnd); break; } nb.ExceptionHandlers.Add(neh); } return(nb); }
public override void VisitInstructionCollection(InstructionCollection instructions) { MethodBody body = instructions.Container; long start = m_codeWriter.BaseStream.Position; ComputeMaxStack(instructions); foreach (Instruction instr in instructions) { instr.Offset = (int)(m_codeWriter.BaseStream.Position - start); if (instr.OpCode.Size == 1) { m_codeWriter.Write(instr.OpCode.Op2); } else { m_codeWriter.Write(instr.OpCode.Op1); m_codeWriter.Write(instr.OpCode.Op2); } if (instr.OpCode.OperandType != OperandType.InlineNone && instr.Operand == null) { throw new ReflectionException("OpCode {0} have null operand", instr.OpCode.Name); } switch (instr.OpCode.OperandType) { case OperandType.InlineNone: break; case OperandType.InlineSwitch: Instruction[] targets = (Instruction[])instr.Operand; for (int i = 0; i < targets.Length + 1; i++) { m_codeWriter.Write((uint)0); } break; case OperandType.ShortInlineBrTarget: m_codeWriter.Write((byte)0); break; case OperandType.InlineBrTarget: m_codeWriter.Write(0); break; case OperandType.ShortInlineI: if (instr.OpCode == OpCodes.Ldc_I4_S) { m_codeWriter.Write((sbyte)instr.Operand); } else { m_codeWriter.Write((byte)instr.Operand); } break; case OperandType.ShortInlineVar: m_codeWriter.Write((byte)body.Variables.IndexOf( (VariableDefinition)instr.Operand)); break; case OperandType.ShortInlineParam: m_codeWriter.Write((byte)GetParameterIndex(body, (ParameterDefinition)instr.Operand)); break; case OperandType.InlineSig: WriteToken(GetCallSiteToken((CallSite)instr.Operand)); break; case OperandType.InlineI: m_codeWriter.Write((int)instr.Operand); break; case OperandType.InlineVar: m_codeWriter.Write((short)body.Variables.IndexOf( (VariableDefinition)instr.Operand)); break; case OperandType.InlineParam: m_codeWriter.Write((short)GetParameterIndex( body, (ParameterDefinition)instr.Operand)); break; case OperandType.InlineI8: m_codeWriter.Write((long)instr.Operand); break; case OperandType.ShortInlineR: m_codeWriter.Write((float)instr.Operand); break; case OperandType.InlineR: m_codeWriter.Write((double)instr.Operand); break; case OperandType.InlineString: WriteToken(new MetadataToken(TokenType.String, m_reflectWriter.MetadataWriter.AddUserString(instr.Operand as string))); break; case OperandType.InlineField: if (instr.Operand is FieldReference) { WriteToken((instr.Operand as FieldReference).MetadataToken); } else { throw new ReflectionException("Wrong operand for InlineField: {0}", instr.Operand.GetType().FullName); } break; case OperandType.InlineMethod: if (instr.Operand is GenericInstanceMethod) { WriteToken(m_reflectWriter.GetMethodSpecToken(instr.Operand as GenericInstanceMethod)); } else if (instr.Operand is MethodReference) { WriteToken((instr.Operand as MethodReference).MetadataToken); } else { throw new ReflectionException("Wrong operand for InlineMethod: {0}", instr.Operand.GetType().FullName); } break; case OperandType.InlineType: if (instr.Operand is TypeReference) { WriteToken(m_reflectWriter.GetTypeDefOrRefToken( instr.Operand as TypeReference)); } else { throw new ReflectionException("Wrong operand for InlineType: {0}", instr.Operand.GetType().FullName); } break; case OperandType.InlineTok: if (instr.Operand is TypeReference) { WriteToken(m_reflectWriter.GetTypeDefOrRefToken( instr.Operand as TypeReference)); } else if (instr.Operand is GenericInstanceMethod) { WriteToken(m_reflectWriter.GetMethodSpecToken(instr.Operand as GenericInstanceMethod)); } else if (instr.Operand is IMetadataTokenProvider) { WriteToken((instr.Operand as IMetadataTokenProvider).MetadataToken); } else { throw new ReflectionException( string.Format("Wrong operand for {0} OpCode: {1}", instr.OpCode.OperandType, instr.Operand.GetType().FullName)); } break; } } long pos = m_codeWriter.BaseStream.Position; foreach (Instruction instr in instructions) { switch (instr.OpCode.OperandType) { case OperandType.InlineSwitch: m_codeWriter.BaseStream.Position = instr.Offset + instr.OpCode.Size; Instruction[] targets = (Instruction[])instr.Operand; m_codeWriter.Write((uint)targets.Length); foreach (Instruction tgt in targets) { m_codeWriter.Write((tgt.Offset - (instr.Offset + instr.OpCode.Size + (4 * (targets.Length + 1))))); } break; case OperandType.ShortInlineBrTarget: m_codeWriter.BaseStream.Position = instr.Offset + instr.OpCode.Size; m_codeWriter.Write((byte)(((Instruction)instr.Operand).Offset - (instr.Offset + instr.OpCode.Size + 1))); break; case OperandType.InlineBrTarget: m_codeWriter.BaseStream.Position = instr.Offset + instr.OpCode.Size; m_codeWriter.Write(((Instruction)instr.Operand).Offset - (instr.Offset + instr.OpCode.Size + 4)); break; } } m_codeWriter.BaseStream.Position = pos; }
public void PatchModifications() { foreach (XElement classNode in mModifications.Elements("Class")) { // We load the class in which the modifications will take place string nameTypeToPatch = classNode.Attribute("Name").Value; TypeDefinition typeToPatch = GetAssembly("Assembly-CSharp").MainModule.Types.FirstOrDefault(t => t.Name == nameTypeToPatch); if (typeToPatch == null) { MessageBox.Show("Couldn't find type/class named" + nameTypeToPatch, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); continue; } foreach (XElement methodNode in classNode.Elements("Method")) { string nameMethodTopatch = methodNode.Attribute("Name").Value; MethodDefinition methodToPatch = typeToPatch.Methods.FirstOrDefault(m => m.Name == nameMethodTopatch); if (methodToPatch == null) { MessageBox.Show("Couldn't find method named" + nameMethodTopatch, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); continue; } Mono.Cecil.Cil.MethodBody methodBody = methodToPatch.Body; ILProcessor processor = methodBody.GetILProcessor(); // By default, we place the modification just before the "ret" instruction // (i.e. before the last instruction) int indexBegin = methodToPatch.Body.Instructions.Count - 1; // But, if the user specified a location, we place the modification there if (methodNode.Attribute("Location") != null) { indexBegin = int.Parse(methodNode.Attribute("Location").Value); } // If the user specified a count of instructions to delete, // we delete them if (methodNode.Attribute("DeleteCount") != null) { int countInstrToDelete = int.Parse(methodNode.Attribute("DeleteCount").Value); for (int i = 0; i < countInstrToDelete; i++) { processor.Remove(methodToPatch.Body.Instructions.ElementAt(indexBegin)); } } Instruction locationInstr = methodToPatch.Body.Instructions.ElementAt(indexBegin); Instruction prevInstr = locationInstr.Previous; foreach (XElement instrNode in methodNode.Elements("Instruction")) { Instruction instr = Call.ParseInstruction(processor, typeToPatch, instrNode); //MessageBox.Show(instr.ToString()); if (instr == null) { continue; } if (prevInstr == null) { processor.InsertBefore(locationInstr, instr); } else { processor.InsertAfter(prevInstr, instr); } prevInstr = instr; } // Optimize the method methodToPatch.Body.OptimizeMacros(); } } }
void checkPatchStatus() { mscloaderUpdate = false; isgameUpdated = false; oldPatchFound = false; oldFilesFound = false; button1.Enabled = false; button3.Enabled = false; bool newpatchfound = false; bool oldpatchfound = false; TypeDefinition typeToPatch = AssemblyDefinition.ReadAssembly(AssemblyFullPath).MainModule.Types.FirstOrDefault(t => t.Name == "PlayMakerArrayListProxy"); MethodDefinition methodToPatch = typeToPatch.Methods.FirstOrDefault(m => m.Name == "Awake"); Mono.Cecil.Cil.MethodBody methodBody = methodToPatch.Body; // MessageBox.Show(methodBody.CodeSize.ToString()); //debug if (methodBody.CodeSize == 24) { //not patched newpatchfound = false; } else if (methodBody.CodeSize == 29) { //patch found newpatchfound = true; } if (!newpatchfound) { TypeDefinition typeToPatch2 = AssemblyDefinition.ReadAssembly(AssemblyFullPath).MainModule.Types.FirstOrDefault(t => t.Name == "StartGame"); MethodDefinition methodToPatch2 = typeToPatch2.Methods.FirstOrDefault(m => m.Name == ".ctor"); Mono.Cecil.Cil.MethodBody methodBody2 = methodToPatch2.Body; if (methodBody2.CodeSize == 18) { //not patched oldpatchfound = false; } else if (methodBody2.CodeSize == 23) { //0.1 patch found oldpatchfound = true; } } if (!newpatchfound && !oldpatchfound) { if (File.Exists(Path.Combine(mscPath, @"mysummercar_Data\Managed\Assembly-CSharp.original.dll"))) { statusLabelText.Text = "Not patched, but MSCLoader 0.1 found (probably there was game update)"; Log("Patch not found, but MSCLoader 0.1 files found (probably there was game update)"); button1.Text = "Install MSCLoader"; button1.Enabled = true; oldFilesFound = true; } else if (File.Exists(Path.Combine(mscPath, @"mysummercar_Data\Managed\MSCLoader.dll")) && File.Exists(Path.Combine(mscPath, @"mysummercar_Data\Managed\Assembly-CSharp.dll.backup"))) { statusLabelText.Text = "Not patched, but MSCLoader found (probably there was game update)"; Log("Patch not found, but MSCLoader files found (looks like there was game update)"); button1.Text = "Install MSCLoader"; button1.Enabled = true; isgameUpdated = true; } else { statusLabelText.Text = "Not installed"; Log("Patch not found, ready to install patch"); button1.Text = "Install MSCLoader"; button1.Enabled = true; } statusLabelText.ForeColor = Color.Red; } else if (newpatchfound) { if (MD5HashFile(Path.Combine(mscPath, @"mysummercar_Data\Managed\MSCLoader.dll")) == MD5HashFile(Path.GetFullPath(Path.Combine("MSCLoader.dll", "")))) { statusLabelText.Text = "Installed, MSCLoader.dll is up to date."; Log("Newest patch found, no need to patch again"); button1.Enabled = false; button3.Enabled = true; statusLabelText.ForeColor = Color.Green; mscloaderUpdate = false; } else { statusLabelText.Text = "Installed, but MSCLoader.dll mismatch, Update?"; Log("Newest patch found, but MSCLoader.dll version mismatch, update MSCLoader?"); button1.Enabled = true; button1.Text = "Update MSCLoader"; button3.Enabled = true; statusLabelText.ForeColor = Color.Blue; mscloaderUpdate = true; } } else if (oldpatchfound) { statusLabelText.Text = "0.1 patch found, upgrade available"; Log("Old patch found, ready to upgrade"); button1.Text = "Upgrade MSCLoader"; button1.Enabled = true; statusLabelText.ForeColor = Color.Orange; oldPatchFound = true; } }
public void Write(Mono.Cecil.Cil.MethodBody body) { }
internal CilWorker(MethodBody body) { m_mbody = body; m_instrs = m_mbody.Instructions; }
private static void EncapsulateMethod(AssemblyDefinition assembly, ModuleDefinition module, TypeDefinition type, MethodDefinition method, string overrideName = null, string overrideMethod = nameof(AOPProcessor.OnMethod)) { // New body for current method (capsule) var newMethodBody = new List <Instruction>(); newMethodBody.Add(Instruction.Create(method.IsStatic ? OpCodes.Ldnull : OpCodes.Ldarg_0)); // ldnull / ldarg_0 newMethodBody.Add(Instruction.Create(OpCodes.Ldtoken, type)); newMethodBody.Add(Instruction.Create(OpCodes.Call, typeof(Type).GetMonoMethod(module, nameof(Type.GetTypeFromHandle)))); var mName = method.Name; if (!string.IsNullOrEmpty(overrideName)) { mName = overrideName; } newMethodBody.Add(Instruction.Create(OpCodes.Ldstr, mName)); newMethodBody.Add(Instruction.Create(OpCodes.Ldc_I4, method.Parameters.Count)); newMethodBody.Add(Instruction.Create(OpCodes.Newarr, module.ImportReference(typeof(object)))); for (var num = 0; num < method.Parameters.Count; num++) { var param = method.Parameters[num]; var pType = param.ParameterType; newMethodBody.Add(Instruction.Create(OpCodes.Dup)); newMethodBody.Add(Instruction.Create(OpCodes.Ldc_I4, num)); newMethodBody.Add(Instruction.Create(OpCodes.Ldarg, param)); if (param.ParameterType.IsValueType || param.ParameterType.IsGenericParameter) { newMethodBody.Add(Instruction.Create(OpCodes.Box, pType)); } newMethodBody.Add(Instruction.Create(OpCodes.Stelem_Ref)); } if (module.HasType(typeof(AOPProcessor))) { newMethodBody.Add(Instruction.Create(OpCodes.Call, module.GetType(typeof(AOPProcessor)) .GetMethod(overrideMethod))); } else { newMethodBody.Add(Instruction.Create(OpCodes.Call, typeof(AOPProcessor).GetMonoMethod(module, overrideMethod))); } if (method.ReturnType.FullName != typeof(void).FullName) { if (method.ReturnType.IsValueType) { newMethodBody.Add(Instruction.Create(OpCodes.Unbox_Any, method.ReturnType)); } } else { newMethodBody.Add(Instruction.Create(OpCodes.Pop)); } newMethodBody.Add(Instruction.Create(OpCodes.Ret)); // Create new method var internalMethod = new MethodDefinition(method.Name + AOPProcessor.APPENDIX, method.Attributes, method.ReturnType); foreach (var param in method.Parameters) { var newParam = new ParameterDefinition(param.Name, param.Attributes, param.ParameterType); newParam.HasDefault = false; newParam.IsOptional = false; internalMethod.Parameters .Add(newParam); } // Copy generic parameters foreach (var genericParameter in method.GenericParameters) { internalMethod.GenericParameters .Add(new GenericParameter(genericParameter.Name, internalMethod)); } var bodyClone = new MethodBody(method); bodyClone.AppendInstructions(newMethodBody); bodyClone.MaxStackSize = 8; // Replace method bodies internalMethod.Body = method.Body; method.Body = bodyClone; type.Methods.Add(internalMethod); }
private void ExtractBasicBlocksOfMethod(MethodReference method_reference) { MethodReference original_method_reference = method_reference; _methods_done.Add(original_method_reference.FullName); // MethodReference new_method_reference = original_method_reference.SubstituteMethod2(); // method_reference = new_method_reference != null ? new_method_reference : original_method_reference; MethodDefinition method_definition = method_reference.Resolve(); if (method_definition == null || method_definition.Body == null) { return; } int change_set = Cfg.StartChangeSet(); int instruction_count = method_definition.Body.Instructions.Count; List <INST> split_point = new List <INST>(); CFG.Vertex basic_block = (CFG.Vertex)Cfg.AddVertex(new CFG.Vertex() { Name = Cfg.NewNodeNumber().ToString() }); basic_block._method_definition = method_definition; basic_block._method_reference = original_method_reference; basic_block.Entry = basic_block; basic_block.Exit = basic_block; basic_block.Entry.BlocksOfMethod = new List <CFG.Vertex>(); basic_block.Entry.BlocksOfMethod.Add(basic_block); Cfg.Entries.Add(basic_block); // Add instructions to the basic block, including debugging information. // First, get debugging information on line/column/offset in method. if (!original_method_reference.Module.HasSymbols) { // Try to get symbols, but if none available, don't worry about it. try { original_method_reference.Module.ReadSymbols(); } catch { } } var symbol_reader = original_method_reference.Module.SymbolReader; var method_debug_information = symbol_reader?.Read(method_definition); Collection <SequencePoint> sequence_points = method_debug_information != null ? method_debug_information.SequencePoints : new Collection <SequencePoint>(); Mono.Cecil.Cil.MethodBody body = method_definition.Body; if (body == null) { throw new Exception("Body null, not expecting it to be."); } if (body.Instructions == null) { throw new Exception("Body has instructions collection."); } if (body.Instructions.Count == 0) { throw new Exception("Body instruction count is zero."); } SequencePoint previous_sp = null; for (int j = 0; j < instruction_count; ++j) { Mono.Cecil.Cil.Instruction instruction = body.Instructions[j]; SequencePoint sp = sequence_points.Where(s => { return(s.Offset == instruction.Offset); }).FirstOrDefault(); if (sp == null) { sp = previous_sp; } INST wrapped_instruction = INST.Wrap(instruction, basic_block, sp); basic_block.Instructions.Add(wrapped_instruction); if (sp != null) { previous_sp = sp; } } var instructions_before_splits = basic_block.Instructions.ToList(); // Accumulate targets of jumps. These are split points for block "v". // Accumalated splits are in "leader_list" following this for-loop. for (int j = 0; j < instruction_count; ++j) { INST wrapped_instruction = basic_block.Instructions[j]; Mono.Cecil.Cil.OpCode opcode = wrapped_instruction.OpCode; Mono.Cecil.Cil.FlowControl flow_control = opcode.FlowControl; switch (flow_control) { case Mono.Cecil.Cil.FlowControl.Branch: case Mono.Cecil.Cil.FlowControl.Cond_Branch: { object operand = wrapped_instruction.Operand; // Two cases of branches: // 1) operand is a single instruction; // 2) operand is an array of instructions via a switch instruction. // In doing this type casting, the resulting instructions are turned // into def's, and operands no longer correspond to what was in the original // method. We override the List<> compare to correct this problem. Mono.Cecil.Cil.Instruction single_instruction = operand as Mono.Cecil.Cil.Instruction; Mono.Cecil.Cil.Instruction[] array_of_instructions = operand as Mono.Cecil.Cil.Instruction[]; if (single_instruction != null) { INST sp = null; for (int i = 0; i < basic_block.Instructions.Count(); ++i) { if (basic_block.Instructions[i].Offset == single_instruction.Offset && basic_block.Instructions[i].OpCode == single_instruction.OpCode) { sp = basic_block.Instructions[i]; break; } } if (sp == null) { throw new Exception("Instruction go to not found."); } bool found = false; foreach (INST split in split_point) { if (split.Offset == sp.Offset && split.OpCode == sp.OpCode) { found = true; break; } } if (!found) { split_point.Add(sp); } } else if (array_of_instructions != null) { foreach (var ins in array_of_instructions) { Debug.Assert(ins != null); INST sp = null; for (int i = 0; i < basic_block.Instructions.Count(); ++i) { if (basic_block.Instructions[i].Offset == ins.Offset && basic_block.Instructions[i].OpCode == ins.OpCode) { sp = basic_block.Instructions[i]; break; } } if (sp == null) { throw new Exception("Instruction go to not found."); } bool found = false; foreach (INST split in split_point) { if (split.Offset == sp.Offset && split.OpCode == sp.OpCode) { found = true; break; } } if (!found) { split_point.Add(sp); } } } else { throw new Exception("Unknown operand type for basic block partitioning."); } } break; } // Split blocks after certain instructions, too. switch (flow_control) { case Mono.Cecil.Cil.FlowControl.Branch: case Mono.Cecil.Cil.FlowControl.Call: case Mono.Cecil.Cil.FlowControl.Cond_Branch: case Mono.Cecil.Cil.FlowControl.Return: case Mono.Cecil.Cil.FlowControl.Throw: { if (flow_control == Mono.Cecil.Cil.FlowControl.Call && !Campy.Utils.Options.IsOn("split_at_calls")) { break; } if (j + 1 < instruction_count) { var ins = basic_block.Instructions[j + 1].Instruction; INST sp = null; for (int i = 0; i < basic_block.Instructions.Count(); ++i) { if (basic_block.Instructions[i].Offset == ins.Offset && basic_block.Instructions[i].OpCode == ins.OpCode) { sp = basic_block.Instructions[i]; break; } } if (sp == null) { throw new Exception("Instruction go to not found."); } bool found = false; foreach (INST split in split_point) { if (split.Offset == sp.Offset && split.OpCode == sp.OpCode) { found = true; break; } } if (!found) { split_point.Add(sp); } } } break; } } // Get try-catch blocks and add those split points. foreach (var eh in body.ExceptionHandlers) { var start = eh.TryStart; var end = eh.TryEnd; // Split at try start. Instruction ins = start; INST sp = null; for (int i = 0; i < basic_block.Instructions.Count(); ++i) { if (basic_block.Instructions[i].Offset == ins.Offset && basic_block.Instructions[i].OpCode == ins.OpCode) { sp = basic_block.Instructions[i]; break; } } if (sp == null) { throw new Exception("Instruction go to not found."); } bool found = false; foreach (INST split in split_point) { if (split.Offset == sp.Offset && split.OpCode == sp.OpCode) { found = true; break; } } if (!found) { split_point.Add(sp); } } // Note, we assume that these splits are within the same method. // Order the list according to offset from beginning of the method. List <INST> ordered_leader_list = new List <INST>(); for (int j = 0; j < instruction_count; ++j) { // Order jump targets. These denote locations // where to split blocks. However, it's ordered, // so that splitting is done from last instruction in block // to first instruction in block. INST i = basic_block.Instructions[j]; if (split_point.Contains(i, new LambdaComparer <INST>( (INST a, INST b) => { if (a.Offset != b.Offset) { return(false); } if (a.OpCode != b.OpCode) { return(false); } return(true); }))) { ordered_leader_list.Add(i); } } if (ordered_leader_list.Count != split_point.Count) { throw new Exception( "Mono Cecil giving weird results for instruction operand type casting. Size of original split points not the same as order list of split points."); } // Split block at all jump targets. foreach (INST i in ordered_leader_list) { var owner = Cfg.PeekChangeSet(change_set).Where( n => n.Instructions.Where(ins => { if (ins.Offset != i.Offset) { return(false); } if (ins.OpCode != i.OpCode) { return(false); } return(true); } ).Any()).ToList(); // Check if there are multiple nodes with the same instruction or if there isn't // any node found containing the instruction. Either way, it's a programming error. if (owner.Count != 1) { throw new Exception("Cannot find instruction!"); } CFG.Vertex target_node = owner.FirstOrDefault(); var j = target_node.Instructions.FindIndex(a => { if (a.Offset != i.Offset) { return(false); } if (a.OpCode != i.OpCode) { return(false); } return(true); }); CFG.Vertex new_node = Split(target_node, j); } LambdaComparer <Instruction> fixed_comparer = new LambdaComparer <Instruction>( (Instruction a, Instruction b) => a.Offset == b.Offset && a.OpCode == b.OpCode ); // Add in all edges. var list_new_nodes = Cfg.PopChangeSet(change_set); foreach (var node in list_new_nodes) { int node_instruction_count = node.Instructions.Count; INST last_instruction = node.Instructions[node_instruction_count - 1]; Mono.Cecil.Cil.OpCode opcode = last_instruction.OpCode; Mono.Cecil.Cil.FlowControl flow_control = opcode.FlowControl; // Add jump edge. switch (flow_control) { case Mono.Cecil.Cil.FlowControl.Branch: case Mono.Cecil.Cil.FlowControl.Cond_Branch: { // Two cases: i.Operand is a single instruction, or an array of instructions. if (last_instruction.Operand as Mono.Cecil.Cil.Instruction != null) { // Handel leave instructions with code below. if (!(last_instruction.OpCode.Code == Code.Leave || last_instruction.OpCode.Code == Code.Leave_S)) { Mono.Cecil.Cil.Instruction target_instruction = last_instruction.Operand as Mono.Cecil.Cil.Instruction; CFG.Vertex target_node = list_new_nodes.FirstOrDefault( (CFG.Vertex x) => { if (!fixed_comparer.Equals(x.Instructions.First().Instruction, target_instruction)) { return(false); } return(true); }); if (target_node != null) { Cfg.AddEdge(new CFG.Edge() { From = node, To = target_node }); } } } else if (last_instruction.Operand as Mono.Cecil.Cil.Instruction[] != null) { foreach (Mono.Cecil.Cil.Instruction target_instruction in (last_instruction.Operand as Mono.Cecil.Cil.Instruction[])) { CFG.Vertex target_node = list_new_nodes.FirstOrDefault( (CFG.Vertex x) => { if (!fixed_comparer.Equals(x.Instructions.First().Instruction, target_instruction)) { return(false); } return(true); }); if (target_node != null) { Cfg.AddEdge(new CFG.Edge() { From = node, To = target_node }); } } } else { throw new Exception("Unknown operand type for conditional branch."); } break; } } // Add fall through edge. switch (flow_control) { //case Mono.Cecil.Cil.FlowControl.Branch: //case Mono.Cecil.Cil.FlowControl.Break: case Mono.Cecil.Cil.FlowControl.Call: case Mono.Cecil.Cil.FlowControl.Cond_Branch: case Mono.Cecil.Cil.FlowControl.Meta: case Mono.Cecil.Cil.FlowControl.Next: case Mono.Cecil.Cil.FlowControl.Phi: case Mono.Cecil.Cil.FlowControl.Throw: { int next = instructions_before_splits.FindIndex( n => { var r = n == last_instruction; return(r); } ); if (next < 0) { break; } next += 1; if (next >= instructions_before_splits.Count) { break; } var next_instruction = instructions_before_splits[next]; var owner = next_instruction.Block; CFG.Vertex target_node = owner; Cfg.AddEdge(new CFG.Edge() { From = node, To = target_node }); } break; case Mono.Cecil.Cil.FlowControl.Return: if (last_instruction.Instruction.OpCode.Code == Code.Endfinally) { // Although the exception handling is like a procedure call, // local variables are all accessible. So, we need to copy stack // values around. In addition, we have to create a fall through // even though there is stack unwinding. int next = instructions_before_splits.FindIndex( n => { var r = n == last_instruction; return(r); } ); if (next < 0) { break; } next += 1; if (next >= instructions_before_splits.Count) { break; } var next_instruction = instructions_before_splits[next]; var owner = next_instruction.Block; CFG.Vertex target_node = owner; Cfg.AddEdge(new CFG.Edge() { From = node, To = target_node }); } break; } } // Get inclusive start/exclusive end ranges of try/catch/finally. Dictionary <int, int> exclusive_eh_range = new Dictionary <int, int>(); foreach (var eh in body.ExceptionHandlers) { int try_start = eh.TryStart.Offset; int eh_end = eh.TryEnd != null ? eh.TryEnd.Offset : 0; if (eh.TryEnd != null && eh.TryEnd.Offset > eh_end) { eh_end = eh.TryEnd.Offset; } if (eh.HandlerEnd != null && eh.HandlerEnd.Offset > eh_end) { eh_end = eh.HandlerEnd.Offset; } exclusive_eh_range[try_start] = eh_end; } // Get inclusive start/inclusive end ranges of try/catch/finally. Dictionary <int, int> inclusive_eh_range = new Dictionary <int, int>(); foreach (var pair in exclusive_eh_range) { int previous_instruction_address = 0; foreach (var i in body.Instructions) { if (pair.Value == i.Offset) { inclusive_eh_range[pair.Key] = previous_instruction_address; break; } previous_instruction_address = i.Offset; } } // Get "finally" blocks for each try, if there is one. Dictionary <int, CFG.Vertex> try_finally_block = new Dictionary <int, CFG.Vertex>(); foreach (var eh in body.ExceptionHandlers) { if (eh.HandlerType == ExceptionHandlerType.Finally) { var finally_entry_block = list_new_nodes.Where( n => { var first = n.Instructions.First().Instruction; if (first.Offset == eh.HandlerStart.Offset) { return(true); } else { return(false); } }).First(); try_finally_block[eh.TryStart.Offset] = finally_entry_block; } } // Set block properties. foreach (var eh in body.ExceptionHandlers) { var block = list_new_nodes.Where( n => { var first = n.Instructions.First().Instruction; if (first.Offset == eh.HandlerStart.Offset) { return(true); } else { return(false); } }).First(); block.CatchType = eh.CatchType; block.IsCatch = eh.HandlerType == ExceptionHandlerType.Catch; block.ExceptionHandler = eh; } // Get "try" block for each try. Dictionary <int, CFG.Vertex> try_entry_block = new Dictionary <int, CFG.Vertex>(); foreach (var pair in inclusive_eh_range) { int start = pair.Key; var entry_block = list_new_nodes.Where( n => { var first = n.Instructions.First().Instruction; if (first.Offset == start) { return(true); } else { return(false); } }).First(); try_entry_block[start] = entry_block; } // Get entry block for each exception handler. Dictionary <int, CFG.Vertex> eh_entry_block = new Dictionary <int, CFG.Vertex>(); foreach (var eh in body.ExceptionHandlers) { int start = eh.HandlerStart.Offset; var entry_block = list_new_nodes.Where( n => { var first = n.Instructions.First().Instruction; if (first.Offset == start) { return(true); } else { return(false); } }).First(); eh_entry_block[start] = entry_block; } foreach (var eh in body.ExceptionHandlers) { int start = eh.TryStart.Offset; var try_block = try_entry_block[start]; int eh_start = eh.HandlerStart.Offset; var eh_block = eh_entry_block[eh_start]; if (eh.HandlerType == ExceptionHandlerType.Finally) { continue; } foreach (var prev in list_new_nodes.First()._graph.Predecessors(try_block)) { Cfg.AddEdge(new CFG.Edge() { From = prev, To = eh_block }); } } // Go through all CIL "leave" instructions and draw up edges. Any leave to end of // endfinally block requires edge to finally block, not the following instruction. foreach (var node in list_new_nodes) { int node_instruction_count = node.Instructions.Count; INST leave_instruction = node.Instructions[node_instruction_count - 1]; Mono.Cecil.Cil.OpCode opcode = leave_instruction.OpCode; Mono.Cecil.Cil.FlowControl flow_control = opcode.FlowControl; if (!(leave_instruction.OpCode.Code == Code.Leave || leave_instruction.OpCode.Code == Code.Leave_S)) { continue; } // Link up any leave instructions object operand = leave_instruction.Operand; Mono.Cecil.Cil.Instruction single_instruction = operand as Mono.Cecil.Cil.Instruction; Mono.Cecil.Cil.Instruction[] array_of_instructions = operand as Mono.Cecil.Cil.Instruction[]; if (single_instruction == null) { throw new Exception("Malformed leave instruction."); } KeyValuePair <int, int> pair = inclusive_eh_range.Where(p => p.Key <= leave_instruction.Instruction.Offset && leave_instruction.Instruction.Offset <= p.Value).FirstOrDefault(); // pair indicates what try/catch/finally block. If not in a try/catch/finally, // draw edge to destination. If the destination is outside try/catch/finally, // draw edge to destination. if (pair.Value == 0 || single_instruction.Offset >= pair.Key && single_instruction.Offset <= pair.Value) { var whereever = list_new_nodes.Where( n => { var first = n.Instructions.First().Instruction; if (first.Offset == single_instruction.Offset) { return(true); } else { return(false); } }).First(); Cfg.AddEdge(new CFG.Edge() { From = node, To = whereever }); continue; } if (try_finally_block.ContainsKey(pair.Key)) { Cfg.AddEdge(new CFG.Edge() { From = node, To = try_finally_block[pair.Key] }); } else { var whereever = list_new_nodes.Where( n => { var first = n.Instructions.First().Instruction; if (first.Offset == single_instruction.Offset) { return(true); } else { return(false); } }).First(); Cfg.AddEdge(new CFG.Edge() { From = node, To = whereever }); } } if (Campy.Utils.Options.IsOn("detailed_import_computation_trace")) { Cfg.OutputDotGraph(); } if (Campy.Utils.Options.IsOn("detailed_import_computation_trace")) { Cfg.OutputEntireGraph(); } }
private void Inject() { body = Method.Body; body.SimplifyMacros(); var ilProcessor = body.GetILProcessor(); var returnFixer = new ReturnFixer { Method = Method }; returnFixer.MakeLastStatementReturn(); var methodBodyFirstInstruction = GetMethodBodyFirstInstruction(); var startInstructions = new List <Instruction>(); startInstructions.AddRange(GetStartInstructions()); foreach (var instruction in startInstructions) { ilProcessor.InsertBefore(methodBodyFirstInstruction, instruction); } var paramInstructions = GetParamInstructions(); paramInstructions.Reverse(); if (paramInstructions.Any()) { foreach (var instruction in paramInstructions) { ilProcessor.InsertAfter(startInstructions.Last(), instruction); } } ilProcessor.InsertBefore(returnFixer.NopBeforeReturn, GetReturnValueInstructions(returnFixer.ReturnVariable)); var tryCatchLeaveInstructions = Instruction.Create(OpCodes.Leave, returnFixer.NopBeforeReturn); var catchInstructions = new List <Instruction>(); catchInstructions.AddRange(GetCatchInstructions()); ilProcessor.InsertBefore(returnFixer.NopBeforeReturn, tryCatchLeaveInstructions); ilProcessor.InsertBefore(returnFixer.NopBeforeReturn, catchInstructions); var endInstructions = new List <Instruction>(); endInstructions.AddRange(GetEndInstructions()); var isMethodLogExecEndAttributeExist = Method.CustomAttributes.ContainsAttribute("Yagasoft.Libraries.Common.LogExecEndAttribute"); if (isMethodLogExecEndAttributeExist) { LogInfo($">> Method is set to end execution."); endInstructions.AddRange(GetExecEndInstructions()); } var finallyInstruction = Instruction.Create(OpCodes.Endfinally); endInstructions.Add(finallyInstruction); endInstructions.Reverse(); foreach (var instruction in endInstructions) { ilProcessor.InsertAfter(catchInstructions.Last(), instruction); } var handler = new ExceptionHandler(ExceptionHandlerType.Catch) { CatchType = ExceptionType, TryStart = methodBodyFirstInstruction, TryEnd = tryCatchLeaveInstructions.Next, HandlerStart = catchInstructions.First(), HandlerEnd = catchInstructions.Last().Next }; body.ExceptionHandlers.Add(handler); handler = new ExceptionHandler(ExceptionHandlerType.Finally) { TryStart = methodBodyFirstInstruction, TryEnd = catchInstructions.Last().Next, HandlerStart = catchInstructions.Last().Next, HandlerEnd = finallyInstruction.Next }; body.ExceptionHandlers.Add(handler); var instructions = body.Instructions; Instruction doubleDupInstruction = null; for (var index = 0; index < instructions.Count; index++) { var instruction = instructions[index]; if (instruction.OpCode == OpCodes.Dup && instructions[index + 1].OpCode == OpCodes.Dup) { doubleDupInstruction = instructions[index + 1]; } if (instruction.OpCode == OpCodes.Pop && doubleDupInstruction != null) { var extraPopInstruction = instructions[index]; ilProcessor.Remove(extraPopInstruction); ilProcessor.InsertAfter(doubleDupInstruction, extraPopInstruction); doubleDupInstruction = null; } } body.InitLocals = true; body.OptimizeMacros(); }
private bool GenerateCalls(TypeReference producerRef, TypeReference jobStructType, MethodBody body, ILProcessor processor, HashSet <string> declaredGenerics) { try { var carrierType = producerRef.CheckedResolve(); MethodDefinition methodToCall = null; while (carrierType != null) { methodToCall = carrierType.GetMethods().FirstOrDefault((x) => x.Name == "EarlyJobInit" && x.Parameters.Count == 0 && x.IsStatic && x.IsPublic); if (methodToCall != null) { break; } carrierType = carrierType.DeclaringType; } // Legacy jobs lazy initialize. if (methodToCall == null) { return(false); } // We need a separate solution for generic jobs if (jobStructType.HasGenericParameters) { if (!declaredGenerics.Contains(jobStructType.FullName)) { AddDiagnostic(UserError.DC3002(jobStructType)); } return(false); } var asm = AssemblyDefinition.MainModule; var errorHandler = asm.ImportReference((asm.ImportReference(typeof(EarlyInitHelpers)).Resolve().Methods.First(x => x.Name == nameof(EarlyInitHelpers.JobReflectionDataCreationFailed)))); var typeType = asm.ImportReference(typeof(Type)).CheckedResolve(); var getTypeFromHandle = asm.ImportReference(typeType.Methods.FirstOrDefault((x) => x.Name == "GetTypeFromHandle")); var mref = asm.ImportReference(asm.ImportReference(methodToCall).MakeGenericInstanceMethod(jobStructType)); var callInsn = Instruction.Create(OpCodes.Call, mref); var handler = Instruction.Create(OpCodes.Nop); var landingPad = Instruction.Create(OpCodes.Nop); processor.Append(callInsn); processor.Append(handler); // This craziness is equivalent to typeof(n) processor.Append(Instruction.Create(OpCodes.Ldtoken, jobStructType)); processor.Append(Instruction.Create(OpCodes.Call, getTypeFromHandle)); processor.Append(Instruction.Create(OpCodes.Call, errorHandler)); processor.Append(landingPad); var leaveSuccess = Instruction.Create(OpCodes.Leave, landingPad); var leaveFail = Instruction.Create(OpCodes.Leave, landingPad); processor.InsertAfter(callInsn, leaveSuccess); processor.InsertBefore(landingPad, leaveFail); var exc = new ExceptionHandler(ExceptionHandlerType.Catch); exc.TryStart = callInsn; exc.TryEnd = leaveSuccess.Next; exc.HandlerStart = handler; exc.HandlerEnd = leaveFail.Next; exc.CatchType = asm.ImportReference(typeof(Exception)); body.ExceptionHandlers.Add(exc); return(true); } catch (Exception ex) { AddDiagnostic(InternalCompilerError.DCICE300(producerRef, jobStructType, ex)); } return(false); }
/// <summary> /// Emits the IL that calculates a hash code from a given service type. /// </summary> /// <param name="module">The module that holds the target type.</param> /// <param name="body">The body of the GetServiceHashCode method.</param> /// <param name="il">The <see cref="ILProcessor"/> that will be used to emit the instructions.</param> /// <param name="getHashCodeMethod">The <see cref="Object.GetHashCode"/> method.</param> /// <returns>The variable that holds the hash code.</returns> private static VariableDefinition EmitGetServiceTypeHashCode(ModuleDefinition module, Mono.Cecil.Cil.MethodBody body, ILProcessor il, MethodReference getHashCodeMethod) { // Get the hash code for the service type var hashVariable = AddLocals(module, body); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, getHashCodeMethod); il.Emit(OpCodes.Stloc, hashVariable); return(hashVariable); }
private void PatchAssembly(Action <byte[]> callback) { if (isPatching) { Interface.Oxide.LogWarning("Already patching plugin assembly: {0} (ignoring)", PluginNames.ToSentence()); RemoteLogger.Warning($"Already patching plugin assembly: {PluginNames.ToSentence()}"); return; } var startedAt = Interface.Oxide.Now; isPatching = true; ThreadPool.QueueUserWorkItem(_ => { try { AssemblyDefinition definition; using (var stream = new MemoryStream(RawAssembly)) definition = AssemblyDefinition.ReadAssembly(stream); var exceptionConstructor = typeof(UnauthorizedAccessException).GetConstructor(new[] { typeof(string) }); var securityException = definition.MainModule.Import(exceptionConstructor); Action <TypeDefinition> patchModuleType = null; patchModuleType = type => { foreach (var method in type.Methods) { var changedMethod = false; if (method.Body == null) { if (method.HasPInvokeInfo) { method.Attributes &= ~MethodAttributes.PInvokeImpl; var body = new MethodBody(method); body.Instructions.Add(Instruction.Create(OpCodes.Ldstr, "PInvoke access is restricted, you are not allowed to use PInvoke")); body.Instructions.Add(Instruction.Create(OpCodes.Newobj, securityException)); body.Instructions.Add(Instruction.Create(OpCodes.Throw)); method.Body = body; } } else { var replacedMethod = false; foreach (var variable in method.Body.Variables) { if (!IsNamespaceBlacklisted(variable.VariableType.FullName)) { continue; } var body = new MethodBody(method); body.Instructions.Add(Instruction.Create(OpCodes.Ldstr, $"System access is restricted, you are not allowed to use {variable.VariableType.FullName}")); body.Instructions.Add(Instruction.Create(OpCodes.Newobj, securityException)); body.Instructions.Add(Instruction.Create(OpCodes.Throw)); method.Body = body; replacedMethod = true; break; } if (replacedMethod) { continue; } var instructions = method.Body.Instructions; var ilProcessor = method.Body.GetILProcessor(); var first = instructions.First(); var i = 0; while (i < instructions.Count) { if (changedMethod) { break; } var instruction = instructions[i]; if (instruction.OpCode == OpCodes.Ldtoken) { var operand = instruction.Operand as IMetadataTokenProvider; var token = operand?.ToString(); if (IsNamespaceBlacklisted(token)) { ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Ldstr, $"System access is restricted, you are not allowed to use {token}")); ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Newobj, securityException)); ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Throw)); changedMethod = true; } } else if (instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Calli || instruction.OpCode == OpCodes.Callvirt) { var methodCall = instruction.Operand as MethodReference; var fullNamespace = methodCall?.DeclaringType.FullName; if ((fullNamespace == "System.Type" && methodCall.Name == "GetType") || IsNamespaceBlacklisted(fullNamespace)) { ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Ldstr, $"System access is restricted, you are not allowed to use {fullNamespace}")); ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Newobj, securityException)); ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Throw)); changedMethod = true; } } else if (instruction.OpCode == OpCodes.Ldfld) { var fieldType = instruction.Operand as FieldReference; var fullNamespace = fieldType?.FieldType.FullName; if (IsNamespaceBlacklisted(fullNamespace)) { ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Ldstr, $"System access is restricted, you are not allowed to use {fullNamespace}")); ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Newobj, securityException)); ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Throw)); changedMethod = true; } } i++; } } if (changedMethod) { method.Body?.OptimizeMacros(); /*//Interface.Oxide.LogDebug("Updating {0} instruction offsets: {1}", instructions.Count, method.FullName); * int curoffset = 0; * for (var i = 0; i < instructions.Count; i++) * { * var instruction = instructions[i]; * instruction.Previous = (i == 0) ? null : instructions[i - 1]; * instruction.Next = (i == instructions.Count - 1) ? null : instructions[i + 1]; * instruction.Offset = curoffset; * curoffset += instruction.GetSize(); * //Interface.Oxide.LogDebug(" {0}", instruction.ToString()); * }*/ } } foreach (var nestedType in type.NestedTypes) { patchModuleType(nestedType); } }; foreach (var type in definition.MainModule.Types) { patchModuleType(type); if (type.Namespace == "Oxide.Plugins") { if (PluginNames.Contains(type.Name)) { var constructor = type.Methods.FirstOrDefault(m => !m.IsStatic && m.IsConstructor && !m.HasParameters && !m.IsPublic); if (constructor != null) { var plugin = CompilablePlugins.SingleOrDefault(p => p.Name == type.Name); if (plugin != null) { plugin.CompilerErrors = "Primary constructor in main class must be public"; } } else { new DirectCallMethod(definition.MainModule, type); } } else { Interface.Oxide.LogWarning( $"A plugin has polluted the global namespace by defining {type.Name}: {PluginNames.ToSentence()}"); RemoteLogger.Info( $"A plugin has polluted the global namespace by defining {type.Name}: {PluginNames.ToSentence()}"); } } } // TODO: Why is there no error on boot using this? foreach (var type in definition.MainModule.Types) { if (type.Namespace != "Oxide.Plugins" || !PluginNames.Contains(type.Name)) { continue; } foreach (var m in type.Methods.Where(m => !m.IsStatic && !m.HasGenericParameters && !m.ReturnType.IsGenericParameter && !m.IsSetter && !m.IsGetter)) { foreach (var parameter in m.Parameters) { foreach (var attribute in parameter.CustomAttributes) { //Interface.Oxide.LogInfo($"{m.FullName} - {parameter.Name} - {attribute.Constructor.FullName}"); } } } } using (var stream = new MemoryStream()) { definition.Write(stream); PatchedAssembly = stream.ToArray(); } Interface.Oxide.NextTick(() => { isPatching = false; //Interface.Oxide.LogDebug("Patching {0} assembly took {1:0.00} ms", ScriptName, Interface.Oxide.Now - startedAt); callback(PatchedAssembly); }); } catch (Exception ex) { Interface.Oxide.NextTick(() => { isPatching = false; Interface.Oxide.LogException($"Exception while patching: {PluginNames.ToSentence()}", ex); RemoteLogger.Exception($"Exception while patching: {PluginNames.ToSentence()}", ex); callback(null); }); } }); }
internal static MethodBody Clone(MethodBody body, MethodDefinition parent, ImportContext context) { MethodBody nb = new MethodBody(parent); nb.MaxStack = body.MaxStack; nb.InitLocals = body.InitLocals; nb.CodeSize = body.CodeSize; foreach (VariableDefinition var in body.Variables) { nb.Variables.Add(new VariableDefinition( context.Import(var.VariableType))); } foreach (Instruction instr in body.Instructions) { Instruction ni = new Instruction(instr.OpCode); switch (instr.OpCode.OperandType) { case OperandType.InlineParam: case OperandType.ShortInlineParam: int param = body.Method.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = parent.Parameters [param]; break; case OperandType.InlineVar: case OperandType.ShortInlineVar: int var = body.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = nb.Variables [var]; break; case OperandType.InlineField: ni.Operand = context.Import((FieldReference)instr.Operand); break; case OperandType.InlineMethod: ni.Operand = context.Import((MethodReference)instr.Operand); break; case OperandType.InlineType: ni.Operand = context.Import((TypeReference)instr.Operand); break; case OperandType.InlineTok: if (instr.Operand is TypeReference) { ni.Operand = context.Import((TypeReference)instr.Operand); } else if (instr.Operand is FieldReference) { ni.Operand = context.Import((FieldReference)instr.Operand); } else if (instr.Operand is MethodReference) { ni.Operand = context.Import((MethodReference)instr.Operand); } break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: break; default: ni.Operand = instr.Operand; break; } nb.Instructions.Add(ni); } for (int i = 0; i < body.Instructions.Count; i++) { Instruction instr = nb.Instructions [i]; if (instr.OpCode.OperandType != OperandType.ShortInlineBrTarget && instr.OpCode.OperandType != OperandType.InlineBrTarget) { continue; } instr.Operand = GetInstruction(body, nb, (Instruction)body.Instructions [i].Operand); } foreach (ExceptionHandler eh in body.ExceptionHandlers) { ExceptionHandler neh = new ExceptionHandler(eh.Type); neh.TryStart = GetInstruction(body, nb, eh.TryStart); neh.TryEnd = GetInstruction(body, nb, eh.TryEnd); neh.HandlerStart = GetInstruction(body, nb, eh.HandlerStart); neh.HandlerEnd = GetInstruction(body, nb, eh.HandlerEnd); switch (eh.Type) { case ExceptionHandlerType.Catch: neh.CatchType = context.Import(eh.CatchType); break; case ExceptionHandlerType.Filter: neh.FilterStart = GetInstruction(body, nb, eh.FilterStart); neh.FilterEnd = GetInstruction(body, nb, eh.FilterEnd); break; } nb.ExceptionHandlers.Add(neh); } return(nb); }
static bool IsEmptyMethodBody(MethodBody body) { return(body.instructions.IsNullOrEmpty() && body.variables.IsNullOrEmpty()); }
private void _CopyMethodToDefinition() { MethodBase method = Method; Module moduleFrom = method.Module; System.Reflection.MethodBody bodyFrom = method.GetMethodBody(); byte[] data = bodyFrom?.GetILAsByteArray(); if (data == null) { throw new NotSupportedException("Body-less method"); } MethodDefinition def = Definition; ModuleDefinition moduleTo = def.Module; Mono.Cecil.Cil.MethodBody bodyTo = def.Body; ILProcessor processor = bodyTo.GetILProcessor(); Type[] typeArguments = null; if (method.DeclaringType.IsGenericType) { typeArguments = method.DeclaringType.GetGenericArguments(); } Type[] methodArguments = null; if (method.IsGenericMethod) { methodArguments = method.GetGenericArguments(); } foreach (LocalVariableInfo info in bodyFrom.LocalVariables) { TypeReference type = moduleTo.ImportReference(info.LocalType); if (info.IsPinned) { type = new PinnedType(type); } bodyTo.Variables.Add(new VariableDefinition(type)); } using (BinaryReader reader = new BinaryReader(new MemoryStream(data))) { while (reader.BaseStream.Position < reader.BaseStream.Length) { int offset = (int)reader.BaseStream.Position; Instruction instr = Instruction.Create(OpCodes.Nop); byte op = reader.ReadByte(); instr.OpCode = op != 0xfe ? _CecilOpCodes1X[op] : _CecilOpCodes2X[reader.ReadByte()]; instr.Offset = offset; ReadOperand(reader, instr); bodyTo.Instructions.Add(instr); } } foreach (Instruction instr in bodyTo.Instructions) { switch (instr.OpCode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: instr.Operand = GetInstruction((int)instr.Operand, false); break; case OperandType.InlineSwitch: int[] offsets = (int[])instr.Operand; Instruction[] targets = new Instruction[offsets.Length]; for (int i = 0; i < offsets.Length; i++) { targets[i] = GetInstruction(offsets[i], false); } instr.Operand = targets; break; } } foreach (ExceptionHandlingClause clause in bodyFrom.ExceptionHandlingClauses) { ExceptionHandler handler = new ExceptionHandler((ExceptionHandlerType)clause.Flags); bodyTo.ExceptionHandlers.Add(handler); handler.TryStart = GetInstruction(clause.TryOffset, false); handler.TryEnd = GetInstruction(handler.TryStart.Offset + clause.TryLength - 1, false); handler.HandlerStart = GetInstruction(clause.HandlerOffset, false); handler.FilterStart = GetInstruction(clause.FilterOffset, false); handler.HandlerEnd = GetInstruction((handler.FilterStart ?? handler.HandlerStart).Offset + clause.HandlerLength + 1, true); handler.CatchType = clause.CatchType == null ? null : moduleTo.ImportReference(clause.CatchType); } void ReadOperand(BinaryReader reader, Instruction instr) { int index, offs, length; switch (instr.OpCode.OperandType) { case OperandType.InlineNone: instr.Operand = null; break; case OperandType.InlineSwitch: length = reader.ReadInt32(); offs = (int)reader.BaseStream.Position + (4 * length); int[] targets = new int[length]; for (int i = 0; i < length; i++) { targets[i] = reader.ReadInt32() + offs; } instr.Operand = targets; break; case OperandType.ShortInlineBrTarget: offs = reader.ReadSByte(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.InlineBrTarget: offs = reader.ReadInt32(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.ShortInlineI: instr.Operand = instr.OpCode == OpCodes.Ldc_I4_S ? reader.ReadSByte() : (object)reader.ReadByte(); break; case OperandType.InlineI: instr.Operand = reader.ReadInt32(); break; case OperandType.ShortInlineR: instr.Operand = reader.ReadSingle(); break; case OperandType.InlineR: instr.Operand = reader.ReadDouble(); break; case OperandType.InlineI8: instr.Operand = reader.ReadInt64(); break; case OperandType.InlineSig: throw new NotSupportedException("Parsing CallSites at runtime currently not supported"); case OperandType.InlineString: instr.Operand = moduleFrom.ResolveString(reader.ReadInt32()); break; case OperandType.InlineTok: switch (moduleFrom.ResolveMember(reader.ReadInt32(), typeArguments, methodArguments)) { case Type i: instr.Operand = moduleTo.ImportReference(i); break; case FieldInfo i: instr.Operand = moduleTo.ImportReference(i); break; case MethodBase i: instr.Operand = moduleTo.ImportReference(i); break; } break; case OperandType.InlineType: instr.Operand = moduleTo.ImportReference(moduleFrom.ResolveType(reader.ReadInt32(), typeArguments, methodArguments)); break; case OperandType.InlineMethod: instr.Operand = moduleTo.ImportReference(moduleFrom.ResolveMethod(reader.ReadInt32(), typeArguments, methodArguments)); break; case OperandType.InlineField: instr.Operand = moduleTo.ImportReference(moduleFrom.ResolveField(reader.ReadInt32(), typeArguments, methodArguments)); break; case OperandType.ShortInlineVar: case OperandType.InlineVar: index = instr.OpCode.OperandType == OperandType.ShortInlineVar ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = bodyTo.Variables[index]; break; case OperandType.InlineArg: case OperandType.ShortInlineArg: index = instr.OpCode.OperandType == OperandType.ShortInlineArg ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = def.Parameters[index]; break; case OperandType.InlinePhi: // No opcode seems to use this default: throw new NotSupportedException($"Unsupported opcode ${instr.OpCode.Name}"); } } Instruction GetInstruction(int offset, bool isEnd) { int last = bodyTo.Instructions.Count - 1; if (offset < 0 || offset > bodyTo.Instructions[last].Offset) { return(null); } int min = 0; int max = last; while (min <= max) { int mid = min + ((max - min) / 2); Instruction instr = bodyTo.Instructions[mid]; if (isEnd) { if (offset == instr.Offset + instr.GetSize() - 1) { return(instr); } } else { if (offset == instr.Offset) { return(instr); } } if (offset < instr.Offset) { max = mid - 1; } else { min = mid + 1; } } return(null); } }
private List <Instruction> CreateInstructionsToInject(ModuleDefinition moduleDefinition, MethodBody body) { var mRef2 = moduleDefinition.ImportReference(typeof(Console).GetMethod("WriteLine", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string), typeof(object) }, null)); var instructions = new List <Instruction>(); //build up call instructions.Add(Instruction.Create(OpCodes.Ldstr, "Hello {0}!")); instructions.Add(Instruction.Create(OpCodes.Ldstr, "Joe")); instructions.Add(Instruction.Create(OpCodes.Call, mRef2)); instructions.Add(Instruction.Create(OpCodes.Nop)); //instructions.Add(Instruction.Create(OpCodes.Ldstr, "Hello {0}!")); //instructions.Add(Instruction.Create(OpCodes.Ldstr, "Jim")); //instructions.Add(Instruction.Create(OpCodes.Call, mRef2)); //instructions.Add(Instruction.Create(OpCodes.Ldstr, "Bye {0}!")); //instructions.Add(Instruction.Create(OpCodes.Ldstr, "Jim")); //instructions.Add(Instruction.Create(OpCodes.Call, mRef2)); return(instructions); }
public static MethodReference Import(MethodBody body, MethodReference newMeth) => body.Method.DeclaringType.Module.ImportReference(newMeth);
public Branch(MethodBody body, OpCode branch) { this.Body = body; this.Instruction = Instruction.Create(branch, Instruction.Create(OpCodes.Nop)); }
private void PatchAssembly(int version, Action callback) { if (isPatching) { Interface.GetMod().LogInfo("Already patching plugin assembly: {0} (ignoring)", ScriptName); return; } if (version == LastGoodVersion) { //Interface.GetMod().LogInfo("Plugin assembly has already been patched: {0}", Name); callback(); return; } var path = string.Format("{0}\\{1}_{2}.dll", Interface.GetMod().TempDirectory, Name, version); //Interface.GetMod().LogInfo("Patching plugin assembly: {0}", Name); isPatching = true; ThreadPool.QueueUserWorkItem((_) => { try { var definition = AssemblyDefinition.ReadAssembly(path); var exception_constructor = typeof(UnauthorizedAccessException).GetConstructor(new Type[] { typeof(string) }); var security_exception = definition.MainModule.Import(exception_constructor); Action <TypeDefinition> patch_module_type = null; patch_module_type = (type) => { foreach (var method in type.Methods) { Collection <Instruction> instructions = null; var changed_method = false; if (method.Body == null) { if (method.HasPInvokeInfo) { method.Attributes &= ~Mono.Cecil.MethodAttributes.PInvokeImpl; var body = new Mono.Cecil.Cil.MethodBody(method); body.Instructions.Add(Instruction.Create(OpCodes.Ldstr, "PInvoke access is restricted, you are not allowed to use PInvoke")); body.Instructions.Add(Instruction.Create(OpCodes.Newobj, security_exception)); body.Instructions.Add(Instruction.Create(OpCodes.Throw)); method.Body = body; } } else { var replaced_method = false; foreach (var variable in method.Body.Variables) { foreach (var namespace_name in blacklistedNamespaces) { if (variable.VariableType.FullName.StartsWith(namespace_name)) { if (whitelistedNamespaces.Any(name => variable.VariableType.FullName.StartsWith(name))) { continue; } var body = new Mono.Cecil.Cil.MethodBody(method); body.Instructions.Add(Instruction.Create(OpCodes.Ldstr, "System access is restricted, you are not allowed to use " + variable.VariableType.FullName)); body.Instructions.Add(Instruction.Create(OpCodes.Newobj, security_exception)); body.Instructions.Add(Instruction.Create(OpCodes.Throw)); method.Body = body; replaced_method = true; break; } } if (replaced_method) { break; } } if (replaced_method) { continue; } instructions = method.Body.Instructions; var i = 0; while (i < instructions.Count) { var instruction = instructions[i]; if (instruction.OpCode == OpCodes.Ldtoken) { var operand = instruction.Operand as IMetadataTokenProvider; var token = operand.ToString(); foreach (var namespace_name in blacklistedNamespaces) { if (token.StartsWith(namespace_name)) { if (whitelistedNamespaces.Any(name => token.StartsWith(name))) { continue; } instructions[i++] = Instruction.Create(OpCodes.Ldstr, "System access is restricted, you are not allowed to use " + token); instructions.Insert(i++, Instruction.Create(OpCodes.Newobj, security_exception)); instructions.Insert(i, Instruction.Create(OpCodes.Throw)); changed_method = true; } } } else if (instruction.OpCode == OpCodes.Call) { var method_call = instruction.Operand as MethodReference; var full_namespace = method_call.DeclaringType.FullName; foreach (var namespace_name in blacklistedNamespaces) { if (full_namespace.StartsWith(namespace_name)) { if (whitelistedNamespaces.Any(name => full_namespace.StartsWith(name))) { continue; } for (var n = 0; n < method.Parameters.Count; n++) { instructions.Insert(i++, Instruction.Create(OpCodes.Pop)); } instructions[i++] = Instruction.Create(OpCodes.Ldstr, "System access is restricted, you are not allowed to use " + full_namespace); instructions.Insert(i++, Instruction.Create(OpCodes.Newobj, security_exception)); instructions.Insert(i, Instruction.Create(OpCodes.Throw)); changed_method = true; } } } i++; } } if (changed_method) { //Interface.GetMod().LogInfo("Updating {0} instruction offsets: {1}", instructions.Count, method.FullName); int curoffset = 0; for (var i = 0; i < instructions.Count; i++) { var instruction = instructions[i]; instruction.Previous = (i == 0) ? null : instructions[i - 1]; instruction.Next = (i == instructions.Count - 1) ? null : instructions[i + 1]; instruction.Offset = curoffset; curoffset += instruction.GetSize(); //Interface.GetMod().LogInfo(" {0}", instruction.ToString()); } } } foreach (var nested_type in type.NestedTypes) { patch_module_type(nested_type); } }; foreach (var type in definition.MainModule.Types) { patch_module_type(type); } definition.Write(path); Interface.GetMod().NextTick(() => { isPatching = false; callback(); }); } catch (Exception ex) { isPatching = false; Interface.GetMod().NextTick(() => Interface.GetMod().LogInfo("Exception while patching {0} assembly: {1}", ScriptName, ex.ToString())); } }); }
public override void VisitMethodBody(MethodBody body) { m_codeWriter.Empty(); }
private void ReplaceReturnWithLeaveInstructions( Mono.Cecil.Cil.MethodBody methodBody, Instruction leaveInstructionOperand, VariableDefinition returnVariable = null) { var ilProcessor = methodBody.GetILProcessor(); var instructions = methodBody.Instructions; var exceptionHandlers = methodBody.ExceptionHandlers; Instruction storeReturnVariableInstruction = null; if (returnVariable != null) { storeReturnVariableInstruction = ilProcessor.Create(OpCodes.Stloc, returnVariable); } foreach (var instruction in instructions.ToList()) { if (instruction.OpCode == OpCodes.Ret) { var leaveInstruction = ilProcessor.Create(OpCodes.Leave, leaveInstructionOperand); ilProcessor.Replace(instruction, leaveInstruction); if (returnVariable != null) { ilProcessor.InsertBefore(leaveInstruction, storeReturnVariableInstruction); } instructions .ToList() .ForEach(i => { if (i.Operand is Instruction operandInstruction && operandInstruction.Equals(instruction)) { i.Operand = leaveInstruction; } }); exceptionHandlers .ToList() .ForEach(eHandler => { if (eHandler.TryStart.Equals(instruction)) { eHandler.TryStart = storeReturnVariableInstruction ?? leaveInstruction; } if (eHandler.TryEnd.Equals(instruction)) { eHandler.TryEnd = storeReturnVariableInstruction ?? leaveInstruction; } if (eHandler.HandlerStart.Equals(instruction)) { eHandler.HandlerStart = storeReturnVariableInstruction ?? leaveInstruction; } if (eHandler.HandlerEnd.Equals(instruction)) { eHandler.HandlerEnd = storeReturnVariableInstruction ?? leaveInstruction; } }); } } }
private static Instruction GetFirstConstructorInstruction(MethodBody body) { var constructorInstruction = body.Instructions.FirstOrDefault(a => a.OpCode == OpCodes.Call && (a.Operand as MethodReference)?.Name == ".ctor"); return(constructorInstruction); }
internal ILProcessor(MethodBody body) { this.body = body; this.instructions = body.Instructions; }
private static bool AnalyzeMethodCalls(MethodDefinition methodDefinition, XElement entity, XElement newMethodNode) { XElement callsNode = null; bool result = false; Mono.Cecil.Cil.MethodBody body = methodDefinition.Body; if (null != body) { // method calls foreach (Instruction itemInstruction in body.Instructions) { if (itemInstruction.OpCode.Name.StartsWith("callvirt")) { Mono.Cecil.Cil.Instruction methodInstruction = itemInstruction as Mono.Cecil.Cil.Instruction; Mono.Cecil.MethodReference methodReference = methodInstruction.Operand as Mono.Cecil.MethodReference; string callName = GetCallNameFromAnalyzeMethodCalls(methodReference); string typeName = GetNameFromNewObjMethodReference(methodReference); string componentName = NetOfficeSupportTable.GetLibrary(typeName); string[] testArray = typeName.Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries); if (testArray.Length >= 3 && testArray[2] == "Tools") { continue; } if ((typeName.StartsWith(_apiName)) && !typeName.Equals(_apiName + ".dll", StringComparison.InvariantCultureIgnoreCase) && CountOf(typeName, ".") > 1 && (!typeName.StartsWith("NetOffice.DeveloperToolbox"))) { string[] supportByLibrary = _netOfficeSupportTable.GetTypeCallSupport(callName); result = true; if (null == callsNode) { callsNode = new XElement("Calls"); newMethodNode.Add(callsNode); } XElement newObject = new XElement("Entity", new XElement("Parameters"), new XAttribute("Type", typeName), new XAttribute("Name", callName), new XAttribute("Api", componentName)); callsNode.Add(newObject); XElement supportByNode = new XElement("SupportByLibrary", new XAttribute("Api", componentName)); newObject.Add(supportByNode); if (null != supportByLibrary) { supportByNode.Add(new XAttribute("Name", callName)); foreach (string item in supportByLibrary) { supportByNode.Add(new XElement("Version", item)); } } bool resultParameter = AnalyzeMethodCallParameters(itemInstruction, newObject); } } } } return(result); }