運用Mono.Ceci類庫修改.NET程序集 走上破解軟件的道路


代碼注入在C++時代很流行,主要是對現有的程序做一些修改,以達到預期的目的。一部分的破解程序,注冊機也是借助於此方法,讓被注入的程序繞過驗證,達到破解的目錄。在.NET中,借助於Mono.Cecil程序集,注入代碼也相當容易。請看下面的代碼,將要被注入的程序:

using System;

namespace Victim
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Console.ReadLine();
        }
    }
}

把上面的程序編譯成一個程序集Victim,執行程序,它會在控制台出版Hello,world。

下面我做一個新的程序,它修改上面的程序集,在Program類型中定義一個新的Test方法,修改Main方法調用我注入的Test方法。

先添加對程序Mono.cecil的引用。

using System;
using Mono.Cecil;
using Mono.Cecil.Cil;

現在,開始加載程序集

AssemblyDefinition asm= AssemblyFactory.GetAssembly("Victim.exe");

添加返回值為void類型的Test方法

//Declare returntype "void"
TypeReference returntype = asm.MainModule.Import(typeof(void));
//Define Methodsignature "private static void Test()"
MethodDefinition testmethod = new MethodDefinition("Test",MethodAttributes.Private|MethodAttributes.Static, returntype);

Test方法的訪問級別為private,static

給Test方法增加方法體,參考下面的代碼寫法

//Push string onto the stack
Instruction msg = testmethod.Body.CilWorker.Create(OpCodes.Ldstr, "Hello from Test()");
//Import external method reference to Console.WriteLine()
MethodReference writeline = asm.MainModule.Import(typeof(Console).GetMethod("WriteLine",new Type[]{typeof(string)}));

加載常量為方法的簽名,在控制台上打印出來

這種寫法,與MSIL代碼一致,C#代碼被翻譯成MSIL,生成的代碼就是這樣的。

最后生成Test方法,代碼如下

//Generate stack-push
testmethod.Body.CilWorker.Append(msg);
//Generate call to WriteLine()
testmethod.Body.CilWorker.InsertAfter (msg,testmethod.Body.CilWorker.Create(OpCodes.Call,writeline));
//Generate return
testmethod.Body.CilWorker.Append (testmethod.Body.CilWorker.Create (OpCodes.Ret));
asm.MainModule.Inject(testmethod, asm.MainModule.Types["Victim.Program"]);

最后,修改程序,讓它調用被注入的Test方法

  //Get Method reference with Name test,
            MethodReference testmethod_ref = null;
            foreach (MethodDefinition mdef in asm.MainModule.Types["Victim.Program"].Methods)
            {
                if (mdef.Name == "Test")
                {
                    testmethod_ref=asm.MainModule.Import(mdef);
                }

            }

            //Create call to the reference
            Instruction call_test = testmethod.Body.CilWorker.Create(OpCodes.Call, testmethod_ref);
         //Insert reference
         asm.EntryPoint.Body.CilWorker.InsertBefore (asm.EntryPoint.Body.Instructions[0],call_test);

保存程序集到磁盤文件中

AssemblyFactory.SaveAssembly(asm, "patched.exe");
 

現在,最初始的程序集代碼看起來是這樣的

using System;

namespace Victim
{
    class Program
    {
        static void Main(string[] args)
        {
            Test();
            Console.WriteLine("Hello World!");
            Console.ReadLine();
        }

        private static void Test()
        {
            Console.WriteLine("Hello from Test()");

        }
    }
}

可以用Reflector來查看生成的Patched.exe,應該與這里的一致。

如果被修改的方法,是許可驗證,或是注冊算法驗證,這一方便可以直接把它的指令清空,另存為一個程序集文件,達到繞過驗證的目的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM