public static void HookMethod(
        HookType hookType,
        ModuleDefinition targetModule, MethodDefinition targetMethod,
        MethodDefinition calleeMethod)
    {
        ILProcessor l = targetMethod.Body.GetILProcessor();
        Instruction instInsertPoint = targetMethod.Body.Instructions.First();

        if (hookType == HookType.PostCall || hookType == HookType.PostCallRet)
        {
            instInsertPoint = targetMethod.Body.Instructions.Last();
        }

        InsertInstDelegate o = newInst =>
        {
            l.InsertBefore(instInsertPoint, newInst);
        };

        // todo 2があるとは限らないので、良い方法を探す
        int tmpLoc = 2;

        if (hookType == HookType.PostCallRet)
        {
            // 戻り値をテンポラリにコピー
            o(l.Create(OpCodes.Dup));           // 最後の ret 用にコピーを作る
            o(l.Create(OpCodes.Stloc, tmpLoc));
        }

        int n = targetMethod.Parameters.Count + (targetMethod.IsStatic ? 0 : 1);

        for (int i = 0; i < n; i++)
        {
            if (i == 0)
            {
                o(l.Create(OpCodes.Ldarg_0));
            }
            else
            {
                // ref 参照にしたい場合は OpCodes.Ldarga にすること
                o(l.Create(OpCodes.Ldarg, i));
            }
        }
        if (hookType == HookType.PostCallRet)
        {
            // 戻り値をテンポラリからスタックへコピー
            o(l.Create(OpCodes.Ldloc, tmpLoc));
        }
        o(l.Create(OpCodes.Call, targetModule.Import(calleeMethod)));

        // PreJumpの場合は元の処理を行わないように、そのままRetする
        if (hookType == HookType.PreJump)
        {
            o(l.Create(OpCodes.Ret));
        }
    }
        void PatchGetAnyMouseAndKey(MethodDefinition targetMethod)
        {
            ILProcessor        l = targetMethod.Body.GetILProcessor();
            Instruction        instInsertPoint = targetMethod.Body.Instructions.First();
            InsertInstDelegate o = newInst =>
            {
                l.InsertBefore(instInsertPoint, newInst);
            };

            o(l.Create(OpCodes.Ldc_I4, 1));
            o(l.Create(OpCodes.Ret));
        }
    public static void HookMethod(
        HookType hookType,
        ModuleDefinition targetModule, MethodDefinition targetMethod,
        MethodDefinition calleeMethod)
    {
        ILProcessor l = targetMethod.Body.GetILProcessor();
        Instruction instInsertPoint = targetMethod.Body.Instructions.First();

        if (hookType == HookType.PostCall)
        {
            instInsertPoint = targetMethod.Body.Instructions.Last();
        }

        InsertInstDelegate o = newInst =>
        {
            l.InsertBefore(instInsertPoint, newInst);
        };

        int n = targetMethod.Parameters.Count + (targetMethod.IsStatic ? 0 : 1);

        for (int i = 0; i < n; i++)
        {
            if (i == 0)
            {
                o(l.Create(OpCodes.Ldarg_0));
            }
            else
            {
                // ref 参照にしたい場合は OpCodes.Ldarga にすること
                o(l.Create(OpCodes.Ldarg, i));
            }
        }
        o(l.Create(OpCodes.Call, targetModule.Import(calleeMethod)));

        // PreJumpの場合は元の処理を行わないように、そのままRetする
        if (hookType == HookType.PreJump)
        {
            o(l.Create(OpCodes.Ret));
        }
    }
        void PatchIsForceSkip(MethodDefinition targetMethod)
        {
            Mono.Cecil.Rocks.MethodBodyRocks.SimplifyMacros(targetMethod.Body);

            // GameMain.Instance.IsForceSkip() の戻り値を捨てて、true を積む
            Instruction inst = targetMethod.Body.Instructions.FirstOrDefault(
                i => i.OpCode == OpCodes.Callvirt && i.Operand.ToString().Contains("GameMain::IsForceSkip"));

            if (inst == null)
            {
                return;
            }
            ILProcessor        l = targetMethod.Body.GetILProcessor();
            Instruction        instInsertPoint = inst.Next;
            InsertInstDelegate o = newInst =>
            {
                l.InsertBefore(instInsertPoint, newInst);
            };

            o(l.Create(OpCodes.Pop));
            o(l.Create(OpCodes.Ldc_I4, 1));
            Mono.Cecil.Rocks.MethodBodyRocks.OptimizeMacros(targetMethod.Body);
        }
        public override void Patch(ReiPatcher.Patch.PatcherArguments args)
        {
            PatchGetAnyMouseAndKey(GetMethod(
                                       args.Assembly.MainModule.GetType("SceneLogo"),
                                       "GetAnyMouseAndKey"));

            PatchGetAnyMouseAndKey(GetMethod(
                                       args.Assembly.MainModule.GetType("SceneWarning"),
                                       "GetAnyMouseAndKey"));

            TypeDefinition tCameraMain = args.Assembly.MainModule.GetType("CameraMain");

            PatchIsForceSkip(GetMethod(tCameraMain, "FadeIn"));
            PatchIsForceSkip(GetMethod(tCameraMain, "FadeInNoUI"));
            PatchIsForceSkip(GetMethod(tCameraMain, "FadeOut"));
            PatchIsForceSkip(GetMethod(tCameraMain, "FadeOutNoUI"));

            {
                // セーブロード画面のフェードアウト
                MethodDefinition targetMethod = GetMethod(
                    args.Assembly.MainModule.GetType("TweenAlpha"), "Begin");
                Mono.Cecil.Rocks.MethodBodyRocks.SimplifyMacros(targetMethod.Body);
                foreach (Instruction inst in targetMethod.Body.Instructions)
                {
                    // 第二引数 (duration) の値の代わりに DefaultUiFadeInTime を積む
                    if (inst.OpCode == OpCodes.Ldarg && ((ParameterDefinition)inst.Operand).Index == 1)
                    {
                        inst.OpCode  = OpCodes.Ldc_R4;
                        inst.Operand = DefaultUiFadeInTime;
                    }
                }
                Mono.Cecil.Rocks.MethodBodyRocks.OptimizeMacros(targetMethod.Body);
            }

            {
                // セーブロード画面のフェードイン
                //      ldc.r4 0.0
                //      stfld float32 TweenAlpha::from
                // を
                //      ldc.r4 1.0
                //      stfld float32 TweenAlpha::from
                // に書き換える
                MethodDefinition targetMethod = GetMethod(
                    args.Assembly.MainModule.GetType("BasePanelMgr"), "FadeInPanel");
                Mono.Cecil.Rocks.MethodBodyRocks.SimplifyMacros(targetMethod.Body);
                foreach (Instruction inst in targetMethod.Body.Instructions)
                {
                    if (inst.OpCode == OpCodes.Stfld && inst.Operand.ToString().Contains("TweenAlpha::from"))
                    {
                        inst.Previous.Operand = 1.0f;
                    }
                }
                Mono.Cecil.Rocks.MethodBodyRocks.OptimizeMacros(targetMethod.Body);
            }

            {
                // 日付アイキャッチ画面スキップ
                //  Input.anyKeyの戻り値を破棄して、常にtrueにする
                MethodDefinition targetMethod = GetMethod(
                    args.Assembly.MainModule.GetType("StartDailyMgr"), "Update");
                Mono.Cecil.Rocks.MethodBodyRocks.SimplifyMacros(targetMethod.Body);
                Instruction inst = targetMethod.Body.Instructions.First(
                    i => i.OpCode == OpCodes.Call && i.Operand.ToString().Contains("Input::get_anyKey"));
                ILProcessor        l = targetMethod.Body.GetILProcessor();
                Instruction        instInsertPoint = inst.Next;
                InsertInstDelegate o = newInst =>
                {
                    l.InsertBefore(instInsertPoint, newInst);
                };
                o(l.Create(OpCodes.Pop));
                o(l.Create(OpCodes.Ldc_I4, 1));
                Mono.Cecil.Rocks.MethodBodyRocks.OptimizeMacros(targetMethod.Body);
            }

            SetPatchedAttribute(args.Assembly, patchTag);
        }
