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); }
// メソッドをラップ 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))); }
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())); } }