public void AddLocals(MethodDefinition hostMethod) { _constructorArguments = hostMethod.AddLocal <List <object> >(); _currentArgument = hostMethod.AddLocal <object>(); _methodContext = hostMethod.AddLocal <ITypeActivationContext>(); _currentActivator = hostMethod.AddLocal <ITypeActivator>(); }
/// <summary> /// Adds a prolog to the given method body. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> that points to the given method body.</param> public void AddProlog(CilWorker IL) { MethodDefinition method = IL.GetMethod(); _surroundingImplementation = method.AddLocal <IAroundInvoke>(); _surroundingClassImplementation = method.AddLocal <IAroundInvoke>(); Instruction skipProlog = IL.Create(OpCodes.Nop); TypeDefinition declaringType = method.DeclaringType; ModuleDefinition module = declaringType.Module; TypeReference modifiableType = module.ImportType <IModifiableType>(); if (method.HasThis) { IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, modifiableType); IL.Emit(OpCodes.Brfalse, skipProlog); } IL.Emit(OpCodes.Ldloc, _interceptionDisabled); IL.Emit(OpCodes.Brtrue, skipProlog); // var provider = this.MethodReplacementProvider; if (_getMethodReplacementProvider != null) { _getMethodReplacementProvider.Emit(IL); } var getAroundInvokeProvider = new GetAroundInvokeProvider(_aroundInvokeProvider, _providerName); getAroundInvokeProvider.Emit(IL); // if (aroundInvokeProvider != null ) { Instruction skipGetSurroundingImplementation = IL.Create(OpCodes.Nop); var getSurroundingImplementationInstance = new GetSurroundingImplementationInstance(_aroundInvokeProvider, _invocationInfo, _surroundingImplementation, skipGetSurroundingImplementation); getSurroundingImplementationInstance.Emit(IL); // } IL.Append(skipGetSurroundingImplementation); var emitBeforeInvoke = new EmitBeforeInvoke(_invocationInfo, _surroundingClassImplementation, _surroundingImplementation, _registryType); emitBeforeInvoke.Emit(IL); IL.Append(skipProlog); }
/// <summary> /// Adds local variables to the <paramref name="hostMethod"/>. /// </summary> /// <param name="hostMethod">The target method.</param> public override void AddLocals(MethodDefinition hostMethod) { _exception = hostMethod.AddLocal <Exception>(); _invocationInfo = hostMethod.AddLocal <IInvocationInfo>(); _exceptionHandler = hostMethod.AddLocal <IExceptionHandler>(); _exceptionInfo = hostMethod.AddLocal <IExceptionHandlerInfo>(); var returnType = hostMethod.ReturnType.ReturnType; if (returnType != _voidType) { _returnValue = hostMethod.AddLocal <object>(); } }
/// <summary> /// Replaces the user code with a stub. /// Moves the original code to a new method /// </summary> /// <param name="td">The class containing the method </param> /// <param name="md">The method to be stubbed </param> /// <param name="ServerRpcAttr">The attribute that made this an RPC</param> /// <returns>The method containing the original code</returns> /// <remarks> /// Generates code like this: /// <code> /// public void MyServerRpc(float thrusting, int spin) /// { /// NetworkWriter networkWriter = new NetworkWriter(); /// networkWriter.Write(thrusting); /// networkWriter.WritePackedUInt32((uint) spin); /// base.SendServerRpcInternal(cmdName, networkWriter, cmdName); /// } /// /// public void UserCode_MyServerRpc(float thrusting, int spin) /// { /// // whatever the user was doing before /// /// } /// </code> /// </remarks> MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute serverRpcAttr) { MethodDefinition cmd = SubstituteMethod(md); ILProcessor worker = md.Body.GetILProcessor(); // NetworkWriter writer = NetworkWriterPool.GetWriter() VariableDefinition writer = md.AddLocal <PooledNetworkWriter>(); worker.Append(worker.Create(OpCodes.Call, md.Module.ImportReference(() => NetworkWriterPool.GetWriter()))); worker.Append(worker.Create(OpCodes.Stloc, writer)); // write all the arguments that the user passed to the Cmd call if (!WriteArguments(worker, md, writer, RemoteCallType.ServerRpc)) { return(cmd); } string cmdName = md.Name; int channel = serverRpcAttr.GetField("channel", 0); bool requireAuthority = serverRpcAttr.GetField("requireAuthority", true); // invoke internal send and return // load 'base.' to call the SendServerRpc function with worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Ldtoken, md.DeclaringType)); // invokerClass worker.Append(worker.Create(OpCodes.Call, () => Type.GetTypeFromHandle(default)));
static Instruction ProcessInstructionLoadAddress(MethodDefinition md, Instruction instr, FieldDefinition opField) { // does it set a field that we replaced? if (Weaver.WeaveLists.replacementSetterProperties.TryGetValue(opField, out MethodDefinition replacement)) { // we have a replacement for this property // is the next instruction a initobj? Instruction nextInstr = instr.Next; if (nextInstr.OpCode == OpCodes.Initobj) { // we need to replace this code with: // var tmp = new MyStruct(); // this.set_Networkxxxx(tmp); ILProcessor worker = md.Body.GetILProcessor(); VariableDefinition tmpVariable = md.AddLocal(opField.FieldType); worker.InsertBefore(instr, worker.Create(OpCodes.Ldloca, tmpVariable)); worker.InsertBefore(instr, worker.Create(OpCodes.Initobj, opField.FieldType)); worker.InsertBefore(instr, worker.Create(OpCodes.Ldloc, tmpVariable)); Instruction newInstr = worker.Create(OpCodes.Call, replacement); worker.InsertBefore(instr, newInstr); worker.Remove(instr); worker.Remove(nextInstr); return(newInstr); } } return(instr); }
/// <summary> /// Emits the instructions that will instantiate the current implementation. /// </summary> /// <param name="dependency">The dependency that describes the service to be instantiated.</param> /// <param name="serviceMap">The service map that contains the list of dependencies in the application.</param> /// <param name="targetMethod">The target method.</param> public void Emit(IDependency dependency, IDictionary <IDependency, IImplementation> serviceMap, MethodDefinition targetMethod) { var declaringType = targetMethod.DeclaringType; var module = declaringType.Module; var listType = typeof(List <>).MakeGenericType(_serviceType); var listCtor = module.ImportConstructor(listType, new System.Type[0]); var listVariable = targetMethod.AddLocal(listType); var IL = targetMethod.GetILGenerator(); IL.Emit(OpCodes.Newobj, listCtor); IL.Emit(OpCodes.Stloc, listVariable); var targetDependencies = (from d in serviceMap.Keys where d.ServiceType == _serviceType select d).ToArray(); var addItem = module.ImportMethod("Add", listType); var serviceType = module.Import(_serviceType); var currentService = targetMethod.AddLocal(_serviceType); foreach (var currentDependency in targetDependencies) { IL.Emit(OpCodes.Ldloc, listVariable); // Instantiate the current service type var implementation = new ContainerCall(currentDependency.ServiceType, currentDependency.ServiceName); implementation.Emit(currentDependency, serviceMap, targetMethod); IL.Emit(OpCodes.Isinst, serviceType); IL.Emit(OpCodes.Stloc, currentService); // Call IInitialize.Initialize(container) on the current service type _initializer.Initialize(IL, module, currentService); IL.Emit(OpCodes.Ldloc, currentService); IL.Emit(OpCodes.Callvirt, addItem); } var enumerableType = typeof(IEnumerable <>).MakeGenericType(_serviceType); var importedEnumerableType = module.Import(enumerableType); IL.Emit(OpCodes.Ldloc, listVariable); IL.Emit(OpCodes.Isinst, importedEnumerableType); }
/// <summary> /// Replaces the user code with a stub. /// Moves the original code to a new method /// </summary> /// <param name="td">The class containing the method </param> /// <param name="md">The method to be stubbed </param> /// <param name="ServerRpcAttr">The attribute that made this an RPC</param> /// <returns>The method containing the original code</returns> /// <remarks> /// Generates code like this: (Observers case) /// <code> /// public void Test (int param) /// { /// NetworkWriter writer = new NetworkWriter(); /// writer.WritePackedUInt32((uint) param); /// base.SendRpcInternal(typeof(class),"RpcTest", writer, 0); /// } /// public void UserCode_Test(int param) /// { /// // whatever the user did before /// } /// </code> /// /// Generates code like this: (Owner/Connection case) /// <code> /// public void TargetTest(NetworkConnection conn, int param) /// { /// NetworkWriter writer = new NetworkWriter(); /// writer.WritePackedUInt32((uint)param); /// base.SendTargetRpcInternal(conn, typeof(class), "TargetTest", val); /// } /// /// public void UserCode_TargetTest(NetworkConnection conn, int param) /// { /// // whatever the user did before /// } /// </code> /// or if no connection is specified /// /// <code> /// public void TargetTest (int param) /// { /// NetworkWriter writer = new NetworkWriter(); /// writer.WritePackedUInt32((uint) param); /// base.SendTargetRpcInternal(null, typeof(class), "TargetTest", val); /// } /// /// public void UserCode_TargetTest(int param) /// { /// // whatever the user did before /// } /// </code> /// </remarks> private MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute clientRpcAttr, int rpcIndex, ValueSerializer[] paramSerializers) { var rpc = SubstituteMethod(md); var worker = md.Body.GetILProcessor(); // if (IsClient) // { // call the body // } CallBody(worker, rpc); // NetworkWriter writer = NetworkWriterPool.GetWriter() var writer = md.AddLocal <PooledNetworkWriter>(); worker.Append(worker.Create(OpCodes.Call, () => NetworkWriterPool.GetWriter())); worker.Append(worker.Create(OpCodes.Stloc, writer)); // write all the arguments that the user passed to the Rpc call WriteArguments(worker, md, writer, paramSerializers, RemoteCallType.ClientRpc); var rpcName = md.FullName; var target = clientRpcAttr.GetField(nameof(ClientRpcAttribute.target), RpcTarget.Observers); var channel = clientRpcAttr.GetField(nameof(ClientRpcAttribute.channel), 0); var excludeOwner = clientRpcAttr.GetField(nameof(ClientRpcAttribute.excludeOwner), false); var sendMethod = GetSendMethod(md, target); // ClientRpcSender.Send(this, 12345, writer, channel, requireAuthority) worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Ldc_I4, rpcIndex)); worker.Append(worker.Create(OpCodes.Ldloc, writer)); worker.Append(worker.Create(OpCodes.Ldc_I4, channel)); // last arg of send is either bool, or NetworkPlayer // see ClientRpcSender.Send methods if (target == RpcTarget.Observers) { worker.Append(worker.Create(excludeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0)); } else if (target == RpcTarget.Player && HasNetworkPlayerParameter(md)) { worker.Append(worker.Create(OpCodes.Ldarg_1)); } else // owner, or Player with no arg { worker.Append(worker.Create(OpCodes.Ldnull)); } worker.Append(worker.Create(OpCodes.Call, sendMethod)); NetworkWriterHelper.CallRelease(module, worker, writer); worker.Append(worker.Create(OpCodes.Ret)); return(rpc); }
private void Create_CryptGet(TypeDefinition moduleType) { var getUtf8 = ModuleDefinition.ImportReference(typeof(Encoding).GetMethod("get_UTF8", Type.EmptyTypes)); var getString = ModuleDefinition.ImportReference(typeof(Encoding).GetMethod("GetString", new Type[] { typeof(byte[]), typeof(Int32), typeof(Int32) })); var lazyValue = ModuleDefinition.ImportReference(typeof(Lazy <byte[]>).GetMethod("get_Value")); var intern = ModuleDefinition.ImportReference(typeof(string).GetMethod("Intern", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)); _cryptGetMethod = new MethodDefinition($"CryptGet_{_id}", MethodAttributes.HideBySig | MethodAttributes.Static, ModuleDefinition.ImportReference(typeof(string))); _cryptGetMethod.Parameters.Add(new ParameterDefinition("ndx", ParameterAttributes.None, ModuleDefinition.ImportReference(typeof(int)))); _cryptGetMethod.Parameters.Add(new ParameterDefinition("len", ParameterAttributes.None, ModuleDefinition.ImportReference(typeof(int)))); _cryptGetMethod.Parameters.Add(new ParameterDefinition("i", ParameterAttributes.None, ModuleDefinition.ImportReference(typeof(int)))); AddAttrs(_cryptGetMethod.CustomAttributes); _cryptGetMethod.DeclaringType = moduleType; _cryptGetMethod.Body = new MethodBody(_cryptGetMethod); var il = _cryptGetMethod.Body.GetILProcessor(); _cryptGetMethod.Body.SimplifyMacros(); _cryptGetMethod.Body.InitLocals = true; _cryptGetMethod.AddLocal(typeof(string)); var loadReturnVal = il.Create(OpCodes.Ldloc_0); il.Append(il.Create(OpCodes.Ldsfld, _stringsArrayField)); il.Append(il.Create(OpCodes.Ldarg_2)); il.Append(il.Create(OpCodes.Ldelem_Ref)); il.Append(il.Create(OpCodes.Stloc_0)); il.Append(il.Create(OpCodes.Ldloc_0)); il.Append(il.Create(OpCodes.Brtrue_S, loadReturnVal)); il.Append(il.Create(OpCodes.Call, getUtf8)); il.Append(il.Create(OpCodes.Ldsfld, _decryptedField)); il.Append(il.Create(OpCodes.Callvirt, lazyValue)); il.Append(il.Create(OpCodes.Ldarg_0)); il.Append(il.Create(OpCodes.Ldarg_1)); il.Append(il.Create(OpCodes.Callvirt, getString)); il.Append(il.Create(OpCodes.Call, intern)); il.Append(il.Create(OpCodes.Stloc_0)); il.Append(il.Create(OpCodes.Ldsfld, _stringsArrayField)); il.Append(il.Create(OpCodes.Ldarg_2)); il.Append(il.Create(OpCodes.Ldloc_0)); il.Append(il.Create(OpCodes.Stelem_Ref)); il.Append(loadReturnVal); il.Append(il.Create(OpCodes.Ret)); moduleType.Methods.Add(_cryptGetMethod); _cryptGetMethod.Body.OptimizeMacros(); }
// this is required to early-out from a function with a return value. static void InjectGuardReturnValue(MethodDefinition md, ILProcessor worker, Instruction top) { if (!md.ReturnType.Is(typeof(void))) { VariableDefinition returnLocal = md.AddLocal(md.ReturnType); worker.InsertBefore(top, worker.Create(OpCodes.Ldloca_S, returnLocal)); worker.InsertBefore(top, worker.Create(OpCodes.Initobj, md.ReturnType)); worker.InsertBefore(top, worker.Create(OpCodes.Ldloc, returnLocal)); } }
/// <summary> /// Rewrites the instructions in the target method body. /// </summary> /// <param name="method">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 method, CilWorker IL, IEnumerable <Instruction> oldInstructions) { if (IsExcluded(method)) { AddOriginalInstructions(IL, oldInstructions); return; } VariableDefinition interceptionDisabled = method.AddLocal <bool>(); VariableDefinition invocationInfo = method.AddLocal <IInvocationInfo>(); VariableDefinition aroundInvokeProvider = method.AddLocal <IAroundInvokeProvider>(); VariableDefinition methodReplacementProvider = method.AddLocal <IMethodReplacementProvider>(); VariableDefinition returnValue = method.AddLocal <object>(); VariableDefinition classMethodReplacementProvider = method.AddLocal <IMethodReplacementProvider>(); Func <ModuleDefinition, MethodReference> getInstanceMethodReplacementProviderMethod = module => module.Import(typeof(IMethodReplacementHost).GetMethod("get_MethodBodyReplacementProvider")); var parameters = new MethodBodyRewriterParameters(IL, oldInstructions, interceptionDisabled, invocationInfo, returnValue, methodReplacementProvider, aroundInvokeProvider, classMethodReplacementProvider, getInstanceMethodReplacementProviderMethod, typeof(AroundMethodBodyRegistry)); var emitter = new InvocationInfoEmitter(true); IInstructionEmitter getMethodReplacementProvider = new GetMethodReplacementProvider(methodReplacementProvider, method, getInstanceMethodReplacementProviderMethod); IInstructionEmitter getInterceptionDisabled = new GetInterceptionDisabled(parameters); ISurroundMethodBody surroundMethodBody = new SurroundMethodBody(parameters, "AroundMethodBodyProvider"); IInstructionEmitter getClassMethodReplacementProvider = new GetClassMethodReplacementProvider(parameters, module => module.Import( typeof( MethodBodyReplacementProviderRegistry ). GetMethod ("GetProvider"))); IInstructionEmitter addMethodReplacement = new AddMethodReplacementImplementation(parameters); var rewriter = new InterceptAndSurroundMethodBody(emitter, getInterceptionDisabled, surroundMethodBody, getMethodReplacementProvider, getClassMethodReplacementProvider, addMethodReplacement, parameters); // Determine whether or not the method should be intercepted rewriter.Rewrite(method, IL, oldInstructions); }
private static void DefineSerializationConstructor(ModuleDefinition module, TypeDefinition targetType) { MethodReference getTypeFromHandle = module.ImportMethod <Type>("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static); var parameterTypes = new[] { typeof(SerializationInfo), typeof(StreamingContext) }; // Define the constructor signature MethodDefinition serializationCtor = targetType.AddDefaultConstructor(); serializationCtor.AddParameters(parameterTypes); serializationCtor.Attributes = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Public; TypeReference interceptorInterfaceType = module.ImportType <IInterceptor>(); VariableDefinition interceptorTypeVariable = serializationCtor.AddLocal <Type>(); MethodBody body = serializationCtor.Body; body.InitLocals = true; CilWorker IL = serializationCtor.GetILGenerator(); IL.Emit(OpCodes.Ldtoken, interceptorInterfaceType); IL.Emit(OpCodes.Call, getTypeFromHandle); IL.Emit(OpCodes.Stloc, interceptorTypeVariable); MethodReference defaultConstructor = module.ImportConstructor <object>(); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Call, defaultConstructor); // __interceptor = (IInterceptor)info.GetValue("__interceptor", typeof(IInterceptor)); MethodReference getValue = module.ImportMethod <SerializationInfo>("GetValue"); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Ldarg_1); IL.Emit(OpCodes.Ldstr, "__interceptor"); IL.Emit(OpCodes.Ldloc, interceptorTypeVariable); IL.Emit(OpCodes.Callvirt, getValue); IL.Emit(OpCodes.Castclass, interceptorInterfaceType); MethodReference setInterceptor = module.ImportMethod <IProxy>("set_Interceptor"); IL.Emit(OpCodes.Callvirt, setInterceptor); ; IL.Emit(OpCodes.Ret); }
/// <summary> /// Replaces the user code with a stub. /// Moves the original code to a new method /// </summary> /// <param name="td">The class containing the method </param> /// <param name="md">The method to be stubbed </param> /// <param name="ServerRpcAttr">The attribute that made this an RPC</param> /// <returns>The method containing the original code</returns> /// <remarks> /// Generates code like this: (Observers case) /// <code> /// public void Test (int param) /// { /// NetworkWriter writer = new NetworkWriter(); /// writer.WritePackedUInt32((uint) param); /// base.SendRpcInternal(typeof(class),"RpcTest", writer, 0); /// } /// public void UserCode_Test(int param) /// { /// // whatever the user did before /// } /// </code> /// /// Generates code like this: (Owner/Connection case) /// <code> /// public void TargetTest(NetworkConnection conn, int param) /// { /// NetworkWriter writer = new NetworkWriter(); /// writer.WritePackedUInt32((uint)param); /// base.SendTargetRpcInternal(conn, typeof(class), "TargetTest", val); /// } /// /// public void UserCode_TargetTest(NetworkConnection conn, int param) /// { /// // whatever the user did before /// } /// </code> /// or if no connection is specified /// /// <code> /// public void TargetTest (int param) /// { /// NetworkWriter writer = new NetworkWriter(); /// writer.WritePackedUInt32((uint) param); /// base.SendTargetRpcInternal(null, typeof(class), "TargetTest", val); /// } /// /// public void UserCode_TargetTest(int param) /// { /// // whatever the user did before /// } /// </code> /// </remarks> MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute clientRpcAttr) { MethodDefinition rpc = SubstituteMethod(md); ILProcessor worker = md.Body.GetILProcessor(); // if (IsClient) // { // call the body // } CallBody(worker, rpc); // NetworkWriter writer = NetworkWriterPool.GetWriter() VariableDefinition writer = md.AddLocal <PooledNetworkWriter>(); worker.Append(worker.Create(OpCodes.Call, () => NetworkWriterPool.GetWriter())); worker.Append(worker.Create(OpCodes.Stloc, writer)); // write all the arguments that the user passed to the Rpc call if (!WriteArguments(worker, md, writer, RemoteCallType.ClientRpc)) { return(rpc); } string rpcName = md.Name; Client target = clientRpcAttr.GetField("target", Client.Observers); int channel = clientRpcAttr.GetField("channel", 0); bool excludeOwner = clientRpcAttr.GetField("excludeOwner", false); // invoke SendInternal and return // this worker.Append(worker.Create(OpCodes.Ldarg_0)); if (target == Client.Connection && HasNetworkConnectionParameter(md)) { worker.Append(worker.Create(OpCodes.Ldarg_1)); } else if (target == Client.Owner) { worker.Append(worker.Create(OpCodes.Ldnull)); } worker.Append(worker.Create(OpCodes.Ldtoken, md.DeclaringType.ConvertToGenericIfNeeded())); // invokerClass worker.Append(worker.Create(OpCodes.Call, () => Type.GetTypeFromHandle(default)));
/// <summary> /// Replaces the user code with a stub. /// Moves the original code to a new method /// </summary> /// <param name="td">The class containing the method </param> /// <param name="md">The method to be stubbed </param> /// <param name="ServerRpcAttr">The attribute that made this an RPC</param> /// <returns>The method containing the original code</returns> /// <remarks> /// Generates code like this: /// <code> /// public void MyServerRpc(float thrusting, int spin) /// { /// NetworkWriter networkWriter = new NetworkWriter(); /// networkWriter.Write(thrusting); /// networkWriter.WritePackedUInt32((uint) spin); /// base.SendServerRpcInternal(cmdName, networkWriter, cmdName); /// } /// /// public void UserCode_MyServerRpc(float thrusting, int spin) /// { /// // whatever the user was doing before /// /// } /// </code> /// </remarks> private MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute serverRpcAttr, int rpcIndex, ValueSerializer[] paramSerializers) { var cmd = SubstituteMethod(md); var worker = md.Body.GetILProcessor(); // if (IsServer) // { // call the body // return; // } CallBody(worker, cmd); // NetworkWriter writer = NetworkWriterPool.GetWriter() var writer = md.AddLocal <PooledNetworkWriter>(); worker.Append(worker.Create(OpCodes.Call, md.Module.ImportReference(() => NetworkWriterPool.GetWriter()))); worker.Append(worker.Create(OpCodes.Stloc, writer)); // write all the arguments that the user passed to the Cmd call WriteArguments(worker, md, writer, paramSerializers, RemoteCallType.ServerRpc); var cmdName = md.FullName; var channel = serverRpcAttr.GetField(nameof(ServerRpcAttribute.channel), 0); var requireAuthority = serverRpcAttr.GetField(nameof(ServerRpcAttribute.requireAuthority), true); var sendMethod = GetSendMethod(md, worker); // ServerRpcSender.Send(this, 12345, writer, channel, requireAuthority) worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Ldc_I4, rpcIndex)); worker.Append(worker.Create(OpCodes.Ldloc, writer)); worker.Append(worker.Create(OpCodes.Ldc_I4, channel)); worker.Append(worker.Create(requireAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0)); worker.Append(worker.Create(OpCodes.Call, sendMethod)); NetworkWriterHelper.CallRelease(module, worker, writer); worker.Append(worker.Create(OpCodes.Ret)); return(cmd); }
// this is required to early-out from a function with "ref" or "out" parameters static void InjectGuardParameters(MethodDefinition md, ILProcessor worker, Instruction top) { int offset = md.Resolve().IsStatic ? 0 : 1; for (int index = 0; index < md.Parameters.Count; index++) { ParameterDefinition param = md.Parameters[index]; if (param.IsOut) { TypeReference elementType = param.ParameterType.GetElementType(); VariableDefinition elementLocal = md.AddLocal(elementType); worker.InsertBefore(top, worker.Create(OpCodes.Ldarg, index + offset)); worker.InsertBefore(top, worker.Create(OpCodes.Ldloca_S, elementLocal)); worker.InsertBefore(top, worker.Create(OpCodes.Initobj, elementType)); worker.InsertBefore(top, worker.Create(OpCodes.Ldloc, elementLocal)); worker.InsertBefore(top, worker.Create(OpCodes.Stobj, elementType)); } } }
/// <summary> /// Adds locals to the target method. /// </summary> /// <param name="hostMethod">The method to be modified</param> public override void AddLocals(MethodDefinition hostMethod) { _fieldContext = hostMethod.AddLocal <IFieldInterceptionContext>("__<>FieldInterceptionContext<>__"); _fieldInterceptor = hostMethod.AddLocal <IFieldInterceptor>("__<>FieldInterceptor<>__"); _currentArgument = hostMethod.AddLocal <object>("__<>CurrentArgument<>__"); }
/// <summary> /// Generates a method body for the <paramref name="targetMethod"/>. /// </summary> /// <param name="originalMethod">The method currently being intercepted.</param> /// <param name="targetMethod">The target method that will contain the new method body.</param> public void Emit(MethodInfo originalMethod, MethodDefinition targetMethod) { var invocationInfo = targetMethod.AddLocal <IInvocationInfo>(); invocationInfo.Name = "___invocationInfo___"; // Emit the code to generate the IInvocationInfo instance // and save it into the invocationInfo local variable if (InvocationInfoEmitter != null) { InvocationInfoEmitter.Emit(originalMethod, targetMethod, invocationInfo); } var declaringType = targetMethod.DeclaringType; var module = declaringType.Module; var proxyType = module.ImportType <IProxy>(); var getInterceptorMethod = module.ImportMethod("get_Interceptor", typeof(IProxy)); var interceptor = targetMethod.AddLocal <IInterceptor>(); var arguments = targetMethod.AddLocal <object[]>(); // if (!(this is IProxy)) var IL = targetMethod.GetILGenerator(); IL.Emit(OpCodes.Ldarg_0); IL.Emit(OpCodes.Isinst, proxyType); var noImplementationFound = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Brfalse, noImplementationFound); var endLabel = IL.Create(OpCodes.Nop); EmitGetInterceptorInstruction(IL, proxyType, getInterceptorMethod); IL.Emit(OpCodes.Stloc, interceptor); //If (interceptor == null) // throw a not implemented exception here IL.Emit(OpCodes.Ldloc, interceptor); IL.Emit(OpCodes.Brfalse, noImplementationFound); // var returnValue = interceptor.Intercept(info); var voidType = module.ImportType(typeof(void)); var interceptMethod = module.ImportMethod <IInterceptor>("Intercept", typeof(IInvocationInfo)); IL.Emit(OpCodes.Ldloc, interceptor); IL.Emit(OpCodes.Ldloc, invocationInfo); IL.Emit(OpCodes.Callvirt, interceptMethod); // Save the ref arguments var parameters = from ParameterDefinition param in targetMethod.Parameters select param; // Determine the return type var returnType = targetMethod.ReturnType != null ? targetMethod.ReturnType.ReturnType : voidType; IL.PackageReturnValue(module, returnType); SaveRefArguments(IL, parameters, invocationInfo, arguments); IL.Emit(OpCodes.Br, endLabel); // This code at this point will execute if no implementation // is found IL.Append(noImplementationFound); ImplementNotFound(IL); IL.Append(endLabel); IL.Emit(OpCodes.Ret); }
public override void AddLocals(MethodDefinition hostMethod) { var body = hostMethod.Body; body.InitLocals = true; _currentArguments = hostMethod.AddLocal <Stack <object> >("__arguments"); _currentArgument = hostMethod.AddLocal <object>("__currentArgument"); _parameterTypes = hostMethod.AddLocal <Type[]>("__parameterTypes"); _typeArguments = hostMethod.AddLocal <Type[]>("__typeArguments"); _invocationInfo = hostMethod.AddLocal <IInvocationInfo>("___invocationInfo"); _target = hostMethod.AddLocal <object>("__target"); _replacement = hostMethod.AddLocal <IInterceptor>("__interceptor"); _canReplaceFlag = hostMethod.AddLocal <bool>("__canReplace"); _staticProvider = hostMethod.AddLocal <IMethodReplacementProvider>("__staticProvider"); _instanceProvider = hostMethod.AddLocal <IMethodReplacementProvider>("__instanceProvider"); _interceptionDisabled = hostMethod.AddLocal <bool>(); _methodReplacementProvider = hostMethod.AddLocal <IMethodReplacementProvider>(); _aroundInvokeProvider = hostMethod.AddLocal <IAroundInvokeProvider>(); _returnValue = hostMethod.AddLocal <object>(); }
/// <summary> /// Adds a named <see cref="VariableDefinition">local variable</see> /// instance to the target <paramref name="methodDef">method definition</paramref>. /// </summary> /// <typeparam name="T">The object <see cref="System.Type">type</see> that describes the type of objects that will be stored by the local variable.</typeparam> /// <param name="methodDef">The <paramref name="methodDef"/> instance which will contain the local variable.</param> /// <param name="variableName">The name of the local variable.</param> /// <returns>A <see cref="VariableDefinition"/> that represents the local variable itself.</returns> public static VariableDefinition AddLocal <T>(this MethodDefinition methodDef, string variableName) { return(methodDef.AddLocal(variableName, typeof(T))); }
/// <summary> /// Adds a <see cref="VariableDefinition">local variable</see> /// instance to the target <paramref name="methodDef">method definition</paramref>. /// </summary> /// <typeparam name="T">The object <see cref="System.Type">type</see> that describes the type of objects that will be stored by the local variable.</typeparam> /// <param name="methodDef">The <paramref name="methodDef"/> instance which will contain the local variable.</param> /// <returns>A <see cref="VariableDefinition"/> that represents the local variable itself.</returns> public static VariableDefinition AddLocal <T>(this MethodDefinition methodDef) { return(methodDef.AddLocal(typeof(T))); }
protected override void WeaveOriginalTarget() { var index = method.Body.Instructions.IndexOf(instruction); if (index == -1) { throw new BytecodeWeavingException("Instruction not found '{0}' in method '{1}'".FormatWith(instruction, method)); } var dispatcher = new MethodDefinition("Dispatcher", MethodAttributes.Static | MethodAttributes.Public, returnType ?? Module.Import(typeof(void))); jpStaticClass.Methods.Add(dispatcher); var il = dispatcher.Body.GetILProcessor(); il.Append(OpCodes.Nop); if (targetType != null) { var target = new ParameterDefinition(targetType); dispatcher.Parameters.Add(target); il.Append(OpCodes.Ldarg, target); if (targetType.IsValueType) { il.Append(OpCodes.Box, targetType); } } else { il.Append(OpCodes.Ldnull); } var args = dispatcher.AddLocal(typeof(object[])); var typeOfObject = Module.Import(typeof(object)); il.Append(OpCodes.Ldc_I4, argTypes.Length); il.Append(OpCodes.Newarr, typeOfObject); il.Append(OpCodes.Stloc, args); for (var i = 0; i < argTypes.Length; i++) { var arg = new ParameterDefinition(argTypes[i]); dispatcher.Parameters.Add(arg); il.Append(OpCodes.Ldloc, args); il.Append(OpCodes.Ldc_I4, i); il.Append(OpCodes.Ldarg, arg); if (argTypes[i].IsValueType) { il.Append(OpCodes.Box, argTypes[i]); } il.Append(OpCodes.Stelem_Ref); } if (!method.IsStatic) { var thisType = method.DeclaringType.MakeGenerics(JpThisGenericParams); var arg = new ParameterDefinition("sac$this", ParameterAttributes.None, thisType); dispatcher.Parameters.Add(arg); il.Append(OpCodes.Ldarg, arg); if (thisType.IsValueType) { il.Append(OpCodes.Box, thisType); } } else { il.Append(OpCodes.Ldnull); } AppendCallDispatch(il, args, jpStaticClass.MakeGenericSelf()); if (returnsVoid) { il.Append(OpCodes.Pop); } else if (returnType.IsValueType) { il.Append(OpCodes.Unbox_Any, Module.Import(returnType)); } il.Append(OpCodes.Ret); // Dispatcher requires extra param (ThisInstance), but previous weaver might have been here if (!method.IsStatic && !isPreviouslyWeaved) { method.Body.GetILProcessor().InsertBefore(instruction, Instruction.Create(OpCodes.Ldarg_0)); } instruction.OpCode = OpCodes.Call; instruction.Operand = dispatcher.MakeHostInstanceGeneric(GetRefThisToJpStatic()); }
public void Rewrite(MethodDefinition method, ModuleDefinition module) { // Ignore methods that have already been modified var customAttributes = method.CustomAttributes; if (customAttributes.Any(c => c.AttributeType == _markerAttributeType)) { return; } var body = method.Body; body.InitLocals = true; var oldInstructions = body.Instructions.ToArray(); var callInstructions = oldInstructions.Where(instruction => instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt).ToArray(); var constructorCalls = oldInstructions.Where(instruction => instruction.OpCode == OpCodes.Newobj).ToArray(); // Skip the method if there are no calls to intercept if (callInstructions.Any() || constructorCalls.Any()) { // Clear the method body if and only if there are methods // that need to be intercepted body.Instructions.Clear(); var objectType = module.ImportType <object>(); var il = body.GetILProcessor(); var targetMethods = callInstructions.Select(instruction => instruction.Operand as MethodReference).ToArray(); var constructors = constructorCalls.Select(instruction => instruction.Operand as MethodReference).Where(c => c.DeclaringType != objectType).ToArray(); // Save the calling method il.PushMethod(method, module); il.Emit(OpCodes.Stloc, _callingMethod); // Precalculate all method call interceptors var provider = method.AddLocal <IMethodCallProvider>(); var getProvider = module.ImportMethod("GetProvider", typeof(MethodCallProviderRegistry)); // Obtain the method call provider instance il.Emit(OpCodes.Call, getProvider); il.Emit(OpCodes.Stloc, provider); il.PushMethod(method, module); var hasMap = module.ImportMethod("ContainsMapFor", typeof(MethodCallMapRegistry), BindingFlags.Public | BindingFlags.Static); il.Emit(OpCodes.Call, hasMap); il.Emit(OpCodes.Stloc, _hasExistingMap); // Instantiate the map var createMap = module.ImportMethod("GetMap", typeof(MethodCallMapRegistry), BindingFlags.Public | BindingFlags.Static); il.PushMethod(method, module); il.Emit(OpCodes.Call, createMap); il.Emit(OpCodes.Stloc, _callMap); var skipCallMapConstruction = il.Create(OpCodes.Nop); il.Emit(OpCodes.Ldloc, _callMap); il.Emit(OpCodes.Brfalse, skipCallMapConstruction); // Reuse the existing map if possible il.Emit(OpCodes.Ldloc, _hasExistingMap); il.Emit(OpCodes.Brtrue, skipCallMapConstruction); il.Emit(OpCodes.Ldloc, provider); il.Emit(OpCodes.Brfalse, skipCallMapConstruction); // if (provider != null) { var interceptedMethods = new List <MethodReference>(); interceptedMethods.AddRange(targetMethods); interceptedMethods.AddRange(constructors); // Store the list of intercepted methods var targetMethodCount = interceptedMethods.Count; il.Emit(OpCodes.Ldc_I4, targetMethodCount); il.Emit(OpCodes.Newarr, module.ImportType <MethodBase>()); il.Emit(OpCodes.Stloc, _interceptedMethods); // Populate the array of intercepted methods for (var i = 0; i < targetMethodCount; i++) { var currentMethod = interceptedMethods[i]; il.Emit(OpCodes.Ldloc, _interceptedMethods); il.Emit(OpCodes.Ldc_I4, i); il.PushMethod(currentMethod, module); il.Emit(OpCodes.Stelem_Ref); } // Build the list of intercepted methods il.Emit(OpCodes.Ldloc, provider); il.Emit(OpCodes.Ldloc, _target); il.PushMethod(method, module); il.Emit(OpCodes.Ldloc, _interceptedMethods); il.Emit(OpCodes.Ldloc, _callMap); il.PushStackTrace(module); il.Emit(OpCodes.Callvirt, _addMethodCalls); il.Append(skipCallMapConstruction); foreach (var instruction in oldInstructions) { var opCode = instruction.OpCode; if (opCode == OpCodes.Newobj) { il.Emit(OpCodes.Newobj, _stackCtor); il.Emit(OpCodes.Stloc, _currentArguments); ReplaceConstructorCall(instruction, method, il); continue; } if (opCode != OpCodes.Call && opCode != OpCodes.Callvirt) { il.Append(instruction); continue; } // Create the stack that will hold the method arguments il.Emit(OpCodes.Newobj, _stackCtor); il.Emit(OpCodes.Stloc, _currentArguments); if (opCode == OpCodes.Call || opCode == OpCodes.Callvirt) { ReplaceMethodCallInstruction(instruction, method, il); } } } // Add the attribute marker so that this method is only modified once customAttributes.Add(new CustomAttribute(_markerAttributeCtor)); }
public void AddLocals(MethodDefinition hostMethod) { _currentArguments = hostMethod.AddLocal <Stack <object> >("__arguments"); _currentArgument = hostMethod.AddLocal <object>("__currentArgument"); _invocationInfo = hostMethod.AddLocal <IInvocationInfo>("___invocationInfo"); _currentMethodCall = hostMethod.AddLocal <IMethodCall>("___currentMethodCall"); _target = hostMethod.AddLocal <object>("__target"); _parameterTypes = hostMethod.AddLocal <Type[]>("__parameterTypes"); _typeArguments = hostMethod.AddLocal <Type[]>("__typeArguments"); _interceptedMethods = hostMethod.AddLocal <MethodBase[]>("___interceptedMethods"); _callMap = hostMethod.AddLocal <IMethodCallMap>(); _hasMethodCall = hostMethod.AddLocal <bool>(); _currentMethod = hostMethod.AddLocal <MethodBase>(); _stackTrace = hostMethod.AddLocal <StackTrace>(); _currentArgsAsArray = hostMethod.AddLocal <object[]>(); _hasExistingMap = hostMethod.AddLocal <bool>(); _callingMethod = hostMethod.AddLocal <MethodBase>(); }
private void FinishDecryptor() { var moduleType = _decryptMethod.DeclaringType; var il = _decryptMethod.Body.GetILProcessor(); _decryptMethod.Body.InitLocals = true; VariableDefinition keyBytes = _decryptMethod.AddLocal(typeof(byte[])); VariableDefinition aesProvider = _decryptMethod.AddLocal(typeof(AesCryptoServiceProvider)); VariableDefinition cryptoTransform = _decryptMethod.AddLocal(typeof(ICryptoTransform)); VariableDefinition memStream = _decryptMethod.AddLocal(typeof(MemoryStream)); VariableDefinition cryptoStream = _decryptMethod.AddLocal(typeof(CryptoStream)); // Get references to the methods we'll be calling. var aesCtor = ModuleDefinition.ImportReference(typeof(AesCryptoServiceProvider).GetConstructor(Type.EmptyTypes)); var setPadding = ModuleDefinition.ImportReference(typeof(SymmetricAlgorithm).GetMethod("set_Padding", new[] { typeof(PaddingMode) })); var fromBase64 = ModuleDefinition.ImportReference(typeof(Convert).GetMethod("FromBase64String", new[] { typeof(string) })); var createDecryptor = ModuleDefinition.ImportReference(typeof(SymmetricAlgorithm).GetMethod("CreateDecryptor", new[] { typeof(byte[]), typeof(byte[]) })); var memStreamCtor = ModuleDefinition.ImportReference(typeof(MemoryStream).GetConstructor(new[] { typeof(byte[]) })); var cryptoStreamCtor = ModuleDefinition.ImportReference(typeof(CryptoStream).GetConstructor(new[] { typeof(Stream), typeof(ICryptoTransform), typeof(CryptoStreamMode) })); var readStream = ModuleDefinition.ImportReference(typeof(Stream).GetMethod("Read", new[] { typeof(byte[]), typeof(int), typeof(int) })); var disposeStream = ModuleDefinition.ImportReference(typeof(Stream).GetMethod("Dispose", Type.EmptyTypes)); var dispose = ModuleDefinition.ImportReference(typeof(IDisposable).GetMethod("Dispose", Type.EmptyTypes)); var disposeSymmetric = ModuleDefinition.ImportReference(typeof(SymmetricAlgorithm).GetMethod("Dispose", Type.EmptyTypes)); il.Append(il.Create(OpCodes.Ldstr, Convert.ToBase64String(_key))); il.Append(il.Create(OpCodes.Call, fromBase64)); il.Append(il.Create(OpCodes.Stloc_0)); il.Append(il.Create(OpCodes.Newobj, aesCtor)); il.Append(il.Create(OpCodes.Stloc_1)); il.Append(il.Create(OpCodes.Ldloc_1)); il.Append(il.Create(OpCodes.Ldc_I4_1)); il.Append(il.Create(OpCodes.Callvirt, setPadding)); il.Append(il.Create(OpCodes.Ldloc_1)); il.Append(il.Create(OpCodes.Ldloc_0)); il.Append(il.Create(OpCodes.Ldloc_0)); il.Append(il.Create(OpCodes.Callvirt, createDecryptor)); il.Append(il.Create(OpCodes.Stloc_2)); il.Append(il.Create(OpCodes.Ldstr, _cipherBytes)); il.Append(il.Create(OpCodes.Call, fromBase64)); il.Append(il.Create(OpCodes.Newobj, memStreamCtor)); il.Append(il.Create(OpCodes.Stloc_3)); il.Append(il.Create(OpCodes.Ldloc_3)); il.Append(il.Create(OpCodes.Ldloc_2)); il.Append(il.Create(OpCodes.Ldc_I4_0)); il.Append(il.Create(OpCodes.Newobj, cryptoStreamCtor)); il.Append(il.Create(OpCodes.Stloc_S, cryptoStream)); il.Append(il.Create(OpCodes.Ldc_I4, _byteCount)); il.Append(il.Create(OpCodes.Newarr, ModuleDefinition.Import(typeof(byte)))); il.Append(il.Create(OpCodes.Stsfld, _decryptedField)); il.Append(il.Create(OpCodes.Ldloc_S, cryptoStream)); il.Append(il.Create(OpCodes.Ldsfld, _decryptedField)); il.Append(il.Create(OpCodes.Ldc_I4_0)); il.Append(il.Create(OpCodes.Ldc_I4, _byteCount)); il.Append(il.Create(OpCodes.Callvirt, readStream)); il.Append(il.Create(OpCodes.Pop)); il.Append(il.Create(OpCodes.Ldloc_S, cryptoStream)); il.Append(il.Create(OpCodes.Callvirt, disposeStream)); il.Append(il.Create(OpCodes.Ldloc_3)); il.Append(il.Create(OpCodes.Callvirt, disposeStream)); il.Append(il.Create(OpCodes.Ldloc_2)); il.Append(il.Create(OpCodes.Callvirt, dispose)); il.Append(il.Create(OpCodes.Ldloc_1)); il.Append(il.Create(OpCodes.Callvirt, disposeSymmetric)); il.Append(il.Create(OpCodes.Ret)); }