使用Mono.Cecil对MSIL进行注入

本文介绍如何使用MonoCecil进行动态注入,通过示例展示了如何在目标方法执行前插入外部方法调用,实现了对原有程序集行为的修改而不改变其源代码。这种方法可用于实现AOP等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mono Cecil十分强大,强大到可以静态注入程序集(注入后生成新的程序集)和动态注入程序集(注入后不改变目标程序集,只在运行时改变程序集行为)

先看Mono.Cecil是如何读取程序集的

点这里


一个基本使用示例(此示例版本为0.6,后期版本AssemblyFactory已被去掉,改用AssemblyDefinition.ReadAssembly)

点这里


下面是网上的一个例子,我觉得比较典型,拿来收藏了


     有一个名为 MyLibrary.dll 的程序集,内有 Class1 类型,我们需要动态创建其对象,并调用 Test 方法。注入的要求是在执行 Test 内部代码前先执行一个外部程序集的方法 InjectMethod。

class Class1
{
   void Test()
  {
    Console.WriteLine("Hello, World!");
  }
}

注入代码

public class Program
{
  public static void InjectMethod()
  {
    Console.WriteLine("Haha...");
  }
  static void Main(string[] args)
  {
    AssemblyDefinition asm = AssemblyFactory.GetAssembly("MyLibrary.dll");
    foreach (TypeDefinition type in asm.MainModule.Types)
    {
      if (type.Name == "Class1")
      {
        foreach (MethodDefinition method in type.Methods)
        {
          if (method.Name == "Test")
          {
            Instruction ins = method.Body.Instructions[0];
            CilWorker worker = method.Body.CilWorker;
            MethodInfo m = typeof(Program).GetMethod("InjectMethod", BindingFlags.Static | BindingFlags.Public);
            MethodReference refernce = asm.MainModule.Import(m);
            Instruction insCall = worker.Create(OpCodes.Call, refernce);
            worker.InsertBefore(ins, insCall);
            Instruction insNop = worker.Create(OpCodes.Nop);
            worker.InsertAfter(insCall, insNop);
          }
        }
      }
    }
    Assembly testAssembly = AssemblyFactory.CreateReflectionAssembly(asm); 
    Type class1Type = testAssembly.GetType("MyLibrary.Class1");
    Object o = Activator.CreateInstance(class1Type);
    class1Type.InvokeMember("Test", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, o, null);
  }
}

输出:
Haha...
Hello, World!
  动态注入和静态注入不同,它不会修改目标程序集文件,因此不会有强类型签名等问题,也不易发生相关 "版权" 问题。可用来跳过某段验证代码,或者替换某些内部执行代码,用途有点像 "外挂"。使用动态注入实现 AOP 可能比较有意思,我们可以遍历添加了 "[AOP(aopMethodName=)]" 方法特性的所有类型,然后动态注入 AOP 拦截代码。


以上这种注入方式十分强大,居然可以注入到某一行代码之前,改变它的行为,一般的AOP实现恐怕也没有这么强大的。


另一个例子是直接把泛型约束给修改掉,例子中由于编译器不支持泛型约束中出现Enum类型,但在IL底层支持这么干,作者就用Mono.Ceil修改了程序集,让泛型约束直接支持Enum类型,详细看这里

点这里


Mono.Cecil 还可以用来破解商业组件(我勒个去的,连程序都可以改,去掉程序集签名,改成自己生成的签名,还有什么办不到的?)

下面的例子是去掉一个组件中的水印,当然作者只不过是举个例子,组件是自己写的,“破解”起来比较容易,真正的商业组件破解起来,得花好多时间研究的

点这里



