.NET程序的序列号控制

本文通过实例解析了如何破解一个采用简单混淆技术保护序列号的.NET程序,揭示了.NET程序安全性的弱点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

业界对于Java/.NET程序的一个批评就是其安全性。由于IL的特点,各种reflector很容易把代码搞出来。混淆器,貌似一个很常用的功能吧?今天看某个软件,与我们的应用有些类似,所以想借鉴一下。安装好之后,发现有一个License Manager,两个按钮,一个是生成申请信息,一个是导入序列号。(通用的做法,我们的应用也是这么做的)
用reflector打开后,ooh,大概80%的信息都被混淆掉了。field/method的名称,都成了稀奇古怪的文字。还有,我的File Disassembler plug-in居然不能用了,于是只能把所有的method/field信息都paste到notepad上面。(下面所有代码,出于众所周知的原因,我又做了第二次“混淆”,所有的变量/方法名称,都是随意写的)

映入眼帘的第一个method是.ctor,我们知道这个是缺省的构造方法。看代码,如下:

public SomeConstructor()
{
      this.Abcdef123456();
}

上面的方法就是被混淆过了,虽然没意义,但是我们能够“猜测”出来!
进入上面的Abcdef123456方法,如下:

private void Abcdef123456()
{
      this.fedcba654321 = new Container();
      Button button1 = new Button();
      Button button2 = new Button();
      ...
}

好熟悉吧!这就是InitializaComponent方法,查找所有的Abcdef123456,统一替换为这个新名字就可以了。同样的道理,通过看程序运行时候的界面、在查找代码,能更正90%以上的混淆名称,变成一个清晰的表达(虽然不一定和源代码相同)

继续看reflector的结果,有两个分别是Button1_Click和Button2_Click方法。
先看第一个,里面有段代码如下:
byte[] buffer1 = MD5.Encrypt(this.B33498573V + '/v' + this.J39475SDf, false);
stream1.Write(buffer1, 0, buffer1.Length);
byte[] buffer2 = MD5.Encrypt(new UnicodeEncoding().GetBytes(text1));
stream1.Flush();
if (SomeCondition == true)
{
      SaveCPUandDISKInfo(this.B33498573V.Text , this.J39475SDf.Text);
}
InfoShow("/u751f/u6210");

看起来似乎很麻烦?晕,居然还有MD5,还有一些复杂的逻辑判断。怎么搞?分析那个MD5怎么加密的吗?没意义!
首先我们看最后面的InfoShow,我们都知道,这是Unicode编码方式下的文字,简单的用Console.WriteLine出来即可,上面的两个字是“生成”,于是我们猜测,这个和序列号可能相关。很自然的,我们会想到,对于注册的话,会有“成功”或者“失败”。前者转换为unicode是:/u6210/u529f。好吧,我们搜索“/u6210/u529f”。幸运!我们在Button2_Click方法中找到了这个字符串。这个方法代码如下:
if (MD5.CheckRegisterKey(this.FileWillImported.Text)){
    File.Copy();
    ReadRegistry();
    GetCPUandDISKinfoFromDatabase();
    if(ResultFromUpline() == true){
        SetCPUandDISKinfoIntoDatabase();
    }
    InfoShow("/u6210/u529f");
}
else{
    InfoShow("/u975e/u6cd5");
}

我们看到上面的代码,进行了一些复杂的操作,包括什么MD5/SHA/RSA等,最后成功才显示出来一个"/u6210/u529f"。作为游戏,我们继续寻找“失败”的unicode bytes,ooh,没有找到!但是从上面的代码我们可以看出,最后的else是有问题的。同样的Console.WriteLine一下,显示出来的是“非法”这两个汉字。

下面的工作就简单了,ildasm /out方式,把IL弄出来,直接调用SetCPUandDISKinfoIntoDatabase方法,屏蔽掉所有的判断即可。
再用reflector看,该文件并没有任何对于非托管代码的refrence,安装目录下面也没有任何非托管dll,所以基本确定就是这样子了。

总结一下,我们用到的方法,都是20年前的方法。找到关键字符串,查找上下文可疑代码,把相关的判断信息都屏蔽掉,工作就完成了。那些花哨的各种“非对称算法”,没有任何意义。因为在加密解密工作中,流程的转向是重要的,流程本身,是无意义的。这里没有我们10年前看到的那些让人目眩的反侦查手法。

前段时间帮一朋友看过一个.net的应用,用usb key来做的,调用了自己写的Win32 API。同样的弊病,写了非常复杂的加密、解密、反跟踪、反调试处理,可惜的是,这一切都是在Win32中作的,.NET代码只是简单的做了CALL。屏蔽掉了200多行的IL,直接return true,唔,这个世界清净了………………

