/// <summary> /// Convert some method data into a method signature. /// </summary> /// <param name="data">Data</param> /// <returns>Signature</returns> MethodSig GetMethodSig(MethodData data) { TypeSig returnType = ResolveType(data.ReturnType); TypeSig[] paramTypes = new TypeSig[data.Parameters.Length]; for (Int32 i = 0; i < paramTypes.Length; i++) { paramTypes[i] = ResolveType(data.Parameters[i]); } UInt32 genericTypeCount = (UInt32)data.GenericArguments.Length; MethodSig methodSig; if (genericTypeCount == 0) { if (data.IsStatic) { methodSig = MethodSig.CreateStatic(returnType, paramTypes); } else { methodSig = MethodSig.CreateInstance(returnType, paramTypes); } } else { if (data.IsStatic) { methodSig = MethodSig.CreateStaticGeneric(genericTypeCount, returnType, paramTypes); } else { methodSig = MethodSig.CreateInstanceGeneric(genericTypeCount, returnType, paramTypes); } } return(methodSig); }
internal static async Task <int> Execute(ModuleDefMD targetModule) { /* * {IL_0046: ldarg.0} * {IL_0047: ldarg.0} * {IL_0048: call UnityEngine.GameObject UnityEngine.Component::get_gameObject()} * {IL_004D: callvirt TrainerManager UnityEngine.GameObject::AddComponent<TrainerManager>()} * {IL_0052: stfld TrainerManager GameManager::trainerManager} * {IL_0057: ret} */ var gameManagerTypeDef = targetModule.Find("GameManager", true); var trainerManagerTypeDef = targetModule.Find("TrainerManager", true); var trainerManagerFieldDef = InjectionHelpers.AddField(targetModule, "GameManager", "trainerManager", trainerManagerTypeDef.ToTypeSig(), FieldAttributes.Private); if (trainerManagerFieldDef == null) { return(await Task.FromResult(1)); } var gameManagerStartMethodDef = gameManagerTypeDef.FindMethod("Start"); var unityEngine = targetModule.GetAssemblyRef(new UTF8String("UnityEngine")); var unityEngineComponentTypeRefUser = new TypeRefUser(targetModule, new UTF8String("UnityEngine"), new UTF8String("Component"), unityEngine); var unityEngineGameObjectTypeRefUser = new TypeRefUser(targetModule, new UTF8String("UnityEngine"), new UTF8String("GameObject"), unityEngine); var gameObjectTypeSig = unityEngineGameObjectTypeRefUser.ToTypeSig(); var getGameObjectMethodSig = MethodSig.CreateInstance(gameObjectTypeSig); var gameManagerStartMethodSig = MethodSig.CreateInstanceGeneric(1, new GenericMVar(0, gameManagerStartMethodDef)); // {UnityEngine.GameObject UnityEngine.Component::get_gameObject()} var getGameObjectMethodRefUser = new MemberRefUser(targetModule, new UTF8String("get_gameObject"), getGameObjectMethodSig, unityEngineComponentTypeRefUser); // {TrainerManager UnityEngine.GameObject::AddComponent<TrainerManager>()} var addComponentMethodRefUser = new MemberRefUser(targetModule, new UTF8String("AddComponent"), gameManagerStartMethodSig, unityEngineGameObjectTypeRefUser); var trainerManagerGenericInstMethodSig = new GenericInstMethodSig(trainerManagerTypeDef.ToTypeSig()); var addComponentMethodSpecUser = new MethodSpecUser(addComponentMethodRefUser, trainerManagerGenericInstMethodSig); var trainerManagerDefinitionMethodInstructions = new List <Instruction> { new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Call, getGameObjectMethodRefUser), new Instruction(OpCodes.Callvirt, addComponentMethodSpecUser), new Instruction(OpCodes.Stfld, trainerManagerFieldDef), new Instruction(OpCodes.Ret), }; var retInstruction = gameManagerStartMethodDef.Body.Instructions.LastOrDefault(); if (retInstruction != null && retInstruction.OpCode == OpCodes.Ret) { gameManagerStartMethodDef.Body.Instructions.Remove(retInstruction); } foreach (var instruction in trainerManagerDefinitionMethodInstructions) { gameManagerStartMethodDef.Body.Instructions.Add(instruction); } return(await Task.FromResult(0)); }
internal static async Task <int> Execute(ModuleDefMD targetModule) { // Fetch assembly refs var unityEngine = targetModule.GetAssemblyRef("UnityEngine"); // Fetch target type defs var characterActionsTypeDef = targetModule.Find("CharacterActions", true); var controllerTypeDef = targetModule.Find("Controller", true); var aiTypeDef = targetModule.Find("AI", true); // Fetch target method defs var aiStartMethodDef = aiTypeDef.FindMethod("Start"); var controllerStartMethodDef = controllerTypeDef.FindMethod("Start"); var characterActionsCreateWithControllerBindingsMethodDef = characterActionsTypeDef.FindMethod("CreateWithControllerBindings"); // Fetch target field defs var aiGoForGunsFieldDef = aiTypeDef.FindField("goForGuns"); var controllerHasControlFieldDef = controllerTypeDef.FindField("mHasControl"); var controllerPlayerActionsFieldDef = controllerTypeDef.FindField("mPlayerActions"); // Fetch type ref users var unityEngineComponentTypeRefUser = new TypeRefUser(targetModule, "UnityEngine", "Component", unityEngine); var unityEngineBehaviourTypeRefUser = new TypeRefUser(targetModule, "UnityEngine", "Behaviour", unityEngine); // Create method ref users var getComponentMethodRefUser = new MemberRefUser(targetModule, "GetComponent", MethodSig.CreateInstanceGeneric(1, new GenericMVar(0, aiStartMethodDef)), unityEngineComponentTypeRefUser); var setEnabledMethodRefUser = new MemberRefUser(targetModule, "set_enabled", MethodSig.CreateInstance(targetModule.CorLibTypes.Void, targetModule.CorLibTypes.Boolean), unityEngineBehaviourTypeRefUser); // Create method spec users var getComponentMethodSpecUser = new MethodSpecUser(getComponentMethodRefUser, new GenericInstMethodSig(aiTypeDef.ToTypeSig())); /* * * {IL_00C3: ldarg.0} * {IL_00C4: call AI UnityEngine.Component::GetComponent<AI>()} * {IL_00C9: ldc.i4.1} * {IL_00CA: callvirt System.Void UnityEngine.Behaviour::set_enabled(System.Boolean)} * */ var controllerStartInstructionSignature = new List <Instruction> { new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Call, getComponentMethodSpecUser), new Instruction(OpCodes.Ldc_I4_1), new Instruction(OpCodes.Callvirt, setEnabledMethodRefUser) }; var matchedControllerStartMethodInstructions = InjectionHelpers.FetchInstructionsBySigComparerSignature(controllerStartMethodDef.Body.Instructions, controllerStartInstructionSignature); if (matchedControllerStartMethodInstructions != null) { var lastMatchedInstruction = matchedControllerStartMethodInstructions.Last(); var injectionIndex = controllerStartMethodDef.Body.Instructions.IndexOf(lastMatchedInstruction) + 1; var controllerStartInstructionsToInject = new List <Instruction> { new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Call, getComponentMethodSpecUser), new Instruction(OpCodes.Ldc_I4_1), new Instruction(OpCodes.Stfld, aiGoForGunsFieldDef), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldc_I4_1), new Instruction(OpCodes.Stfld, controllerHasControlFieldDef), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Call, characterActionsCreateWithControllerBindingsMethodDef), new Instruction(OpCodes.Stfld, controllerPlayerActionsFieldDef), }; // Add new instructions after the matched signature for (var i = 0; i < controllerStartInstructionsToInject.Count; i++) { controllerStartMethodDef.Body.Instructions.Insert(injectionIndex + i, controllerStartInstructionsToInject[i]); } controllerStartMethodDef.Body.UpdateInstructionOffsets(); } else { return(await Task.FromResult(1)); } return(await Task.FromResult(0)); }
IList <MethodSig> PossibleMethodSigs(ITypeDefOrRef declaringType, MethodSig sig, MethodData data) { // Setup generic types IList <TypeSig> typeGenerics = new List <TypeSig>(), methodGenerics = new List <TypeSig>(); // Add all declaring spec generic types TypeSpec declaringSpec = declaringType as TypeSpec; if (declaringSpec != null) { var genericInstSig = declaringSpec.TryGetGenericInstSig(); foreach (var garg in genericInstSig.GenericArguments) { typeGenerics.Add(garg); } } // Add all method generic types if (data.HasGenericArguments) { foreach (var operand in data.GenericArguments) { var gtype = this.ResolveType_NoLock(operand.Position); methodGenerics.Add(gtype.ToTypeSig()); } } // Todo: Combinations factoring in the possibility that return type might match // a generic type TypeSig returnType = ResolveType(data.ReturnType); IList <TypeSig> returnTypes = GenericUtils.PossibleTypeSigs(returnType, typeGenerics, methodGenerics); TypeSig[] paramTypes = new TypeSig[data.Parameters.Length]; for (Int32 i = 0; i < paramTypes.Length; i++) { paramTypes[i] = ResolveType(data.Parameters[i]); } UInt32 genericTypeCount = (UInt32)data.GenericArguments.Length; IList <MethodSig> signatures = new List <MethodSig>(); var paramCombos = GenericUtils.CreateGenericParameterCombinations(paramTypes, typeGenerics, methodGenerics); foreach (var rType in returnTypes) { foreach (var combo in paramCombos) { var paramCombo = combo.ToArray(); MethodSig methodSig; if (genericTypeCount == 0) { if (data.IsStatic) { methodSig = MethodSig.CreateStatic(rType, paramCombo); } else { methodSig = MethodSig.CreateInstance(rType, paramCombo); } } else { if (data.IsStatic) { methodSig = MethodSig.CreateStaticGeneric(genericTypeCount, rType, paramCombo); } else { methodSig = MethodSig.CreateInstanceGeneric(genericTypeCount, rType, paramCombo); } } signatures.Add(methodSig); } } return(signatures); }
public static void Run() { // This is the file that will be created string newFileName = "GenericExample3.exe"; // Create the module var mod = new ModuleDefUser("GenericExample3", Guid.NewGuid(), new AssemblyRefUser(new AssemblyNameInfo(typeof(int).Assembly.GetName().FullName))); // It's a console app mod.Kind = ModuleKind.Console; // Create the assembly and add the created module to it new AssemblyDefUser("GenericExample3", new Version(1, 2, 3, 4)).Modules.Add(mod); // Add the startup type. It derives from System.Object. TypeDef startUpType = new TypeDefUser("My.Namespace", "Startup", mod.CorLibTypes.Object.TypeDefOrRef); startUpType.Attributes = TypeAttributes.NotPublic | TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.AnsiClass; // Add the type to the module mod.Types.Add(startUpType); // Create the entry point method MethodDef entryPoint = new MethodDefUser("Main", MethodSig.CreateStatic(mod.CorLibTypes.Int32, new SZArraySig(mod.CorLibTypes.String))); entryPoint.Attributes = MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot; entryPoint.ImplAttributes = MethodImplAttributes.IL | MethodImplAttributes.Managed; // Name the 1st argument (argument 0 is the return type) entryPoint.ParamDefs.Add(new ParamDefUser("args", 1)); // Add the method to the startup type startUpType.Methods.Add(entryPoint); // Set module entry point mod.EntryPoint = entryPoint; // Create a type with 2 generic parameters, A and B // Would look like: public class GClass<A, B> var genericType = new TypeDefUser("My.Namespace", "GClass", mod.CorLibTypes.Object.TypeDefOrRef); genericType.Attributes = TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit; genericType.GenericParameters.Add(new GenericParamUser(0, GenericParamAttributes.NonVariant, "A")); genericType.GenericParameters.Add(new GenericParamUser(1, GenericParamAttributes.NonVariant, "B")); // Add generic type to module mod.Types.Add(genericType); // Note: NestedPublic instead of Public, blank namespace // Would look like: public class GSubClass<A, B, C> var genericSubType = new TypeDefUser("", "GSubClass", mod.CorLibTypes.Object.TypeDefOrRef); genericSubType.Attributes = TypeAttributes.NestedPublic | TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit; // Need to add the 2 generic parameters from the nested-parent class, A and B genericSubType.GenericParameters.Add(new GenericParamUser(0, GenericParamAttributes.NonVariant, "A")); genericSubType.GenericParameters.Add(new GenericParamUser(1, GenericParamAttributes.NonVariant, "B")); // Add a generic parameter specific to this nested class, C genericSubType.GenericParameters.Add(new GenericParamUser(2, GenericParamAttributes.NonVariant, "C")); // public void GSubClass<A, B, C>.SomeMethod(B arg1, C arg2) { ... } // or: public void GSubClass<!0, !1, !2>.SomeMethod(!1, !2) { ... } var someMethod = new MethodDefUser("SomeMethod", MethodSig.CreateInstance(mod.CorLibTypes.Void, new GenericVar(1), new GenericVar(2))); someMethod.Attributes = MethodAttributes.Public; someMethod.ImplAttributes = MethodImplAttributes.IL | MethodImplAttributes.Managed; genericSubType.Methods.Add(someMethod); // Create method with a method generic parameter (GenericMVar) // public void GSubClass<A, B, C>.SomeOtherMethod<D>(D arg1, A arg2, C arg3) { ... } // or: public void GSubClass<!0, !1, !2>.SomeOtherMethod<!!0>(!!0, !0, !2) { ... } var someGenericMethod = new MethodDefUser("SomeOtherMethod", MethodSig.CreateInstanceGeneric(1, mod.CorLibTypes.Void, new GenericMVar(0), new GenericVar(0), new GenericVar(2))); someGenericMethod.Attributes = MethodAttributes.Public; someGenericMethod.ImplAttributes = MethodImplAttributes.IL | MethodImplAttributes.Managed; // Create GenericParam for !!0 someGenericMethod.GenericParameters.Add(new GenericParamUser(0, GenericParamAttributes.NonVariant, "D")); genericSubType.Methods.Add(someGenericMethod); // Add as nested type genericType.NestedTypes.Add(genericSubType); someMethod.Body = new CilBody(); someMethod.Body.Instructions.Add(OpCodes.Ret.ToInstruction()); someGenericMethod.Body = new CilBody(); someGenericMethod.Body.Instructions.Add(OpCodes.Ret.ToInstruction()); entryPoint.Body = new CilBody(); entryPoint.Body.Instructions.Add(OpCodes.Ldc_I4_0.ToInstruction()); entryPoint.Body.Instructions.Add(OpCodes.Ret.ToInstruction()); mod.Write(newFileName); }