public static MethodAttributes ConvertToHookAttributes(this MethodAttributes originalAttrs) { var newAttrs = originalAttrs; newAttrs &= ~(MethodAttributes.Assembly | MethodAttributes.Private); newAttrs |= MethodAttributes.Public; return(newAttrs); }
static void RemoveCall(MethodDef method) { var instructions = method.Body.Instructions; foreach (var instr in instructions) { if (instr.OpCode != OpCodes.Call) { continue; } var tamperMethod = instr.Operand as MethodDef; if (tamperMethod == null) { continue; } if (!tamperMethod.DeclaringType.IsGlobalModuleType) { continue; } const MethodAttributes attributes = MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig; if (tamperMethod.Attributes != attributes) { continue; } if (tamperMethod.CodeType != MethodImplAttributes.IL) { continue; } if (tamperMethod.ReturnType.ElementType != ElementType.Void) { continue; } // The decrypter method just have 1 call to VirtualProtect if (tamperMethod.FindInstructionsNumber(OpCodes.Call, "(System.IntPtr,System.UInt32,System.UInt32,System.UInt32&)") != 1) { continue; } instr.OpCode = OpCodes.Nop; instr.Operand = null; Logger.Verbose("Anti-tamper decrypter call was removed from .cctor."); return; } }
/// <summary> /// Creates a property method (getter or setter). /// </summary> /// <param name="name">The name.</param> /// <param name="returnType">Type of the return.</param> /// <param name="parameters">The parameters.</param> /// <returns></returns> private static MethodDefUser CreatePropertyMethod(string name, TypeSig returnType, params Tuple <TypeSig, string>[] parameters) { const MethodAttributes methodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; var methodSig = new MethodSig(CallingConvention.HasThis, 0, returnType, parameters.Select(p => p.Item1).ToArray()); var methodDefinition = new MethodDefUser(name, methodSig, methodAttributes); var methodParameters = new MethodParameters(methodDefinition); for (int index = 0; index < parameters.Length; index++) { methodParameters[0].ParamDef.Name = parameters[index].Item2; } methodDefinition.Body = new CilBody { InitLocals = true }; return(methodDefinition); }
void FindDecrypterMethods(ModuleDef module) { foreach (var method in module.GlobalType.Methods) { const MethodAttributes attributes = MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig; if (method.Attributes != attributes) { continue; } if (method.GenericParameters.Count != 1) { continue; } if (method.Parameters.Count != 1) { continue; } if (method.Parameters[0].Type.ElementType != ElementType.U4) { continue; } if (method.FindInstructionsNumber(OpCodes.Call, "System.Buffer::BlockCopy(System.Array,System.Int32,System.Array,System.Int32,System.Int32)") != 2) { continue; } if (method.FindInstructionsNumber(OpCodes.Call, "System.Array::CreateInstance(System.Type,System.Int32)") != 1) { continue; } if (method.FindInstructionsNumber(OpCodes.Callvirt, "System.Text.Encoding::GetString(System.Byte[],System.Int32,System.Int32)") != 1) { continue; } decrypterMethods.Add(method); Logger.Verbose($"Constant decrypter method detected: {method.FullName}."); } Logger.Verbose($"Decrypter methods detected: {decrypterMethods.Count}."); }
static void RemoveCall(MethodDef method) { var instructions = method.Body.Instructions; foreach (var instr in instructions) { if (instr.OpCode != OpCodes.Call) { continue; } var tamperMethod = instr.Operand as MethodDef; if (tamperMethod == null) { continue; } const MethodAttributes attributes = MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig; if (tamperMethod.Attributes != attributes) { continue; } if (tamperMethod.CodeType != dnlib.DotNet.MethodImplAttributes.IL) { continue; } if (tamperMethod.ReturnType.ElementType != ElementType.Void) { continue; } instr.OpCode = OpCodes.Nop; instr.Operand = null; return; } }
void RemoveInitializeCall(ModuleDef module) { var cctor = module.GlobalType.FindStaticConstructor(); var instructions = cctor.Body.Instructions; foreach (var instruction in instructions) { if (instruction.OpCode != OpCodes.Call) { continue; } var initializeMethod = instruction.Operand as MethodDef; if (initializeMethod == null) { continue; } if (!initializeMethod.DeclaringType.IsGlobalModuleType) { continue; } const MethodAttributes attributes = MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig; if (initializeMethod.Attributes != attributes) { continue; } if (initializeMethod.ReturnType.ElementType != ElementType.Void) { continue; } if (initializeMethod.HasParamDefs) { continue; } if (initializeMethod.FindInstructionsNumber(OpCodes.Call, "System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") != 1) { continue; } var field = FindArrayField(module); var operand = (from instr in initializeMethod.Body.Instructions where instr.OpCode == OpCodes.Stsfld let fieldArray = instr.Operand as FieldDef where fieldArray != null where field == fieldArray select instr.Operand.ToString()).FirstOrDefault(); if (initializeMethod.FindInstructionsNumber(OpCodes.Stsfld, operand) != 1) { continue; } instruction.OpCode = OpCodes.Nop; instruction.Operand = null; Logger.Verbose("Removed constans initialize call."); } }
/// <summary> /// Weaves the interface. /// What we do here is: /// - creating a class (which is named after the interface name) /// - this class implements all interface members /// - all members invoke Invocation.ProcessInterfaceMethod /// </summary> /// <param name="moduleDefinition">The module definition.</param> /// <param name="interfaceType">Type of the interface.</param> /// <param name="context">The context.</param> private void WeaveInterface(ModuleDefMD moduleDefinition, TypeDef interfaceType, WeavingContext context) { var importedInterfaceType = moduleDefinition.Import(interfaceType); Logging.WriteDebug("Weaving interface '{0}'", interfaceType.FullName); TypeDef implementationType; TypeDef advisedInterfaceType; lock (moduleDefinition) { // ensure we're creating the interface only once var implementationTypeName = GetImplementationTypeName(interfaceType.Name); var implementationTypeNamespace = interfaceType.Namespace; if (moduleDefinition.GetTypes().Any(t => t.Namespace == implementationTypeNamespace && t.Name == implementationTypeName)) { return; } // now, create the implementation type var typeAttributes = (InjectAsPrivate ? TypeAttributes.NotPublic : TypeAttributes.Public) | TypeAttributes.Class | TypeAttributes.BeforeFieldInit; advisedInterfaceType = TypeResolver.Resolve(moduleDefinition, typeof(AdvisedInterface)); // TODO: this should work using TypeImporter.Import var advisedInterfaceTypeReference = moduleDefinition.Import(advisedInterfaceType); implementationType = new TypeDefUser(implementationTypeNamespace, implementationTypeName, advisedInterfaceTypeReference) { Attributes = typeAttributes }; implementationType.Interfaces.Add(new InterfaceImplUser(importedInterfaceType)); lock (moduleDefinition) moduleDefinition.Types.Add(implementationType); } // create empty .ctor. This .NET mofo wants it! var baseEmptyConstructor = moduleDefinition.SafeImport(advisedInterfaceType.FindConstructors().Single()); const MethodAttributes ctorAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; var method = new MethodDefUser(".ctor", baseEmptyConstructor.MethodSig, ctorAttributes); method.Body = new CilBody(); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, baseEmptyConstructor)); method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); implementationType.Methods.Add(method); // create implementation methods foreach (var currentInterfaceType in interfaceType.GetAllInterfaces(TypeResolver)) { foreach (var interfaceMethod in currentInterfaceType.Methods.Where(m => !m.IsSpecialName)) { WeaveInterfaceMethod(interfaceMethod, implementationType, true, context); } // create implementation properties foreach (var interfaceProperty in currentInterfaceType.Properties) { var implementationProperty = new PropertyDefUser(interfaceProperty.Name, interfaceProperty.PropertySig); implementationType.Properties.Add(implementationProperty); if (interfaceProperty.GetMethod != null) { implementationProperty.GetMethod = WeaveInterfaceMethod(interfaceProperty.GetMethod, implementationType, InjectAsPrivate, context); } if (interfaceProperty.SetMethod != null) { implementationProperty.SetMethod = WeaveInterfaceMethod(interfaceProperty.SetMethod, implementationType, InjectAsPrivate, context); } } // create implementation events foreach (var interfaceEvent in currentInterfaceType.Events) { var implementationEvent = new EventDefUser(interfaceEvent.Name, interfaceEvent.EventType); implementationType.Events.Add(implementationEvent); if (interfaceEvent.AddMethod != null) { implementationEvent.AddMethod = WeaveInterfaceMethod(interfaceEvent.AddMethod, implementationType, InjectAsPrivate, context); } if (interfaceEvent.RemoveMethod != null) { implementationEvent.RemoveMethod = WeaveInterfaceMethod(interfaceEvent.RemoveMethod, implementationType, InjectAsPrivate, context); } } } }
/// <summary> /// Weaves the specified method. /// </summary> /// <param name="markedMethod">The marked method.</param> /// <param name="context">The context.</param> private void WeaveAdvices(MarkedNode markedMethod, WeavingContext context) { var method = markedMethod.Node.Method; // sanity check if (!method.HasReturnType) { var customAttributes = method.CustomAttributes; if (customAttributes.Any(c => c.AttributeType.Name == "AsyncStateMachineAttribute")) { Logging.WriteWarning("Advising async void method '{0}' could confuse async advices. Consider switching its return type to async Task.", method.FullName); } } if (method.IsAbstract) { method.Attributes = (method.Attributes & ~MethodAttributes.Abstract) | MethodAttributes.Virtual; Logging.WriteDebug("Weaving abstract method '{0}'", method.FullName); WritePointcutBody(method, null, false, context); } else if (markedMethod.AbstractTarget) { Logging.WriteDebug("Weaving and abstracting method '{0}'", method.FullName); WritePointcutBody(method, null, true, context); } else { Logging.WriteDebug("Weaving method '{0}'", method.FullName); var methodName = method.Name; // create inner method const MethodAttributes attributesToKeep = MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.PInvokeImpl | MethodAttributes.UnmanagedExport | MethodAttributes.HasSecurity | MethodAttributes.RequireSecObject; var innerMethodAttributes = method.Attributes & attributesToKeep | (InjectAsPrivate ? MethodAttributes.Private : MethodAttributes.Public); string innerMethodName; if (method.IsGetter) { innerMethodName = GetPropertyInnerGetterName(GetSpecialOwnerName(methodName)); } else if (method.IsSetter) { innerMethodName = GetPropertyInnerSetterName(GetSpecialOwnerName(methodName)); } else if (method.IsAddOn) { innerMethodName = GetEventInnerAdderName(GetSpecialOwnerName(methodName)); } else if (method.IsRemoveOn) { innerMethodName = GetEventInnerRemoverName(GetSpecialOwnerName(methodName)); } else { innerMethodName = GetInnerMethodName(methodName); } var innerMethod = new MethodDefUser(innerMethodName, method.MethodSig, innerMethodAttributes); new MethodParameters(method).SetParamDefs(innerMethod); innerMethod.GenericParameters.AddRange(method.GenericParameters.Select(p => p.Clone(innerMethod))); innerMethod.ImplAttributes = method.ImplAttributes; innerMethod.SemanticsAttributes = method.SemanticsAttributes; if (method.IsPinvokeImpl) { innerMethod.ImplMap = method.ImplMap; method.ImplMap = null; method.IsPreserveSig = false; method.IsPinvokeImpl = false; } else { innerMethod.Body = method.Body; method.Body = new CilBody(); } AddGeneratedAttribute(innerMethod, context); lock (method.DeclaringType) method.DeclaringType.Methods.Add(innerMethod); var stepInfos = innerMethod.CustomDebugInfos.OfType <PdbAsyncMethodCustomDebugInfo>().SelectMany(d => d.StepInfos).ToArray(); for (var stepInfoIndex = 0; stepInfoIndex < stepInfos.Length; stepInfoIndex++) { var stepInfo = stepInfos[stepInfoIndex]; Logging.WriteDebug("Found stepInfo for '{0}'", stepInfo.BreakpointMethod.ToString()); if (stepInfo.BreakpointMethod.SafeEquivalent(method)) { Logging.WriteDebug("Replacing '{0}' with '{1}'", stepInfo.BreakpointMethod.ToString(), innerMethod.ToString()); stepInfo.BreakpointMethod = innerMethod; stepInfos[stepInfoIndex] = stepInfo; } } WritePointcutBody(method, innerMethod, false, context); } }
/// <summary> /// Weaves the specified method. /// </summary> /// <param name="markedMethod">The marked method.</param> /// <param name="context">The context.</param> private void WeaveAdvices(MarkedNode markedMethod, WeavingContext context) { var method = markedMethod.Node.Method; // sanity check var moduleDefinition = (ModuleDefMD)method.Module; if (method.ReturnType.SafeEquivalent(moduleDefinition.CorLibTypes.Void)) { var customAttributes = method.CustomAttributes; if (customAttributes.Any(c => c.AttributeType.Name == "AsyncStateMachineAttribute")) { Logging.WriteWarning("Advising async void method '{0}' could confuse async advices. Consider switching its return type to async Task.", method.FullName); } } if (method.IsAbstract) { method.Attributes = (method.Attributes & ~MethodAttributes.Abstract) | MethodAttributes.Virtual; Logging.WriteDebug("Weaving abstract method '{0}'", method.FullName); WritePointcutBody(method, null, false, context); } else if (markedMethod.AbstractTarget) { Logging.WriteDebug("Weaving and abstracting method '{0}'", method.FullName); WritePointcutBody(method, null, true, context); } else { Logging.WriteDebug("Weaving method '{0}'", method.FullName); var methodName = method.Name; // create inner method const MethodAttributes attributesToKeep = MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.PInvokeImpl | MethodAttributes.UnmanagedExport | MethodAttributes.HasSecurity | MethodAttributes.RequireSecObject; var innerMethodAttributes = method.Attributes & attributesToKeep | (InjectAsPrivate ? MethodAttributes.Private : MethodAttributes.Public); string innerMethodName; if (method.IsGetter) { innerMethodName = GetPropertyInnerGetterName(GetSpecialOwnerName(methodName)); } else if (method.IsSetter) { innerMethodName = GetPropertyInnerSetterName(GetSpecialOwnerName(methodName)); } else if (method.IsAddOn) { innerMethodName = GetEventInnerAdderName(GetSpecialOwnerName(methodName)); } else if (method.IsRemoveOn) { innerMethodName = GetEventInnerRemoverName(GetSpecialOwnerName(methodName)); } else { innerMethodName = GetInnerMethodName(methodName); } var innerMethod = new MethodDefUser(innerMethodName, method.MethodSig, innerMethodAttributes); new MethodParameters(method).SetParamDefs(innerMethod); innerMethod.GenericParameters.AddRange(method.GenericParameters.Select(p => p.Clone(innerMethod))); innerMethod.ImplAttributes = method.ImplAttributes; innerMethod.SemanticsAttributes = method.SemanticsAttributes; if (method.IsPinvokeImpl) { innerMethod.ImplMap = method.ImplMap; method.ImplMap = null; method.IsPreserveSig = false; method.IsPinvokeImpl = false; } else { innerMethod.Body = method.Body; method.Body = new CilBody(); } AddGeneratedAttribute(innerMethod, context); lock (method.DeclaringType) method.DeclaringType.Methods.Add(innerMethod); WritePointcutBody(method, innerMethod, false, context); } }