打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
.NET方法注入

.NET方法注入

Uncategorized, by Zen.

最近帮朋友做个东西,由于历史原因,有一些文件没有代码,但是又需要修改。这就需要干吃力不讨好的事情了——反编译。Google了一圈,发现.NET平台比较流行的也就是mono项目里的神器——Cecil了。原没Java平台的Javassist用起来里面爽,这里是一个应用。最不爽的是Cecil官方基本没什么文档,只有一个非常简单的介绍和示例。网上相关的文章也都是基于0.6版本的,不幸中大幸就是官方出了文档说明了0.6和0.9之间的差别了。Cecil非常让人不爽的一点是不能直接插入或修改C#代码,只能插入和修改IL代码,悲摧的。

reflector之前有个非常强悍的插件叫Reflexil,也是基于Cecil实现的,可以非常方便地删除,重命名,注入方法的,可惜和新版的reflector不兼容了。再说reflector开始收费了,之前的免费版本也不能用了。这时SharpDevelopILSpy就应运而生了,可惜刚出来没多久,相关的插件很少。好吧,其实只有两个,一个还不能用,另一个也没试。废话不多说了,下面进入正题。


由于注入方法需要通过IL代码来实现。下面这个方法可以把执行过程打印出来,帮助进行下面的操作。

123456789101112131415161718192021
public static void PrintTypes(string fileName){    var asm = AssemblyDefinition.ReadAssembly(fileName);    foreach (TypeDefinition type in asm.MainModule.Types)    {        if (type.Name.Equals("<Module>"))            continue;        Console.WriteLine("ClassName is : {0}", type.Name);        foreach (MethodDefinition method in type.Methods)        {            Console.WriteLine("{0} .maxstack {1}", method.FullName, method.Body.MaxStackSize);            foreach (var ins in method.Body.Instructions)            {                Console.WriteLine("L_{0}: {1} {2}", ins.Offset.ToString("x4"),                    ins.OpCode.Name,                    ins.Operand is String ? String.Format("\"{0}\"", ins.Operand) : ins.Operand);            }        }        Console.WriteLine("============================");    }}

新建一个工程,生成TestCecil.dll供测试

12345678910111213141516171819
using System; namespace TestCecil{    public class Class1    {        public void Test()        {            string t = "test_xxxx";            t = t.Replace("_", ".");            Console.WriteLine(t);        }         public void Test1(string content)        {            Console.WriteLine(content);        }    }}

在已有方法中注入新的操作的过程

12345
var processor = method.Body.GetILProcessor();var newInstruction = processor.Create(OpCodes.Call, someMethodReference);var firstInstruction = method.Body.Instructions[0]; processor.InsertBefore(firstInstruction, newInstruction);

具体示例,在类TestCecil.Class1Test方法中的第一行,打印字符I am a test message !!!

12345678910111213141516
static void Main(string[] args){    var asm = AssemblyDefinition.ReadAssembly("TestCecil.dll");    var type = asm.MainModule.GetType("TestCecil.Class1");    var method = type.Methods[0];    var processor = method.Body.GetILProcessor();    var ldstr = processor.Create(OpCodes.Ldstr, "I am a test message !!!");    var call = processor.Create(OpCodes.Call,        method.Module.Import(            typeof(Console).GetMethod("WriteLine", new[] { typeof(string) })));     processor.InsertBefore(method.Body.Instructions[0], ldstr);    processor.InsertAfter(method.Body.Instructions[0], call);    asm.Write("TestCecil.patch.dll");    PrintTypes("TestCecil.patch.dll");}

在类TestCecil.Class1中注入Test2(string)方法

1234567891011
static void Main(string[] args){    var asm = AssemblyDefinition.ReadAssembly("TestCecil.dll");    var module = asm.Modules[0];    var type = module.Types.FirstOrDefault(m => m.Name == "Class1");    var method = new MethodDefinition("Test2", MethodAttributes.Public,module.Import(typeof(void)));    type.Methods.Add(method);    method.Parameters.Add(new ParameterDefinition(module.Import(typeof(string))));    asm.Write("TestCecil.patch.dll");    PrintTypes("TestCecil.patch.dll");}

移除一个现有方法

12345678
public static void RemoveMethod(TypeDefinition self, string methodName){    var method = self.Methods.FirstOrDefault(m => m.Name == methodName);    if (method != null)    {        self.Methods.Remove(method);    }}

具体的使用方法,移除类TestCecil.Class1中的Test方法

12345678
static void Main(string[] args){    var asm = AssemblyDefinition.ReadAssembly("TestCecil.dll");    TypeDefinition type = asm.MainModule.GetType("TestCecil.Class1");    RemoveMethod(type, "Test");    asm.Write("TestCecil.patch.dll");    PrintTypes("TestCecil.patch.dll");}

这里只是一些简单的示例,常见使用都包括了。不过这种操作只能用来救急用的,偶尔干干还可以,要是在生产环境中用此方法会死人的-_-||

--EOF--

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C# Dynamic 与Var关键字 简析
C#基础系列:反射笔记
C#学习笔记
不同程序语言之间的互动,IronPython 与C#交互
LINQ系列:LINQ to DataSet的DataTable操作
.net 匿名函数的变化
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服