當我在使用 AssetStudioGUI v0.16.47的 Android Apk拆包工具時,解析檔案時,出現了以下錯誤: 如需叫用 Just-In-Time (JIT) 偵錯的詳細資料, 請參閱本訊息結尾處 (而非這個對話方塊) 的資訊。 ************** 例外狀況文字 ************** System.IO.DirectoryNotFoundException: 找不到路徑 'C:\Users\daniiellyu\Desktop\Merge\split_UnityDataAssetPack\assets\aa\Android\outgamelandeventscenegroup_assets_assets\mergesurvival\runtime\addressableasset\prefab\outgame\land\outgameobject\eventscene\activeroot_eventscene_bunker.prefab_4c4c51ad35a7b8d25fdd75d571d79ead.bundle' 的一部分。 於 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 於 System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) 於 System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) 於 AssetStudio.AssetsManager.Load(String[] files) 於 C:\projects\assetstudio\AssetStudio\AssetsManager.cs: 行 52 於 System.Threading.Tasks.Task.Execute() --- 先前擲回例外狀況之位置中的堆疊追蹤結尾 --- 於 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 於 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 於 AssetStudioGUI.AssetStudioGUIForm.<loadFolder_Click>d__52.MoveNext() 於 C:\projects\assetstudio\AssetStudioGUI\AssetStudioGUIForm.cs: 行 164 --- 先前擲回例外狀況之位置中的堆疊追蹤結尾 --- 於 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() ************** 已載入的組件 ************** mscorlib 組件版本: 4.0.0.0 Win32 版本: 4.8.4772.0 built by: NET48REL1LAST_C 程式碼庫: file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll ---------------------------------------- AssetStudioGUI 組件版本: 0.16.47.0 Win32 版本: 0.16.47 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/AssetStudioGUI.exe ---------------------------------------- System.Windows.Forms 組件版本: 4.0.0.0 Win32 版本: 4.8.4734.0 built by: NET48REL1LAST_C 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll ---------------------------------------- System 組件版本: 4.0.0.0 Win32 版本: 4.8.4767.0 built by: NET48REL1LAST_C 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll ---------------------------------------- System.Drawing 組件版本: 4.0.0.0 Win32 版本: 4.8.4390.0 built by: NET48REL1LAST_C 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll ---------------------------------------- AssetStudioUtility 組件版本: 0.16.47.0 Win32 版本: 0.16.47 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/AssetStudioUtility.DLL ---------------------------------------- OpenTK 組件版本: 3.1.0.0 Win32 版本: 3.1.0 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/OpenTK.DLL ---------------------------------------- AssetStudio 組件版本: 0.16.47.0 Win32 版本: 0.16.47 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/AssetStudio.DLL ---------------------------------------- System.Core 組件版本: 4.0.0.0 Win32 版本: 4.8.4762.0 built by: NET48REL1LAST_B 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll ---------------------------------------- Mono.Cecil 組件版本: 0.11.3.0 Win32 版本: 0.11.3.0 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/Mono.Cecil.DLL ---------------------------------------- System.Configuration 組件版本: 4.0.0.0 Win32 版本: 4.8.4190.0 built by: NET48REL1LAST_B 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll ---------------------------------------- System.Xml 組件版本: 4.0.0.0 Win32 版本: 4.8.4084.0 built by: NET48REL1 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll ---------------------------------------- OpenTK.GLControl 組件版本: 3.1.0.0 Win32 版本: 3.1.0 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/OpenTK.GLControl.DLL ---------------------------------------- mscorlib.resources 組件版本: 4.0.0.0 Win32 版本: 4.8.4084.0 built by: NET48REL1 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/mscorlib.resources/v4.0_4.0.0.0_zh-Hant_b77a5c561934e089/mscorlib.resources.dll ---------------------------------------- AssetStudio.PInvoke 組件版本: 0.16.47.0 Win32 版本: 0.16.47 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/AssetStudio.PInvoke.DLL ---------------------------------------- Accessibility 組件版本: 4.0.0.0 Win32 版本: 4.8.4084.0 built by: NET48REL1 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/Accessibility/v4.0_4.0.0.0__b03f5f7f11d50a3a/Accessibility.dll ---------------------------------------- System.Memory 組件版本: 4.0.1.1 Win32 版本: 4.6.28619.01 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/System.Memory.DLL ---------------------------------------- System.Runtime.CompilerServices.Unsafe 組件版本: 4.0.6.0 Win32 版本: 4.700.19.56404 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/System.Runtime.CompilerServices.Unsafe.DLL ---------------------------------------- System.Runtime 組件版本: 4.0.0.0 Win32 版本: 4.8.4084.0 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Runtime/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Runtime.dll ---------------------------------------- K4os.Compression.LZ4 組件版本: 1.1.11.0 Win32 版本: 1.1.11 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/K4os.Compression.LZ4.DLL ---------------------------------------- System.Buffers 組件版本: 4.0.3.0 Win32 版本: 4.6.28619.01 程式碼庫: file:///C:/Users/daniiellyu/Desktop/Work/Downloads/AssetStudio.net472.v0.16.47/System.Buffers.DLL ---------------------------------------- System.Windows.Forms.resources 組件版本: 4.0.0.0 Win32 版本: 4.8.4084.0 built by: NET48REL1 程式碼庫: file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms.resources/v4.0_4.0.0.0_zh-Hant_b77a5c561934e089/System.Windows.Forms.resources.dll ---------------------------------------- ************** JIT 偵錯 ************** 若要啟用 Just-In-Time (JIT) 偵錯功能,則必須在 此應用程式或電腦的 .config 檔案中,設定 system.windows.forms 區段內的 jitDebugging 值。 且該應用程式也必須在啟用偵錯的狀態下進行 編譯。 例如: <configuration> <system.windows.forms jitDebugging="true" /> </configuration> 當 JIT 偵錯功能啟用後,會將所有未處理的例外狀況 傳送給電腦上已註冊的 JIT 偵錯工具進行處 理,而不是使用這個對話方塊來處理。
最新发布
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值