(再次声明,本文纯属对于.NET简单混淆的一个讨论,文中对于该软件的任何可以识别的特征,都进行了“混淆”)
(对于破解和反汇编,可以看卡巴斯基本人写的那本黑客反汇编揭秘,本人对于汇编纯属文盲)

反过头来,我们考虑本文标题的内容,.NET或者J2EE代码应该如何保护?混淆是必要的,但太脆弱。反跟踪、反调试,我记着有高手在作,但是我不认为这能解决根本问题。不管多复杂的加密手段,被一些低级的代码调用的时候,总能很快的被搞定,如上面分析的那些代码。

 

发表于 2007年1月10日 14:57 - (阅读:1221;评论:7)
href="http://blog.joycode.com/juqiang/Services/Pingback.aspx" rel="pingback" />
评论
发条木偶
日期: 2007-1-10 16:21
呵呵,解这样的混淆就是一个体力活......
10年前就有人搞类似这个的混淆工具了吧,记得vbs和js也都有类似的混淆器
  • #  回复: .NET程序的序列号控制
    juqiang
    日期: 2007-1-10 16:32
    大概也就是5分钟,商业软件这么做,实在让人晕倒………………
  • #  回复: .NET程序的序列号控制
    NCindy
    日期: 2007-1-10 17:24
    所以,做了这么多也是白费,直接开源得啦。还能赚点眼球。
  • #  回复: .NET程序的序列号控制
    Tom Max
    日期: 2007-1-11 8:02
    原因就是.Net的Assembly不能被加壳,现在的Win32本地程序,大部分的Dll和EXE都是加壳的,还有一大堆防止被跟踪调试的工具。
    而.Net程序集为了反射,根本无法做到把接口细细屏蔽。

    所以解决方法只有一个,就是根本不要在很多地方用反射。
    反射信息很有用,这个大家谁都知道。不过,如果我做了一个项目,把产品安装到客户计算机上以后。安装的各种.exe文件,.dll文件上的反射信息用它干嘛?

    即使这个信息.Net Runtime要用,但是也不用做得这么露骨吧。
    博客堂中与微软关系好的人很多,有谁能够向微软提一个意见,让他们放出来NGEN的本地化文件生成版本出来。

    这个东西就是调用.Net即时编译器,把.Net Dll/EXE中的MSIL转成本机代码就可以了,反射信息不用去掉。
    如果有这个工具,可以在安装软件的过程中最后加一步,就是调用NGEN生成本机代码的程序集。安装完毕了以后,客户端的程序文件夹内就是本地代码,与VC,VB6等开发出的程序一样。

    这样就可以防止代码被修改了。
  • #  回复: .NET程序的序列号控制
    geniusleft
    日期: 2007-1-11 11:03
    一个比较好点的办法就是,在程序集里直接加IL.
    包括使用汇编时代也适用的花指令,包括让ILDASM拒绝反编译的一些特殊指令等等.
    其实IL和汇编的思路是一样的,所以反向工程以及反反向工程的套路都是一样适用.
    楼主的思路还是静态跟踪,能被静态反向,这不是.net自己的问题,这是实现的问题.
    reflector的反静态跟踪就做得很好,想要破解reflector,就只有dump内存,这和汇编还是一样呀!
    所以不用说.net程序多脆弱之类的话,只不过大家觉得C#之类用的太顺手,没有关注到IL才是核心.
    别人用C#,你用IL,有心算无心,别人当然无招架之力啊, 别人也用IL, 你破解试试?
    不过,楼主是这半年来博客堂里面发文质量最高的人,此致敬礼!
  • #  回复: .NET程序的序列号控制
    geniusleft
    日期: 2007-1-11 11:10
    @Tom Max:
    其实程序集加不加壳,并不是起决定性作用的,博客园一位兄弟的MaxtoCode,对.net混淆已经做到相当于加壳的程度了,还不是被同一个园子里的兄弟当玩具玩.
    没有不被反编译的,就是汇编也一样,只要被执行,就能被破解,就像密码学的只要有加密就会有解密,必然是双向的.差别只在于成本.
    如果强行破解的成本,超过正常接受的成本,破解成功也没有意义.
  • #  回复: .NET程序的序列号控制
    ec
    日期: 2007-1-11 14:59
    感觉C#下面好像就是开源的一样,开发一点安全感都没有;(
    老兄能不能给个建设性意见?VC.NET编译出来的好像并不能被reflector看到源代码,是否该转VC.NET?  
#  回复: .NET程序的序列号控制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值