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

简介: 这里研究的对象是某壳3.1试用版.这里只探讨程序代码的加密.   对.Net程序代码的加密过程如下: 1. 运行 ildasm 将程序集反编译成 il代码文件. 2. 对IL代码文件进行处理.(*) 3. 运行 ilasm 将 IL代码文件编译成程序文件. 4. 直接对程序文件中的il字节码加密.(**)   粗体表示的 2 , 4 是关键步骤. 我们先来看看第四步.这一步就是加密的关键步骤,这里就是使用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的。

今天就到这里吧。

目录
相关文章
|
10月前
|
安全 算法 网络协议
解析:HTTPS通过SSL/TLS证书加密的原理与逻辑
HTTPS通过SSL/TLS证书加密,结合对称与非对称加密及数字证书验证实现安全通信。首先,服务器发送含公钥的数字证书,客户端验证其合法性后生成随机数并用公钥加密发送给服务器,双方据此生成相同的对称密钥。后续通信使用对称加密确保高效性和安全性。同时,数字证书验证服务器身份,防止中间人攻击;哈希算法和数字签名确保数据完整性,防止篡改。整个流程保障了身份认证、数据加密和完整性保护。
|
7月前
|
数据采集 监控 API
加密货币 Pump 监测刮刀工具开发原理及实现路径
开发Pump监测刮刀工具需综合运用高频数据采集、波动率建模、跨平台对冲三大核心技术,2025年的技术瓶颈已从基础数据获取转向超低延迟执行与合规适配。建议采用模块化开发策略,优先实现核心监控功能,再逐步接入AI决策与链上套利模块。代码示例需根据最新交易所API文档动态调整,并严格遵守所在地监管法规。
|
12月前
|
安全 算法 网络协议
【网络原理】——图解HTTPS如何加密(通俗简单易懂)
HTTPS加密过程,明文,密文,密钥,对称加密,非对称加密,公钥和私钥,证书加密
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
602 13
|
Java Maven 数据安全/隐私保护
如何实现Java打包程序的加密代码混淆,避免被反编译?
【10月更文挑战第15天】如何实现Java打包程序的加密代码混淆,避免被反编译?
2512 2
|
存储 安全 算法
网络安全与信息安全:构建数字世界的防线在数字化浪潮席卷全球的今天,网络安全与信息安全已成为维系现代社会正常运转的关键支柱。本文旨在深入探讨网络安全漏洞的成因与影响,剖析加密技术的原理与应用,并强调提升公众安全意识的重要性。通过这些综合性的知识分享,我们期望为读者提供一个全面而深刻的网络安全视角,助力个人与企业在数字时代中稳健前行。
本文聚焦网络安全与信息安全领域,详细阐述了网络安全漏洞的潜在威胁、加密技术的强大防护作用以及安全意识培养的紧迫性。通过对真实案例的分析,文章揭示了网络攻击的多样性和复杂性,强调了构建全方位、多层次防御体系的必要性。同时,结合当前技术发展趋势,展望了未来网络安全领域的新挑战与新机遇,呼吁社会各界共同努力,共筑数字世界的安全防线。
|
存储 开发框架 .NET
浅析.NET6中的await原理
浅析.NET6中的await原理
209 1
|
Ubuntu 持续交付 API
如何使用 dotnet pack 打包 .NET 跨平台程序集?
`dotnet pack` 是 .NET Core 的 NuGet 包打包工具,用于将代码打包成 NuGet 包。通过命令 `dotnet pack` 可生成 `.nupkg` 文件。使用 `--include-symbols` 和 `--include-source` 选项可分别创建包含调试符号和源文件的包。默认情况下,`dotnet pack` 会先构建项目,可通过 `--no-build` 跳过构建。此外,还可以使用 `--output` 指定输出目录、`-c` 设置配置等。示例展示了创建类库项目并打包的过程。更多详情及命令选项,请参考官方文档。
808 13
|
存储 运维
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
310 2
|
自然语言处理 C# 图形学
使用dnSpyEx对.NET Core程序集进行反编译、编辑和调试
使用dnSpyEx对.NET Core程序集进行反编译、编辑和调试
273 0