您的位置:首頁 > 網絡編程 > C#

MaxtoCode對.Net程序加密的原理及解密探討

日期:2007-06-26 14:47:34 點擊: 來自: 作者:

這里研究的對象是 MaxtoCode 3.1試用版.這里只探討程序代碼的加密.
 

對.Net程序代碼的加密過程如下:

1. 運行 ildasm 將程序集反編譯成 il代碼文件.

2. 對IL代碼文件進行處理.(*)

3. 運行 ilasm 將 IL代碼文件編譯成程序文件.

4. 直接對程序文件中的il字節碼加密.(**)

 

粗體表示的 2 , 4 是關鍵步驟. 

我們先來看看第四步.這一步就是加密的關鍵步驟,這里就是使用MaxtoCode的加密算法對程序代碼進行加密。

顯然,對于破解來說最直接直觀的方法就是對其第四步的逆向解密。

如果從這個方向去破解解密加密過的程序,那就像MaxtoCode號稱的那樣MAXTOCODE的強度建立在加密算法之上。

理論上方法是可行的,但是工作量是非常大的。

 

那么我們還有其它的路可行呢?

現在來看看第二步MaxtoCode都做了什么。

用vs2003建一個最簡單的winform程序,然后用MaxtoCode加密試試。我們將第三步之后,第四步之前的exe文件拿來研究。這個時候的exe程序代碼是還沒有被加密的。可以reflector。

看看 這個exe和我們直接的exe有什么區別:

1. 增加了一個類InFaceMaxtoCode .

2. 類都被增加了一個靜態構造函數,在這個函數里面調用了InFaceMaxtoCode的一個靜態函數Startup。

3. 類的原有構造函數里面也增加了調用InFaceMaxtoCode.Startup的語句。

從這些來看,MaxtoCode的目的是要確保InFaceMaxtoCode.Startup 在程序中能夠最早的運行。

這個行為和win32程序加殼很像,一般殼都是加密程序代碼,然后修改程序的啟動入口,首先執行殼的代碼,完成程序的解密,然后再執行程序。一般殼有一個特點:加密是對整個程序,啟動時也是整個程序完全解密,然后再執行。(我也見到過一個很特別的殼,程序是部分解密的,軟件注冊算法的那一塊, 是執行一部分解密一部分,然后之前解密的又被垃圾信息填充了。)

對于殼只要我們找對了時間和地點,就能從內存中得到我們需要的東西。

那么 MaxtoCode加密后的。Net程序呢?

先來看看 MaxtoCode的加密方式。用ildasm反編譯 加密后的程序,會報很多錯誤,這是正常的,從生產的IL文件看,各個類,函數都還在,只是函數體里面是只有ildasm的錯誤信息。顯然是加密后的代碼無法反編譯。MaxtoCode對。Net程序的加密不是對程序整體的,而只是對函數體加密,程序類結構不變。有一點我們是很清楚的,加密后的程序要能夠正常運行,在運行時肯定是需要解密的。而解密的關鍵就在InFaceMaxtoCode.Startup 里面。

現在我們來看看InFaceMaxtoCode.Startup 里面究竟做了什么。InFaceMaxtoCode 類的代碼如下:

 

 

using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

public class InFaceMaxtoCode
{
    static InFaceMaxtoCode()
    {
        InFaceMaxtoCode.started = false;
    }

    [DllImport("MRuntime3.dll", EntryPoint="CheckRuntime", CharSet=CharSet.Unicode, SetLastError=true, ExactSpelling=true)]
    private static extern int A______();
    [DllImport("KERNEL32.DLL", EntryPoint="GetModuleHandleA", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)]
    private static extern int B______(string x13d52f7d8e232e61);
    private static string ByteToString(byte[] x5fc6100148519126)
    {
        return Encoding.ASCII.GetString(x5fc6100148519126);
    }

    [DllImport("MRuntime3.dll", EntryPoint="MainDLL", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)]
    private static extern bool C______(int x19218ffab70283ef, int xe7ebe10fa44d8d49);
    [DllImport("KERNEL32.DLL", EntryPoint="SetEnvironmentVariableA", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)]
    private static extern bool D______(string x427bb0e14ed9e9b1, string x84ee6c5b88919f4c);
    public static void Startup()
    {
        if (!InFaceMaxtoCode.started)
        {
            string text1 = "";
            string text2 = "MRuntime3.dll";
            if (AppDomain.CurrentDomain.RelativeSearchPath != null)
            {
                if (AppDomain.CurrentDomain.RelativeSearchPath.IndexOf(@":") != -1)
                {
                    text1 = AppDomain.CurrentDomain.RelativeSearchPath;
                }
                else
                {
                    text1 = AppDomain.CurrentDomain.BaseDirectory + AppDomain.CurrentDomain.RelativeSearchPath;
                }
            }
            else
            {
                text1 = AppDomain.CurrentDomain.BaseDirectory;
            }
            string text3 = Environment.GetEnvironmentVariable("path");
            if (text3.IndexOf(text1) == -1)
            {
                InFaceMaxtoCode.D______("path", text3 + ";" + text1.Replace("/", @""));
            }
            if (text1.Substring(text1.Length - 1, 1) == @"")
            {
                text1 = text1;
            }
            else
            {
                text1 = text1 + @"";
            }
            if (File.Exists(text1 + text2) && !File.Exists(Path.GetTempPath() + text2))
            {
                File.Copy(text1 + text2, Path.GetTempPath() + text2);
            }
            if (text3.IndexOf(Path.GetTempPath()) == -1)
            {
                InFaceMaxtoCode.D______("path", text3 + ";" + Path.GetTempPath().Replace("/", @""));
            }
            int num1 = 5;
            num1 = InFaceMaxtoCode.A______();
            if (num1 == 0)
            {
                int num2 = InFaceMaxtoCode.B______(text2);
                int num3 = InFaceMaxtoCode.B______(Assembly.GetExecutingAssembly().Location);
                InFaceMaxtoCode.started = InFaceMaxtoCode.C______(num2, num3);
            }
            else
            {
                //一堆垃圾代碼,報告啟動錯誤信息的。
            }
        }
    }


    private static bool started;
}


Startup精簡后的代碼如下:
public static void Startup()
        {
        if (!InFaceMaxtoCode.started)
        {
            //準備運行庫;
            int num1 = 5;
            num1 = InFaceMaxtoCode.A______();
            if (num1 == 0)
            {
                int num2 = InFaceMaxtoCode.B______(text2);
                int num3 = InFaceMaxtoCode.B______(Assembly.GetExecutingAssembly().Location);
                InFaceMaxtoCode.started = InFaceMaxtoCode.C______(num2, num3);
            }
            else
            {
                //一堆垃圾代碼,報告啟動錯誤信息的。
            }
        }
 

從代碼里面我們看得到InFaceMaxtoCode.Startup 正常啟動后,在整個程序集中只會運行一次。

關鍵函數是 運行庫的MainDLL,這個函數有兩個參數,一個是運行庫的句柄,一個是程序集的句柄。這個句柄實際上就是程序在內存中加載的位置。MaxtoCode加密后的程序都是對齊到0x1000的。

今天就到這里吧。

More..素材圖片 Picture Navigation
相關鏈接 Correlation Link
C#熱門 Class Hot
C#推薦 Class Commend
版權所有:中國網站資源 2005- 未經授權禁止復制或建立鏡像 This Site Tech:XHTML+DIV+CSS+Javascript
CopyRight ® 2005- www.patiodelivery.com online services. all rights reserved. ICP06016627
Optimized to 1024x768 to Firefox,Netscape,Opera,MS-IE6+.
99视频30精品视频在线观看