C# 运行时替换方法(需要unsafe编译)

第一种方法的基本原理是将函数指针替换成想要的方法(https://stackoverflow.com/questions/7299097/dynamically-replace-the-contents-of-a-c-sharp-method);还有一种方式是用 methodInfo.GetMethodBody().GetILAsByteArray() 获得IL字节码,然后(利用C++?)编写注入代码对其字节码重新写入(https://www.codeproject.com/Articles/463508/NET-CLR-Injection-Modify-IL-Code-during-Run-time)。

这两种方法都需要先调用 RuntimeHelpers.PrepareMethod (https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.preparemethod(v=vs.110).aspx)来准备方法。

第一种方法实现简便,下面是演示代码:

  1 /* https://stackoverflow.com/questions/7299097/dynamically-replace-the-contents-of-a-c-sharp-method
  2    For .NET 4 and above
  3 
  4 "C:\Program Files (x86)\MSBuild\14.0\Bin\csc.exe" /unsafe+ /out:replacemethod.exe replacemethod.cs && start "replacemethod.exe" replacemethod.exe
  5 Foo1 is called.
  6 Foo2 is called.
  7 Foo2 returns.
  8 Foo3 is called. I‘m foo3‘s argument.
  9 Foo4 is called.
 10 --------------------
 11 Version x64 Relaese
 12 Version x64 Relaese
 13 Version x64 Relaese
 14 Version x64 Relaese
 15 --------------------
 16 Bar1 is called.
 17 Bar2 is called.
 18 Bar2 returns.
 19 Bar3 is called. I‘m foo3‘s argument.
 20 Bar4 is called.
 21 
 22 Press any key to EXIT...
 23 */
 24 
 25 using System;
 26 using System.Reflection;
 27 using System.Runtime.CompilerServices;
 28 
 29 class Program {
 30     public static void Main(params string[] args){
 31         var sp = new string(‘-‘, 20);
 32 
 33         Target targetInstance = new Target();
 34 
 35         targetInstance.Test();
 36         Console.WriteLine(sp);
 37 
 38         Injection.Install(1);
 39         Injection.Install(2);
 40         Injection.Install(3);
 41         Injection.Install(4);
 42         
 43         Console.WriteLine(sp);
 44         targetInstance.Test();
 45 
 46         Console.Write("\nPress any key to EXIT...");
 47         Console.ReadKey(true);
 48     }
 49 }
 50 
 51 
 52 public class Injection {
 53     public static void Install(int funcNum) {
 54         MethodInfo methodToReplace = typeof(Target).GetMethod("Foo"+funcNum, BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Public);
 55         MethodInfo methodToInject = typeof(Injection).GetMethod("Bar"+funcNum, BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Public);
 56         RuntimeHelpers.PrepareMethod(methodToReplace.MethodHandle);
 57         RuntimeHelpers.PrepareMethod(methodToInject.MethodHandle);
 58 
 59         unsafe {
 60             if (IntPtr.Size == 4) 
 61             {
 62                 int* inj = (int*)methodToInject.MethodHandle.Value.ToPointer() + 2;
 63                 int* tar = (int*)methodToReplace.MethodHandle.Value.ToPointer() + 2;
 64 #if DEBUG
 65                 Console.WriteLine("Version x86 Debug");
 66                 byte* injInst = (byte*)*inj;
 67                 byte* tarInst = (byte*)*tar;
 68                 int* injSrc = (int*)(injInst + 1);
 69                 int* tarSrc = (int*)(tarInst + 1);
 70                 *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
 71 #else
 72                 Console.WriteLine("Version x86 Relaese");
 73                 *tar = *inj;
 74 #endif
 75             }
 76             else 
 77             {
 78                 long* inj = (long*)methodToInject.MethodHandle.Value.ToPointer() + 1;
 79                 long* tar = (long*)methodToReplace.MethodHandle.Value.ToPointer() + 1;
 80 #if DEBUG
 81                 Console.WriteLine("Version x64 Debug");
 82                 byte* injInst = (byte*)*inj;
 83                 byte* tarInst = (byte*)*tar;
 84                 int* injSrc = (int*)(injInst + 1);
 85                 int* tarSrc = (int*)(tarInst + 1);
 86                 *tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
 87 #else
 88                 Console.WriteLine("Version x64 Relaese");
 89                 *tar = *inj;
 90 #endif
 91             }
 92         }
 93     }
 94 
 95     private void Bar1() {
 96         Console.WriteLine("Bar1 is called.");
 97     }
 98     private string Bar2() {
 99         Console.WriteLine("Bar2 is called.");
100         return "Bar2 returns.";
101     }
102     private void Bar3(string arg) {
103         Console.WriteLine("Bar3 is called. " + arg);
104     }
105     private void Bar4() {
106         Console.WriteLine("Bar4 is called.");
107     }
108 }
109 
110 
111 public class Target {
112     public void Test() {
113         Foo1();
114         Console.WriteLine(Foo2());
115         Foo3("I‘m foo3‘s argument.");
116         Foo4();
117     }
118 
119     private void Foo1() {
120         Console.WriteLine("Foo1 is called.");
121     }
122     public string Foo2() {
123         Console.WriteLine("Foo2 is called.");
124         return "Foo2 returns.";
125     }
126     private void Foo3(string arg) {
127         Console.WriteLine("Foo3 is called. "+arg);
128     }
129     private void Foo4() {
130         Console.WriteLine("Foo4 is called.");
131     }
132 }

 

第二种方法请查阅连接

C# 运行时替换方法(需要unsafe编译)

标签:console   debug   help   pre   ...   amp   adk   sharp   type   

原文地址:http://www.cnblogs.com/Bob-wei/p/7345574.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值