using dnlib.DotNet; using dnlib.DotNet.Emit; using System.Collections.Generic; using System.Linq; namespace Server.RenamingObfuscation.Classes { public static class InjectHelper { /// /// Clones the specified origin TypeDef. /// /// The origin TypeDef. /// The cloned TypeDef. static TypeDefUser Clone(TypeDef origin) { var ret = new TypeDefUser(origin.Namespace, origin.Name); ret.Attributes = origin.Attributes; if (origin.ClassLayout != null) ret.ClassLayout = new ClassLayoutUser(origin.ClassLayout.PackingSize, origin.ClassSize); foreach (GenericParam genericParam in origin.GenericParameters) ret.GenericParameters.Add(new GenericParamUser(genericParam.Number, genericParam.Flags, "-")); return ret; } /// /// Clones the specified origin MethodDef. /// /// The origin MethodDef. /// The cloned MethodDef. static MethodDefUser Clone(MethodDef origin) { var ret = new MethodDefUser(origin.Name, null, origin.ImplAttributes, origin.Attributes); foreach (GenericParam genericParam in origin.GenericParameters) ret.GenericParameters.Add(new GenericParamUser(genericParam.Number, genericParam.Flags, "-")); return ret; } /// /// Clones the specified origin FieldDef. /// /// The origin FieldDef. /// The cloned FieldDef. static FieldDefUser Clone(FieldDef origin) { var ret = new FieldDefUser(origin.Name, null, origin.Attributes); return ret; } /// /// Populates the context mappings. /// /// The origin TypeDef. /// The injection context. /// The new TypeDef. static TypeDef PopulateContext(TypeDef typeDef, InjectContext ctx) { TypeDef ret; IDnlibDef existing; if (!ctx.Map.TryGetValue(typeDef, out existing)) { ret = Clone(typeDef); ctx.Map[typeDef] = ret; } else ret = (TypeDef)existing; foreach (TypeDef nestedType in typeDef.NestedTypes) ret.NestedTypes.Add(PopulateContext(nestedType, ctx)); foreach (MethodDef method in typeDef.Methods) ret.Methods.Add((MethodDef)(ctx.Map[method] = Clone(method))); foreach (FieldDef field in typeDef.Fields) ret.Fields.Add((FieldDef)(ctx.Map[field] = Clone(field))); return ret; } /// /// Copies the information from the origin type to injected type. /// /// The origin TypeDef. /// The injection context. static void CopyTypeDef(TypeDef typeDef, InjectContext ctx) { var newTypeDef = (TypeDef)ctx.Map[typeDef]; newTypeDef.BaseType = (ITypeDefOrRef)ctx.Importer.Import(typeDef.BaseType); foreach (InterfaceImpl iface in typeDef.Interfaces) newTypeDef.Interfaces.Add(new InterfaceImplUser((ITypeDefOrRef)ctx.Importer.Import(iface.Interface))); } /// /// Copies the information from the origin method to injected method. /// /// The origin MethodDef. /// The injection context. static void CopyMethodDef(MethodDef methodDef, InjectContext ctx) { var newMethodDef = (MethodDef)ctx.Map[methodDef]; newMethodDef.Signature = ctx.Importer.Import(methodDef.Signature); newMethodDef.Parameters.UpdateParameterTypes(); if (methodDef.ImplMap != null) newMethodDef.ImplMap = new ImplMapUser(new ModuleRefUser(ctx.TargetModule, methodDef.ImplMap.Module.Name), methodDef.ImplMap.Name, methodDef.ImplMap.Attributes); foreach (CustomAttribute ca in methodDef.CustomAttributes) newMethodDef.CustomAttributes.Add(new CustomAttribute((ICustomAttributeType)ctx.Importer.Import(ca.Constructor))); if (methodDef.HasBody) { newMethodDef.Body = new CilBody(methodDef.Body.InitLocals, new List(), new List(), new List()); newMethodDef.Body.MaxStack = methodDef.Body.MaxStack; var bodyMap = new Dictionary(); foreach (Local local in methodDef.Body.Variables) { var newLocal = new Local(ctx.Importer.Import(local.Type)); newMethodDef.Body.Variables.Add(newLocal); newLocal.Name = local.Name; bodyMap[local] = newLocal; } foreach (Instruction instr in methodDef.Body.Instructions) { var newInstr = new Instruction(instr.OpCode, instr.Operand); newInstr.SequencePoint = instr.SequencePoint; if (newInstr.Operand is IType) newInstr.Operand = ctx.Importer.Import((IType)newInstr.Operand); else if (newInstr.Operand is IMethod) newInstr.Operand = ctx.Importer.Import((IMethod)newInstr.Operand); else if (newInstr.Operand is IField) newInstr.Operand = ctx.Importer.Import((IField)newInstr.Operand); newMethodDef.Body.Instructions.Add(newInstr); bodyMap[instr] = newInstr; } foreach (Instruction instr in newMethodDef.Body.Instructions) { if (instr.Operand != null && bodyMap.ContainsKey(instr.Operand)) instr.Operand = bodyMap[instr.Operand]; else if (instr.Operand is Instruction[]) instr.Operand = ((Instruction[])instr.Operand).Select(target => (Instruction)bodyMap[target]).ToArray(); } foreach (ExceptionHandler eh in methodDef.Body.ExceptionHandlers) newMethodDef.Body.ExceptionHandlers.Add(new ExceptionHandler(eh.HandlerType) { CatchType = eh.CatchType == null ? null : (ITypeDefOrRef)ctx.Importer.Import(eh.CatchType), TryStart = (Instruction)bodyMap[eh.TryStart], TryEnd = (Instruction)bodyMap[eh.TryEnd], HandlerStart = (Instruction)bodyMap[eh.HandlerStart], HandlerEnd = (Instruction)bodyMap[eh.HandlerEnd], FilterStart = eh.FilterStart == null ? null : (Instruction)bodyMap[eh.FilterStart] }); newMethodDef.Body.SimplifyMacros(newMethodDef.Parameters); } } /// /// Copies the information from the origin field to injected field. /// /// The origin FieldDef. /// The injection context. static void CopyFieldDef(FieldDef fieldDef, InjectContext ctx) { var newFieldDef = (FieldDef)ctx.Map[fieldDef]; newFieldDef.Signature = ctx.Importer.Import(fieldDef.Signature); } /// /// Copies the information to the injected definitions. /// /// The origin TypeDef. /// The injection context. /// if set to true, copy information of . static void Copy(TypeDef typeDef, InjectContext ctx, bool copySelf) { if (copySelf) CopyTypeDef(typeDef, ctx); foreach (TypeDef nestedType in typeDef.NestedTypes) Copy(nestedType, ctx, true); foreach (MethodDef method in typeDef.Methods) CopyMethodDef(method, ctx); foreach (FieldDef field in typeDef.Fields) CopyFieldDef(field, ctx); } /// /// Injects the specified TypeDef to another module. /// /// The source TypeDef. /// The target module. /// The injected TypeDef. public static TypeDef Inject(TypeDef typeDef, ModuleDef target) { var ctx = new InjectContext(typeDef.Module, target); PopulateContext(typeDef, ctx); Copy(typeDef, ctx, true); return (TypeDef)ctx.Map[typeDef]; } /// /// Injects the specified MethodDef to another module. /// /// The source MethodDef. /// The target module. /// The injected MethodDef. public static MethodDef Inject(MethodDef methodDef, ModuleDef target) { var ctx = new InjectContext(methodDef.Module, target); ctx.Map[methodDef] = Clone(methodDef); CopyMethodDef(methodDef, ctx); return (MethodDef)ctx.Map[methodDef]; } /// /// Injects the members of specified TypeDef to another module. /// /// The source TypeDef. /// The new type. /// The target module. /// Injected members. public static IEnumerable Inject(TypeDef typeDef, TypeDef newType, ModuleDef target) { var ctx = new InjectContext(typeDef.Module, target); ctx.Map[typeDef] = newType; PopulateContext(typeDef, ctx); Copy(typeDef, ctx, false); return ctx.Map.Values.Except(new[] { newType }); } public class ImportResolver { /// /// Resolves the specified TypeDef. /// /// The TypeDef. /// The resolved TypeDef, or null if cannot be resolved. public virtual TypeDef Resolve(TypeDef typeDef) { return null; } /// /// Resolves the specified MethodDef. /// /// The MethodDef. /// The resolved MethodDef, or null if cannot be resolved. public virtual MethodDef Resolve(MethodDef methodDef) { return null; } /// /// Resolves the specified FieldDef. /// /// The FieldDef. /// The resolved FieldDef, or null if cannot be resolved. public virtual FieldDef Resolve(FieldDef fieldDef) { return null; } } /// /// Context of the injection process. /// class InjectContext : ImportResolver { /// /// The mapping of origin definitions to injected definitions. /// public readonly Dictionary Map = new Dictionary(); /// /// The module which source type originated from. /// public readonly ModuleDef OriginModule; /// /// The module which source type is being injected to. /// public readonly ModuleDef TargetModule; /// /// The importer. /// readonly Importer importer; /// /// Initializes a new instance of the class. /// /// The origin module. /// The target module. public InjectContext(ModuleDef module, ModuleDef target) { OriginModule = module; TargetModule = target; importer = new Importer(target, ImporterOptions.TryToUseTypeDefs); } /// /// Gets the importer. /// /// The importer. public Importer Importer { get { return importer; } } /// public override TypeDef Resolve(TypeDef typeDef) { if (Map.ContainsKey(typeDef)) return (TypeDef)Map[typeDef]; return null; } /// public override MethodDef Resolve(MethodDef methodDef) { if (Map.ContainsKey(methodDef)) return (MethodDef)Map[methodDef]; return null; } /// public override FieldDef Resolve(FieldDef fieldDef) { if (Map.ContainsKey(fieldDef)) return (FieldDef)Map[fieldDef]; return null; } } } }