public static void CreateMethodRestore(MethodDef target, MethodDef newMethod, ModuleDefMD module) { AssemblyRef dnlib = module.GetAssemblyRef(new UTF8String("dnlib")); TypeRefUser Instruction = new TypeRefUser(module, new UTF8String("dnlib"), new UTF8String("Instruction"), dnlib); TypeSig instructionSig = Instruction.ToTypeSig(); var assemblyRef = module.CorLibTypes.AssemblyRef; var listRef = new TypeRefUser(module, @"System.Collections.Generic", "List`1", assemblyRef); var listGenericInstSig = new GenericInstSig(new ClassSig(listRef), instructionSig); var listTypeSpec = new TypeSpecUser(listGenericInstSig); var listCtor = new MemberRefUser(module, ".ctor", MethodSig.CreateInstance(module.CorLibTypes.Void), listTypeSpec); var instruictionCtor = new MemberRefUser(module, ".ctor", MethodSig.CreateInstance(module.CorLibTypes.Void), instructionSig.TryGetTypeSpec()); var listAdd = new MemberRefUser(module, "Add", MethodSig.CreateInstance(module.CorLibTypes.Void, new GenericVar(0)), listTypeSpec); // sdsd newMethod.Body.Instructions.Add(OpCodes.Newobj.ToInstruction(listCtor)); newMethod.Body.Instructions.Add(OpCodes.Stloc_0.ToInstruction()); // Store list to local[0] /* * newMethod.Body.Instructions.Add(new Instruction(OpCodes.Dup)); * newMethod.Body.Instructions.Add(new Instruction(OpCodes.Ldsfld, OpCodes.Add)); * newMethod.Body.Instructions.Add(new Instruction(OpCodes.Ldc_I4_S, 0x37)); * newMethod.Body.Instructions.Add(new Instruction(OpCodes.Box, module.CorLibTypes.Int32)); * newMethod.Body.Instructions.Add(new Instruction(OpCodes.Newobj, instruictionCtor)); * newMethod.Body.Instructions.Add(new Instruction(OpCodes.Callvirt, listAdd)); */ }
AssemblyRef FindAssemblyRef(string asmSimpleName) { var asmRef = module.GetAssemblyRef(asmSimpleName); if (asmRef == null) { throw new ApplicationException(string.Format("Could not find assembly {0} in assembly references", asmSimpleName)); } return(asmRef); }
string GetMscorlibFullname() { var mscorlibRef = module.GetAssemblyRef("mscorlib"); if (mscorlibRef != null) { return(mscorlibRef.FullName); } return("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); }
string tryGetRealAssemblyName(string assemblyName) { var simpleName = Utils.getAssemblySimpleName(assemblyName); var asmRef = module.GetAssemblyRef(simpleName); if (asmRef != null) { return(asmRef.FullName); } var asm = TheAssemblyResolver.Instance.Resolve(new AssemblyNameInfo(simpleName), module); return(asm == null ? null : asm.FullName); }
private static void Hook_SpriteFetcher_GetSprite(ModuleDefMD module) { TypeDef cecilSource = module.Find("SpriteFetcher", isReflectionName: true); MethodDef sourceMethod = cecilSource.Methods.Single(m => m.FullName == "UnityEngine.Sprite SpriteFetcher::GetSprite(ObjectTypes,System.Int32)"); TypeDef cecilTarget = module.GetNuterraType(typeof(Hooks.ResourceLookup)); MethodDef targetMethod = cecilTarget.Methods.Single(m => m.Name == nameof(Hooks.ResourceLookup.GetSprite)); AssemblyRef unityEngine = module.GetAssemblyRef(new UTF8String("UnityEngine")); TypeRefUser unityEngine_Object = new TypeRefUser(module, new UTF8String("UnityEngine"), new UTF8String("Object"), unityEngine); TypeSig objectSig = unityEngine_Object.ToTypeSig(); MethodSig op_Equality = MethodSig.CreateStatic(module.CorLibTypes.Boolean, objectSig, objectSig); MemberRefUser op_EqualityMethod = new MemberRefUser(module, new UTF8String("op_Inequality"), op_Equality, unityEngine_Object); var body = sourceMethod.Body.Instructions; var originalMethodStart = body.First(); int index = 0; sourceMethod.Body.MaxStack = 6; body.Insert(index++, new Instruction(OpCodes.Ldarg_1)); body.Insert(index++, new Instruction(OpCodes.Ldarg_2)); body.Insert(index++, new Instruction(OpCodes.Call, targetMethod)); body.Insert(index++, new Instruction(OpCodes.Stloc_0)); body.Insert(index++, new Instruction(OpCodes.Ldloc_0)); body.Insert(index++, new Instruction(OpCodes.Ldnull)); body.Insert(index++, new Instruction(OpCodes.Call, op_EqualityMethod)); body.Insert(index++, new Instruction(OpCodes.Brfalse_S, originalMethodStart)); body.Insert(index++, new Instruction(OpCodes.Ldloc_0)); body.Insert(index++, new Instruction(OpCodes.Ret)); /* * 0 0000 ldarg.1 * 1 0001 ldarg.2 * 2 0002 call class [UnityEngine]UnityEngine.Sprite Maritaria.BlockLoader::SpriteFetcher_GetSprite(valuetype ObjectTypes, int32) * 3 0007 stloc.0 * 4 0008 ldloc.0 * 5 0009 ldnull * 6 000A call bool [UnityEngine]UnityEngine.Object::op_Inequality(class [UnityEngine]UnityEngine.Object, class [UnityEngine]UnityEngine.Object) * 7 000F brfalse.s { original method start instruction } * 8 0011 ldloc.0 * 9 0012 ret * ... remaining method code ... */ }
private string TryGetRealAssemblyName(IAssembly asm) { var simpleName = asm.Name; if (simpleName == module.CorLibTypes.AssemblyRef.Name) { return(module.CorLibTypes.AssemblyRef.FullName); } if (moduleMD != null) { var asmRef = moduleMD.GetAssemblyRef(simpleName); if (asmRef != null) { return(asmRef.FullName); } } return(GetAssemblyFullName(simpleName)); }
internal static async Task <int> Execute(ModuleDefMD targetModule) { // Fetch target type defs var controllerTypeDef = targetModule.Find("Controller", true); // Fetch target method defs var controllerJumpMethodDef = controllerTypeDef.FindMethod("Jump"); // Fetch target field defs var controllerMovementStateFieldDef = controllerTypeDef.FindField("m_MovementState"); /* * * Remove redundant code that always sets 'movementState' to 'GroundJump' in the 'Controller.Jump' method. * * Target instructions to patch: * * 62 00EE ldarg.0 * 63 00EF ldloc.0 * 64 00F0 brfalse 67 (00FB) ldc.i4.8 * 65 00F5 ldc.i4.4 * 66 00F6 br 68 (00FC) stfld valuetype Controller/MovementStateEnum Controller::m_MovementState * 67 00FB ldc.i4.8 * 68 00FC stfld valuetype Controller/MovementStateEnum Controller::m_MovementState * */ var controllerJumpInstructionSignature = new List <Instruction> { new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldloc_0), new Instruction(OpCodes.Brfalse, new Instruction(OpCodes.Ldc_I4_8, null)), new Instruction(OpCodes.Ldc_I4_4), new Instruction(OpCodes.Br, new Instruction(OpCodes.Stfld, null)), new Instruction(OpCodes.Ldc_I4_8), new Instruction(OpCodes.Stfld, controllerMovementStateFieldDef) }; var matchedControllerJumpMethodInstructions = InjectionHelpers.FetchInstructionsBySignature(controllerJumpMethodDef.Body.Instructions, controllerJumpInstructionSignature, false); if (matchedControllerJumpMethodInstructions != null) { // NOP the matched instructions matchedControllerJumpMethodInstructions.ForEach(matchedInstruction => matchedInstruction.OpCode = OpCodes.Nop); } else { return(await Task.FromResult(1)); } /* * * The 'Movement.Jump' method unsafely accesses the AudioClip array when selecting a random 'jump' sound to play. * Add appropriate length check to fix the index out of bounds exception. * * Target instructions to patch: * * 0 0000 ldarg.0 * 1 0001 ldarg.1 * 2 0002 ldarg.2 * 3 0003 call instance bool Movement::DoJump(bool, bool) * 4 0008 stloc.0 * 5 0009 ldarg.0 * 6 000A ldfld class [UnityEngine]UnityEngine.AudioSource Movement::au * 7 000F ldarg.0 * 8 0010 ldfld class [UnityEngine]UnityEngine.AudioClip[] Movement::jumpClips * 9 0015 ldc.i4.0 * 10 0016 ldarg.0 * 11 0017 ldfld class [UnityEngine]UnityEngine.AudioClip[] Movement::jumpClips * 12 001C ldlen * 13 001D conv.i4 * 14 001E call int32 [UnityEngine]UnityEngine.Random::Range(int32, int32) * 15 0023 ldelem.ref * 16 0024 callvirt instance void [UnityEngine]UnityEngine.AudioSource::PlayOneShot(class [UnityEngine]UnityEngine.AudioClip) * 17 0029 ldloc.0 * 18 002A ret * * * Resulting instructions after patching: * * 0 0000 ldarg.0 * 1 0001 ldarg.1 * 2 0002 ldarg.2 * 3 0003 call instance bool Movement::DoJump(bool, bool) * 4 0008 ldarg.0 * 5 0009 ldfld class [UnityEngine]UnityEngine.AudioClip[] Movement::jumpClips * 6 000E ldlen * 7 000F brfalse.s 24 (0039) ret * 8 0011 ldarg.0 * 9 0012 ldfld class [UnityEngine]UnityEngine.AudioSource Movement::au * 10 0017 ldarg.0 * 11 0018 ldfld class [UnityEngine]UnityEngine.AudioClip[] Movement::jumpClips * 12 001D ldc.i4.0 * 13 001E ldarg.0 * 14 001F ldfld class [UnityEngine]UnityEngine.AudioClip[] Movement::jumpClips * 15 0024 ldlen * 16 0025 conv.i4 * 17 0026 ldc.i4.1 * 18 0027 sub * 19 0028 ldc.i4.0 * 20 0029 call int32 [mscorlib]System.Math::Max(int32, int32) * 21 002E call int32 [UnityEngine]UnityEngine.Random::Range(int32, int32) * 22 0033 ldelem.ref * 23 0034 callvirt instance void [UnityEngine]UnityEngine.AudioSource::PlayOneShot(class [UnityEngine]UnityEngine.AudioClip) * 24 0039 ret * */ // Fetch target type defs var movementTypeDef = targetModule.Find("Movement", true); // Fetch target method defs var movementJumpMethodDef = movementTypeDef.FindMethod("Jump"); var movementDoJumpMethodDef = movementTypeDef.FindMethod("DoJump"); // Fetch target field defs var movementAuFieldDef = movementTypeDef.FindField("au"); var movementJumpClipsFieldDef = movementTypeDef.FindField("jumpClips"); // Fetch reference assembly refs var mscorlibAssemblyRef = targetModule.GetAssemblyRef(new UTF8String("mscorlib")); var unityEngineAssemblyRef = targetModule.GetAssemblyRef(new UTF8String("UnityEngine")); // Construct type ref users var systemMathTypeRefUser = new TypeRefUser(targetModule, new UTF8String("System"), new UTF8String("Math"), mscorlibAssemblyRef); var unityEngineAudioClipTypeRefUser = new TypeRefUser(targetModule, new UTF8String("UnityEngine"), new UTF8String("AudioClip"), unityEngineAssemblyRef); var unityEngineRandomTypeRefUser = new TypeRefUser(targetModule, new UTF8String("UnityEngine"), new UTF8String("Random"), unityEngineAssemblyRef); var unityEngineAudioSourceTypeRefUser = new TypeRefUser(targetModule, new UTF8String("UnityEngine"), new UTF8String("AudioSource"), unityEngineAssemblyRef); // Construct member ref users var maxMethodRefUser = new MemberRefUser(targetModule, new UTF8String("Max"), MethodSig.CreateStatic(targetModule.CorLibTypes.Int32, targetModule.CorLibTypes.Int32, targetModule.CorLibTypes.Int32), systemMathTypeRefUser); var randomRangeMethodRefUser = new MemberRefUser(targetModule, new UTF8String("Range"), MethodSig.CreateStatic(targetModule.CorLibTypes.Int32, targetModule.CorLibTypes.Int32, targetModule.CorLibTypes.Int32), unityEngineRandomTypeRefUser); var playOneShotMethodRefUser = new MemberRefUser(targetModule, new UTF8String("PlayOneShot"), MethodSig.CreateInstance(targetModule.CorLibTypes.Void, unityEngineAudioClipTypeRefUser.ToTypeSig()), unityEngineAudioSourceTypeRefUser); // Construct list of instructions to be injected var retInstruction = new Instruction(OpCodes.Ret); var movementJumpInstructions = new List <Instruction>() { new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldarg_1), new Instruction(OpCodes.Ldarg_2), new Instruction(OpCodes.Call, movementDoJumpMethodDef), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldfld, movementJumpClipsFieldDef), new Instruction(OpCodes.Ldlen), new Instruction(OpCodes.Brfalse_S, retInstruction), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldfld, movementAuFieldDef), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldfld, movementJumpClipsFieldDef), new Instruction(OpCodes.Ldc_I4_0), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldfld, movementJumpClipsFieldDef), new Instruction(OpCodes.Ldlen), new Instruction(OpCodes.Conv_I4), new Instruction(OpCodes.Ldc_I4_1), new Instruction(OpCodes.Sub), new Instruction(OpCodes.Ldc_I4_0), new Instruction(OpCodes.Call, maxMethodRefUser), new Instruction(OpCodes.Call, randomRangeMethodRefUser), new Instruction(OpCodes.Ldelem_Ref), new Instruction(OpCodes.Callvirt, playOneShotMethodRefUser), retInstruction }; // Replace all instructions in the method with the new instructions movementJumpMethodDef.Body.Instructions.Clear(); movementJumpInstructions.ForEach(movementJumpInstruction => movementJumpMethodDef.Body.Instructions.Add(movementJumpInstruction)); movementJumpMethodDef.Body.UpdateInstructionOffsets(); return(await Task.FromResult(0)); }
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 type defs var controllerTypeDef = targetModule.Find("Controller", true); var fightingTypeDef = targetModule.Find("Fighting", true); var networkPlayerTypeDef = targetModule.Find("NetworkPlayer", true); var chatManagerTypeDef = targetModule.Find("ChatManager", true); if (controllerTypeDef == null) { return(await Task.FromResult(1)); } if (fightingTypeDef == null) { return(await Task.FromResult(2)); } if (networkPlayerTypeDef == null) { return(await Task.FromResult(3)); } if (chatManagerTypeDef == null) { return(await Task.FromResult(4)); } // Fetch field defs var isAiFieldDef = controllerTypeDef.FindField("isAI"); var fightingFieldDef = controllerTypeDef.FindField("fighting"); var mNetworkPlayerFieldDef = fightingTypeDef.FindField("mNetworkPlayer"); var mChatManagerFieldDef = networkPlayerTypeDef.FindField("mChatManager"); if (isAiFieldDef == null) { return(await Task.FromResult(5)); } if (fightingFieldDef == null) { return(await Task.FromResult(6)); } if (mNetworkPlayerFieldDef == null) { return(await Task.FromResult(7)); } if (mChatManagerFieldDef == null) { return(await Task.FromResult(8)); } // Fetch method defs var onTakeDamageMethodDef = controllerTypeDef.FindMethod("OnTakeDamage"); var talkMethodDef = chatManagerTypeDef.FindMethod("Talk"); if (onTakeDamageMethodDef == null) { return(await Task.FromResult(9)); } if (talkMethodDef == null) { return(await Task.FromResult(10)); } // Fetch reference assembly refs var unityEngineAssemblyRef = targetModule.GetAssemblyRef(new UTF8String("UnityEngine")); // Construct type ref users var unityEngineRandomTypeRefUser = new TypeRefUser(targetModule, new UTF8String("UnityEngine"), new UTF8String("Random"), unityEngineAssemblyRef); // Construct member ref users var randomRangeMethodRefUser = new MemberRefUser(targetModule, new UTF8String("Range"), MethodSig.CreateStatic(targetModule.CorLibTypes.Int32, targetModule.CorLibTypes.Int32, targetModule.CorLibTypes.Int32), unityEngineRandomTypeRefUser); /* * * // Instructions to inject * * 0 0000 ldarg.0 * 1 0001 ldfld bool Controller::isAI * 2 0006 brfalse.s 40 (0085) ldarg.0 * 3 0008 ldarg.0 * 4 0009 ldfld class Fighting Controller::fighting * 5 000E ldfld class NetworkPlayer Fighting::mNetworkPlayer * 6 0013 brfalse.s 40 (0085) ldarg.0 * 7 0015 ldc.i4.0 * 8 0016 ldc.i4 10 * 9 001B call int32 [UnityEngine]UnityEngine.Random::Range(int32, int32) * 10 0020 stloc.0 * 11 0021 ldloc.0 * 12 0022 ldc.i4.s 1 * 13 0024 bne.un.s 21 (0042) ldloc.0 * 14 0026 ldarg.0 * 15 0027 ldfld class Fighting Controller::fighting * 16 002C ldfld class NetworkPlayer Fighting::mNetworkPlayer * 17 0031 ldfld class ChatManager NetworkPlayer::mChatManager * 18 0036 ldstr "Ouch!" * 19 003B callvirt instance void ChatManager::Talk(string) * 20 0040 br.s 40 (0085) ldarg.0 * 21 0042 ldloc.0 * 22 0043 ldc.i4 0x1D1 * 23 0048 bne.un.s 31 (0066) ldloc.0 * 24 004A ldarg.0 * 25 004B ldfld class Fighting Controller::fighting * 26 0050 ldfld class NetworkPlayer Fighting::mNetworkPlayer * 27 0055 ldfld class ChatManager NetworkPlayer::mChatManager * 28 005A ldstr "Ow!" * 29 005F callvirt instance void ChatManager::Talk(string) * 30 0064 br.s 40 (0085) ldarg.0 * 31 0066 ldloc.0 * 32 0067 ldc.i4.s 10 * 33 0069 bne.un.s 40 (0085) ldarg.0 * 34 006B ldarg.0 * 35 006C ldfld class Fighting Controller::fighting * 36 0071 ldfld class NetworkPlayer Fighting::mNetworkPlayer * 37 0076 ldfld class ChatManager NetworkPlayer::mChatManager * 38 007B ldstr "That's monk-y business!" * 39 0080 callvirt instance void ChatManager::Talk(string) * */ var firstInstruction = onTakeDamageMethodDef.Body.Instructions.First(); var branches = new List <Instruction>() { new Instruction(OpCodes.Ldloc_0), new Instruction(OpCodes.Ldloc_0) }; var condition1 = new List <Instruction>() { new Instruction(OpCodes.Ldloc_0), new Instruction(OpCodes.Ldc_I4_S, Convert.ToByte(10)), new Instruction(OpCodes.Bne_Un_S, branches[0]), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldfld, fightingFieldDef), new Instruction(OpCodes.Ldfld, mNetworkPlayerFieldDef), new Instruction(OpCodes.Ldfld, mChatManagerFieldDef), new Instruction(OpCodes.Ldstr, "Ouch!"), new Instruction(OpCodes.Callvirt, talkMethodDef), new Instruction(OpCodes.Br_S, firstInstruction) }; var condition2 = new List <Instruction>() { branches[0], new Instruction(OpCodes.Ldc_I4, 500), new Instruction(OpCodes.Bne_Un_S, branches[1]), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldfld, fightingFieldDef), new Instruction(OpCodes.Ldfld, mNetworkPlayerFieldDef), new Instruction(OpCodes.Ldfld, mChatManagerFieldDef), new Instruction(OpCodes.Ldstr, "Existence is pain!"), new Instruction(OpCodes.Callvirt, talkMethodDef), new Instruction(OpCodes.Br_S, firstInstruction) }; var condition3 = new List <Instruction>() { branches[1], new Instruction(OpCodes.Ldc_I4_S, Convert.ToByte(100)), new Instruction(OpCodes.Bne_Un_S, firstInstruction), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldfld, fightingFieldDef), new Instruction(OpCodes.Ldfld, mNetworkPlayerFieldDef), new Instruction(OpCodes.Ldfld, mChatManagerFieldDef), new Instruction(OpCodes.Ldstr, "That's monk-y business!"), new Instruction(OpCodes.Callvirt, talkMethodDef) }; var instructionsToInject = new List <Instruction>() { new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldfld, isAiFieldDef), new Instruction(OpCodes.Brfalse_S, firstInstruction), new Instruction(OpCodes.Ldarg_0), new Instruction(OpCodes.Ldfld, fightingFieldDef), new Instruction(OpCodes.Ldfld, mNetworkPlayerFieldDef), new Instruction(OpCodes.Brfalse_S, firstInstruction), new Instruction(OpCodes.Ldc_I4_0), new Instruction(OpCodes.Ldc_I4, 800), new Instruction(OpCodes.Call, randomRangeMethodRefUser), new Instruction(OpCodes.Stloc_0) } .Concat(condition1) .Concat(condition2) .Concat(condition3) .ToList(); for (var i = 0; i < instructionsToInject.Count; i++) { onTakeDamageMethodDef.Body.Instructions.Insert(i, instructionsToInject[i]); } onTakeDamageMethodDef.Body.Variables.Add(new Local(targetModule.CorLibTypes.Int32, "num")); onTakeDamageMethodDef.Body.OptimizeBranches(); onTakeDamageMethodDef.Body.UpdateInstructionOffsets(); 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)); }