Esempio n. 6
0
    // メソッドをラップ
    public static void WrapPostCallRet(
        ModuleDefinition targetModule, TypeDefinition targetType,
        MethodDefinition targetMethod,
        MethodDefinition calleeMethod)
    {
        // 元メソッド名前を変更
        var name    = targetMethod.Name;
        var newName = name + "_WrapPostCallRet";

        while (targetType.Methods.Any(x => x.Name == newName))
        {
            newName = newName + "_";
        }

        // 元の名前を変更しただけだとモジュール内のメソッドの参照はそのままになってしまう
        //targetMethod.Name = newName;
        //var wrapper = new MethodDefinition(name, targetMethod.Attributes, targetMethod.ReturnType);
        //ILProcessor l = wrapper.Body.GetILProcessor();

        // ラッパーメソッド生成
        var wrapper = new MethodDefinition(newName, targetMethod.Attributes, targetMethod.ReturnType);

        Console.WriteLine("*** HookType.WrapPostCallRet: wrapping method " + name + " => " + newName);

        // 引数をターゲットから複製
        foreach (var p in targetMethod.Parameters)
        {
            wrapper.Parameters.Add(p);
        }

        // メソッド追加
        targetType.Methods.Add(wrapper);
        var wrapperBody = wrapper.Body;

        // Bodyの置換
        var body = targetMethod.Body;

        targetMethod.Body = wrapper.Body;
        wrapper.Body      = body;

        // ILGenerator
        ILProcessor l = wrapperBody.GetILProcessor();

        l.Emit(OpCodes.Ret);

        Instruction instInsertPoint = wrapperBody.Instructions.First();

        InsertInstDelegate o = newInst =>
        {
            l.InsertBefore(instInsertPoint, newInst);
        };

        int n = targetMethod.Parameters.Count + (targetMethod.IsStatic ? 0 : 1);

        // 元メソッド呼び出し
        for (int i = 0; i < n; i++)
        {
            if (i == 0)
            {
                o(l.Create(OpCodes.Ldarg_0));
            }
            else
            {
                // ref 参照にしたい場合は OpCodes.Ldarga にすること
                o(l.Create(OpCodes.Ldarg, i));
            }
        }
        //置換済み o(l.Create(OpCodes.Call, targetMethod));
        o(l.Create(OpCodes.Call, wrapper));

        // ExPostCallRet
        for (int i = 0; i < n; i++)
        {
            if (i == 0)
            {
                o(l.Create(OpCodes.Ldarg_0));
            }
            else
            {
                // ref 参照にしたい場合は OpCodes.Ldarga にすること
                o(l.Create(OpCodes.Ldarg, i));
            }
        }
        o(l.Create(OpCodes.Call, targetModule.ImportReference(calleeMethod)));
    }
