• 某壳对.Net程序加密的原理及解密探讨一


     

    这里研究的对象是某壳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 - 11== @"\")
                {
                    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的。

    今天就到这里吧。

  • 相关阅读:
    单例类
    日期类2
    日历类
    日期转换类
    抓取网页内容并截图
    关于计时器与多线程
    让页面上图片不变形
    Thread 调用方法的方式
    语音放大缩小
    阻止Enter键回发到服务端Asp.net
  • 原文地址:https://www.cnblogs.com/rick/p/453150.html
Copyright © 2020-2023  润新知