public bool PatchMethod2(MethodDefinition method, Injection injection) { bool success = true; if (method.IsConstructor || method.IsAbstract || method.IsSetter || (method.IsSpecialName && !method.IsGetter) || // to allow getter methods method.IsGenericInstance || method.IsManaged == false || method.Body == null) { SendMessage("Ignored method: " + method.Name, MessageType.Warning); return(true); } try { var constructor = injection.Constructor; constructor.Resolve(); bool isInjected = method.Body.Variables.Count(x => x.VariableType.Scope == injection.TypeReference.Scope && x.VariableType.FullName == injection.TypeReference.FullName && x.VariableType.Namespace == injection.TypeReference.Namespace) > 0; MethodInjector editor = new MethodInjector(method); VariableDefinition vInject = editor.AddVariable(injection.TypeReference); VariableDefinition vInjection = editor.AddVariable(_cinjection); VariableDefinition vObjectArray = editor.AddVariable(Assembly.ImportType <object[]>()); Instruction firstExistingInstruction = method.Body.Instructions[0]; // create constructor of Injector editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Newobj, constructor)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Stloc_S, vInject)); #region OnInvoke without Param editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vInject)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Callvirt, injection.OnInvoke)); #endregion method.Resolve(); SendMessage("Injected method " + method, MessageType.Output); } catch (Exception ex) { SendMessage(ex.Message, MessageType.Error); return(false); } return(true); }
public bool PatchMethod(MethodDefinition method, Injection injection) { bool success = true; if (method.IsConstructor || method.IsAbstract || method.IsSetter || (method.IsSpecialName && !method.IsGetter) || // to allow getter methods method.IsGenericInstance || method.IsManaged == false || method.Body == null) { SendMessage("Ignored method: " + method.Name, MessageType.Warning); return(true); } try { var constructor = injection.Constructor; constructor.Resolve(); bool isInjected = method.Body.Variables.Count(x => x.VariableType.Scope == injection.TypeReference.Scope && x.VariableType.FullName == injection.TypeReference.FullName && x.VariableType.Namespace == injection.TypeReference.Namespace) > 0; if (isInjected) // already injected { SendMessage("Already injected method " + method.Name + " with " + injection.TypeReference.Name, MessageType.Warning); return(true); } MethodInjector editor = new MethodInjector(method); VariableDefinition vInject = editor.AddVariable(injection.TypeReference); VariableDefinition vInjection = editor.AddVariable(_cinjection); VariableDefinition vObjectArray = editor.AddVariable(Assembly.ImportType <object[]>()); Instruction firstExistingInstruction = method.Body.Instructions[0]; // create constructor of Injector editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Newobj, constructor)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Stloc_S, vInject)); #region OnInvoke without Param //editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vInject)); //editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Callvirt, injection.OnInvoke)); #endregion #region OnInvoke with Param // create constructor of CInjection editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Newobj, _cinjectionCtor)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Stloc_S, vInjection)); // create parameter of GetCurrentMethod editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vInjection)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Call, _methodGetCurrentMethod)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Callvirt, _methodSetMethod)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Nop)); // create parameter of GetExecutingAssembly editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vInjection)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Call, _methodGetExecutingAssembly)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Callvirt, _methodSetExecutingAssembly)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Nop)); if (method.Parameters.Count > 0) { // create array of object (arguments) editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vInjection)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldc_I4, method.Parameters.Count)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Newarr, Assembly.ImportType <object>())); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Stloc_S, vObjectArray)); for (int i = 0; i < method.Parameters.Count; i++) { bool processAsNormal = true; if (method.Parameters[i].ParameterType.IsByReference) { /* Sample Instruction set: * L_002a: ldloc.2 * L_002b: ldc.i4.0 * L_002c: ldarg.1 * L_002d: ldind.ref * L_002e: stelem.ref * */ editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vObjectArray)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldc_I4, i)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldarg, method.Parameters[i])); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldind_Ref)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Stelem_Ref)); processAsNormal = false; } //else if (method.Parameters[i].ParameterType.IsArray) //{ //} //else if (method.Parameters[i].ParameterType.IsDefinition) // delegate needs no seperate handling //{ //} else if (method.Parameters[i].ParameterType.IsFunctionPointer) { } //else if (method.Parameters[i].ParameterType.IsOptionalModifier) //{ //} else if (method.Parameters[i].ParameterType.IsPointer) { } else { processAsNormal = true; } if (processAsNormal) { /* Sample Instruction set: for simple PARAMETER * L_0036: ldloc.s objArray * L_0038: ldc.i4 0 * L_003d: ldarg array * L_0041: box Int32 <-------------- anything can be here * L_0046: stelem.ref * */ /* Sample Instruction set: for ARRAY * L_0036: ldloc.s objArray * L_0038: ldc.i4 0 * L_003d: ldarg array * L_0041: box string[] * L_0046: stelem.ref * */ editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vObjectArray)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldc_I4, i)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldarg, method.Parameters[i])); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Box, method.Parameters[i].ParameterType)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Stelem_Ref)); } } editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vObjectArray)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Callvirt, _methodSetArguments)); } // call OnInvoke with appropriate parameters editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vInject)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Ldloc_S, vInjection)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Callvirt, injection.OnInvoke)); editor.InsertBefore(firstExistingInstruction, editor.Create(OpCodes.Nop)); #endregion #region OnComplete Instruction[] exitInstructions = method.Body.Instructions.Where(x => x.OpCode == OpCodes.Ret).ToArray(); for (int i = 0; i < exitInstructions.Length; i++) { var previous = exitInstructions[i].Previous; // most likely previous statement will be NOP, LDLOC.0 (pop, or load from stack) editor.InsertBefore(previous, editor.Create(OpCodes.Ldloc_S, vInject)); editor.InsertBefore(previous, editor.Create(OpCodes.Callvirt, injection.OnComplete)); Debug.WriteLine(method.Name + " " + method.ReturnType.Name + " " + previous.OpCode); } #endregion method.Resolve(); SendMessage("Injected method " + method, MessageType.Output); } catch (Exception ex) { SendMessage(ex.Message, MessageType.Error); return(false); } return(true); }