Esempio n. 7
0
    public static void HookMethod(
        HookType hookType,
        ModuleDefinition targetModule, MethodDefinition targetMethod,
        MethodDefinition calleeMethod)
    {
        Console.WriteLine("HookMethod " + hookType + "/" + targetModule + "/" + targetMethod + "/" + calleeMethod);
        Console.WriteLine("ImportReference" + targetModule.ImportReference(calleeMethod));
        Console.WriteLine("***");

        ILProcessor l = targetMethod.Body.GetILProcessor();
        Instruction instInsertPoint = targetMethod.Body.Instructions.First();

        if (hookType == HookType.PostCallLast || hookType == HookType.PostCallLastReplace)
        {
            //instInsertPoint = targetMethod.Body.Instructions.Last();
            //一番最後のretだけを検索してパッチする
            Instruction ret   = targetMethod.Body.Instructions.Last(i => i.OpCode == OpCodes.Ret);
            int         index = targetMethod.Body.Instructions.IndexOf(ret);

            var il = targetMethod.Body.GetILProcessor();

            InsertInstDelegate o2 = newInst =>
            {
                l.InsertBefore(ret, newInst);
            };
            if (hookType == HookType.PostCallLastReplace)
            {
                // 新しいretを追加
                var ret2 = il.Create(OpCodes.Ret);
                il.InsertAfter(ret, ret2);

                // 元のretを置換
                il.ReplaceInstruction(ret, il.Create(OpCodes.Nop));
                ret = ret2;
            }

            // 引数をセット
            int n2 = targetMethod.Parameters.Count + (targetMethod.IsStatic ? 0 : 1);
            for (int i = 0; i < n2; i++)
            {
                if (i == 0)
                {
                    o2(l.Create(OpCodes.Ldarg_0));
                }
                else
                {
                    // ref 参照にしたい場合は OpCodes.Ldarga にすること
                    o2(l.Create(OpCodes.Ldarg, i));
                }
            }

            // Hookメソッド呼び出し
            il.InsertBefore(ret, il.Create(OpCodes.Call, targetModule.ImportReference(calleeMethod)));

            //Instruction call = targetMethod.Body.Instructions.Last(i => i.OpCode == OpCodes.Ldarg_0);

            // デバッグ用出力
            for (int i = index; i < targetMethod.Body.Instructions.Count; i++)
            {
                Instruction testx = targetMethod.Body.Instructions[i];
                Console.WriteLine("*** il.Code({0}): " + testx, i);
            }
            return;
        }

        if (hookType == HookType.PostCall || hookType == HookType.PostCallRet || hookType == HookType.ExPostCallRet)
        {
            //instInsertPoint = targetMethod.Body.Instructions.Last();
            //全てのretを検索してパッチする
            targetMethod.Body.Instructions
            .Where(i => i.OpCode == OpCodes.Ret)
            .ToList()
            .ForEach(end =>
            {
                Console.WriteLine("*** il.InsertAfter:" + end);

                //ret位置にジャンプしてくる処理への対策としてret位置をずらす
                int index = targetMethod.Body.Instructions.IndexOf(end);
                Console.WriteLine("*** index:" + index + "/" + (targetMethod.Body.Instructions.Count() - 1));
                l.InsertAfter(end, l.Create(OpCodes.Ret));

                l.ReplaceInstruction(end, l.Create(OpCodes.Nop));      // bug fix
                Console.WriteLine("*** Replace({0}): Ret -> " + /*OpCodes.Nop*/ targetMethod.Body.Instructions[index], index);

                Instruction next = targetMethod.Body.Instructions[index + 1];
                Console.WriteLine("*** il.InsertBefore({0}):" + next, index + 1);
                InsertInstDelegate o2 = newInst =>
                {
                    l.InsertBefore(next, newInst);
                };

                // todo 2があるとは限らないので、良い方法を探す(ExPostCallRetなら一応汎用使用可)
                int tmpLoc2 = 2;
                if (hookType == HookType.PostCallRet)
                {
                    // 戻り値をテンポラリにコピー
                    o2(l.Create(OpCodes.Dup));               // 最後の ret 用にコピーを作る
                    o2(l.Create(OpCodes.Stloc, tmpLoc2));
                }
                if (hookType == HookType.ExPostCallRet)
                {
                    // 戻り値をテンポラリにコピーしない
                    // 元の戻り値は第一引数に入る
                }
                int iTest = 0;
                int n2    = targetMethod.Parameters.Count + (targetMethod.IsStatic ? 0 : 1);
                for (int i = 0; i < n2; i++)
                {
                    if (i == 0)
                    {
                        o2(l.Create(OpCodes.Ldarg_0));
                    }
                    else
                    {
                        // ref 参照にしたい場合は OpCodes.Ldarga にすること
                        o2(l.Create(OpCodes.Ldarg, i));
                    }
                    iTest++;
                }
                if (hookType == HookType.PostCallRet)
                {
                    // 戻り値をテンポラリからスタックへコピー
                    o2(l.Create(OpCodes.Ldloc, tmpLoc2));
                }
                o2(l.Create(OpCodes.Call, targetModule.ImportReference(calleeMethod)));

                for (int i = 0; i <= iTest; i++)
                {
                    Instruction testx = targetMethod.Body.Instructions[index + 1 + i];
                    Console.WriteLine("*** il.InsertBefore({0}):" + testx, index + 1 + i);
                }
            });
            return;
        }

        Console.WriteLine("*** il.InsertBefore:" + instInsertPoint);
        InsertInstDelegate o = newInst =>
        {
            l.InsertBefore(instInsertPoint, newInst);
        };

        /*ここにはこない
         * // todo 2があるとは限らないので、良い方法を探す
         * int tmpLoc = 2;
         * if (hookType == HookType.PostCallRet)
         * {
         *  // 戻り値をテンポラリにコピー
         *  o(l.Create(OpCodes.Dup));           // 最後の ret 用にコピーを作る
         *  o(l.Create(OpCodes.Stloc, tmpLoc));
         * }*/

        int n = targetMethod.Parameters.Count + (targetMethod.IsStatic ? 0 : 1);

        for (int i = 0; i < n; i++)
        {
            if (i == 0)
            {
                o(l.Create(OpCodes.Ldarg_0));
            }
            else
            {
                // ref 参照にしたい場合は OpCodes.Ldarga にすること
                o(l.Create(OpCodes.Ldarg, i));
            }
        }

        /*ここにはこない
         * if (hookType == HookType.PostCallRet)
         * {
         *  // 戻り値をテンポラリからスタックへコピー
         *  o(l.Create(OpCodes.Ldloc, tmpLoc));
         * }*/
        o(l.Create(OpCodes.Call, targetModule.ImportReference(calleeMethod)));

        // PreJumpの場合は元の処理を行わないように、そのままRetする
        if (hookType == HookType.PreJump)
        {
            o(l.Create(OpCodes.Ret));
        }
        // ExPreCallの場合は戻り値がFalseなら、元の処理を行わないように、そのままRetする

        if (hookType == HookType.ExPreCall)
        {
            Console.WriteLine("*** HookType.ExPreCall:" + instInsertPoint.Previous + "/" + String.Format("{0:X}", instInsertPoint.Previous.GetHashCode()));
            //Console.WriteLine(l.Create(OpCodes.Brfalse, instInsertPoint));
            //Console.WriteLine(l.Create(OpCodes.Brfalse_S, instInsertPoint));
            o(l.Create(OpCodes.Brfalse_S, instInsertPoint));

            Console.WriteLine("*** HookType.ExPreCall:" + instInsertPoint.Previous + "/" + String.Format("{0:X}", instInsertPoint.Previous.GetHashCode()) + " → " + instInsertPoint + "/" + String.Format("{0:X}", instInsertPoint.GetHashCode()));
            o(l.Create(OpCodes.Ret));

            Console.WriteLine("*** HookType.ExPreCall:" + instInsertPoint.Previous + "/" + String.Format("{0:X}", instInsertPoint.Previous.GetHashCode()));
            Console.WriteLine("*** HookType.ExPreCall:" + instInsertPoint + "/" + String.Format("{0:X}", instInsertPoint.GetHashCode()));
        }
    }