private static void InsertInvalidIl(MethodBody methodBody) { //Get the instructions and cil worker var instructions = methodBody.Instructions; if (instructions.Count <= 0) { return; //We can only do this if we have instructions to work with } ILProcessor il = methodBody.GetILProcessor(); //First create an invalid il instruction OpCode fakeOpCode = CreateInvalidOpCode(); Instruction invalidIlInstr1 = il.Create(fakeOpCode); Instruction invalidIlInstr2 = il.Create(fakeOpCode); Instruction originalFirst = instructions[0]; //Insert invalid il at the start il.InsertBefore(originalFirst, invalidIlInstr1); il.InsertBefore(invalidIlInstr1, invalidIlInstr2); //Create the branch statement Instruction branchStatement = il.Create(OpCodes.Br_S, originalFirst); //Add the branch to the start il.InsertBefore(invalidIlInstr2, branchStatement); //Readjust the offsets il.AdjustOffsets(methodBody, 4); }
/// <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; }
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)); }
public static void RewriteCilCodeBlock(Mono.Cecil.Cil.MethodBody body) { List <Instruction> result = new List <Instruction>(); for (int j = 0; j < body.Instructions.Count; ++j) { Instruction i = body.Instructions[j]; var inst_to_insert = i; if (i.OpCode.FlowControl == FlowControl.Call) { object method = i.Operand; if (method as Mono.Cecil.MethodReference == null) { throw new Exception(); } var method_reference = method as Mono.Cecil.MethodReference; TypeReference mr_dt = method_reference.DeclaringType; var bcl_substitute = SubstituteMethod(method_reference); if (bcl_substitute != null) { CallSite cs = new CallSite(typeof(void).ToMonoTypeReference()); body.Instructions.RemoveAt(j); var worker = body.GetILProcessor(); Instruction new_inst = worker.Create(i.OpCode, bcl_substitute); new_inst.Offset = i.Offset; body.Instructions.Insert(j, new_inst); } } } }
private void InsertEventHandler(bool before, Assembly asm, AssemblyDefinition asmDef, InjectionMethod im, string eventType, Type[] eventArgumentTypes) { ModuleDefinition module = asmDef.MainModule; MethodReference mrHandleEvent = module.ImportReference(asm.GetType("TSML.Event.EventHandler").GetMethod("OnEvent", new Type[] { asm.GetType("TSML.Event.Event") })); MethodReference eventCtor = module.ImportReference(asm.GetType(eventType).GetConstructor(eventArgumentTypes)); Mono.Cecil.Cil.MethodBody body = im.MethodDef.Body; ILProcessor proc = body.GetILProcessor(); Instruction target = body.Instructions[before ? 0 : body.Instructions.Count - 1]; List <Instruction> insns = new List <Instruction>(); // Load arguments, index 0 being the object itself for (int i = 0; i < eventArgumentTypes.Length; i++) { insns.Add(proc.Create(OpCodes.Ldarg, i)); } insns.Add(proc.Create(OpCodes.Newobj, eventCtor)); insns.Add(proc.Create(OpCodes.Call, mrHandleEvent)); foreach (Instruction insn in insns) { proc.InsertBefore(target, insn); } }
static void FillArgs(MethodDefinition target, Instruction endPoint, Action <MethodDefinition, Instruction, int> parseReferenceProcess) { MethodBody targetBody = target.Body; ILProcessor il = targetBody.GetILProcessor(); int paramCount = target.Parameters.Count + (target.HasThis ? 1 : 0); for (int i = 0; i < paramCount; ++i) { if (i < ldargs.Length) { il.InsertBefore(endPoint, il.Create(ldargs[i])); } else if (i <= byte.MaxValue) { il.InsertBefore(endPoint, il.Create(OpCodes.Ldarg_S, (byte)i)); } else { il.InsertBefore(endPoint, il.Create(OpCodes.Ldarg, (short)i)); } if (parseReferenceProcess != null) { parseReferenceProcess(target, endPoint, i); } } }
public static void FillMMILProxy(ModuleDefinition proxyMod, TypeDefinition proxy, MethodInfo stub) { MethodDefinition method = new MethodDefinition( stub.Name, MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, proxyMod.ImportReference(stub.ReturnType) ); ParameterInfo[] args = stub.GetParameters(); int argsCount = args.Length; for (int i = 1; i < argsCount; i++) { method.Parameters.Add( new ParameterDefinition(args[i].Name, (ParameterAttributes)args[i].Attributes, proxyMod.ImportReference(args[i].ParameterType)) ); } --argsCount; // MMILRT contains self as first parameter MethodBody body = method.Body = new MethodBody(method); ILProcessor il = body.GetILProcessor(); // Always required to get the MonoModder instance. il.Emit(OpCodes.Call, proxyMod.ImportReference(m_get_Self)); // Load arguments to stack. // TODO: What about generic arguments in MMILProxy? if (argsCount > 0) { il.Emit(OpCodes.Ldarg_0); } if (argsCount > 1) { il.Emit(OpCodes.Ldarg_1); } if (argsCount > 2) { il.Emit(OpCodes.Ldarg_2); } if (argsCount > 3) { il.Emit(OpCodes.Ldarg_3); } for (int i = 4; i < argsCount && i < 256; i++) { il.Emit(OpCodes.Ldarg_S, (byte)i); } for (int i = 256; i < argsCount; i++) { il.Emit(OpCodes.Ldarg, i); } // Call the actual method. il.Emit(OpCodes.Call, proxyMod.ImportReference(stub)); // Finish it off with a ret. il.Emit(OpCodes.Ret); proxy.Methods.Add(method); }
public virtual void PatchTrampoline(MethodDefinition targetMethod, MethodDefinition method) { method.IsManaged = true; method.IsIL = true; method.IsNative = false; method.PInvokeInfo = null; method.IsInternalCall = false; method.IsPInvokeImpl = false; method.NoInlining = true; MethodBody body = method.Body = new MethodBody(method); ILProcessor il = body.GetILProcessor(); for (int i = 64; i > -1; --i) { il.Emit(OpCodes.Nop); } if (method.ReturnType.MetadataType != MetadataType.Void) { il.Emit(OpCodes.Ldnull); if (method.ReturnType.IsValueType) { il.Emit(OpCodes.Box, method.ReturnType); } } il.Emit(OpCodes.Ret); RegisterTrampoline(targetMethod, method); }
private void ProcessMethodDefinition(MethodDefinition method) { MethodBody body = method.Body; body.SimplifyMacros(); ILProcessor ilProcessor = body.GetILProcessor(); if (body.HasExceptionHandlers) { for (int i = 0; i < body.ExceptionHandlers.Count; i++) { //This doesn't rethrow per se, but it might be the path to more fine grained control //var exceptionType = typeof(Exception); //var exceptionCtor = exceptionType.GetConstructor(new Type[] {}); //var constructorReference = ModuleDefinition.ImportReference(exceptionCtor); //ilProcessor.InsertBefore(body.ExceptionHandlers[i].HandlerEnd.Previous, Instruction.Create(OpCodes.Newobj, constructorReference)); //ilProcessor.InsertBefore(body.ExceptionHandlers[i].HandlerEnd.Previous, Instruction.Create(OpCodes.Throw)); ilProcessor.Replace(body.ExceptionHandlers[i].HandlerEnd.Previous, Instruction.Create(OpCodes.Rethrow)); } } body.InitLocals = true; body.OptimizeMacros(); }
static void FillCoroutineState(MethodDefinition coroutineCarrier) { MethodBody targetBody = coroutineCarrier.Body; ILProcessor il = targetBody.GetILProcessor(); il.InsertBefore(cursor, il.Create(OpCodes.Ldarg_0)); var stateField = coroutineCarrier.DeclaringType.Fields.Single(field => field.Name == "$PC"); il.InsertBefore(cursor, il.Create(OpCodes.Ldfld, stateField)); }
public static void PatchMethodThatUsedDisplayClassToTreatItAsAStruct(MethodBody body, VariableDefinition displayClassVariable) { var displayClassTypeReference = displayClassVariable.VariableType; var instructions = body.Instructions.ToArray(); var ilProcessor = body.GetILProcessor(); foreach (var instruction in instructions) { // We will replace all LdLoc of our displayclass to LdLoca of our displayclass variable that now lives on the stack. // Except in the case where we are storing a nested DisplayClass! if ((instruction.IsLoadLocal(out int loadIndex) && displayClassVariable.Index == loadIndex) && !(instruction.Next != null && instruction.Next.OpCode == OpCodes.Stfld && (instruction.Next.Operand as FieldReference).IsNestedDisplayClassField())) { instruction.OpCode = OpCodes.Ldloca; instruction.Operand = body.Variables[loadIndex]; } // We also need to replace and ldfld a nested DisplayClass that we turned into a struct with ldflda if (instruction.OpCode == OpCodes.Ldfld && ((FieldReference)instruction.Operand).IsNestedDisplayClassField()) { instruction.OpCode = OpCodes.Ldflda; } // Roselyn should never double assign the DisplayClass to a variable, throw if we somehow detect this. if (instruction.IsStoreLocal(out int storeIndex) && displayClassVariable.Index == storeIndex) { InternalCompilerError.DCICE003(body.Method, instruction).Throw(); } bool IsInstructionNewObjOfDisplayClass(Instruction thisInstruction) { return(thisInstruction.OpCode.Code == Code.Newobj && ((MethodReference)thisInstruction.Operand).DeclaringType.TypeReferenceEquals(displayClassTypeReference)); } // We need to replace the creation of the displayclass object on the heap, with a initobj of the displayclass on the stack. // The final sequence will be ldloca, initobj (which will replace newobj, stloc.1. if (IsInstructionNewObjOfDisplayClass(instruction)) { // Remove next stloc.1 instruction so that we can replace both of these with the instructions below if (!instruction.Next.IsStoreLocal(out _)) { InternalCompilerError.DCICE004(body.Method, instruction).Throw(); } instruction.Next.MakeNOP(); ilProcessor.Replace(instruction, new[] { Instruction.Create(OpCodes.Ldloca, displayClassVariable), Instruction.Create(OpCodes.Initobj, displayClassTypeReference), }); } } }
static void FillJumpInfo(MethodDefinition target, bool bConfirmPopReturnValue) { MethodBody targetBody = target.Body; ILProcessor il = targetBody.GetILProcessor(); if (!bConfirmPopReturnValue) { Instruction retIns = il.Create(OpCodes.Ret); if (!injectType.HasFlag(InjectType.Before)) { if (cursor.Previous.OpCode == OpCodes.Nop) { cursor.Previous.OpCode = retIns.OpCode; cursor.Previous.Operand = retIns.Operand; retIns = cursor.Previous; } else { il.InsertBefore(cursor, retIns); } } else { Instruction start = il.Create(OpCodes.Ldloc, flagDef); if (cursor.Previous.OpCode == OpCodes.Nop) { cursor.Previous.OpCode = start.OpCode; cursor.Previous.Operand = start.Operand; il.InsertAfter(cursor.Previous, retIns); } else { il.InsertBefore(cursor, retIns); il.InsertBefore(retIns, start); } Instruction popIns = il.Create(OpCodes.Pop); bool bGotReturnValue = !target.ReturnVoid(); if (bGotReturnValue) { il.InsertBefore(cursor, popIns); } il.InsertBefore(retIns, il.Create(ldcI4s[(int)InjectType.Before / 2])); il.InsertBefore(retIns, il.Create(OpCodes.Ble_Un, bGotReturnValue ? popIns : cursor)); } } else if (cursor.Previous.OpCode == OpCodes.Nop) { targetBody.Instructions.Remove(cursor.Previous); } }
/// <summary> /// Create a clone of the given method body /// </summary> public static MethodBody Clone(this MethodBody source, MethodDefinition target) { var result = new MethodBody(target) { InitLocals = source.InitLocals, MaxStackSize = source.MaxStackSize }; var worker = result.GetILProcessor(); foreach (var i in source.Instructions) { // Poor mans clone, but sufficient for our needs var clone = Instruction.Create(OpCodes.Nop); clone.OpCode = i.OpCode; clone.Operand = i.Operand; worker.Append(clone); } return result; }
public static void ILMethodIntrument(MethodDefinition md, long methodID, MethodReference startMR, MethodReference endMR) { Mono.Cecil.Cil.MethodBody mb = md.Body; Instruction startInst; List <Instruction> endInst = new List <Instruction>(); Console.WriteLine(" -- StartMSpan"); foreach (Instruction inst in mb.Instructions) { switch (inst.OpCode.Code) { case Code.Ret: case Code.Throw: case Code.Rethrow: endInst.Add(inst); Console.WriteLine(" -- EndMSpan"); break; } Console.WriteLine(inst.OpCode.Name); } mb.InitLocals = true; VariableDefinition vd = new VariableDefinition(startMR.ReturnType); mb.Variables.Add(vd); ILProcessor ilp = mb.GetILProcessor(); startInst = mb.Instructions[0]; if (startInst.OpCode.Code != Code.Nop) { ilp.InsertBefore(startInst, ilp.Create(OpCodes.Nop)); startInst = mb.Instructions[0]; } ilp.InsertBefore(startInst, ilp.Create(OpCodes.Nop)); ilp.InsertBefore(startInst, ilp.Create(OpCodes.Ldc_I8, methodID)); ilp.InsertBefore(startInst, ilp.Create(OpCodes.Call, startMR)); ilp.InsertBefore(startInst, ilp.Create(OpCodes.Stloc, vd)); foreach (Instruction inst in endInst) { ilp.InsertBefore(inst, ilp.Create(OpCodes.Ldloc, vd)); ilp.InsertBefore(inst, ilp.Create(OpCodes.Call, endMR)); } ilp.Body.OptimizeMacros(); }
public MethodBodyPatcher(string methodName, MethodDefinition method) { _methodName = methodName; _methodBody = method.Body; _processor = _methodBody.GetILProcessor(); _realBodyStart = _methodBody.Instructions.First(); _realBodyEnd = _methodBody.Instructions.Last(); _markStart1BeforeCreateArgumentsArray = _processor.Create(OpCodes.Nop); _markStart2BeforeCreateMethodExecutionArgs = _processor.Create(OpCodes.Nop); _markStart3BeforeOnEntryCall = _processor.Create(OpCodes.Nop); _markStart4BeforeRealBodyStartExceptionHandler = _processor.Create(OpCodes.Nop); _markEnd1NewRealBodyEnd = _processor.Create(OpCodes.Nop); _markEnd2BeforeOnExitCall = _processor.Create(OpCodes.Nop); _markRetNew = EndsWithThrow ? _processor.Create(OpCodes.Throw) : _processor.Create(OpCodes.Ret); }
public void AddInstruction() { var object_ref = new TypeReference ("System", "Object", null, null, false); var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref); var body = new MethodBody (method); var il = body.GetILProcessor (); var first = il.Create (OpCodes.Nop); var second = il.Create (OpCodes.Nop); body.Instructions.Add (first); body.Instructions.Add (second); Assert.IsNull (first.Previous); Assert.AreEqual (second, first.Next); Assert.AreEqual (first, second.Previous); Assert.IsNull (second.Next); }
static Action <MethodDefinition, InjectType> GetCoroutineInjectInfoFiller(MethodDefinition coroutineCreator, FieldDefinition hostRef) { return((coroutineCarrier, runtimeInjectType) => { MethodBody targetBody = coroutineCarrier.Body; ILProcessor il = targetBody.GetILProcessor(); il.InsertBefore(cursor, il.Create(OpCodes.Ldloc, funcDef)); if (coroutineCreator.HasThis) { il.InsertBefore(cursor, il.Create(OpCodes.Ldarg_0)); il.InsertBefore(cursor, il.Create(OpCodes.Ldfld, hostRef)); } CopyCarrierFieldsToArg(coroutineCreator, coroutineCarrier); FillCoroutineState(coroutineCarrier); il.InsertBefore(cursor, il.Create(OpCodes.Call, GetLuaMethodInvoker(coroutineCreator, true, true))); }); }
static void FillBaseCall(MethodDefinition target, InjectType runtimeInjectType, bool preCall) { MethodBody targetBody = target.Body; ILProcessor il = targetBody.GetILProcessor(); InjectType curBaseInjectType = preCall ? InjectType.ReplaceWithPreInvokeBase : InjectType.ReplaceWithPostInvokeBase; if (runtimeInjectType.HasFlag(curBaseInjectType)) { Instruction end = il.Create(OpCodes.Nop); il.InsertBefore(cursor, end); il.InsertBefore(end, il.Create(OpCodes.Ldloc, flagDef)); il.InsertBefore(end, il.Create(OpCodes.Ldc_I4, (int)curBaseInjectType)); il.InsertBefore(end, il.Create(OpCodes.Bne_Un, end)); FillArgs(target, end, PostProcessBaseMethodArg); il.InsertBefore(end, il.Create(OpCodes.Call, target.GetBaseMethodInstance())); if (!target.ReturnVoid()) { il.InsertBefore(end, il.Create(OpCodes.Pop)); } } }
private MsilBodyGenerator(MethodDefinition method) { _module = method.Module; _method = method; _body = method.Body = new MethodBody(method); _processor = _body.GetILProcessor(); _elementTypes = new[] { _module.TypeSystem.Void.Resolve(), _module.TypeSystem.Boolean.Resolve(), _module.TypeSystem.Char.Resolve(), _module.TypeSystem.String.Resolve(), _module.TypeSystem.Byte.Resolve(), _module.TypeSystem.SByte.Resolve(), _module.TypeSystem.UInt16.Resolve(), _module.TypeSystem.Int16.Resolve(), _module.TypeSystem.UInt32.Resolve(), _module.TypeSystem.Int32.Resolve(), _module.TypeSystem.UInt64.Resolve(), _module.TypeSystem.Int64.Resolve(), }; }
static void FillBegin(MethodDefinition target, int methodIndex) { MethodBody targetBody = target.Body; ILProcessor il = targetBody.GetILProcessor(); targetBody.InitLocals = true; flagDef = new VariableDefinition(injectFlagTypeRef); funcDef = new VariableDefinition(luaFunctionTypeDef); targetBody.Variables.Add(flagDef); targetBody.Variables.Add(funcDef); Instruction startInsertPos = targetBody.Instructions[0]; il.InsertBefore(startInsertPos, il.Create(OpCodes.Ldc_I4, methodIndex)); il.InsertBefore(startInsertPos, il.Create(OpCodes.Call, injectFlagGetter)); il.InsertBefore(startInsertPos, il.Create(OpCodes.Stloc, flagDef)); il.InsertBefore(startInsertPos, il.Create(OpCodes.Ldloc, flagDef)); il.InsertBefore(startInsertPos, il.Create(OpCodes.Brfalse, startInsertPos)); il.InsertBefore(startInsertPos, il.Create(OpCodes.Ldc_I4, methodIndex)); il.InsertBefore(startInsertPos, il.Create(OpCodes.Call, injectedFuncGetter)); il.InsertBefore(startInsertPos, il.Create(OpCodes.Stloc, funcDef)); offset = targetBody.Instructions.IndexOf(startInsertPos); }
#pragma warning restore xUnit1019 public void CorrectBranchSizes_CorrectsOpCodeFromShortOne_IfOffsetDoesNotFitSByte(OpCode opCode) { var body = new MethodBody(new MethodDefinition("", 0, new TypeReference("", "", null, null))); var il = body.GetILProcessor(); var target = il.Create(OpCodes.Ret); il.Emit(opCode, target); for (var i = 0; i < 129; i++) { il.Emit(OpCodes.Nop); } il.InsertAfter(body.Instructions.Last(), target); il.CorrectAllAfterChanges(); var corrected = body.Instructions.First(); Assert.Equal( Regex.Replace(opCode.Code.ToString(), "_S$", ""), corrected.OpCode.Code.ToString() ); }
static void FillInjectMethod(MethodDefinition target, Action <MethodDefinition, InjectType> fillInjectInfo, InjectType runtimeInjectType) { if (runtimeInjectType == InjectType.None) { return; } MethodBody targetBody = target.Body; ILProcessor il = targetBody.GetILProcessor(); cursor = GetMethodNextInsertPosition(target, null, runtimeInjectType.HasFlag(InjectType.After)); while (cursor != null) { bool bAfterInject = runtimeInjectType == InjectType.After; Instruction startPos = il.Create(OpCodes.Ldloc, flagDef); if (bAfterInject) { /// Replace instruction with references reserved Instruction endPos = il.Create(OpCodes.Ret); int replaceIndex = targetBody.Instructions.IndexOf(cursor); cursor.OpCode = startPos.OpCode; cursor.Operand = startPos.Operand; il.InsertAfter(targetBody.Instructions[replaceIndex], endPos); cursor = targetBody.Instructions[replaceIndex + 1]; } else { il.InsertBefore(cursor, startPos); } il.InsertBefore(cursor, il.Create(ldcI4s[(int)InjectType.After / 2])); il.InsertBefore(cursor, il.Create(bAfterInject ? OpCodes.Bne_Un : OpCodes.Ble_Un, cursor)); fillInjectInfo(target, runtimeInjectType); cursor = GetMethodNextInsertPosition(target, cursor, runtimeInjectType.HasFlag(InjectType.After)); } }
static void FillReplaceCoroutine(MethodDefinition target, InjectType runtimeInjectType) { if (runtimeInjectType == InjectType.None) { return; } MethodBody targetBody = target.Body; ILProcessor il = targetBody.GetILProcessor(); cursor = GetMethodNextInsertPosition(target, null, false); if (cursor != null) { il.InsertBefore(cursor, il.Create(OpCodes.Ldloc, flagDef)); il.InsertBefore(cursor, il.Create(ldcI4s[(int)InjectType.Replace / 2])); il.InsertBefore(cursor, il.Create(OpCodes.Bne_Un, cursor)); il.InsertBefore(cursor, il.Create(OpCodes.Ldloc, funcDef)); FillArgs(target, cursor, null); il.InsertBefore(cursor, il.Create(OpCodes.Call, GetLuaMethodInvoker(target, false, false))); il.InsertBefore(cursor, il.Create(OpCodes.Ret)); } }
public override void VisitMethodBody(MethodBody body) { _body = body; _il = body.GetILProcessor(); }
public override void ProcessType(TypeDefinition type) { if (!type.Is ("System.Net.Http", "HttpClient")) return; MethodDefinition default_ctor = null; MethodDefinition full_ctor = null; foreach (var m in type.Methods) { if (m.IsStatic || !m.IsConstructor) continue; if (!m.HasParameters) { default_ctor = m; } else if (m.Parameters.Count == 2) { full_ctor = m; } } if (default_ctor == null || full_ctor == null) throw new Exception ("Could not set the default HttpMessageHandler"); var handler = RuntimeOptions.GetHttpMessageHandler (Options.RuntimeOptions, type.Module); MethodDefinition handler_ctor = null; foreach (var m in handler.Methods) { if (m.IsStatic || !m.IsConstructor || m.HasParameters) continue; handler_ctor = m; break; } // re-write default ctor var body = new MethodBody (default_ctor); var il = body.GetILProcessor (); il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Newobj, handler_ctor); il.Emit (OpCodes.Ldc_I4_1); il.Emit (OpCodes.Call, full_ctor); il.Emit (OpCodes.Ret); default_ctor.Body = body; }
private MethodBody GenerateDelegateMethod(MethodDefinition method, Class declaringClass) { // Delegate type var delegateType = corlib.MainModule.GetType(typeof(Delegate).FullName); // Delegate fields var targetField = delegateType.Fields.First(x => x.Name == "_target"); var methodPtrField = delegateType.Fields.First(x => x.Name == "_methodPtr"); var methodPtrAuxField = delegateType.Fields.First(x => x.Name == "_methodPtrAux"); var body = new MethodBody(method); var il = body.GetILProcessor(); if (method.Name == ".ctor") { // Mark //GenerateMulticastInvokeThunk(declaringClass); // Two main cases: // - Instance method: // this._methodPtr = fnptr; // this._target = target; // Result: this._methodPtr(this._target, arg1, ..) will directly work // - Static method: // this._target = this; // this._methodPtrAux = fnptr; // this._methodPtr = (delegate, arg1, ...) => { delegate->_methodPtrAux(arg1, ...); } // Result: this._methodPtr(this._target, arg1, ...) will call thunk, // which will call fnptr (from this._target._methodPtr) without the first argument var target = Instruction.Create(OpCodes.Ldarg_0); // if (target == null) // { il.Append(Instruction.Create(OpCodes.Ldarg, method.Parameters[0])); il.Append(Instruction.Create(OpCodes.Brtrue, target)); // Generate thunk (for now, done using direct LLVM, not sure weither LLVM or IL is better) // this._methodPtr = (delegate, arg1, ...) => { delegate->_methodPtrAux(arg1, ...); } var invokeMethodHelper = GenerateStaticInvokeThunk(declaringClass); // Fake Nop to push this thunk on stack (TODO: Better way to do this? i.e. store it in some static field?) il.Append(Instruction.Create(OpCodes.Ldarg_0)); var loadFunctionPointerInstruction = Instruction.Create(OpCodes.Nop); InstructionActions.Add(loadFunctionPointerInstruction, (stack) => { // Push the generated method pointer on the stack stack.Add(new StackValue(StackValueType.NativeInt, intPtr, LLVM.BuildPointerCast(builder, invokeMethodHelper, intPtrLLVM, string.Empty))); }); il.Append(loadFunctionPointerInstruction); il.Append(Instruction.Create(OpCodes.Stfld, methodPtrField)); // this._methodPtrAux = method; il.Append(Instruction.Create(OpCodes.Ldarg_0)); il.Append(Instruction.Create(OpCodes.Ldarg, method.Parameters[1])); il.Append(Instruction.Create(OpCodes.Stfld, methodPtrAuxField)); // this._target = this; il.Append(Instruction.Create(OpCodes.Ldarg_0)); il.Append(Instruction.Create(OpCodes.Ldarg_0)); il.Append(Instruction.Create(OpCodes.Stfld, targetField)); // return; // } il.Append(Instruction.Create(OpCodes.Ret)); // this._target = target; il.Append(target); il.Append(Instruction.Create(OpCodes.Ldarg, method.Parameters[0])); il.Append(Instruction.Create(OpCodes.Stfld, targetField)); // this._methodPtr = method; il.Append(Instruction.Create(OpCodes.Ldarg_0)); il.Append(Instruction.Create(OpCodes.Ldarg, method.Parameters[1])); il.Append(Instruction.Create(OpCodes.Stfld, methodPtrField)); // return; il.Append(Instruction.Create(OpCodes.Ret)); } else if (method.Name == "GetMulticastDispatchMethod") { var invokeMethodHelper = GenerateMulticastInvokeThunk(declaringClass); var loadFunctionPointerInstruction = Instruction.Create(OpCodes.Nop); InstructionActions.Add(loadFunctionPointerInstruction, (stack) => { // Push the generated method pointer on the stack stack.Add(new StackValue(StackValueType.NativeInt, intPtr, LLVM.BuildPointerCast(builder, invokeMethodHelper, intPtrLLVM, string.Empty))); }); il.Append(loadFunctionPointerInstruction); il.Append(Instruction.Create(OpCodes.Ret)); } else if (method.Name == "Invoke") { // For now, generate IL // Note that we could probably optimize at callsite too, // but probably not necessary if LLVM and sealed class are optimized/inlined well enough // ldarg_0 // ldfld _target il.Append(Instruction.Create(OpCodes.Ldarg_0)); il.Append(Instruction.Create(OpCodes.Ldfld, targetField)); var callsite = new CallSite(method.ReturnType); callsite.Parameters.Add(new ParameterDefinition(targetField.FieldType)); foreach (var parameter in method.Parameters) { callsite.Parameters.Add(new ParameterDefinition(parameter.Name, parameter.Attributes, parameter.ParameterType)); // ldarg il.Append(Instruction.Create(OpCodes.Ldarg, parameter)); } // ldarg_0 // ldfld _methodPtr il.Append(Instruction.Create(OpCodes.Ldarg_0)); il.Append(Instruction.Create(OpCodes.Ldfld, methodPtrField)); // calli il.Append(Instruction.Create(OpCodes.Calli, callsite)); // ret il.Append(Instruction.Create(OpCodes.Ret)); } else { LLVM.BuildUnreachable(builder); return null; } return body; }
public static void Emit(this MethodBody body, Action <ILProcessor> il) { il(body.GetILProcessor()); }
private void InnerProcess(MethodDefinition method, bool returnVoid, ReferenceContainer references) { body = method.Body; body.SimplifyMacros(); if (body.Instructions.Count <= 3) return; // nothing to do (empty method) HandleReturnType(method, returnVoid, references); var ilProcessor = body.GetILProcessor(); var firstInstruction = FirstInstructionSkipCtor(method); firstInstruction = RejigFirstInstruction(ilProcessor, firstInstruction); InjectContext(ilProcessor, firstInstruction, method, references); var returnInstruction = FixReturns(); var beforeReturn = Instruction.Create(OpCodes.Nop); ilProcessor.InsertBefore(returnInstruction, beforeReturn); // exclude try-catch from constructors (lot's of pain otherwise) if (!method.IsConstructor) { var beginCatch = InjectIlForCatch(ilProcessor, beforeReturn, references); var beginFinally = InjectIlForFinaly(ilProcessor, beforeReturn, references); var catchHandler = new ExceptionHandler(ExceptionHandlerType.Catch) { TryStart = firstInstruction, TryEnd = beginCatch, CatchType = references.ExceptionType, HandlerStart = beginCatch, HandlerEnd = beginFinally, }; body.ExceptionHandlers.Add(catchHandler); var finallyHandler = new ExceptionHandler(ExceptionHandlerType.Finally) { TryStart = firstInstruction, TryEnd = beginFinally, HandlerStart = beginFinally, HandlerEnd = beforeReturn, }; body.ExceptionHandlers.Add(finallyHandler); } else { InjectIlForDispose(ilProcessor, returnInstruction, references); } body.InitLocals = true; body.OptimizeMacros(); }
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 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(); }
/// <summary> /// Processes the instructions replacing all strings being loaded with an encrypted version. /// </summary> /// <param name="assemblyDef">The assembly definition.</param> /// <param name="body">The body.</param> /// <param name="decryptMethod">The decrypt method.</param> private void ProcessInstructions(AssemblyDefinition assemblyDef, MethodBody body, MethodReference decryptMethod) { var instructions = body.Instructions; var il = body.GetILProcessor(); List<Instruction> instructionsToExpand = new List<Instruction>(); List<int> offsets = new List<int>(); foreach (Instruction instruction in instructions) { //Find the call statement switch (instruction.OpCode.Name) { case "ldstr": //We've found a string load message - we need to replace this instruction if (instruction.Operand is string) //Only do the direct strings for now instructionsToExpand.Add(instruction); break; } } //Fix each ldstr instruction found foreach (Instruction instruction in instructionsToExpand) { //What we do is replace the ldstr "bla" with: //ldstr bytearray encrypted_array //ldc.i4 random_integer //call string class Decrypt(string, int32) //First get the original value string originalValue = instruction.Operand.ToString(); offsets.Add(instruction.Offset); //Secondly generate a random integer as a salt int salt = random.Next(5000, 10000); //Now we need to work out what the encrypted value is and set the operand OutputHelper.WriteLine("Encrypting string \"{0}\"", originalValue); string byteArray = EncryptString(originalValue, salt); Instruction loadString = il.Create(OpCodes.Ldstr, byteArray); il.Replace(instruction, loadString); //Now load the salt Instruction loadSalt = il.Create(OpCodes.Ldc_I4, salt); il.InsertAfter(loadString, loadSalt); //Process the decryption Instruction call = il.Create(OpCodes.Call, decryptMethod); il.InsertAfter(loadSalt, call); } //Unfortunately one thing Mono.Cecil doesn't do is adjust instruction offsets for branch statements //and exception handling start points. We need to fix these manually if (offsets.Count == 0) return; //Do the adjustments il.AdjustOffsets(body, offsets, 6 + assemblyDef.GetAddressSize()); }
private void _CopyMethodToDefinition() { MethodBase method = OriginalMethod; 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); 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]); } 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); handler.TryEnd = GetInstruction(clause.TryOffset + clause.TryLength); handler.FilterStart = handler.HandlerType != ExceptionHandlerType.Filter ? null : GetInstruction(clause.FilterOffset); handler.HandlerStart = GetInstruction(clause.HandlerOffset); handler.HandlerEnd = GetInstruction(clause.HandlerOffset + clause.HandlerLength); handler.CatchType = handler.HandlerType != ExceptionHandlerType.Catch ? null : 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) { 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 (offset == instr.Offset) { return(instr); } if (offset < instr.Offset) { max = mid - 1; } else { min = mid + 1; } } return(null); } }
public bool Compile() { LogLine(1, "Compiling Xaml"); LogLine(1, "\nAssembly: {0}", Assembly); if (!string.IsNullOrEmpty(DependencyPaths)) LogLine(1, "DependencyPaths: \t{0}", DependencyPaths); if (!string.IsNullOrEmpty(ReferencePath)) LogLine(1, "ReferencePath: \t{0}", ReferencePath.Replace("//", "/")); LogLine(3, "DebugSymbols:\"{0}\"", DebugSymbols); var skipassembly = true; //change this to false to enable XamlC by default bool success = true; if (!File.Exists(Assembly)) { LogLine(1, "Assembly file not found. Skipping XamlC."); return true; } var resolver = new XamlCAssemblyResolver(); if (!string.IsNullOrEmpty(DependencyPaths)) { foreach (var dep in DependencyPaths.Split(';')) { LogLine(3, "Adding searchpath {0}", dep); resolver.AddSearchDirectory(dep); } } if (!string.IsNullOrEmpty(ReferencePath)) { var paths = ReferencePath.Replace("//", "/").Split(';'); foreach (var p in paths) { var searchpath = Path.GetDirectoryName(p); LogLine(3, "Adding searchpath {0}", searchpath); resolver.AddSearchDirectory(searchpath); // LogLine (3, "Referencing {0}", p); // resolver.AddAssembly (p); } } var assemblyDefinition = AssemblyDefinition.ReadAssembly(Path.GetFullPath(Assembly), new ReaderParameters { AssemblyResolver = resolver, ReadSymbols = DebugSymbols }); CustomAttribute xamlcAttr; if (assemblyDefinition.HasCustomAttributes && (xamlcAttr = assemblyDefinition.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) skipassembly = true; if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) skipassembly = false; } foreach (var module in assemblyDefinition.Modules) { var skipmodule = skipassembly; if (module.HasCustomAttributes && (xamlcAttr = module.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) skipmodule = true; if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) skipmodule = false; } LogLine(2, " Module: {0}", module.Name); var resourcesToPrune = new List<EmbeddedResource>(); foreach (var resource in module.Resources.OfType<EmbeddedResource>()) { Log(2, " Resource: {0}... ", resource.Name); string classname; if (!resource.IsXaml(out classname)) { LogLine(2, "skipped."); continue; } TypeDefinition typeDef = module.GetType(classname); if (typeDef == null) { LogLine(2, "no type found... skipped."); continue; } var skiptype = skipmodule; if (typeDef.HasCustomAttributes && (xamlcAttr = typeDef.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) skiptype = true; if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) skiptype = false; } if (skiptype) { LogLine(2, "Has XamlCompilationAttribute set to Skip and not Compile... skipped"); continue; } var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent"); if (initComp == null) { LogLine(2, "no InitializeComponent found... skipped."); continue; } LogLine(2, ""); Log(2, " Parsing Xaml... "); var rootnode = ParseXaml(resource.GetResourceStream(), typeDef); if (rootnode == null) { LogLine(2, "failed."); continue; } LogLine(2, "done."); hasCompiledXamlResources = true; try { Log(2, " Replacing {0}.InitializeComponent ()... ", typeDef.Name); var body = new MethodBody(initComp); var il = body.GetILProcessor(); il.Emit(OpCodes.Nop); var visitorContext = new ILContext(il, body); rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null); rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null); rootnode.Accept(new CreateObjectVisitor(visitorContext), null); rootnode.Accept(new SetNamescopesAndRegisterNamesVisitor(visitorContext), null); rootnode.Accept(new SetFieldVisitor(visitorContext), null); rootnode.Accept(new SetResourcesVisitor(visitorContext), null); rootnode.Accept(new SetPropertiesVisitor(visitorContext, true), null); il.Emit(OpCodes.Ret); initComp.Body = body; } catch (XamlParseException xpe) { LogLine(2, "failed."); LogError(null, null, null, resource.Name, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source); LogLine(4, xpe.StackTrace); success = false; continue; } catch (XmlException xe) { LogLine(2, "failed."); LogError(null, null, null, resource.Name, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source); LogLine(4, xe.StackTrace); success = false; continue; } catch (Exception e) { LogLine(2, "failed."); LogError(null, null, null, resource.Name, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source); LogLine(4, e.StackTrace); success = false; continue; } LogLine(2, "done."); if (OptimizeIL) { Log(2, " Optimizing IL... "); initComp.Body.OptimizeMacros(); LogLine(2, "done"); } if (OutputGeneratedILAsCode) { var filepath = Path.Combine(Path.GetDirectoryName(Assembly), typeDef.FullName + ".decompiled.cs"); Log(2, " Decompiling {0} into {1}...", typeDef.FullName, filepath); var decompilerContext = new DecompilerContext(module); using (var writer = new StreamWriter(filepath)) { var output = new PlainTextOutput(writer); var codeDomBuilder = new AstBuilder(decompilerContext); codeDomBuilder.AddType(typeDef); codeDomBuilder.GenerateCode(output); } LogLine(2, "done"); } resourcesToPrune.Add(resource); } if (!KeepXamlResources) { if (resourcesToPrune.Any()) LogLine(2, " Removing compiled xaml resources"); foreach (var resource in resourcesToPrune) { Log(2, " Removing {0}... ", resource.Name); module.Resources.Remove(resource); LogLine(2, "done"); } } LogLine(2, ""); } if (!hasCompiledXamlResources) { LogLine(1, "No compiled resources. Skipping writing assembly."); return success; } Log(1, "Writing the assembly... "); try { assemblyDefinition.Write(Assembly, new WriterParameters { WriteSymbols = DebugSymbols }); LogLine(1, "done."); } catch (Exception e) { LogLine(1, "failed."); LogError(null, null, null, null, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source); LogLine(4, e.StackTrace); success = false; } return success; }
/// <summary> /// Patches the (entry) method to output the used MonoMod version in the console. /// </summary> /// <returns>The new entry method.</returns> /// <param name="entryOld">The old entry method.</param> public virtual MethodDefinition PatchEntry(MethodDefinition entryOld) { if (entryOld == null) { Log("Entry point not found; skipping..."); return null; } Log("M:"+entryOld.Name); entryOld.Name = "orig_"+entryOld.Name; MethodDefinition entry = new MethodDefinition("Main", MethodAttributes.Public | MethodAttributes.Static, Module.Import(typeof(void))); entry.Parameters.Add(new ParameterDefinition(Module.Import(typeof(string[])))); MethodBody body = new MethodBody(entry); ILProcessor processor = body.GetILProcessor(); processor.Emit(OpCodes.Ldstr, "MonoMod "+System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); processor.Emit(OpCodes.Call, Module.Import(typeof(Console).GetMethod("WriteLine", new Type[] {typeof(string)}))); processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Call, entryOld); processor.Emit(OpCodes.Ret); entry.Body = body; entryOld.DeclaringType.Methods.Add(entry); Module.EntryPoint = entry; return entry; }
/// <summary> /// Processes and writes IL to the provided method body. /// Note that this cleans the existing method body (removes insturctions and exception handlers). /// </summary> /// <param name="body">Method body to write to.</param> /// <param name="original">Original method that transpiler can optionally call into</param> /// <exception cref="NotSupportedException"> /// One of IL opcodes contains a CallSide (e.g. calli), which is currently not /// fully supported. /// </exception> /// <exception cref="ArgumentNullException">One of IL opcodes with an operand contains a null operand.</exception> public void WriteTo(MethodBody body, MethodBase original = null) { // Clean up the body of the target method body.Instructions.Clear(); body.ExceptionHandlers.Clear(); var il = new CecilILGenerator(body.GetILProcessor()); var cil = il.GetProxy(); // Define an "empty" label // In Harmony, the first label can point to the end of the method // Apparently, some transpilers naively call new Label() to define a label and thus end up // using the first label without knowing it // By defining the first label we'll ensure label count is correct il.DefineLabel(); // Step 1: Prepare labels for instructions Prepare(vDef => il.GetLocal(vDef), il.DefineLabel); // Step 2: Run the code instruction through transpilers var newInstructions = ApplyTranspilers(cil, original); // We don't remove trailing `ret`s because we need to do so only if prefixes/postfixes are present // Step 3: Emit code foreach (var ins in newInstructions) { ins.labels.ForEach(l => il.MarkLabel(l)); ins.blocks.ForEach(b => il.MarkBlockBefore(b)); // We don't replace `ret`s yet because we might not need to // We do that only if we add prefixes/postfixes // We also don't need to care for long/short forms thanks to Cecil/MonoMod // Temporary fix: CecilILGenerator doesn't properly handle ldarg switch (ins.opcode.OperandType) { case SRE.OperandType.InlineNone: il.Emit(ins.opcode); break; case SRE.OperandType.InlineSig: throw new NotSupportedException( "Emitting opcodes with CallSites is currently not fully implemented"); default: if (ins.operand == null) { throw new ArgumentNullException(nameof(ins.operand), $"Invalid argument for {ins}"); } il.Emit(ins.opcode, ins.operand); break; } ins.blocks.ForEach(b => il.MarkBlockAfter(b)); } // Note: We lose all unassigned labels here along with any way to log them // On the contrary, we gain better logging anyway down the line by using Cecil // Step 4: Run the code through raw IL manipulators (if any) // TODO: IL Manipulators }
protected virtual void InjectAdditionalInstructionBeforeStartCall(Mono.Cecil.Cil.MethodBody body, Instruction call) { Instruction pickMyself = body.GetILProcessor().Create(OpCodes.Ldarg_0); body.GetILProcessor().InsertBefore(call, pickMyself); }
/// <summary> /// Inserts the invalid il. /// </summary> /// <param name="methodBody">The method body.</param> private static void InsertInvalidIl(MethodBody methodBody) { //Get the instructions and cil worker var instructions = methodBody.Instructions; if (instructions.Count <= 0) return; //We can only do this if we have instructions to work with ILProcessor il = methodBody.GetILProcessor(); //First create an invalid il instruction OpCode fakeOpCode = CreateInvalidOpCode(); Instruction invalidIlInstr1 = il.Create(fakeOpCode); Instruction invalidIlInstr2 = il.Create(fakeOpCode); Instruction originalFirst = instructions[0]; //Insert invalid il at the start il.InsertBefore(originalFirst, invalidIlInstr1); il.InsertBefore(invalidIlInstr1, invalidIlInstr2); //Create the branch statement Instruction branchStatement = il.Create(OpCodes.Br_S, originalFirst); //Add the branch to the start il.InsertBefore(invalidIlInstr2, branchStatement); //Readjust the offsets il.AdjustOffsets(methodBody, 4); }
public override bool Execute() { InMsBuild = true; Verbosity = Int32.MaxValue; LogLine(1, "Preparing debug code for xamlc"); LogLine(1, "\nAssembly: {0}", Assembly); var resolver = new DefaultAssemblyResolver(); if (!string.IsNullOrEmpty(DependencyPaths)) { foreach (var dep in DependencyPaths.Split(';')) { LogLine(3, "Adding searchpath {0}", dep); resolver.AddSearchDirectory(dep); } } if (!string.IsNullOrEmpty(ReferencePath)) { var paths = ReferencePath.Replace("//", "/").Split(';'); foreach (var p in paths) { var searchpath = Path.GetDirectoryName(p); LogLine(3, "Adding searchpath {0}", searchpath); resolver.AddSearchDirectory(searchpath); // LogLine (3, "Referencing {0}", p); // resolver.AddAssembly (p); } } var assemblyDefinition = AssemblyDefinition.ReadAssembly(Assembly, new ReaderParameters { //ReadSymbols = DebugSymbols, AssemblyResolver = resolver }); foreach (var module in assemblyDefinition.Modules) { LogLine(2, " Module: {0}", module.Name); foreach (var resource in module.Resources.OfType<EmbeddedResource>()) { Log(2, " Resource: {0}... ", resource.Name); string classname; if (!resource.IsXaml(out classname)) { LogLine(2, "skipped."); continue; } TypeDefinition typeDef = module.GetType(classname); if (typeDef == null) { LogLine(2, "no type found... skipped."); continue; } var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent"); if (initComp == null) { LogLine(2, "no InitializeComponent found... skipped."); continue; } if (typeDef.Methods.FirstOrDefault(md => md.Name == "InitCompRuntime") != null) { LogLine(2, "InitCompRuntime already exists... skipped"); continue; } LogLine(2, ""); Log(2, " Duplicating {0}.InitializeComponent () into {0}.InitCompRuntime ... ", typeDef.Name); var initCompRuntime = new MethodDefinition("InitCompRuntime", initComp.Attributes, initComp.ReturnType); initCompRuntime.Body = initComp.Body; typeDef.Methods.Add(initCompRuntime); LogLine(2, "done."); // IL_0000: ldarg.0 // IL_0001: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ContentPage::'.ctor'() // // IL_0006: nop // IL_0007: ldarg.1 // IL_0008: brfalse IL_0018 // // IL_000d: ldarg.0 // IL_000e: callvirt instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::InitializeComponent() // IL_0013: br IL_001e // // IL_0018: ldarg.0 // IL_0019: callvirt instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::InitCompRuntime() // IL_001e: ret var altCtor = typeDef.Methods.Where( md => md.IsConstructor && md.Parameters.Count == 1 && md.Parameters[0].ParameterType == module.TypeSystem.Boolean) .FirstOrDefault(); if (altCtor != null) Log(2, " Replacing body of {0}.{0} (bool {1}) ... ", typeDef.Name, altCtor.Parameters[0].Name); else { Log(2, " Adding {0}.{0} (bool useCompiledXaml) ... ", typeDef.Name); altCtor = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, module.TypeSystem.Void); altCtor.Parameters.Add(new ParameterDefinition("useCompiledXaml", ParameterAttributes.None, module.TypeSystem.Boolean)); } var body = new MethodBody(altCtor); var il = body.GetILProcessor(); var br2 = Instruction.Create(OpCodes.Ldarg_0); var ret = Instruction.Create(OpCodes.Ret); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, module.Import(typeDef.BaseType.Resolve().GetConstructors().First(c => c.HasParameters == false))); il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Brfalse, br2); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, initComp); il.Emit(OpCodes.Br, ret); il.Append(br2); il.Emit(OpCodes.Callvirt, initCompRuntime); il.Append(ret); altCtor.Body = body; if (!typeDef.Methods.Contains(altCtor)) typeDef.Methods.Add(altCtor); LogLine(2, "done."); } LogLine(2, ""); } Log(1, "Writing the assembly... "); assemblyDefinition.Write(Assembly, new WriterParameters { WriteSymbols = DebugSymbols }); LogLine(1, "done."); return true; }
new void ProcessMethod(MethodDefinition method) { ProcessParameters (method); if (!method.HasBody) return; var body = new MethodBody (method); var il = body.GetILProcessor (); il.Emit (OpCodes.Call, get_nse); il.Emit (OpCodes.Throw); method.Body = body; }
/// <summary> /// Callback when compliation finished /// <paramref name="assemblyPath"/> Path compiled assembly /// <paramref name="messages"/> Compliation messages /// </summary> public static void OnCompilationFinished(string assemblyPath, CompilerMessage[] messages) { if (assemblyPath.Contains("-Editor")) { return; } List <Type> derivedTypes = new List <Type>(); List <PropertyDefinition> properties = new List <PropertyDefinition>(); bool isModified = false; #region Cecil using (AssemblyDefinition currentAssembly = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters { ReadWrite = true, ReadSymbols = true /*, AssemblyResolver = asmResolver*/ })) { _mainModule = currentAssembly.MainModule; var p = currentAssembly.MainModule.Types.Where(o => o.IsClass).SelectMany(t => t.Properties); if (p != null) { properties.AddRange(p); } foreach (PropertyDefinition pd in properties) { CustomAttribute attr = pd.CustomAttributes.SingleOrDefault(i => i.AttributeType.Name == nameof(UIBindable)); if (attr != null) { Mono.Cecil.Cil.MethodBody body = pd.SetMethod.Body; ILProcessor processor = body.GetILProcessor(); var instructions = body.Instructions; var targetInst = instructions.Last(); #region Trying Generic /*// importing the generic type * var eq = _mainModule.ImportReference(typeof(UIBindProxy<>)); * * // importing the type of T we want to instantiate the generic type * var t = _mainModule.ImportReference(typeof(float)); * var genericEq = new GenericInstanceType(eq); * genericEq.GenericArguments.Add(t); * var importedGenericEq = _mainModule.ImportReference(genericEq); * // getting the method we want to call on the generic instance * var td = SafeResolve(importedGenericEq); * td.DeclaringType = SafeResolve(t); * var defaultMethodDef = td.Methods.Single(m => m.Name == "UpdateValue"); * * var methodRef = _mainModule.ImportReference(defaultMethodDef); * * // Important - setting the method declaring type to the correct instantiated type * methodRef.DeclaringType = importedGenericEq; * * * processor.InsertBefore(targetInst, processor.Create(OpCodes.Nop)); * processor.InsertBefore(targetInst, processor.Create(OpCodes.Ldarg_0)); * processor.InsertBefore(targetInst, processor.Create(OpCodes.Ldstr, pd.Name)); * processor.InsertBefore(targetInst, processor.Create(OpCodes.Ldarg_1)); * processor.InsertBefore(targetInst, processor.Create(OpCodes.Call, methodRef)); * isModified = true; * continue; * * var td2 = _mainModule.GetType("HDV.UIBindProxy`1"); * td2.DeclaringType = SafeResolve(_mainModule.ImportReference(typeof(float))); * * //td.DeclaringType * // td = _mainModule.GetType("HDV.UIBindProxyTest"); * foreach (var md in td2.Methods) * { * if (md.Name == "UpdateValue") * { * processor.InsertBefore(targetInst, processor.Create(OpCodes.Nop)); * processor.InsertBefore(targetInst, processor.Create(OpCodes.Ldarg_0)); * processor.InsertBefore(targetInst, processor.Create(OpCodes.Ldstr, pd.Name)); * processor.InsertBefore(targetInst, processor.Create(OpCodes.Ldarg_1)); * processor.InsertBefore(targetInst, processor.Create(OpCodes.Call, md)); * isModified = true; * } * } * continue;*/ #endregion TypeDefinition td = _mainModule.GetType("HDV.UIBinding.UIBindProxy"); string methodName; switch (pd.PropertyType.MetadataType) { case MetadataType.Single: { methodName = "UpdateFloatValue"; break; } case MetadataType.Int32: { methodName = "UpdateIntValue"; break; } //TODO: Need Generic case MetadataType.String: case MetadataType.Class: case MetadataType.Object: { methodName = "UpdateObjectValue"; break; } default: { UnityDebug.LogError("Missing type " + pd.PropertyType.MetadataType); continue; } } MethodDefinition md = td.Methods.Single(m => m.Name == methodName); processor.InsertBefore(targetInst, processor.Create(OpCodes.Nop)); processor.InsertBefore(targetInst, processor.Create(OpCodes.Ldarg_0)); processor.InsertBefore(targetInst, processor.Create(OpCodes.Ldstr, pd.Name)); processor.InsertBefore(targetInst, processor.Create(OpCodes.Ldarg_1)); processor.InsertBefore(targetInst, processor.Create(OpCodes.Call, md)); isModified = true; } } if (isModified) { currentAssembly.Write(new WriterParameters { WriteSymbols = true }); } } #endregion }
public static void Apply(ModuleDefinition module, Logger logger) { //AppDomain currentDomain = AppDomain.CurrentDomain; //currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder); Assembly assembly = Assembly.LoadFrom(Deobfuscator.sourceAssemblyPath.path + Path.DirectorySeparatorChar + Deobfuscator.sourceAssemblyPath.filename); Module target = assembly.GetModules()[0]; logger.KeyInfo("Looking for string decryption calls..."); int decryptStats = 0; List <MethodDefinition> decryptMethods = new List <MethodDefinition>(); MethodDefinition[] mdefs = HelperClass.findMembers <MethodDefinition>(module, null, true); for (int __i = 0; __i < mdefs.Length; __i++) { MethodDefinition mdef = mdefs[__i]; if (mdef.HasBody) { Mono.Cecil.Cil.MethodBody mdefBody = mdef.Body; for (int i = 0; i < (mdefBody.Instructions.Count - 1); i++) { Instruction instr1 = mdefBody.Instructions[i]; Instruction instr2 = mdefBody.Instructions[i + 1]; if (loadIntegerCodes.ContainsKey(instr1.OpCode.Code) && (instr2.OpCode == OpCodes.Call)) { int key = loadIntegerCodes[instr1.OpCode.Code](instr1.Operand); //(int)instr1.Operand; MethodDefinition targetMethod = ((MethodReference)instr2.Operand).Resolve(); if (targetMethod != null && targetMethod.IsStatic && targetMethod.Parameters.Count == 1 && targetMethod.ReturnType.FullName.Equals("System.String") && targetMethod.HasBody && targetMethod.Body.Instructions.Count > 5 && targetMethod.Body.Instructions[4].OpCode == OpCodes.Ldelem_U1) { Type decryptorType = null; MethodInfo decryptorMethod = null; try { decryptorType = target.GetType(targetMethod.DeclaringType.FullName); decryptorMethod = decryptorType.GetMethod(targetMethod.Name, BindingFlags.Static | BindingFlags.NonPublic); string decrypted = (string)decryptorMethod.Invoke(null, new object[] { key }); Instruction newInstr; ILProcessor proc = mdefBody.GetILProcessor(); HelperClass.SafeInsertBefore(proc, instr1, (newInstr = mdefBody.GetILProcessor().Create(OpCodes.Ldstr, decrypted))); //mdefBody.GetILProcessor().InsertBefore(instr1, (newInstr = mdefBody.GetILProcessor().Create(OpCodes.Ldstr, decrypted))); HelperClass.PatchInstructionReferences(mdefBody, instr1, newInstr); for (int _i = 0; _i < 2; _i++) { HelperClass.SafeRemove(proc, mdefBody.Instructions[i + 1]); } //mdefBody.Instructions.RemoveAt(i+1); if (!decryptMethods.Contains(targetMethod)) { decryptMethods.Add(targetMethod); } //logger.Info(decrypted); //i++; decryptStats++; } catch (Exception e) { logger.Warning("Unable to decrypt " + targetMethod.Name + " (" + key + ") :\r\n" + e.ToString()); continue; } } } } } if ((__i % (mdefs.Length / 10)) == 0 && __i > 0) { logger.KeyInfo("Decrypted strings from method #" + (__i + 1) + "."); } } for (int i = 0; i < decryptMethods.Count; i++) { MethodDefinition mdef = decryptMethods[i]; //module.Types.Remove(mdef.DeclaringType); mdef.DeclaringType.Name = "decryptor" + i; mdef.Name = "Decrypt"; } logger.KeyInfo("Finished decrypting " + decryptStats + " strings!"); }
private void RewriteIL (MethodBody body, Dictionary<Expr,Instruction> instructionLookup, Expr remove, Expr insert) { var il = body.GetILProcessor (); Instruction instInsertBefore; if (remove != null) { var vInstExtent = new InstructionExtentVisitor (instructionLookup); vInstExtent.Visit (remove); instInsertBefore = vInstExtent.Instructions.Last ().Next; foreach (var instRemove in vInstExtent.Instructions) { il.Remove (instRemove); } } else { instInsertBefore = body.Instructions [0]; } if (insert != null) { var compiler = new CompileVisitor (il, instructionLookup, inst => il.InsertBefore (instInsertBefore, inst)); compiler.Visit (insert); } }
private static MethodBody CloneMethodBody(MethodBody body, MethodDefinition source, MethodDefinition target) { var context = target.DeclaringType.Module; var nb = new MethodBody(target) { MaxStackSize = body.MaxStackSize, InitLocals = body.InitLocals, CodeSize = body.CodeSize }; var worker = nb.GetILProcessor(); foreach (var var in body.Variables) nb.Variables.Add(new VariableDefinition( var.Name, FixTypeImport(context, source, target, var.VariableType))); foreach (var instr in body.Instructions) { var ni = new Instruction(instr.OpCode, OpCodes.Nop); switch (instr.OpCode.OperandType) { case OperandType.InlineArg: case OperandType.ShortInlineArg: if (instr.Operand == body.ThisParameter) ni.Operand = nb.ThisParameter; else { var param = body.Method.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = target.Parameters[param]; } break; case OperandType.InlineVar: case OperandType.ShortInlineVar: var var = body.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = nb.Variables[var]; break; case OperandType.InlineField: ni.Operand = FixFieldImport(context, source, target, (FieldReference)instr.Operand); break; case OperandType.InlineMethod: ni.Operand = FixMethodImport(context, source, target, (MethodReference)instr.Operand); break; case OperandType.InlineType: ni.Operand = FixTypeImport(context, source, target, (TypeReference)instr.Operand); break; case OperandType.InlineTok: if ((instr.Operand) is TypeReference) ni.Operand = FixTypeImport(context, source, target, (TypeReference)instr.Operand); else if ((instr.Operand) is FieldReference) ni.Operand = FixFieldImport(context, source, target, (FieldReference)instr.Operand); else if ((instr.Operand) is MethodReference) ni.Operand = FixMethodImport(context, source, target, (MethodReference)instr.Operand); break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: case OperandType.InlineSwitch: break; default: ni.Operand = instr.Operand; break; } worker.Append(ni); } for (var i = 0; i < body.Instructions.Count; i++) { var instr = nb.Instructions[i]; var oldi = body.Instructions[i]; switch (instr.OpCode.OperandType) { case OperandType.InlineSwitch: { var olds = (Instruction[])oldi.Operand; var targets = new Instruction[olds.Length]; for (var j = 0; j < targets.Length; j++) targets[j] = GetInstruction(body, nb, olds[j]); instr.Operand = targets; } break; case OperandType.InlineBrTarget: case OperandType.ShortInlineBrTarget: instr.Operand = GetInstruction(body, nb, (Instruction)oldi.Operand); break; } } foreach (var eh in body.ExceptionHandlers) { var neh = new ExceptionHandler(eh.HandlerType) { TryStart = GetInstruction(body, nb, eh.TryStart), TryEnd = GetInstruction(body, nb, eh.TryEnd), HandlerStart = GetInstruction(body, nb, eh.HandlerStart), HandlerEnd = GetInstruction(body, nb, eh.HandlerEnd) }; switch (eh.HandlerType) { case ExceptionHandlerType.Catch: neh.CatchType = FixTypeImport(context, source, target, eh.CatchType); break; case ExceptionHandlerType.Filter: neh.FilterStart = GetInstruction(body, nb, eh.FilterStart); break; } nb.ExceptionHandlers.Add(neh); } return nb; }
/// <summary> /// Generates the xor decryption method. /// </summary> /// <param name="assembly">The assembly.</param> /// <param name="body">The body.</param> private static void GenerateXorDecryptionMethod(AssemblyDefinition assembly, MethodBody body) { var worker = body.GetILProcessor(); //Generate the decryption method //Since this is XOR it is the same as the encryption method //In reality its a bit of a joke calling this encryption as its really //just obfusaction /* char[] characters = value.ToCharArray(); for (int i = 0; i < characters.Length; i++) { characters[i] = (char)(characters[i] ^ salt); } return new String(characters); */ //Declare a local to store the char array body.InitLocals = true; body.Method.AddLocal(typeof(char[])); body.Method.AddLocal(typeof(int)); body.Method.AddLocal(typeof(string)); body.Method.AddLocal(typeof(bool)); //Start with a nop worker.Append(worker.Create(OpCodes.Nop)); //Load the first argument into the register Instruction ldArg0 = worker.Create(OpCodes.Ldarg_0); worker.Append(ldArg0); //Call ToCharArray on this -- need to find it first var toCharArrayMethodRef = assembly.Import(typeof(string).GetMethod("ToCharArray", Type.EmptyTypes)); //Import the method first toCharArrayMethodRef = body.ImportMethod(toCharArrayMethodRef); Instruction toCharArray = worker.Create(OpCodes.Callvirt, toCharArrayMethodRef); worker.Append(toCharArray); //Store it in the first local Instruction stLoc0 = worker.Create(OpCodes.Stloc_0); worker.Append(stLoc0); //Set up the loop worker.Append(worker.Create(OpCodes.Ldc_I4_0)); Instruction stLoc1 = worker.Create(OpCodes.Stloc_1); worker.Append(stLoc1); //We'll insert a br.s here later.... //Insert another nop and do the rest of our loop Instruction loopNop = worker.Create(OpCodes.Nop); worker.Append(loopNop); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldelem_U2)); //Load the array worker.Append(worker.Create(OpCodes.Ldarg_1)); worker.Append(worker.Create(OpCodes.Xor)); //Do the xor worker.Append(worker.Create(OpCodes.Conv_U2)); worker.Append(worker.Create(OpCodes.Stelem_I2)); //Store back in the array worker.Append(worker.Create(OpCodes.Nop)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldc_I4_1)); worker.Append(worker.Create(OpCodes.Add)); worker.Append(worker.Create(OpCodes.Stloc_1)); Instruction ldLoc = worker.Create(OpCodes.Ldloc_1); worker.Append(ldLoc); //Link to this line from an earlier statement worker.InsertAfter(stLoc1, worker.Create(OpCodes.Br_S, ldLoc)); worker.Append(worker.Create(OpCodes.Ldloc_0)); worker.Append(worker.Create(OpCodes.Ldlen)); worker.Append(worker.Create(OpCodes.Conv_I4)); worker.Append(worker.Create(OpCodes.Clt)); //i < array.Length worker.Append(worker.Create(OpCodes.Stloc_3)); worker.Append(worker.Create(OpCodes.Ldloc_3)); worker.Append(worker.Create(OpCodes.Brtrue_S, loopNop)); //Do the loop //Return a new string worker.Append(worker.Create(OpCodes.Ldloc_0)); //Find the constructor we want to use MethodReference constructor = assembly.Import(typeof(string).GetConstructor(new [] { typeof(char[])})); constructor = body.ImportMethod(constructor); worker.Append(worker.Create(OpCodes.Newobj, constructor)); Instruction stloc2 = worker.Create(OpCodes.Stloc_2); worker.Append(stloc2); Instruction ldloc2 = worker.Create(OpCodes.Ldloc_2); worker.Append(ldloc2); worker.InsertAfter(stloc2, worker.Create(OpCodes.Br_S, ldloc2)); worker.Append(worker.Create(OpCodes.Ret)); }
public void UnattachedMethodBody() { var system_void = typeof (void).ToDefinition (); var method = new MethodDefinition ("NewMethod", MethodAttributes.Assembly | MethodAttributes.Static, system_void); var body = new MethodBody (method); var il = body.GetILProcessor (); il.Emit (OpCodes.Ret); method.Body = body; Assert.AreEqual (body, method.Body); }
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)); }
public IlBuilder(MethodBody body) { _body = body; this._il = body.GetILProcessor(); _list = new List <Instruction>(); }
//TODO: move this out of here public virtual Instruction Create(MethodBody methodBody, ModuleDefinition moduleDefinition) { object operand = 0; Instruction instruction = null; var processor = methodBody.GetILProcessor(); switch (OpCode.OperandType) { case OperandType.ShortInlineR: { float parsedOpcode = 0.0f; if (_operandSrc != null) { if (_operandSrc is string) { float.TryParse((string)_operandSrc, out parsedOpcode); } else if (_operandSrc is float) { parsedOpcode =(float)_operandSrc; } } instruction = processor.Create(OpCode, parsedOpcode); break; } case OperandType.ShortInlineVar: case OperandType.InlineVar: { VariableDefinition variable = null; if (_operandSrc != null) { if (_operandSrc is string) { int tempN = 0; if (int.TryParse((string) _operandSrc, out tempN)) //deserialised ints come in as strings { variable = methodBody.Variables[tempN]; } else { variable = methodBody.Variables.First(v => v.Name == (string) _operandSrc); } } else if (_operandSrc is int || _operandSrc is short) { variable = methodBody.Variables[(int) _operandSrc]; } } instruction = processor.Create(OpCode, variable); break; } case OperandType.InlineMethod: { MethodReference method = CodeHelper.ResolveMethod(moduleDefinition, _operandSrc.ToString()); if (method == null) { Debug.WriteLine("Method {0} can't be resolved yet. Postponing.", _operandSrc.ToString()); instruction = processor.CreateUnsafe(OpCode, _operandSrc); instruction.ResolveOperand = (ins) => CodeHelper.ResolveMethod(moduleDefinition, _operandSrc.ToString()); } else { instruction = processor.Create(OpCode, method); } } break; case OperandType.InlineString: instruction = processor.Create(OpCode, _operandSrc.ToString()); break; case OperandType.InlineBrTarget: case OperandType.ShortInlineBrTarget: if (_operandSrc == null) { throw new ApplicationException("invalid codeline"); } instruction = processor.CreateUnsafe(OpCode, _operandSrc); instruction.ResolveOperand = (ins) => { //Debug.Assert(_operandSrc != "GOTO_ENDHW"); var resolved = processor.Body.Instructions.FirstOrDefault(i => !string.IsNullOrEmpty(i.Label) && i.Label == (string) _operandSrc); if (resolved == null) { throw new ApplicationException("Unresolved break target"); } return resolved; }; break; case OperandType.InlineNone: instruction = processor.Create(OpCode); break; case OperandType.InlineField: { var names = _operandSrc.ToString().Split(new[] {" ", "::"}, 3, StringSplitOptions.RemoveEmptyEntries); TypeReference foundType = CodeHelper.ResolveType(moduleDefinition, names[1]); var typeDef = (TypeDefinition) (foundType is TypeDefinition ? foundType : foundType.Resolve()); FieldReference fieldReference = typeDef.Fields.FirstOrDefault(f => f.FullName == _operandSrc.ToString()); var importedRef = moduleDefinition.Import(fieldReference); if (fieldReference == null) { throw new ApplicationException(String.Format("Field {0} not found", _operandSrc)); } instruction = processor.Create(OpCode, importedRef); } break; default: instruction = processor.CreateUnsafe(OpCode, _operandSrc); break; } instruction.Label = Label; return instruction; }
public static MethodDefinition Inject(ModuleDefinition mod, MethodDefinition mtd) { MethodDefinition ret = new MethodDefinition(mtd.Name, mtd.Attributes, mod.TypeSystem.Void); ret.Attributes = mtd.Attributes; ret.ImplAttributes = mtd.ImplAttributes; if (mtd.IsPInvokeImpl) { ret.PInvokeInfo = mtd.PInvokeInfo; bool has = false; foreach (ModuleReference modRef in mod.ModuleReferences) if (modRef.Name == ret.PInvokeInfo.Module.Name) { has = true; ret.PInvokeInfo.Module = modRef; break; } if (!has) mod.ModuleReferences.Add(ret.PInvokeInfo.Module); } if (mtd.HasCustomAttributes) { foreach (CustomAttribute attr in mtd.CustomAttributes) { CustomAttribute nAttr = new CustomAttribute(ImportMethod(attr.Constructor, mod, ret, null), attr.GetBlob()); ret.CustomAttributes.Add(nAttr); } } foreach (GenericParameter param in mtd.GenericParameters) { var p = new GenericParameter(param.Name, ret); if (param.HasCustomAttributes) { foreach (CustomAttribute attr in param.CustomAttributes) { CustomAttribute nAttr = new CustomAttribute(ImportMethod(attr.Constructor, mod, ret, null), attr.GetBlob()); p.CustomAttributes.Add(nAttr); } } ret.GenericParameters.Add(p); } ret.ReturnType = ImportType(mtd.ReturnType, mod, ret, null); foreach (ParameterDefinition param in mtd.Parameters) { var p = new ParameterDefinition(param.Name, param.Attributes, ImportType(param.ParameterType, mod, ret, null)); if (param.HasCustomAttributes) { foreach (CustomAttribute attr in param.CustomAttributes) { CustomAttribute nAttr = new CustomAttribute(ImportMethod(attr.Constructor, mod, ret, null), attr.GetBlob()); p.CustomAttributes.Add(nAttr); } } ret.Parameters.Add(p); } if (mtd.HasBody) { MethodBody old = mtd.Body; MethodBody bdy = new MethodBody(ret); bdy.MaxStackSize = old.MaxStackSize; bdy.InitLocals = old.InitLocals; ILProcessor psr = bdy.GetILProcessor(); foreach (VariableDefinition var in old.Variables) bdy.Variables.Add(new VariableDefinition(var.Name, ImportType(var.VariableType, mod, ret, null))); foreach (Instruction inst in old.Instructions) { switch (inst.OpCode.OperandType) { case OperandType.InlineArg: case OperandType.ShortInlineArg: if (inst.Operand == old.ThisParameter) psr.Emit(inst.OpCode, bdy.ThisParameter); else { int param = mtd.Parameters.IndexOf(inst.Operand as ParameterDefinition); psr.Emit(inst.OpCode, ret.Parameters[param]); } break; case OperandType.InlineVar: case OperandType.ShortInlineVar: int var = old.Variables.IndexOf(inst.Operand as VariableDefinition); psr.Emit(inst.OpCode, bdy.Variables[var]); break; case OperandType.InlineField: psr.Emit(inst.OpCode, ImportField(inst.Operand as FieldReference, mod, null)); break; case OperandType.InlineMethod: if (inst.Operand == mtd) psr.Emit(inst.OpCode, ret); else psr.Emit(inst.OpCode, ImportMethod(inst.Operand as MethodReference, mod, ret, null)); break; case OperandType.InlineType: psr.Emit(inst.OpCode, ImportType(inst.Operand as TypeReference, mod, ret, null)); break; case OperandType.InlineTok: if (inst.Operand is TypeReference) psr.Emit(inst.OpCode, ImportType(inst.Operand as TypeReference, mod, ret, null)); else if (inst.Operand is FieldReference) psr.Emit(inst.OpCode, ImportField(inst.Operand as FieldReference, mod, null)); else if (inst.Operand is MethodReference) psr.Emit(inst.OpCode, ImportMethod(inst.Operand as MethodReference, mod, ret, null)); break; default: psr.Append(inst.Clone()); break; } } for (int i = 0; i < bdy.Instructions.Count; i++) { Instruction inst = bdy.Instructions[i]; Instruction o = old.Instructions[i]; if (inst.OpCode.OperandType == OperandType.InlineSwitch) { Instruction[] olds = (Instruction[])o.Operand; Instruction[] news = new Instruction[olds.Length]; for (int ii = 0; ii < news.Length; ii++) news[ii] = bdy.Instructions[old.Instructions.IndexOf(olds[ii])]; inst.Operand = news; } else if (inst.OpCode.OperandType == OperandType.ShortInlineBrTarget || inst.OpCode.OperandType == OperandType.InlineBrTarget) inst.Operand = bdy.Instructions[old.Instructions.IndexOf(inst.Operand as Instruction)]; } foreach (ExceptionHandler eh in old.ExceptionHandlers) { ExceptionHandler neh = new ExceptionHandler(eh.HandlerType); if (old.Instructions.IndexOf(eh.TryStart) != -1) neh.TryStart = bdy.Instructions[old.Instructions.IndexOf(eh.TryStart)]; if (old.Instructions.IndexOf(eh.TryEnd) != -1) neh.TryEnd = bdy.Instructions[old.Instructions.IndexOf(eh.TryEnd)]; if (old.Instructions.IndexOf(eh.HandlerStart) != -1) neh.HandlerStart = bdy.Instructions[old.Instructions.IndexOf(eh.HandlerStart)]; if (old.Instructions.IndexOf(eh.HandlerEnd) != -1) neh.HandlerEnd = bdy.Instructions[old.Instructions.IndexOf(eh.HandlerEnd)]; switch (eh.HandlerType) { case ExceptionHandlerType.Catch: neh.CatchType = ImportType(eh.CatchType, mod, ret, null); break; case ExceptionHandlerType.Filter: neh.FilterStart = bdy.Instructions[old.Instructions.IndexOf(eh.FilterStart)]; //neh.FilterEnd = bdy.Instructions[old.Instructions.IndexOf(eh.FilterEnd)]; break; } bdy.ExceptionHandlers.Add(neh); } ret.Body = bdy; } return ret; }
//protected override void InjectAdditionalInstructionBeforeStartCall(Mono.Cecil.Cil.MethodBody body, Mono.Cecil.Cil.Instruction call) //{ // Instruction pickMyself = body.GetILProcessor().Create(OpCodes.Ldarg_0); // body.GetILProcessor().InsertBefore(call, pickMyself); //} protected override void InjectAdditionalInstructionAfterStartCall(Mono.Cecil.Cil.MethodBody body, Mono.Cecil.Cil.Instruction call) { var ret = body.GetILProcessor().Create(OpCodes.Ret); body.GetILProcessor().InsertAfter(call, ret); }
public override void ProcessType(TypeDefinition type) { if (!type.Is ("ObjCRuntime", "RuntimeOptions")) return; MethodDefinition method = type.Methods.First (x => x.Name == "GetHttpMessageHandler" && !x.HasParameters); AssemblyDefinition systemNetHTTPAssembly = context.GetAssemblies ().First (x => x.Name.Name == "System.Net.Http"); TypeDefinition handler = RuntimeOptions.GetHttpMessageHandler (Options.RuntimeOptions, systemNetHTTPAssembly.MainModule, type.Module); MethodReference handler_ctor = handler.Methods.First (x => x.IsConstructor && !x.HasParameters && !x.IsStatic); // HttpClientHandler is defined not in Xamarin.Mac.dll so we need to import if (handler.Name.Contains ("HttpClientHandler")) handler_ctor = type.Module.Import (handler_ctor); var body = new MethodBody (method); var il = body.GetILProcessor (); il.Emit (OpCodes.Newobj, handler_ctor); il.Emit (OpCodes.Ret); method.Body = body; }
private static void FoldAndReplace( ref Dictionary<KeyValuePair<int, int>, ExInstruction> markings, ref MethodBody body) { var instrList = body.Instructions; var foldedBody = new Collection<Instruction>(); foreach(var marking in markings) { for(var i = 0;i < instrList.Count;i++) { if(marking.Key.Key == i) { for (var x = 0; x < marking.Key.Value +1; x++) instrList.RemoveAt(marking.Key.Key -2); switch(marking.Value.OpCode.Code) { case Code.Ldc_I4: instrList.Insert(marking.Key.Key -3, body.GetILProcessor().Create(OpCodes.Ldc_I4, (int)marking.Value.Value)); break; case Code.Ldc_I8: instrList.Insert(marking.Key.Key -3, body.GetILProcessor().Create(OpCodes.Ldc_I8, (long)marking.Value.Value)); break; } break; } } } body.Instructions.Clear(); //body.SimplifyMacros(); var ilProc = body.GetILProcessor(); foreach (var instr in instrList) ilProc.Append(instr); //body.OptimizeMacros();//it can't resolve the tokens from rocks }
public override void ProcessType(TypeDefinition type) { #if XAMARIN_NO_TLS return; #else if (!type.Is (Namespaces.ObjCRuntime, "Runtime")) return; MethodDefinition callbackMethod = null; foreach (var m in type.Methods) { if (!m.IsStatic || m.HasParameters) continue; if (m.Name.Equals ("TlsProviderFactoryCallback", StringComparison.Ordinal)) { callbackMethod = m; break; } } if (callbackMethod == null) throw new Exception ("Could not set the default TlsProvider"); var providerCtor = FindProviderConstructor (type.Module); if (providerCtor == null) return; // re-write TlsProviderFactoryCallback() var body = new MethodBody (callbackMethod); var il = body.GetILProcessor (); if (providerCtor != null) il.Emit (OpCodes.Newobj, providerCtor); else il.Emit (OpCodes.Ldnull); il.Emit (OpCodes.Ret); callbackMethod.Body = body; #endif }
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(); } } }
private void _CopyMethodToDefinition() { MethodBase method = OriginalMethod; 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))) { for (Instruction instr = null, prev = null; reader.BaseStream.Position < reader.BaseStream.Length; prev = instr) { int offset = (int)reader.BaseStream.Position; instr = Instruction.Create(OpCodes.Nop); byte op = reader.ReadByte(); instr.OpCode = op != 0xfe ? _CecilOpCodes1X[op] : _CecilOpCodes2X[reader.ReadByte()]; instr.Offset = offset; if (prev != null) { prev.Next = instr; } instr.Previous = prev; 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); 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]); } 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); handler.TryEnd = GetInstruction(clause.TryOffset + clause.TryLength); handler.FilterStart = handler.HandlerType != ExceptionHandlerType.Filter ? null : GetInstruction(clause.FilterOffset); handler.HandlerStart = GetInstruction(clause.HandlerOffset); handler.HandlerEnd = GetInstruction(clause.HandlerOffset + clause.HandlerLength); handler.CatchType = handler.HandlerType != ExceptionHandlerType.Catch ? null : 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: instr.Operand = moduleTo.ImportCallSite(moduleFrom, moduleFrom.ResolveSignature(reader.ReadInt32())); break; case OperandType.InlineString: instr.Operand = moduleFrom.ResolveString(reader.ReadInt32()); break; case OperandType.InlineTok: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Any); break; case OperandType.InlineType: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Type); break; case OperandType.InlineMethod: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Method); break; case OperandType.InlineField: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Field); 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}"); } } MemberReference ResolveTokenAs(int token, TokenResolutionMode resolveMode) { try { switch (resolveMode) { case TokenResolutionMode.Type: return(moduleTo.ImportReference(moduleFrom.ResolveType(token, typeArguments, methodArguments))); case TokenResolutionMode.Method: return(moduleTo.ImportReference(moduleFrom.ResolveMethod(token, typeArguments, methodArguments))); case TokenResolutionMode.Field: return(moduleTo.ImportReference(moduleFrom.ResolveField(token, typeArguments, methodArguments))); case TokenResolutionMode.Any: switch (moduleFrom.ResolveMember(token, typeArguments, methodArguments)) { case Type i: return(moduleTo.ImportReference(i)); case MethodBase i: return(moduleTo.ImportReference(i)); case FieldInfo i: return(moduleTo.ImportReference(i)); case var resolved: throw new NotSupportedException($"Invalid resolved member type {resolved.GetType()}"); } default: throw new NotSupportedException($"Invalid TokenResolutionMode {resolveMode}"); } } catch (MissingMemberException) { // we could not resolve the method normally, so lets read the import table // but we can only do that if the module was loaded from disk // this can still throw if the assembly is a dynamic one, but if that's broken, you have bigger issues string filePath = moduleFrom.Assembly.Location; if (!File.Exists(filePath)) { // in this case, the fallback cannot be followed, and so throwing the original error gives the user information throw; } // TODO: make this cached somehow so its not read and re-opened a bunch using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(filePath, new ReaderParameters { ReadingMode = ReadingMode.Deferred })) { ModuleDefinition module = assembly.Modules.First(m => m.Name == moduleFrom.Name); // this should only fail if the token itself is somehow wrong MemberReference reference = (MemberReference)module.LookupToken(token); // the explicit casts here are to throw if they are incorrect // normally the references would need to be imported, but moduleTo isn't written to anywhere switch (resolveMode) { case TokenResolutionMode.Type: return((TypeReference)reference); case TokenResolutionMode.Method: return((MethodReference)reference); case TokenResolutionMode.Field: return((FieldReference)reference); case TokenResolutionMode.Any: return(reference); default: throw new NotSupportedException($"Invalid TokenResolutionMode {resolveMode}"); } } } } Instruction GetInstruction(int offset) { 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 (offset == instr.Offset) { return(instr); } if (offset < instr.Offset) { max = mid - 1; } else { min = mid + 1; } } return(null); } }