转:.NET程序的序列号控制

转:http://blog.joycode.com/juqiang/archive/2007/01/10/91279.aspx

业界对于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代码应该如何保护?混淆是必要的,但太脆弱。反跟踪、反调试,我记着有高手在作,但是我不认为这能解决根本问题。不管多复杂的加密手段,被一些低级的代码调用的时候,总能很快的被搞定,如上面分析的那些代码。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值