예제 #1
0
        internal static async Task <int> Execute(ModuleDefMD targetModule)
        {
            var bodyPartTypeDef   = targetModule.Find("BodyPart", true);
            var controllerTypeDef = targetModule.Find("Controller", true);

            var onCollisionEnterMethod = bodyPartTypeDef.FindMethod("OnCollisionEnter");
            var canFlyFieldDef         = controllerTypeDef.FindField("canFly");

            var bodyPartControllerFieldDef = bodyPartTypeDef.FindField("controller");

            var instructionSignature = new List <Instruction> {
                new Instruction(OpCodes.Ldfld, bodyPartControllerFieldDef),
                new Instruction(OpCodes.Ldfld, canFlyFieldDef),
                new Instruction(OpCodes.Brtrue, new Instruction(OpCodes.Ldarg_1, null)),
                new Instruction(OpCodes.Ldarg_0, null)
            };

            var matchedInstructions = InjectionHelpers.FetchInstructionsBySignature(onCollisionEnterMethod.Body.Instructions, instructionSignature, false);

            if (matchedInstructions != null)
            {
                // NOP the matched instructions
                matchedInstructions.ForEach(matchedInstruction => matchedInstruction.OpCode = OpCodes.Nop);
            }
            else
            {
                return(await Task.FromResult(2));
            }

            return(await Task.FromResult(0));
        }
예제 #2
0
        internal static async Task <int> Execute(ModuleDefMD targetModule)
        {
            // Fetch target type defs
            var controllerTypeDef = targetModule.Find("Controller", true);

            // Fetch target method defs
            var controllerSetCollisionMethodDef = controllerTypeDef.FindMethod("SetCollision");

            // Fetch target field defs
            var controllerIsAiFieldDef     = controllerTypeDef.FindField("isAI");
            var controllerPlayerIdFieldDef = controllerTypeDef.FindField("playerID");

            /*
             *
             *  32	004C	ldarg.0
             *  33	004D	ldfld	    bool Controller::isAI
             *  34	0052	brfalse.s	40 (0063) ldloc.2
             *
             */

            // Signature of the condition to which the check will be added
            var controllerSetCollisionAiCheckInstructionSignature = new List <Instruction> {
                new Instruction(OpCodes.Ldarg_0),
                new Instruction(OpCodes.Ldfld, controllerIsAiFieldDef),
                new Instruction(OpCodes.Brfalse, null)
            };

            var matchedControllerSetCollisionAiCheckMethodInstructions = InjectionHelpers.FetchInstructionsBySignature(controllerSetCollisionMethodDef.Body.Instructions, controllerSetCollisionAiCheckInstructionSignature, false);

            if (matchedControllerSetCollisionAiCheckMethodInstructions != null)
            {
                var branchInstruction = matchedControllerSetCollisionAiCheckMethodInstructions.Last();
                var injectionIndex    = controllerSetCollisionMethodDef.Body.Instructions.IndexOf(branchInstruction) + 1;

                // Set unique gameObject layer in Controller.SetCollision for AIs with Player IDs.
                var controllerSetCollisionAiCheckInstructionsToInject = new List <Instruction>
                {
                    new Instruction(OpCodes.Ldarg_0),
                    new Instruction(OpCodes.Ldfld, controllerPlayerIdFieldDef),
                    new Instruction(OpCodes.Ldc_I4_0),
                    new Instruction(OpCodes.Bge_S, branchInstruction.Operand),
                };

                // Add new instructions after the matched signature
                for (var i = 0; i < controllerSetCollisionAiCheckInstructionsToInject.Count; i++)
                {
                    controllerSetCollisionMethodDef.Body.Instructions.Insert(injectionIndex + i, controllerSetCollisionAiCheckInstructionsToInject[i]);
                }

                controllerSetCollisionMethodDef.Body.UpdateInstructionOffsets();
            }
            else
            {
                return(await Task.FromResult(1));
            }

            return(await Task.FromResult(0));
        }
예제 #3
0
        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));
        }
예제 #4
0
        internal static async Task <int> Execute(ModuleDefMD targetModule)
        {
            // Fetch target type defs
            var controllerTypeDef    = targetModule.Find("Controller", true);
            var healthHandlerTypeDef = targetModule.Find("HealthHandler", true);

            // Fetch target method defs
            var healthHandlerDieMethodDef = healthHandlerTypeDef.FindMethod("Die");

            // Fetch target field defs
            var controllerIsAiFieldDef          = controllerTypeDef.FindField("isAI");
            var controllerPlayerIdFieldDef      = controllerTypeDef.FindField("playerID");
            var healthHandlerControllerFieldDef = healthHandlerTypeDef.FindField("controller");

            /*
             *
             *  55	009F	brfalse.s	69 (00CB) call bool MatchmakingHandler::get_IsNetworkMatch()
             *  56	00A1	ldarg.0
             *  57	00A2	ldfld	    class Controller HealthHandler::controller
             *  58	00A7	ldfld	    bool Controller::isAI
             *  59	00AC	brfalse.s	69 (00CB) call bool MatchmakingHandler::get_IsNetworkMatch()
             *
             */

            // Signature of the condition to which the check will be added
            var healthHandlerAiCheckInstructionSignature = new List <Instruction> {
                new Instruction(OpCodes.Brfalse, null),
                new Instruction(OpCodes.Ldarg_0),
                new Instruction(OpCodes.Ldfld, healthHandlerControllerFieldDef),
                new Instruction(OpCodes.Ldfld, controllerIsAiFieldDef),
                new Instruction(OpCodes.Brfalse, null)
            };

            var matchedHealthHandlerDieMethodInstructions = InjectionHelpers.FetchInstructionsBySignature(healthHandlerDieMethodDef.Body.Instructions, healthHandlerAiCheckInstructionSignature, false);

            if (matchedHealthHandlerDieMethodInstructions != null)
            {
                var branchInstruction = matchedHealthHandlerDieMethodInstructions.Last();
                var injectionIndex    = healthHandlerDieMethodDef.Body.Instructions.IndexOf(branchInstruction) + 1;

                // Add check for a valid playerID when checking that the controller is an AI
                var healtHandlerAiCheckInstructionsToInject = new List <Instruction>
                {
                    new Instruction(OpCodes.Ldarg_0),
                    new Instruction(OpCodes.Ldfld, healthHandlerControllerFieldDef),
                    new Instruction(OpCodes.Ldfld, controllerPlayerIdFieldDef),
                    new Instruction(OpCodes.Ldc_I4_M1),
                    new Instruction(OpCodes.Bgt_S, branchInstruction.Operand),
                };

                // Add new instructions after the matched signature
                for (var i = 0; i < healtHandlerAiCheckInstructionsToInject.Count; i++)
                {
                    healthHandlerDieMethodDef.Body.Instructions.Insert(injectionIndex + i, healtHandlerAiCheckInstructionsToInject[i]);
                }

                healthHandlerDieMethodDef.Body.UpdateInstructionOffsets();
            }
            else
            {
                return(await Task.FromResult(1));
            }

            return(await Task.FromResult(0));
        }