/// <summary> /// Adds method body interception to the target method. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param> public void Emit(CilWorker IL) { MethodDefinition method = IL.GetMethod(); TypeReference returnType = method.ReturnType.ReturnType; Instruction endLabel = IL.Create(OpCodes.Nop); Instruction executeOriginalInstructions = IL.Create(OpCodes.Nop); // Execute the method body replacement if and only if // interception is enabled IL.Emit(OpCodes.Ldloc, _interceptionDisabled); IL.Emit(OpCodes.Brtrue, executeOriginalInstructions); Instruction invokeReplacement = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, _methodReplacementProvider); IL.Emit(OpCodes.Brtrue, invokeReplacement); IL.Emit(OpCodes.Ldloc, _classMethodReplacementProvider); IL.Emit(OpCodes.Brtrue, invokeReplacement); IL.Emit(OpCodes.Br, executeOriginalInstructions); IL.Append(invokeReplacement); // This is equivalent to the following code: // var replacement = provider.GetMethodReplacement(info); var invokeMethodReplacement = new InvokeMethodReplacement(executeOriginalInstructions, _methodReplacementProvider, _classMethodReplacementProvider, _invocationInfo); invokeMethodReplacement.Emit(IL); IL.Emit(OpCodes.Br, endLabel); #region The original instruction block IL.Append(executeOriginalInstructions); var addOriginalInstructions = new AddOriginalInstructions(_oldInstructions, endLabel); addOriginalInstructions.Emit(IL); #endregion // Mark the end of the method body IL.Append(endLabel); var saveReturnValue = new SaveReturnValue(returnType, _returnValue); saveReturnValue.Emit(IL); }
/// <summary> /// Saves the return value from a given method call. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param> public void Emit(CilWorker IL) { ModuleDefinition module = IL.GetModule(); TypeReference voidType = module.ImportType(typeof(void)); bool returnTypeIsValueType = _returnType != voidType && _returnType.IsValueType; if (_returnType is GenericParameter || returnTypeIsValueType) { IL.Create(OpCodes.Box, _returnType); } if (_returnType != voidType) { IL.Create(OpCodes.Stloc, _returnValue); } }
private void changeMethod(MethodDefinition method) { ModuleDefinition module = method.DeclaringType.Module; MethodInfo writeline = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); MethodReference writeLineRef = module.Import(writeline); CilWorker cil = method.Body.CilWorker; Instruction op1 = cil.Create(OpCodes.Ldstr, "Say hello was called!"); Instruction op2 = cil.Create(OpCodes.Call, writeLineRef); cil.InsertBefore(method.Body.Instructions[0], op1); cil.InsertAfter(op1, op2); module.Import(method.DeclaringType); AssemblyFactory.SaveAssembly(module.Assembly, @"c:\temp\cilTemp\tempasm.dll"); }
public void Emit(CilWorker IL) { var module = IL.GetModule(); var modifiableType = module.ImportType <IModifiableType>(); var getInterceptionDisabledMethod = module.ImportMethod <IModifiableType>("get_IsInterceptionDisabled"); if (!_hostMethod.HasThis) { IL.Emit(OpCodes.Ldc_I4_0); IL.Emit(OpCodes.Stloc, _interceptionDisabled); return; } var skipLabel = IL.Create(OpCodes.Nop); // var interceptionDisabled = this.IsInterceptionDisabled; IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, modifiableType); IL.Emit(OpCodes.Brfalse, skipLabel); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, modifiableType); IL.Emit(OpCodes.Callvirt, getInterceptionDisabledMethod); IL.Emit(OpCodes.Stloc, _interceptionDisabled); IL.Append(skipLabel); }
/// <summary> /// Saves the return value from a given method call. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param> public void Emit(CilWorker IL) { var module = IL.GetModule(); var voidType = module.ImportType(typeof(void)); var returnTypeIsValueType = _returnType != voidType && _returnType.IsValueType; if (_returnType is GenericParameter || returnTypeIsValueType) { IL.Create(OpCodes.Box, _returnType); } if (_returnType != voidType) { IL.Create(OpCodes.Stloc, _returnValue); } }
public Instruction CreateConditionalBranch() { Instruction branch = CilWorker.Create(OpCodes.Nop); Instruction instruction = CilWorker.Create(OpCodes.Brtrue, branch); instruction.Next = CilWorker.Create(OpCodes.Nop); return(instruction); }
private static void InsertCustomCodeCall( MethodDefinition method, MethodReference generatedTypeCtorRef, MethodReference generatedMethodRef, CilWorker cilWorker, Instruction instructionToInsertBefore, bool replaceMethod ) { bool hasReturnValue = (method.ReturnType.ReturnType.FullName != typeof(void).FullName); Instruction nop = cilWorker.Create(OpCodes.Nop); cilWorker.InsertBefore(instructionToInsertBefore, nop); // call ctor Instruction newGeneratedType = cilWorker.Create(OpCodes.Newobj, generatedTypeCtorRef); cilWorker.InsertBefore(instructionToInsertBefore, newGeneratedType); // load arguments on stack if any for (int i = 0; i < method.Parameters.Count; i++) { Instruction loadArg = cilWorker.Create(OpCodes.Ldarga_S, method.Parameters[i]); cilWorker.InsertBefore(instructionToInsertBefore, loadArg); } // call replacing method Instruction callGeneratedMethod = cilWorker.Create(OpCodes.Call, generatedMethodRef); cilWorker.InsertBefore(instructionToInsertBefore, callGeneratedMethod); if (hasReturnValue) { if (replaceMethod) { // add variable to list var generatedValueVar = new VariableDefinition(method.ReturnType.ReturnType); method.Body.Variables.Add(generatedValueVar); // assign to variable Instruction assignNewGeneratedValue = cilWorker.Create(OpCodes.Stloc, generatedValueVar); cilWorker.InsertBefore(instructionToInsertBefore, assignNewGeneratedValue); Instruction ldLoc = cilWorker.Create(OpCodes.Ldloc_0); Instruction brs = cilWorker.Create(OpCodes.Br_S, ldLoc); cilWorker.InsertBefore(instructionToInsertBefore, brs); cilWorker.InsertBefore(instructionToInsertBefore, ldLoc); } else { // remove value from stack Instruction pop = cilWorker.Create(OpCodes.Pop); cilWorker.InsertBefore(instructionToInsertBefore, pop); } } }
/// <summary> /// Emits a Console.WriteLine call to using the current CilWorker that will only be called if the contents /// of the target variable are null at runtime. /// </summary> /// <param name="IL">The target CilWorker.</param> /// <param name="text">The text that will be written to the console.</param> /// <param name="targetVariable">The target variable that will be checked for null at runtime.</param> public static void EmitWriteLineIfNull(this CilWorker IL, string text, VariableDefinition targetVariable) { var skipWrite = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, targetVariable); IL.Emit(OpCodes.Brtrue, skipWrite); IL.EmitWriteLine(text); IL.Append(skipWrite); }
private void EmitCanReplace(CilWorker IL, IMethodSignature hostMethod, VariableDefinition provider) { var skipGetProvider = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, provider); IL.Emit(OpCodes.Brfalse, skipGetProvider); IL.Emit(OpCodes.Ldloc, provider); // Push the host instance var pushInstance = hostMethod.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull); IL.Append(pushInstance); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Callvirt, _canReplace); IL.Emit(OpCodes.Stloc, _canReplaceFlag); IL.Append(skipGetProvider); }
public Instruction CreateSwitchBranch() { Instruction branch1 = CilWorker.Create(OpCodes.Nop); Instruction branch2 = CilWorker.Create(OpCodes.Nop); Instruction branch3 = CilWorker.Create(OpCodes.Nop); Instruction instruction = CilWorker.Create(OpCodes.Switch, new Instruction[] { branch1, branch2, branch3 }); instruction.Next = CilWorker.Create(OpCodes.Nop); return(instruction); }
public void codeBlock_CallToMethod(MethodDefinition targetMethod, MethodInfo methodToCall) { CilWorker cliWorker = targetMethod.Body.CilWorker; var lsInstructions = new List <Instruction> { cliWorker.Create(OpCodes.Call, getMethodReference(methodToCall)) }; CecilOpCodeUtils.addInstructionsToMethod_InsertAtEnd(targetMethod, lsInstructions); }
private static bool hookStaticVoidMethodAtBegin_Int(MethodDefinition hookedMethod, MethodDefinition callMeth) { try { CilWorker initProc = hookedMethod.Body.CilWorker; initProc.InsertBefore(hookedMethod.Body.Instructions[0], initProc.Create(OpCodes.Call, baseAssembly.MainModule.Import(callMeth.Resolve()))); return(true); } catch { return(false); } }
public void Rewrite(MethodDefinition method, CilWorker IL, IEnumerable <Instruction> oldInstructions) { var targetMethod = _parameters.TargetMethod; var worker = targetMethod.GetILGenerator(); var module = worker.GetModule(); _getInterceptionDisabled.Emit(worker); // Construct the InvocationInfo instance var skipInvocationInfo = worker.Create(OpCodes.Nop); worker.Emit(OpCodes.Ldloc, _parameters.InterceptionDisabled); worker.Emit(OpCodes.Brtrue, skipInvocationInfo); var interceptedMethod = targetMethod; _emitter.Emit(targetMethod, interceptedMethod, _parameters.InvocationInfo); var skipGetReplacementProvider = IL.Create(OpCodes.Nop); // var provider = this.MethodReplacementProvider; //IL.Emit(OpCodes.Ldloc, _interceptionDisabled); //IL.Emit(OpCodes.Brtrue, skipGetReplacementProvider); _getInstanceMethodReplacementProvider.Emit(IL); _surroundMethodBody.AddProlog(worker); IL.Append(skipGetReplacementProvider); worker.Append(skipInvocationInfo); _getClassMethodReplacementProvider.Emit(worker); var returnType = targetMethod.ReturnType.ReturnType; _addMethodReplacement.Emit(worker); // Save the return value TypeReference voidType = module.Import(typeof(void)); _surroundMethodBody.AddEpilog(worker); if (returnType != voidType) { worker.Emit(OpCodes.Ldloc, _parameters.ReturnValue); } worker.Emit(OpCodes.Ret); }
private void EmitGetMethodReplacement(CilWorker IL, IMethodSignature hostMethod, VariableDefinition provider) { // var replacement = MethodReplacementProvider.GetReplacement(info); IL.Emit(OpCodes.Ldloc, provider); // Push the host instance Instruction pushInstance = hostMethod.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull); IL.Append(pushInstance); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Callvirt, _getReplacement); IL.Emit(OpCodes.Stloc, _replacement); }
protected override void Replace(Instruction oldInstruction, MethodDefinition hostMethod, CilWorker IL) { var targetMethod = (MethodReference)oldInstruction.Operand; var callOriginalMethod = IL.Create(OpCodes.Nop); var returnType = targetMethod.ReturnType.ReturnType; var endLabel = IL.Create(OpCodes.Nop); var module = hostMethod.DeclaringType.Module; // Create the stack that will hold the method arguments IL.Emit(OpCodes.Newobj, _stackCtor); IL.Emit(OpCodes.Stloc, _currentArguments); // Make sure that the argument stack doesn't show up in // any of the other interception routines IgnoreLocal(IL, _currentArguments, module); SaveInvocationInfo(IL, targetMethod, module, returnType); var getInterceptionDisabled = new GetInterceptionDisabled(hostMethod, _interceptionDisabled); getInterceptionDisabled.Emit(IL); var surroundMethodBody = new SurroundMethodBody(_methodReplacementProvider, _aroundInvokeProvider, _invocationInfo, _interceptionDisabled, _returnValue, typeof(AroundInvokeMethodCallRegistry), "AroundMethodCallProvider"); surroundMethodBody.AddProlog(IL); // Use the MethodReplacementProvider attached to the // current host instance Replace(IL, oldInstruction, targetMethod, hostMethod, endLabel, callOriginalMethod); IL.Append(endLabel); surroundMethodBody.AddEpilog(IL); }
private void EmitCreateMethodActivationContext(MethodDefinition method, CilWorker IL, TypeReference concreteType) { // TODO: Add static method support var pushThis = method.IsStatic ? IL.Create(OpCodes.Ldnull) : IL.Create(OpCodes.Ldarg_0); // Push the 'this' pointer onto the stack IL.Append(pushThis); var module = method.DeclaringType.Module; // Push the current method onto the stack IL.PushMethod(method, module); // Push the concrete type onto the stack IL.Emit(OpCodes.Ldtoken, concreteType); IL.Emit(OpCodes.Call, _getTypeFromHandle); IL.Emit(OpCodes.Ldloc, _constructorArguments); IL.Emit(OpCodes.Callvirt, _toArrayMethod); IL.Emit(OpCodes.Newobj, _methodActivationContextCtor); // var context = new MethodActivationContext(this, currentMethod, concreteType, args); IL.Emit(OpCodes.Stloc, _methodContext); }
override protected void ProcessMethod(MethodDefinition method) { if (!method.HasBody) { return; } MethodBody body = method.Body; Instruction firstInstruction = body.Instructions[0]; CilWorker worker = body.CilWorker; // ldstr "TRACE: " + method worker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldstr, "TRACE: " + method)); // call Console.WriteLine(string) MethodReference Console_WriteLine = Import(typeof(Console).GetMethod( "WriteLine", new Type[] { typeof(string) }) ); worker.InsertBefore(firstInstruction, worker.Create(OpCodes.Call, Console_WriteLine)); }
public void AddEpilog(CilWorker IL) { var skipEpilog = IL.Create(OpCodes.Nop); // if (!IsInterceptionDisabled && surroundingImplementation != null) { IL.Emit(OpCodes.Ldloc, _interceptionDisabled); IL.Emit(OpCodes.Brtrue, skipEpilog); // surroundingImplementation.AfterInvoke(invocationInfo, returnValue); var emitAfterInvoke = new EmitAfterInvoke(_surroundingImplementation, _surroundingClassImplementation, _invocationInfo, _returnValue); emitAfterInvoke.Emit(IL); // } IL.Append(skipEpilog); }
private void GetInstanceProvider(CilWorker IL) { var skipInstanceProvider = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, _hostInterfaceType); IL.Emit(OpCodes.Brfalse, skipInstanceProvider); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, _hostInterfaceType); IL.Emit(OpCodes.Callvirt, _getProvider); IL.Emit(OpCodes.Stloc, _instanceProvider); IL.Emit(OpCodes.Ldloc, _instanceProvider); IL.Emit(OpCodes.Brtrue, skipInstanceProvider); IL.Append(skipInstanceProvider); }
public void WeaveConstructorCalls(IEnumerable <ConstructorCallWeave> weaves, FactoryMap factories) { MethodInfo getFactoryMethod = typeof(Factories).GetMethod("Create"); foreach (ConstructorCallWeave weave in weaves) { Factory factory = factories.GetForObjectType(weave.Constructor.DeclaringType); _log.Log("Weaving {0} in {1}", factory.ObjectType, weave.ParentMethod); MethodReference getObjectMethodReference = weave.ParentAssembly.Import(getFactoryMethod); GenericInstanceMethod methodCall = new GenericInstanceMethod(getObjectMethodReference); methodCall.GenericArguments.Add(factory.ObjectType); CilWorker worker = weave.ParentMethod.Body.CilWorker; Instruction callGetFactory = worker.Create(OpCodes.Call, methodCall); worker.Replace(weave.NewInstruction, callGetFactory); } }
public void Emit(CilWorker IL) { var module = IL.GetModule(); var method = IL.GetMethod(); var returnType = method.ReturnType.ReturnType; var methodReplacement = MethodDefinitionExtensions.AddLocal(method, typeof(IInterceptor)); GetMethodReplacementInstance(method, IL, methodReplacement, _methodReplacementProvider, _invocationInfo); var skipGetClassMethodReplacement = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, methodReplacement); IL.Emit(OpCodes.Brtrue, skipGetClassMethodReplacement); GetMethodReplacementInstance(method, IL, methodReplacement, _classMethodReplacementProvider, _invocationInfo); IL.Append(skipGetClassMethodReplacement); IL.Emit(OpCodes.Ldloc, methodReplacement); IL.Emit(OpCodes.Brfalse, _executeOriginalInstructions); // var returnValue = replacement.Intercept(info); InvokeInterceptor(module, IL, methodReplacement, returnType, _invocationInfo); }
private static bool hookStaticVoidMethodAtEnd_Int(MethodDefinition hookedMethod, MethodDefinition callMeth) { try { HashSet <Instruction> retInstructions = new HashSet <Instruction>(); foreach (Instruction instr in hookedMethod.Body.Instructions) { if (instr.OpCode == OpCodes.Ret) { retInstructions.Add(instr); } } CilWorker initProc = hookedMethod.Body.CilWorker; bool overriden = false; foreach (Instruction ret in retInstructions) { initProc.InsertBefore(ret, initProc.Create(OpCodes.Call, baseAssembly.MainModule.Import(callMeth.Resolve()))); overriden = true; } return(overriden); } catch { return(false); } }
/// <summary> /// Rewrites the instructions in the target method body to support dynamic exception handling. /// </summary> /// <param name="targetMethod">The target method.</param> /// <param name="IL">The <see cref="CilWorker"/> instance that represents the method body.</param> /// <param name="oldInstructions">The IL instructions of the original method body.</param> protected override void RewriteMethodBody(MethodDefinition targetMethod, CilWorker IL, IEnumerable <Instruction> oldInstructions) { var endOfOriginalInstructionBlock = IL.Create(OpCodes.Nop); var addOriginalInstructions = new AddOriginalInstructions(oldInstructions, endOfOriginalInstructionBlock); var endLabel = IL.Create(OpCodes.Nop); var tryStart = IL.Emit(OpCodes.Nop); var tryEnd = IL.Emit(OpCodes.Nop); var catchStart = IL.Emit(OpCodes.Nop); var catchEnd = IL.Emit(OpCodes.Nop); var module = IL.GetModule(); var handler = new ExceptionHandler(ExceptionHandlerType.Catch); var body = targetMethod.Body; body.ExceptionHandlers.Add(handler); handler.CatchType = module.ImportType <Exception>(); handler.TryStart = tryStart; handler.TryEnd = tryEnd; handler.HandlerStart = catchStart; handler.HandlerEnd = catchEnd; var emitter = new InvocationInfoEmitter(true); var returnType = targetMethod.ReturnType.ReturnType; // try { IL.Append(tryStart); addOriginalInstructions.Emit(IL); IL.Append(endOfOriginalInstructionBlock); if (returnType != _voidType && _returnValue != null) { IL.Emit(OpCodes.Stloc, _returnValue); } IL.Emit(OpCodes.Leave, endLabel); // } IL.Append(tryEnd); // catch (Exception ex) { IL.Append(catchStart); IL.Emit(OpCodes.Stloc, _exception); SaveExceptionInfo(targetMethod, emitter); IL.Emit(OpCodes.Ldloc, _exceptionInfo); var getHandlerMethodInfo = typeof(ExceptionHandlerRegistry).GetMethod("GetHandler"); var getHandlerMethod = module.Import(getHandlerMethodInfo); IL.Emit(OpCodes.Call, getHandlerMethod); IL.Emit(OpCodes.Stloc, _exceptionHandler); // if (exceptionHandler == null) // throw; var doRethrow = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, _exceptionHandler); IL.Emit(OpCodes.Brfalse, doRethrow); // if (handler.CanCatch(exceptionInfo)) { var leaveBlock = IL.Create(OpCodes.Nop); var canCatch = module.ImportMethod <IExceptionHandler>("CanCatch"); IL.Emit(OpCodes.Ldloc, _exceptionHandler); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, canCatch); IL.Emit(OpCodes.Brfalse, doRethrow); var catchMethod = module.ImportMethod <IExceptionHandler>("Catch"); IL.Emit(OpCodes.Ldloc, _exceptionHandler); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, catchMethod); // } var getShouldSkipRethrow = module.ImportMethod <IExceptionHandlerInfo>("get_ShouldSkipRethrow"); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, getShouldSkipRethrow); IL.Emit(OpCodes.Brfalse, doRethrow); IL.Emit(OpCodes.Br, leaveBlock); IL.Append(doRethrow); IL.Emit(OpCodes.Rethrow); IL.Append(leaveBlock); IL.Emit(OpCodes.Leave, endLabel); IL.Append(catchEnd); // } IL.Append(endLabel); if (returnType != _voidType && _returnValue != null) { var returnOriginalValue = IL.Create(OpCodes.Nop); var getReturnValue = module.ImportMethod <IExceptionHandlerInfo>("get_ReturnValue"); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Brfalse, returnOriginalValue); IL.Emit(OpCodes.Ldloc, _exceptionInfo); IL.Emit(OpCodes.Callvirt, getReturnValue); IL.Emit(OpCodes.Stloc, _returnValue); IL.Append(returnOriginalValue); IL.Emit(OpCodes.Ldloc, _returnValue); } IL.Emit(OpCodes.Ret); }
private void InjectCustomCode(MethodDefinition method, MethodHook methodHook) { // generate assembly with custom code m_codeGenerator.GenerateAssembly(methodHook, Path.GetDirectoryName(m_assemblyPath)); // load generated assembly string assemblyName = methodHook.GetSafeName(); AssemblyDefinition generatedAssembly = LoadGeneratedAssembly(assemblyName); // get method reference with custom code string generatedClassName = String.Format("{0}_{1}", assemblyName, "Class"); var generatedType = generatedAssembly.MainModule.Types.Cast <TypeDefinition>().First(t => t.Name == generatedClassName); string generatedMethodName = String.Format("{0}_{1}", assemblyName, "Hook"); // TODO: take parameter types into account, to resolve methods with the same names var generatedMethod = generatedType.Methods.Cast <MethodDefinition>().First(m => m.Name == generatedMethodName); MethodReference generatedTypeCtor = null; for (int i = 0; i <= generatedType.Constructors.Count; i++) { if (!generatedType.Constructors[i].HasParameters) { generatedTypeCtor = generatedType.Constructors[i]; break; } } if (generatedTypeCtor == null) { throw new InvalidOperationException("Default constructor was not found in generated assembly"); } // inject call MethodReference generatedTypeCtorRef = m_assemblyDefinition.MainModule.Import(generatedTypeCtor); MethodReference generatedMethodRef = m_assemblyDefinition.MainModule.Import(generatedMethod); method.Body.InitLocals = true; CilWorker cilWorker = method.Body.CilWorker; if (methodHook.HookType == HookType.ReplaceMethod) { method.Body.Instructions.Clear(); method.Body.Variables.Clear(); // return value Instruction returnInstruction = cilWorker.Create(OpCodes.Ret); cilWorker.Append(returnInstruction); InsertCustomCodeCall(method, generatedTypeCtorRef, generatedMethodRef, cilWorker, returnInstruction, true); } else if ((methodHook.HookType & HookType.OnMethodEnter) == HookType.OnMethodEnter) { Instruction firstInstruction = method.Body.Instructions[0]; InsertCustomCodeCall(method, generatedTypeCtorRef, generatedMethodRef, cilWorker, firstInstruction, false); } else if ((methodHook.HookType & HookType.OnMethodExit) == HookType.OnMethodExit) { Instruction returnInstruction = method.Body.Instructions[method.Body.Instructions.Count - 1]; if (returnInstruction.OpCode != OpCodes.Ret) { throw new InvalidOperationException(String.Format("Method '{0}' has no valid ret instruction", method.Name)); } InsertCustomCodeCall(method, generatedTypeCtorRef, generatedMethodRef, cilWorker, returnInstruction, false); } }
/// <summary> /// Emits the IL to save information about /// the method currently being executed. /// </summary> /// <seealso cref="IInvocationInfo"/> /// <param name="targetMethod">The target method currently being executed.</param> /// <param name="interceptedMethod">The method that will be passed to the <paramref name="invocationInfo"/> as the currently executing method.</param> /// <param name="invocationInfo">The local variable that will store the resulting <see cref="IInvocationInfo"/> instance.</param> public void Emit(MethodDefinition targetMethod, MethodReference interceptedMethod, VariableDefinition invocationInfo) { ModuleDefinition module = targetMethod.DeclaringType.Module; VariableDefinition currentMethod = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(MethodBase)); VariableDefinition parameterTypes = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(Type[])); VariableDefinition arguments = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(object[])); VariableDefinition typeArguments = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(Type[])); TypeReference systemType = ModuleDefinitionExtensions.ImportType(module, typeof(Type)); CilWorker IL = MethodDefinitionExtensions.GetILGenerator(targetMethod); #region Initialize the InvocationInfo constructor arguments // Type[] typeArguments = new Type[genericTypeCount]; int genericParameterCount = targetMethod.GenericParameters.Count; IL.Emit(OpCodes.Ldc_I4, genericParameterCount); IL.Emit(OpCodes.Newarr, systemType); IL.Emit(OpCodes.Stloc, typeArguments); // object[] arguments = new object[argumentCount]; IL.PushArguments(targetMethod, module, arguments); // object target = this; if (targetMethod.HasThis) { IL.Emit(OpCodes.Ldarg_0); } else { IL.Emit(OpCodes.Ldnull); } IL.PushMethod(interceptedMethod, module); IL.Emit(OpCodes.Stloc, currentMethod); // MethodBase targetMethod = currentMethod as MethodBase; IL.Emit(OpCodes.Ldloc, currentMethod); // Push the generic type arguments onto the stack if (genericParameterCount > 0) { IL.PushGenericArguments(targetMethod, module, typeArguments); } // Make sure that the generic methodinfo is instantiated with the // proper type arguments if (targetMethod.GenericParameters.Count > 0) { TypeReference methodInfoType = module.Import(typeof(MethodInfo)); IL.Emit(OpCodes.Isinst, methodInfoType); MethodReference getIsGenericMethodDef = module.ImportMethod <MethodInfo>("get_IsGenericMethodDefinition"); IL.Emit(OpCodes.Dup); IL.Emit(OpCodes.Callvirt, getIsGenericMethodDef); // Determine if the current method is a generic method // definition Instruction skipMakeGenericMethod = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Brfalse, skipMakeGenericMethod); // Instantiate the specific generic method instance MethodReference makeGenericMethod = module.ImportMethod <MethodInfo>("MakeGenericMethod", typeof(Type[])); IL.Emit(OpCodes.Ldloc, typeArguments); IL.Emit(OpCodes.Callvirt, makeGenericMethod); IL.Append(skipMakeGenericMethod); } if (_pushStackTrace) { IL.PushStackTrace(module); } else { IL.Emit(OpCodes.Ldnull); } // Save the parameter types IL.Emit(OpCodes.Ldc_I4, targetMethod.Parameters.Count); IL.Emit(OpCodes.Newarr, systemType); IL.Emit(OpCodes.Stloc, parameterTypes); IL.SaveParameterTypes(targetMethod, module, parameterTypes); IL.Emit(OpCodes.Ldloc, parameterTypes); // Push the type arguments back onto the stack IL.Emit(OpCodes.Ldloc, typeArguments); // Save the return type MethodReference getTypeFromHandle = module.Import(_getTypeFromHandle); TypeReference returnType = targetMethod.ReturnType.ReturnType; IL.Emit(OpCodes.Ldtoken, returnType); IL.Emit(OpCodes.Call, getTypeFromHandle); // Push the arguments back onto the stack IL.Emit(OpCodes.Ldloc, arguments); #endregion // InvocationInfo info = new InvocationInfo(...); MethodReference infoConstructor = module.Import(_invocationInfoConstructor); IL.Emit(OpCodes.Newobj, infoConstructor); IL.Emit(OpCodes.Stloc, invocationInfo); IL.Emit(OpCodes.Ldloc, invocationInfo); MethodReference addInstance = module.Import(typeof(IgnoredInstancesRegistry).GetMethod("AddInstance")); IL.Emit(OpCodes.Call, addInstance); }
public void StoreFactoryMap(IAssembly assembly, FactoryMap factoryMap) { MethodInfo getTypeFromHandleReflect = typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) }); MethodReference getTypeFromHandle = assembly.Import(getTypeFromHandleReflect); TypeReference systemType = assembly.Import(typeof(Type)); TypeReference arrayOfTypes = assembly.Import(typeof(Type[])); TypeReference arrayOfArrayOfTypes = assembly.Import(typeof(Type[][])); // Now we create the actual type and stuff... TypeDefinition mapType = GetFactoryMapType(assembly); MethodDefinition getFactoriesMethod = new MethodDefinition(FactoryMapMethodName, MethodAttributes.Public, arrayOfArrayOfTypes); getFactoriesMethod.IsVirtual = true; mapType.Methods.Add(getFactoriesMethod); getFactoriesMethod.Body.Variables.Add(new VariableDefinition("map", 0, getFactoriesMethod, arrayOfArrayOfTypes)); getFactoriesMethod.Body.Variables.Add(new VariableDefinition("row", 1, getFactoriesMethod, arrayOfTypes)); getFactoriesMethod.Body.InitLocals = true; CilWorker worker = getFactoriesMethod.Body.CilWorker; List <Factory> factories = new List <Factory>(factoryMap.Factories); worker.Append(worker.Create(OpCodes.Nop)); worker.Append(worker.Create(OpCodes.Ldc_I4, factories.Count)); worker.Append(worker.Create(OpCodes.Newarr, arrayOfTypes)); worker.Append(worker.Create(OpCodes.Stloc_0)); worker.Append(worker.Create(OpCodes.Ldloc_0)); int index = 0; foreach (Factory factory in factories) { worker.Append(worker.Create(OpCodes.Ldc_I4, index)); worker.Append(worker.Create(OpCodes.Ldc_I4, 2)); worker.Append(worker.Create(OpCodes.Newarr, systemType)); worker.Append(worker.Create(OpCodes.Stloc_1)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldc_I4_0)); worker.Append(worker.Create(OpCodes.Ldtoken, factory.ObjectType)); worker.Append(worker.Create(OpCodes.Call, getTypeFromHandle)); worker.Append(worker.Create(OpCodes.Stelem_Ref)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Ldc_I4_1)); worker.Append(worker.Create(OpCodes.Ldtoken, factory.FactoryType)); worker.Append(worker.Create(OpCodes.Call, getTypeFromHandle)); worker.Append(worker.Create(OpCodes.Stelem_Ref)); worker.Append(worker.Create(OpCodes.Ldloc_1)); worker.Append(worker.Create(OpCodes.Stelem_Ref)); index++; worker.Append(worker.Create(OpCodes.Ldloc_0)); } worker.Append(worker.Create(OpCodes.Ret)); assembly.Inject(mapType); }
public static bool Run(string dllFile, string projectFile) { if (!File.Exists(projectFile)) { WriteLineStatus("Project file not found."); return(false); } if (!File.Exists(dllFile)) { WriteLineStatus("Compiled DLL not found."); return(false); } try { List <Function> functions = GetFunctionsWithAttribute(projectFile, "ApiExtension"); AssemblyDefinition assembly = AssemblyFactory.GetAssembly( dllFile); assembly.MainModule.LoadSymbols(); StringBuilder sb = new StringBuilder(); // Gets all types which are declared in the Main Module of the assembly foreach (TypeDefinition type in assembly.MainModule.Types) { // Writes the full name of a type sb.AppendLine(type.FullName); // Gets all methods of the current type foreach (MethodDefinition method in type.Methods) { if (method.CustomAttributes.Count > 0) { string attributeName = method.CustomAttributes[0].Constructor.DeclaringType.Name; if (attributeName == "ApiExtensionAttribute") { bool matchingFunctionFound = false; List <Function> possibleMathes = new List <Function>(); // Find the matching function in the source-code functions foreach (Function function in functions) { if (function.Name != method.Name) { continue; } bool isMatch = false; string signature1 = function.FullyQualifiedDisplayNameWithBCLTypes.Replace(".Fields.Constructors.Properties.Functions.Inner Classes", "").Replace(".Fields.Constructors.Properties.Functions", "").Replace(".Fields.Constructors.Functions", "").Replace(".Constructors.Functions", "").Replace(".Functions", "").Replace(" ", "").ToLower(); string signature2 = GetFullyQualifiedDisplayName(type, method).ToLower(); if (function.Name == method.Name) { //string gg = ""; } isMatch = signature1 == signature2; if (isMatch) { possibleMathes.Add(function); } else { // It might still be a match, but parameter types might be qualified differently //if (function.FullyQualifiedName.IndexOf(type.FullName.Replace("/", ".Fields.Constructors.Properties.Functions.Inner Classes.")) == 0 && method.Name == function.Name && method.Parameters.Count == function.Parameters.Count) string name1 = function.FullyQualifiedName.Replace(".Fields.Constructors.Properties.Functions.Inner Classes", "").Replace(".Fields.Constructors.Properties.Functions", "").Replace(".Fields.Constructors.Functions", "").Replace(".Constructors.Functions", "").Replace(".Functions", ""); string name2 = string.Format("{0}.{1}", type.FullName, method.Name).Replace("/", "."); if (name1 == name2 && method.Parameters.Count == function.Parameters.Count) { bool parametersMatch = true; for (int paramCounter = 0; paramCounter < method.Parameters.Count; paramCounter++) { if (method.Parameters[paramCounter].Name != function.Parameters[paramCounter].Name) { parametersMatch = false; break; } } if (parametersMatch) { if (!method.IsPublic) { WriteLineStatus(string.Format("Function is not public: {0}.{1}", type.FullName, method.Name)); return(false); } possibleMathes.Add(function); } } } } if (possibleMathes.Count == 0) { WriteLineStatus(string.Format("Function not found in source-code: {0}.{1}", type.FullName, method.Name)); return(false); } else if (possibleMathes.Count == 1) { // No need to perform any further checks matchingFunctionFound = true; StringBuilder xmlComments = new StringBuilder(100); foreach (string xmlComment in possibleMathes[0].XmlComments) { xmlComments.AppendLine(xmlComment); } string functionBody = Slyce.Common.Utility.StandardizeLineBreaks(possibleMathes[0].BodyText, Slyce.Common.Utility.LineBreaks.Unix). Replace("\n", ""); functionBody = CleanFunctionBodyEnds(functionBody); if (method.CustomAttributes[0].ConstructorParameters.Count == 0) { method.CustomAttributes.RemoveAt(0); CustomAttribute ca = new CustomAttribute(assembly.MainModule.Import( typeof(ArchAngel.Interfaces.Attributes.ApiExtensionAttribute). GetConstructor( new Type[] { typeof(string), typeof(string) }))); ca.ConstructorParameters.Clear(); ca.ConstructorParameters.Add(xmlComments.ToString()); ca.ConstructorParameters.Add(functionBody); method.CustomAttributes.Add(ca); } else if (method.CustomAttributes[0].ConstructorParameters.Count == 2) { method.CustomAttributes[0].ConstructorParameters[0] = xmlComments.ToString(); method.CustomAttributes[0].ConstructorParameters[1] = functionBody; } else { WriteLineStatus("FAILED - ApiExtensionAttribute has unexpected number of arguments: " + method.Name); return(false); } WriteLineStatus("Processed: " + method.Name); } else { bool parametersMatch = true; matchingFunctionFound = false; foreach (Function function in possibleMathes) { for (int paramCounter = 0; paramCounter < method.Parameters.Count; paramCounter++) { if (method.Parameters[paramCounter].ParameterType.Name != function.Parameters[paramCounter].DataType) { parametersMatch = false; break; } } if (parametersMatch) { matchingFunctionFound = true; method.CustomAttributes[0].ConstructorParameters[0] = function.Comments.PreceedingComments; method.CustomAttributes[0].ConstructorParameters[1] = CleanFunctionBodyEnds(Slyce.Common.Utility.StandardizeLineBreaks(function.BodyText, Slyce.Common.Utility.LineBreaks.Unix).Replace( "\n", "")); break; } } if (!matchingFunctionFound) { WriteLineStatus("Many possible matching functions found in source-code: " + method.Name); return(false); } } //} if (method.Body == null) { continue; } // Gets the CilWorker of the method for working with CIL instructions CilWorker worker = method.Body.CilWorker; FieldReference projectInstance = assembly.MainModule.Import(typeof(SharedData).GetField("CurrentProject")); //MethodReference projectInstance = // assembly.MainModule.Import(typeof(SharedData).GetMethod("get_CurrentProject")); MethodReference callApiExtFunctionMethodRef = assembly.MainModule.Import(typeof(IWorkbenchProject).GetMethod("CallApiExtensionFunction")); // Create local variables VariableDefinition archAngelApiExtResult = new VariableDefinition(assembly.MainModule.Import(typeof(object))); VariableDefinition parameters1 = new VariableDefinition(assembly.MainModule.Import(typeof(object[]))); VariableDefinition parameters2 = new VariableDefinition(assembly.MainModule.Import(typeof(object[]))); int localVarIndexOffset = method.Body.Variables.Count; method.Body.Variables.Add(archAngelApiExtResult); method.Body.Variables.Add(parameters1); method.Body.Variables.Add(parameters2); // Get the first instruction of the current method Instruction firstInstruction = method.Body.Instructions[0]; // Arguments in a non-static method are one-based, because arg[0] is 'this'. int argIndexOffset = method.IsStatic ? 0 : 1; #region Initialize all "out" arguments to null for (int argIndex = 0; argIndex < method.Parameters.Count; argIndex++) { ParameterDefinition arg = method.Parameters[argIndex]; int realArgIndex = argIndex + argIndexOffset; if (arg.IsOut) { // Load the argument switch (realArgIndex) { case 0: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_0)); break; case 1: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_1)); break; case 2: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_2)); break; case 3: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_3)); break; default: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_S, arg)); break; } // Set it to null method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldnull)); // Store the ref object method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stind_Ref)); } } #endregion #region Initialize object array #region Size array to number of arguments switch (method.Parameters.Count) { case 0: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_0)); break; case 1: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_1)); break; case 2: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_2)); break; case 3: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_3)); break; case 4: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_4)); break; case 5: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_5)); break; case 6: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_6)); break; case 7: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_7)); break; case 8: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_8)); break; default: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_S, (sbyte)method.Parameters.Count)); //method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_S, method.Parameters[method.Parameters.Count - 1])); break; } #endregion // Create a new array of objects, load the object array method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Newarr, assembly.MainModule.Import(typeof(object)))); // Create new object[] - must be declared as a local variable // parameters2 is the third variable we added switch (localVarIndexOffset + 2) { case 0: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_0)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_0)); break; case 1: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_1)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_1)); break; case 2: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_2)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_2)); break; case 3: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_3)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_3)); break; default: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_S, parameters2)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_S, parameters2)); break; } #endregion // Load all method arguments into the object array for (int argIndex = 0; argIndex < method.Parameters.Count; argIndex++) { int realArgIndex = argIndex + argIndexOffset; ParameterDefinition arg = method.Parameters[argIndex]; // Specify the array insertion index. switch (argIndex) { case 0: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_0)); break; case 1: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_1)); break; case 2: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_2)); break; case 3: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_3)); break; case 4: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_4)); break; case 5: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_5)); break; case 6: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_6)); break; case 7: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_7)); break; case 8: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_8)); break; default: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldc_I4_S, (sbyte)argIndex)); break; } // Load the argument switch (realArgIndex) { case 0: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_0)); break; case 1: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_1)); break; case 2: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_2)); break; case 3: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_3)); break; default: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldarg_S, arg)); break; } if (arg.ParameterType.IsValueType) { method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Box, arg.ParameterType)); } // If the parameter is out or ref if (arg.IsOut) { // Load as indirect reference method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldind_Ref)); } // Replace the current array object with the new object method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stelem_Ref)); // Assign the new object // parameters2 is the third variable we added switch (localVarIndexOffset + 2) { case 0: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_0)); break; case 1: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_1)); break; case 2: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_2)); break; case 3: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_3)); break; default: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_S, parameters2)); break; } } // POP (parameters variable) OFF STACK AND STORE IN LOCAL VARIABLE AT INDEX 1 (object[] parameters) // parameters1 is the third variable we added switch (localVarIndexOffset + 1) { case 0: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_0)); break; case 1: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_1)); break; case 2: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_2)); break; case 3: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_3)); break; default: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Stloc_S, parameters1)); break; } // Call the ApiExtension function //// NEW method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldsfld, projectInstance)); // END NEW //method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Call, projectInstance)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldstr, method.DeclaringType.FullName + "." + method.Name)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloca_S, archAngelApiExtResult)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloca_S, parameters1)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Callvirt, callApiExtFunctionMethodRef)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Brfalse_S, firstInstruction)); if (method.ReturnType.ReturnType.FullName != "System.Void") { switch (localVarIndexOffset) { case 0: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_0)); break; case 1: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_1)); break; case 2: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_2)); break; case 3: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_3)); break; default: method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ldloc_S, archAngelApiExtResult)); break; } //method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Castclass, method.ReturnType.ReturnType)); method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Unbox_Any, method.ReturnType.ReturnType)); } method.Body.CilWorker.InsertBefore(firstInstruction, worker.Create(OpCodes.Ret)); method.Body.InitLocals = true; } //}// Added } //Import the modifying type into the AssemblyDefinition of //"MyLibrary" assembly.MainModule.Import(type); } } //Save the modified "MyLibrary" assembly string newFilename = GetNewFilename(dllFile); AssemblyFactory.SaveAssembly(assembly, newFilename); // Copy the existing pdb sideways string sourceDirectory = Path.GetDirectoryName(dllFile); string targetDirectory = Path.GetDirectoryName(newFilename); string sourcePdbFilePath = Path.Combine(sourceDirectory, Path.GetFileNameWithoutExtension(dllFile) + ".pdb"); string tempPdbFilePath = Path.Combine(sourceDirectory, Path.GetFileNameWithoutExtension(dllFile) + "_temp.pdb"); string targetPdbFilePath = Path.Combine(targetDirectory, Path.GetFileNameWithoutExtension(dllFile) + "_EXT.pdb"); File.Copy(sourcePdbFilePath, tempPdbFilePath); assembly.MainModule.SaveSymbols(); if (File.Exists(targetPdbFilePath)) { File.Delete(targetPdbFilePath); } File.Move(sourcePdbFilePath, targetPdbFilePath); File.Move(tempPdbFilePath, sourcePdbFilePath); WriteLineStatus("Finished"); return(true); } catch (Exception ex) { WriteLineStatus("Error: " + ex.Message); return(false); } }
/// <summary> /// Replaces the <paramref name="oldInstruction"/> with a set of new instructions. /// </summary> /// <param name="oldInstruction">The instruction currently being evaluated.</param> /// <param name="hostMethod">The method that contains the target instruction.</param> /// <param name="IL">The CilWorker that will be used to emit the method body instructions.</param> protected override void Replace(Instruction oldInstruction, MethodDefinition hostMethod, CilWorker IL) { var targetField = (FieldReference)oldInstruction.Operand; TypeReference fieldType = targetField.FieldType; bool isSetter = oldInstruction.OpCode == OpCodes.Stsfld || oldInstruction.OpCode == OpCodes.Stfld; if (isSetter) { hostMethod.Body.InitLocals = true; // Save the setter argument and box it if necessary if (fieldType.IsValueType || fieldType is GenericParameter) { IL.Emit(OpCodes.Box, fieldType); } IL.Emit(OpCodes.Stloc, _currentArgument); } // There's no need to push the current object instance // since the this pointer is pushed prior to the field call if (hostMethod.IsStatic) { IL.Emit((OpCodes.Ldnull)); } // Push the current method ModuleDefinition module = hostMethod.DeclaringType.Module; // Push the current method onto the stack IL.PushMethod(hostMethod, module); // Push the current field onto the stack IL.PushField(targetField, module); // Push the host type onto the stack IL.PushType(hostMethod.DeclaringType, module); // Create the IFieldInterceptionContext instance IL.Emit(OpCodes.Newobj, _fieldContextCtor); IL.Emit(OpCodes.Stloc, _fieldContext); Instruction skipInterception = IL.Create(OpCodes.Nop); // Obtain an interceptor instance if (hostMethod.IsStatic) { IL.Emit(OpCodes.Ldloc, _fieldContext); IL.Emit(OpCodes.Call, _getInterceptor); } else { IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, _fieldInterceptionHostType); IL.Emit(OpCodes.Brfalse, skipInterception); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, _fieldInterceptionHostType); IL.Emit(OpCodes.Callvirt, _getInstanceInterceptor); } // The field interceptor cannot be null IL.Emit(OpCodes.Stloc, _fieldInterceptor); IL.Emit(OpCodes.Ldloc, _fieldInterceptor); IL.Emit(OpCodes.Brfalse, skipInterception); // if (FieldInterceptor.CanIntercept(context) { IL.Emit(OpCodes.Ldloc, _fieldInterceptor); IL.Emit(OpCodes.Ldloc, _fieldContext); IL.Emit(OpCodes.Callvirt, _canIntercept); IL.Emit(OpCodes.Brfalse, skipInterception); bool isGetter = oldInstruction.OpCode == OpCodes.Ldsfld || oldInstruction.OpCode == OpCodes.Ldfld; Instruction endLabel = IL.Create(OpCodes.Nop); //Call the interceptor instead of the getter or setter if (isGetter) { IL.Emit(OpCodes.Ldloc, _fieldInterceptor); IL.Emit(OpCodes.Ldloc, _fieldContext); IL.Emit(OpCodes.Callvirt, _getValue); IL.Emit(OpCodes.Unbox_Any, fieldType); } if (isSetter) { // Push the 'this' pointer for instance field setters if (!hostMethod.IsStatic) { IL.Emit(OpCodes.Ldarg_0); } IL.Emit(OpCodes.Ldloc, _fieldInterceptor); IL.Emit(OpCodes.Ldloc, _fieldContext); IL.Emit(OpCodes.Ldloc, _currentArgument); // Unbox the setter value IL.Emit(OpCodes.Unbox_Any, fieldType); IL.Emit(OpCodes.Callvirt, _setValue); // Set the actual field value IL.Emit(OpCodes.Unbox_Any, fieldType); IL.Emit(oldInstruction.OpCode, targetField); } IL.Emit(OpCodes.Br, endLabel); // } IL.Append(skipInterception); // else { // Load the original field if (!hostMethod.IsStatic) { IL.Emit(OpCodes.Ldarg_0); } if (isSetter) { IL.Emit(OpCodes.Ldloc, _currentArgument); // Unbox the setter value IL.Emit(OpCodes.Unbox_Any, fieldType); } IL.Emit(oldInstruction.OpCode, targetField); // } IL.Append(endLabel); }
private void Replace(CilWorker IL, Instruction oldInstruction, MethodReference targetMethod, MethodDefinition hostMethod, Instruction endLabel, Instruction callOriginalMethod) { var returnType = targetMethod.ReturnType.ReturnType; var module = hostMethod.DeclaringType.Module; if (!hostMethod.IsStatic) { GetInstanceProvider(IL); } var pushInstance = hostMethod.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull); // If all else fails, use the static method replacement provider IL.Append(pushInstance); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Call, _getStaticProvider); IL.Emit(OpCodes.Stloc, _staticProvider); var restoreArgumentStack = IL.Create(OpCodes.Nop); var callReplacement = IL.Create(OpCodes.Nop); var useStaticProvider = IL.Create(OpCodes.Nop); #region Use the instance method replacement provider IL.Emit(OpCodes.Ldloc, _instanceProvider); IL.Emit(OpCodes.Brfalse, useStaticProvider); EmitCanReplace(IL, hostMethod, _instanceProvider); IL.Emit(OpCodes.Ldloc, _canReplaceFlag); IL.Emit(OpCodes.Brfalse, useStaticProvider); EmitGetMethodReplacement(IL, hostMethod, _instanceProvider); IL.Emit(OpCodes.Ldloc, _replacement); IL.Emit(OpCodes.Brtrue, callReplacement); #endregion IL.Append(useStaticProvider); // if (!MethodReplacementProvider.CanReplace(info)) // CallOriginalMethod(); EmitCanReplace(IL, hostMethod, _staticProvider); IL.Emit(OpCodes.Ldloc, _canReplaceFlag); IL.Emit(OpCodes.Brfalse, restoreArgumentStack); EmitGetMethodReplacement(IL, hostMethod, _staticProvider); IL.Append(callReplacement); // if (replacement == null) // CallOriginalMethod(); IL.Emit(OpCodes.Ldloc, _replacement); IL.Emit(OpCodes.Brfalse, restoreArgumentStack); EmitInterceptorCall(IL); IL.PackageReturnValue(module, returnType); IL.Emit(OpCodes.Br, endLabel); IL.Append(restoreArgumentStack); // Reconstruct the method arguments if the interceptor // cannot be found // Push the target instance ReconstructMethodArguments(IL, targetMethod); // Mark the CallOriginalMethod instruction label IL.Append(callOriginalMethod); // Call the original method IL.Append(oldInstruction); }
public void ObfuscateFlow(TypeDefinition type, MethodDefinition method) { if (method.IsConstructor) { return; } if (method.IsRuntime) { return; } if (method.IsRuntimeSpecialName) { return; } if (method.IsSpecialName) { return; } if (method.IsVirtual) { return; } if (method.IsAbstract) { return; } if (method.Overrides.Count > 0) { return; } if (method.Name.StartsWith("<")) { return; } if (method.Body == null) { return; } if (method.Name.Contains("Dispose")) { return; } if (method.Name.Contains("ctor")) { return; } int count = method.Body.Instructions.Count - 1; if (count <= 1) { return; } CilWorker worker = method.Body.CilWorker; //Instruction insertSentencess = worker.Create(OpCodes.Testy); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[0], insertSentencess); //Instruction insertSentencesss = worker.Create(OpCodes.Br_S, method.Body.Instructions[2]); //method.Body.CilWorker.InsertBefore(method.Body.Instructions[1], insertSentencesss); //Instruction redirect22 = worker.Create(OpCodes.Ret); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[method.Body.Instructions.Count - 1], redirect22); List <Instruction> collection = new List <Instruction>(); //string collection2 = String.Empty; foreach (Instruction i in method.Body.Instructions) { collection.Add(i); } foreach (Instruction i in collection) { method.Body.Instructions.Remove(i); } method.Body.CilWorker.Append(collection[0]); for (int i = 1; i < collection.Count - 1; i++) { int position = r.Next(0, method.Body.Instructions.Count - 1); method.Body.CilWorker.InsertAfter(method.Body.Instructions[position], collection[i]); } int lastpos = 0; Instruction redirect = worker.Create(OpCodes.Br_S, method.Body.Instructions[method.Body.Instructions.IndexOf(collection[0]) + 1]); method.Body.CilWorker.InsertBefore(method.Body.Instructions[0], redirect); lastpos = method.Body.Instructions.IndexOf(collection[0]); for (int i = 1; i < collection.Count - 1; i++) { //try //{ int track = 0; if (lastpos < method.Body.Instructions.IndexOf(collection[i])) { track += 1; } //Instruction blank = worker.Create(OpCodes.Nop); //method.Body.CilWorker.InsertBefore(method.Body.Instructions[lastpos + 1], blank); Instruction redirect2 = worker.Create(OpCodes.Br_S, method.Body.Instructions[method.Body.Instructions.IndexOf(collection[i]) + track]); //method.Body.CilWorker.Remove(method.Body.Instructions[lastpos + 1]); method.Body.CilWorker.InsertBefore(method.Body.Instructions[lastpos + 1], redirect2); lastpos = method.Body.Instructions.IndexOf(collection[i]); //} //catch //{ // MessageBox.Show("Error"); //} } //Instruction redirect2 = worker.Create(OpCodes.Br_S, method.Body.Instructions[method.Body.Instructions.IndexOf(i)]); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[lastpos], redirect2); //Instruction in1 = worker.Create(OpCodes.Br_S, method.Body.Instructions[2]); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[1], in1); //Instruction in2 = worker.Create(OpCodes.Ldstr, "ajsndjkasndjknaskjdn"); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[1], in2); //Instruction in3 = worker.Create(OpCodes.Br_S, method.Body.Instructions[3]); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[1], in3); //Instruction in4 = worker.Create(OpCodes.Ldstr, "ajsndjkasndjknaskjdn"); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[1], in4); //Instruction in5 = worker.Create(OpCodes.Br_S, method.Body.Instructions[3]); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[1], in5); //Instruction in6 = worker.Create(OpCodes.Ldstr, "ajsndjkasndjknaskjdn"); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[1], in6); //Instruction in7 = worker.Create(OpCodes.Br_S, method.Body.Instructions[5]); //method.Body.CilWorker.InsertAfter(method.Body.Instructions[1], in7); }