某壳对.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 - 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的。

今天就到这里吧。

时间: 2024-12-23 18:57:44

某壳对.Net程序加密的原理及解密探讨一的相关文章

某壳对.Net程序加密的原理及解密探讨五(元数据还原以及IL解码的改进)

前一回讲了 IL字节码的解码问题,并提供了一个小工具,但解码的效果和 ildasm还是差很多,给阅读也带来了一些困难.还有就是有些文件选择文件后解码会出错,这是因为maxtocode对文件里面的元数据进行了随机加密.这一回主要解决元数据的还原以及对解码进行改进. 题外话:国庆后maxtocode推出了3.12版,称对.net formwork 2.0获取msil代码的方式进行了限制.即在不作任何改进的情况下,我们前面介绍的方法将无法取得IL字节码.dreaman已经找到了取消这个限制的方法了,不

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

自上次写第一篇文章到现在不知不觉两个月过去了,这篇文章我们将介绍怎么获取解密后的IL字节代码.我们先回顾一下前文,在上一回我们提到"InFaceMaxtoCode.Startup 正常启动后,在整个程序集中只会运行一次.".当时这种说法是很武断的,如果 "InFaceMaxtoCode.C______(num2, num3)" 的返回值总是 false的话,该函数就会被执行多次,不过根据后来动态调试的结果,我们证实了"InFaceMaxtoCode.C__

某壳对.Net程序加密的原理及解密探讨三(实例解密)

上一回我们试验了通过反射的方式获取method的源代码.这次我们就用一个实例来演示dump一个程序集中的所有类型和方法的IL源代码. 首先打开VS2005 新建一个C#的windows程序:在窗体添加添加一个2个 button,2个label,一个textbox,一个 checkbox,一个savefiledialog.界面如下: 事件代码如下:   1  public class Form1 : Form  2       {  3             // Methods  4     

某壳对.Net程序加密的原理及解密探讨四(翻译IL字节码)

在前面几章我们已经能够去掉被加密程序原始的IL字节码了.这些字节码是十六进制的,我人脑直接来阅读是非常困难的.这一章主要介绍将字节码翻译成 可阅读的 MSIL 汇编代码,以及前几章的遗留问题解决.  这里我们将用到上面这个工具软件 IlByteDecoder. 软件下载地址:http://www.bbsftp.com/temp/ILByteDecode.rar使用比较简单,注意中间那个 文件名 一项,这个可以填也可以不填,如果没有填的话,解码出来的 msil 代码中将无法显示字符串值和方法名称.

android-求360隐私保险箱中的加密视频原理

问题描述 求360隐私保险箱中的加密视频原理 我的android系统手机中装了一个360隐私保险箱 用了一下其中的加密视频的功能 发现加密大视频一下子就完成了 所以我怀疑他只是改个文件名移动一下位置,于是我到他的目录下用播放器播放 发现无法播放 然后我又到保险箱里 发现竟然可以直接播放 没看见解密过程 感到十分不解 求解 解决方案 估计就是加密了头文件,头文件动了,别的播放器当然无法识别了. 加密音视频有特定的一套方案,卷积好像,是需要时间的 解决方案二: 这不难吧,它可以将关键的数据段比如一些

代码 还原 不执行-程序加密需要替换回车符,但解密还原后,遇到不执行的问题,怎么处理?

问题描述 程序加密需要替换回车符,但解密还原后,遇到不执行的问题,怎么处理? <%dd=5555bb=6666response.Write(dd&bb)%> 但换个方式就不执行.测试一下下面这个,它不运行. <%function UnEncode(cc)cc=replace(ccaaaa""vbcr)UnEncode=ccend functionss=""dd=5555aaaabb=6666aaaaresponse.Write(dd&

批量对加密的asp代码解密的asp程序

程序|加密|解密 <% @Language="JavaScript" %><% /* *--------------- decode.asp ----------------- * 功能:遍历某个目录下的所有文件,对加密过的.asp文件 *      进行解密,并写入源文件中. * 实例:单个文件解密 * Response.Write(DncodeFile(Server.MapPath("conn.asp"))); * 实例:目录下所有文件解密. 

网站安全之ASP程序加密/解密方法大揭密

安全|程序|加密|解密 如今,用ASP技术构建的网站随处可见.由于ASP脚本是在服务器上解释执行的(无法编译),因此你辛苦开发出来的ASP代码,很容易被人拷去任意修改,如何保护ASP源代码呢?这是每个ASP站长都会遇到的难题,网上求解这类问题的帖子非常多,下面我们就来谈谈ASP程序的加密方法. 一.如何加密ASP程序? 目前对ASP程序的加密方法主要有三种:脚本编码器(SRCENC.EXE)加密.组件加密.自编程序加密,下面我们就来展开介绍这三种加密方法. 1.使用微软的MS Script En

C++ 学习之旅一——Windows程序内部运行原理

      学习C++与.net不同的是,一定要搞清楚Windows程序内部运行原理,因为他所涉及大多数是操作系统的调用,而.net毕竟是在.netFrameWork上唱戏.        那Windows应用程序,操作系统,计算机硬件之间的相互关系究竟什么了,下面的图就给予很好的解释.       向下箭头①是 应用程序运行判断处理的结果,输出到输出的设备.       向上箭头②是输入设备,输入到操作系统中.       向下箭头③代表API,我们要解释以下API是什么.API是应用程序接口