.NET开发效率的确是高,也非常简单,比起Delphi,BC,Vc来说,在某些方面有很多的优势。我已经打算开始做一位共享软件的作者,看看共享软件市场上有多少.net写的东西,非常抱歉基本上没有,为什么?因为MSIL实在太容易反编译了。。。
关于.net源代码的安全性,关于如何保护您的知识产权,关于市场上流动的混淆工具以及最新的混淆加密工具,我将给您展示一下,全新的保护手段,也能让您使用.net开发共享程序并保护自己的知识产权。
.NET 源代码的安全性(源代码工具真正比拼) (論)(1) .NET开发效率的确是高,也非常简单,比起Delphi,BC,Vc来说,在某些方面有很多的优势。 我已经打算开始做一位共享软件的作者,看看共享软件市场上有多少.net写的东西,非常抱歉基本上没有,为什么?因为MSIL实在太容易反编译了。。。 我时常听到朋友的抱怨,跨什么平台嘛,跨了平台吗?还没有,那为什么不能将.net编译成本机代码?我真不敢相信拿到2002正式版的时候,那种到处找本地编译选项的心情,直到VS2003,我已经放弃了本机代码的愿望……我知道这一切不可能了,.NET是为企业而设计的,不过企业的软件就真的完全没有这样的问题了吗?。 呵呵,相信你也有这种抱怨吧。 关于.net源代码的安全性,关于如何保护您的知识产权,关于市场上流动的混淆工具以及最新的混淆加密工具,我将给您展示一下,全新的保护手段,也能让您使用.net开发共享程序并保护自己的知识产权。
.NET 源代码的安全性(源代码工具真正比拼) (論)(2) 今天被屠宰的对象就是 我们公司使用vb.net开发的一套管理系统。名字就不说了,此系统主程序约3M,其中共有约 3000个方法,事件,等等。是一个中大型的程序,源代码约有 5万行左右(去掉一些自动生成的代码计算后),其中有底层硬件操作类,也有水晶报表操作,数据库操作。我们最关心的是其中的一块,注册类,以及一些核心代码。而我们演示的时候将会把注册代码拿出来演示(当然,不是原来的注册代码。。。那个拿出去,BOSS要杀我的) 而代码保护工具的主角是: 1. Dotfuscator Community Edition //微软推荐的东东,我个人认为非常烂 2. XeonCode //最近最好的混淆器,有可取点.它号称安全,我们今 //天来看看是不是真的安全 3. MaxtoCode //一个不同于混淆的.NET源码工具 MaxtoCode //目前普及版只支持 WindowsApplication的加密 //以后开放 WEB APPlication and Class Library 我们的反编译目标分为二种: 1. C#语言 2. MSIL语言 使用的全是市场上流通的免费反编译工具,我知道收费的反编译工具还会自动还源混淆.收费的我也没有条件去测试 好,开始测试: 我们分别使用上面三样对代码进行混淆或加密。 完毕,测试程序所有功能: 1. Dotfuscator Community Edition 我最不喜欢的混淆器,由于是1.2免费版,所以必须混淆所有模块,导致部分功能不能使用。但我们不关心那些,我们一会将展现被混淆的注册代码(因为类和方法都被混淆,所以必须要花点时间) 2. XeonCode 一个相对强大的混淆工具,我一直认为他与某著名的反编译工具捆绑,导至其它工具能反编译的代码而它不能反编译。我们把它的强度开到最大,勾上所有能勾的选项。(它混淆的Windows Application可以正常运行) 3. MaxtoCode 这是一个加密器,可以与XeonCode叠加使用,并且在2.0版中,将会加入自混淆功能,成为混淆加密一体化的工具。(它混淆的 Windows Applicaton 可以正常运行)
我们最关心的是混淆或加密的结果。OK,请不要急,让我们先看看源代码,再比较一下反编译后的代码。
Private Function Encrypt(ByVal inStr As String) As String Dim key As String = "a#2151336fdaghksfges" Dim out As String Dim j, i, s As Integer i = inStr.Length s = 0 For j = 0 To i - 1 out = out + inStr.Substring(j, 1) + key.Substring(s, 1) s = s + 1 If s >= 20 Then s = 0 Next Return out End Function Private Function Register(ByVal instr As String) As String Dim pRsa As New System.Security.Cryptography.RSACryptoServiceProvider Dim en As New System.Text.ASCIIEncoding Return en.GetString(pRsa.Encrypt(en.GetBytes(Encrypt(instr)), False)) 'Dim a As String 'a = Encrypt(instr) 'Dim b() As Byte 'Dim c() As Byte 'b = en.GetBytes(a) 'c = pRsa.Encrypt(b, False) 'Return en.GetString(c) 这里怕大家看不清楚,特别加了展开的代码 End Function
源代码很清楚,即是对字符串进行插入,然后使用 RSA 进行加密(这里省去了RSA的KEY) 好,那么我们首先来看看使用上面三种工具混淆后的C#代码 1. Dotfuscator Community Edition
private string b(string A_0) { string text3; string text2 = "a#2151336fdaghksfges"; int num1 = A_0.Length; int num3 = 0; int num4 = num1 - 1; for (int num2 = 0; num2 <= num4; num2++) { text3 = text3 + A_0.Substring(num2, 1) + text2.Substring(num3, 1); num3++; if (num3 >= 20) { num3 = 0; } } return text3; } private string a(string A_0) { RSACryptoServiceProvider provider1 = new RSACryptoServiceProvider(); ASCIIEncoding encoding1 = new ASCIIEncoding(); return encoding1.GetString(provider1.Encrypt(encoding1.GetBytes(this.b(A_0)), false));
评价:跟原代码一模一样,只是混淆了类和方法名称,代码中根本未进行混淆,由于是免费版,也只能提供这么多功能.毫无意义 2. XeonCode private string x246b032720dd4c0d(string x96c91b85a03f00b0) {
string str2; string str3; int k; int j; str2 = String.Intern(x1110bdd110cdcea4._d574bb1a8f3e9cbc("uec3buf2faufa06u0102u0803u0efcu15fbu1cf8u23f8u2b25u3220u391au401du471bu4e1bu5520u5c10u630eu6a09u7114", 281144282)); int i1 = x96c91b85a03f00b0.Length; k = 0; i2 = i1 - 1; j = 0; goto IL_003c; VariableExp: k ConstantExp: 20 IL_0029: blt.s IL_0038 //自动的跳转混合 k = 0; goto IL_0038; //花指令 ConstantExp: 1 IL_0031: add.ovf IL_0032: stloc.s 5 VariableExp: k int j; int i2; IL_0038: j++; if (j > i2) { return str3; } str3 = String.Concat(str3, x96c91b85a03f00b0.Substring(j, 1), str2.Substring(k, 1)); } private string x2a0cb95ab84ba877(string x5b3e4cba383dedd9) { RSACryptoServiceProvider provider1 = new RSACryptoServiceProvider(); ASCIIEncoding encoding1 = new ASCIIEncoding(); return encoding1.GetString(provider1.Encrypt(encoding1.GetBytes(this.x246b032720dd4c0d(x5b3e4cba383dedd9)), false)); }
评价:功能强大许多,对于较长的代码会加入花指令进行混淆,从而达到混淆反编译器的目地.这种混淆已经是XeonCode的最大混淆较果,虽然有达到混淆反编译的较果,但耐心仔细的看,并结合IL代码一起阅读,想得到其其算法是一件很容易的事情,最重要的是,有某些反编译器竟然可以去掉花指令,从而达反混淆的较果.所以使用它来保护你的知识版权是不是还不够强大呢? 3. MaxtoCode private string Encrypt(string inStr) { } private string Register(string instr) { } 评价:代码呢????代码已经不见了……不过这就是MaxtoCode的功效,它是加密,不是混淆,你看不到代码了,你完全无法入手去分析,那怕一点珠丝马迹都没有.您还可以结合XeonCode一起使用,达到双重的保护(因为现版本的MaxtoCode不提供混淆功能,您能清楚的看到类及方法的正确名称) 好,刚刚展现的是反编译出来的C#代码,那么,我们再深入一点,真接反汇编为MSIL代码看看能达到什么较果
.NET 源代码的安全性(源代码工具真正比拼) (論)(3)
上面我们展现了反编译技术对混淆过后代码的比较,我们清楚的看到了三个工具的强大性.从C#的反编译结果上来说,无疑MaxtoCode是最优秀的,它已经完全的杜绝你的源代码外泄. 但C#只是一种高级语言,我们希望更底层一点,希望读到更深层的代码MSIL,那么,现在让我们来用各种工具取得它的MSIL代码吧. 源文件的MSIL代码如下: .method private instance string Encrypt(string inStr) cil managed { // Code Size: 84 byte(s) .maxstack 5 .locals ( string text1, int32 num1, int32 num2, string text2, string text3, int32 num3, int32 num4) L_0000: nop L_0001: ldstr "a#2151336fdaghksfges" L_0006: stloc.3 L_0007: ldarg.1 L_0008: callvirt instance int32 string::get_Length() L_000d: stloc.1 L_000e: ldc.i4.0 L_000f: stloc.s num3 L_0011: ldc.i4.0 L_0012: ldloc.1 L_0013: ldc.i4.1 L_0014: sub.ovf L_0015: stloc.s num4 L_0017: stloc.2 L_0018: br.s L_0048 L_001a: ldloc.s text3 L_001c: ldarg.1 L_001d: ldloc.2 L_001e: ldc.i4.1 L_001f: callvirt instance string string::Substring(int32, int32) L_0024: ldloc.3 L_0025: ldloc.s num3 L_0027: ldc.i4.1 L_0028: callvirt instance string string::Substring(int32, int32) L_002d: call string string::Concat(string, string, string) L_0032: stloc.s text3 L_0034: ldloc.s num3 L_0036: ldc.i4.1 L_0037: add.ovf L_0038: stloc.s num3 L_003a: ldloc.s num3 L_003c: ldc.i4.s 20 L_003e: blt.s L_0043 L_0040: ldc.i4.0 L_0041: stloc.s num3 L_0043: nop L_0044: ldloc.2 L_0045: ldc.i4.1 L_0046: add.ovf L_0047: stloc.2 L_0048: ldloc.2 L_0049: ldloc.s num4 L_004b: ble.s L_001a L_004d: ldloc.s text3 L_004f: stloc.0 L_0050: br.s L_0052 L_0052: ldloc.0 L_0053: ret } .method private instance string Register(string instr) cil managed { // Code Size: 44 byte(s) .maxstack 5 .locals ( [mscorlib]System.Text.ASCIIEncoding encoding1, [mscorlib]System.Security.Cryptography.RSACryptoServiceProvider provider1, string text1) L_0000: nop L_0001: newobj instance void [mscorlib]System.Security.Cryptography.RSACryptoServiceProvider::.ctor() L_0006: stloc.1 L_0007: newobj instance void [mscorlib]System.Text.ASCIIEncoding::.ctor() L_000c: stloc.0 L_000d: ldloc.0 L_000e: ldloc.1 L_000f: ldloc.0 L_0010: ldarg.0 L_0011: ldarg.1 L_0012: callvirt instance string TestRegister.Form1::Encrypt(string) L_0017: callvirt instance unsigned int8[] [mscorlib]System.Text.Encoding::GetBytes(string) L_001c: ldc.i4.0 L_001d: callvirt instance unsigned int8[] [mscorlib]System.Security.Cryptography.RSACryptoServiceProvider::Encrypt(unsigned int8[], bool) L_0022: callvirt instance string [mscorlib]System.Text.ASCIIEncoding::GetString(unsigned int8[]) L_0027: stloc.2 L_0028: br.s L_002a L_002a: ldloc.2 L_002b: ret }
1. Dotfuscator Community Edition MSIL .method private instance string b(string A_0) cil managed { // Code Size: 84 byte(s) .maxstack 5 .locals ( string text1, int32 num1, int32 num2, string text2, string text3, int32 num3, int32 num4) L_0000: nop L_0001: ldstr "a#2151336fdaghksfges" L_0006: stloc.3 L_0007: ldarg.1 L_0008: callvirt instance int32 string::get_Length() L_000d: stloc.1 L_000e: ldc.i4.0 L_000f: stloc.s num3 L_0011: ldc.i4.0 L_0012: ldloc.1 L_0013: ldc.i4.1 L_0014: sub.ovf L_0015: stloc.s num4 L_0017: stloc.2 L_0018: br.s L_0048 L_001a: ldloc.s text3 L_001c: ldarg.1 L_001d: ldloc.2 L_001e: ldc.i4.1 L_001f: callvirt instance string string::Substring(int32, int32) L_0024: ldloc.3 L_0025: ldloc.s num3 L_0027: ldc.i4.1 L_0028: callvirt instance string string::Substring(int32, int32) L_002d: call string string::Concat(string, string, string) L_0032: stloc.s text3 L_0034: ldloc.s num3 L_0036: ldc.i4.1 L_0037: add.ovf L_0038: stloc.s num3 L_003a: ldloc.s num3 L_003c: ldc.i4.s 20 L_003e: blt.s L_0043 L_0040: ldc.i4.0 L_0041: stloc.s num3 L_0043: nop L_0044: ldloc.2 L_0045: ldc.i4.1 L_0046: add.ovf L_0047: stloc.2 L_0048: ldloc.2 L_0049: ldloc.s num4 L_004b: ble.s L_001a L_004d: ldloc.s text3 L_004f: stloc.0 L_0050: br.s L_0052 L_0052: ldloc.0 L_0053: ret } .method private instance string a(string A_0) cil managed { // Code Size: 44 byte(s) .maxstack 5 .locals ( [mscorlib]System.Text.ASCIIEncoding encoding1, [mscorlib]System.Security.Cryptography.RSACryptoServiceProvider provider1, string text1) L_0000: nop L_0001: newobj instance void [mscorlib]System.Security.Cryptography.RSACryptoServiceProvider::.ctor() L_0006: stloc.1 L_0007: newobj instance void [mscorlib]System.Text.ASCIIEncoding::.ctor() L_000c: stloc.0 L_000d: ldloc.0 L_000e: ldloc.1 L_000f: ldloc.0 L_0010: ldarg.0 L_0011: ldarg.1 L_0012: callvirt instance string c::b(string) L_0017: callvirt instance unsigned int8[] [mscorlib]System.Text.Encoding::GetBytes(string) L_001c: ldc.i4.0 L_001d: callvirt instance unsigned int8[] [mscorlib]System.Security.Cryptography.RSACryptoServiceProvider::Encrypt(unsigned int8[], bool) L_0022: callvirt instance string [mscorlib]System.Text.ASCIIEncoding::GetString(unsigned int8[]) L_0027: stloc.2 L_0028: br.s L_002a L_002a: ldloc.2 L_002b: ret }
评价:还是和源代码基本上一样…我不知道把这种东西给我们有什么意思 2. XeonCode MSIL .method private instance string x246b032720dd4c0d(string x96c91b85a03f00b0) cil managed { // Code Size: 105 byte(s) .maxstack 6 .locals ( string text1, int32 num1, int32 num2, string text2, string text3, int32 num3, int32 num4) L_0000: ldstr "uec3buf2faufa06u0102u0803u0efcu15fbu1cf8u23f8u2b25u3220u391au401du471bu4e1bu5520u5c10u630eu6a09u7114" L_0005: ldc.i4 281144282 L_000a: call string x2715eff98365d956.x1110bdd110cdcea4::_d574bb1a8f3e9cbc(string, int32) L_000f: call string string::Intern(string) L_0014: stloc.3 L_0015: ldarg.1 L_0016: callvirt instance int32 string::get_Length() L_001b: stloc.1 L_001c: ldc.i4.0 L_001d: stloc.s num3 L_001f: br.s L_0043 L_0021: stloc.s text3 L_0023: ldloc.s num3 L_0025: br.s L_0030 L_0027: ldc.i4.s 20 L_0029: blt.s L_0038 L_002b: ldc.i4.0 L_002c: stloc.s num3 L_002e: br.s L_0038 L_0030: ldc.i4.1 L_0031: add.ovf L_0032: stloc.s num3 L_0034: ldloc.s num3 L_0036: br.s L_0027 L_0038: ldloc.2 L_0039: ldc.i4.1 L_003a: add.ovf L_003b: stloc.2 L_003c: ldloc.2 L_003d: ldloc.s num4 L_003f: ble.s L_004c L_0041: br.s L_0066 L_0043: ldc.i4.0 L_0044: ldloc.1 L_0045: ldc.i4.1 L_0046: sub.ovf L_0047: stloc.s num4 L_0049: stloc.2 L_004a: br.s L_003c L_004c: ldloc.s text3 L_004e: ldarg.1 L_004f: ldloc.2 L_0050: ldc.i4.1 L_0051: callvirt instance string string::Substring(int32, int32) L_0056: ldloc.3 L_0057: ldloc.s num3 L_0059: ldc.i4.1 L_005a: callvirt instance string string::Substring(int32, int32) L_005f: call string string::Concat(string, string, string) L_0064: br.s L_0021 L_0066: ldloc.s text3 L_0068: ret } .method private instance string x2a0cb95ab84ba877(string x5b3e4cba383dedd9) cil managed { // Code Size: 39 byte(s) .maxstack 6 .locals ( [mscorlib]System.Text.ASCIIEncoding encoding1, [mscorlib]System.Security.Cryptography.RSACryptoServiceProvider provider1, string text1) L_0000: newobj instance void [mscorlib]System.Security.Cryptography.RSACryptoServiceProvider::.ctor() L_0005: stloc.1 L_0006: newobj instance void [mscorlib]System.Text.ASCIIEncoding::.ctor() L_000b: stloc.0 L_000c: ldloc.0 L_000d: ldloc.1 L_000e: ldloc.0 L_000f: ldarg.0 L_0010: ldarg.1 L_0011: callvirt instance string x9324a7f62e6a3ae4.xaa4f033827d75b4d::x246b032720dd4c0d(string) L_0016: callvirt instance unsigned int8[] [mscorlib]System.Text.Encoding::GetBytes(string) L_001b: ldc.i4.0 L_001c: callvirt instance unsigned int8[] [mscorlib]System.Security.Cryptography.RSACryptoServiceProvider::Encrypt(unsigned int8[], bool) L_0021: callvirt instance string [mscorlib]System.Text.ASCIIEncoding::GetString(unsigned int8[]) L_0026: ret }
评价:有点花指令,不过在MSIL的状态下,源码的逻辑尽显无疑,也可以畅读一番,不太理想 3. MaxtoCode MSIL .method private instance string Encrypt(string inStr) cil managed { } .method private instance string Register(string instr) cil managed { } 评价:依然无法看到代码,那怕是较底层的MSIL也无法看见.这下应该安全了. 以上的比较让您更清楚谁对您的知识产权保护更完美了吧。 排除代码层面上的因素,我们再看看其它方面吧。
.NET 源代码的安全性(源代码工具真正比拼) (論)(4)
1. Dotfuscator Community Edition 不知道Microsoft为什么推荐这个东东,是不是出来的最早还是别的什么,反正它的功能是最弱的,唯一不同的是,它将类名,方法名缩成1~2个字符,从而缩小了整个文件的尺寸,虽然缩小尺寸并不多,不过我可能也只是它唯一的优点了(免费版,高强度的收费版可达数千美元,用不起啊) 2. XeonCode 这个东东破解版很多,功能也很强大。它可以集成整个FrameWork到你的程序中……我实在没有想出来这有什么用,除了使程序的启动速度巨慢以及尺寸变得大。 它还可以不让ilDasm以及一些使用Ms提供的API的反编译器查看 它会在你的程序中加足使Method的数量变为0x2000个,从而混淆某个重要标志的位数 它会在你的代码中加入花指指令及其它的跳转指令,从而混淆代码,同时降低执行率 总的来说,它的混淆强度已经算是不错了 3. MaxtoCode 最新版的它目前还不提供混淆功能,它计划在推出WEB application and Class Library加密功能后才推出加密混淆一体化的功能。 它使用的技术手段是利用ASM对MSIL代码加密,从而不用禁止任何反编译工具也可以达到无法反编译的功能,上面的例子已经很清楚的展现给你们了。 它的执行效率:在普及版中,我们的用例程序大约3000个方法需要加密的情况下,加密耗时 < 1秒。您根本感觉不到与正常使用有什么区别 它有一个缺点,就是加过密后的程序,只能运行在WINDOWS系列平台上。如果您的程序目前只运行在WINDOWS平台上,那么MaxtoCode将是你知识产权的最佳武器(.NET的设计是可以跨平台的,不过Microsoft并没有去考虑跨平台的工作)。如果您的程序需要运行在其它系统上,您可以只用MaxtoCode的混淆功能在以后的版本中。 总的来的,我只是从客观的因素上对以上工具进行评价,你也可以有自己的见解。
|