/// <summary> /// Hook a field by injecting a static "setter" method. /// If target field is a static field, your setter should accept a value that is originally used to write the field. /// If target field is not a static field, your setter should accept a object having the field followed by a value. /// Your setter method should not have any return value. /// </summary> /// <param name="target field"></param> /// <param name="hook method">your "setter"</param> /// <param name="resolver">This is used to find every IL instruction that writes the field.</param> /// <param name="hookName"></param> static public void HookFieldWrite(FieldDefinition target, MethodDefinition hookMethod, ReferenceResolver resolver = null, string hookName = null) { if (hookName == null) { hookName = target.Name + "__hookwrite__" + hookMethod.Name; } if (resolver == null) { resolver = new ReferenceResolver(); resolver.ScanAssembly(target.DeclaringType.Module.Assembly); } var injectedMethod = InjectMethod(target.DeclaringType, hookMethod, hookName); var references = resolver.FindAllReferences(target); foreach (var reference in references) { if (reference.instruction.OpCode == OpCodes.Stfld || reference.instruction.OpCode == OpCodes.Stsfld) { reference.instruction.OpCode = OpCodes.Call; reference.instruction.Operand = injectedMethod; } } }
/// <summary> /// Replace target method with your hook method. /// To call the original method, just call hook method from the hook method. /// </summary> /// <param name="target method"></param> /// <param name="hook method"></param> /// <param name="resolver">This is used to find all instructions that call the target method.</param> /// <param name="hook prefix">This will be used as the prefix of the original target method.</param> static public void HookMethod(MethodDefinition targetMethod, MethodDefinition hookMethod, ReferenceResolver resolver = null, string hookPrefix = "__hooked__") { if (resolver == null) { resolver = new ReferenceResolver(); resolver.ScanAssembly(targetMethod.DeclaringType.Module.Assembly); } var injectedMethod = InjectMethod(targetMethod.DeclaringType, hookMethod); injectedMethod.Attributes = targetMethod.Attributes; if (!targetMethod.IsStatic && hookMethod.IsStatic) { // first argument is keyword "this" injectedMethod.HasThis = true; injectedMethod.Parameters.RemoveAt(0); // should not appear here } // rename original method injectedMethod.Name = targetMethod.Name; targetMethod.Name = hookPrefix + targetMethod.Name; // replace the original method with the new one resolver.ReplaceAllReferences(targetMethod, injectedMethod); // process self-calls for (int i = 0; i < injectedMethod.Body.Instructions.Count; ++i) { var ins = injectedMethod.Body.Instructions[i]; if (ins.OpCode == OpCodes.Call || ins.OpCode == OpCodes.Callvirt) { if ((ins.Operand as MethodReference).FullName == hookMethod.FullName) { ins.Operand = targetMethod; } } } }