.NET核心代码保护策略-隐藏核心程序集
2013-09-26 14:34
525 查看
经过之前那个道德指责风波过后也有一段时间没写博客了,当然不是我心怀内疚才这么久不写,纯粹是程序员的通病。。怎一个懒字了得,本来想写一些长篇大论反讽一下那些道德高人的。想想还是算了,那样估计会引来新一波攻势,没什么实际意义,影响风气,大家看了也不爽,这次写点有实际意义的,说说我是怎么保护我的代码的,个人心得,如有不妥的地方请见谅。
我们都知道.NET的代码容易被反编译出来,站在破解者的角度来看,破解一个软件情况可分为几种:
1.修改注册验证的代码,达到绕过注册的效果;
2.破解出注册核心算法,写出注册机;
3.完全复制代码,做成一个可编译修改的项目;
从危害是上来看,第三种是最严重的,如果你的软件被实力更强的竞争对手复制了,那简直是毁灭性的打击,理论上.NET没有什么软件是不能破解复制的,只要有高手死了心要破你的软件,保护再好也是无意义的,那时只能认命,当然一般高手也不屑于破解一些没意义的东西。我们虽然做不到完全保护代码,但是我们可以增加他们的破解难度,防不了高手,至少我们要防住像我这种普通的程序员,不能随便什么阿猫阿狗都能染指我们的代码,这简直是对程序员智商的侮辱嘛。
一般我们保护软件的几个重要过程:
1.设计机器码;
2.根据机器码生成注册码;
3.验证注册码(本地+远程验证);
4.给程序集加强命名;
5.对程序集进行代码混淆;
当然这么多步骤一次性也说不完,当前我主要就说说怎么隐藏自己的核心程序集,也就是.DLL动态库。我们平时写项目的时候,里面肯定会有各种各样的动态库出现,当我们编译的时候都会有一个*.DLL的动态库出现,DLL里包含了许多元数据,这就很容易被人用反编译软件完全看到里面的代码,所以隐藏程序集就很重要了,思路是:把程序集存入内存中,到该用的时候才会去用它,这样反编译软件就不能轻易的看到我们的代码了,但是一个比较大的项目,把全部程序集存入内存是不现实的,我们只能把几个比较核心的程序集,如注册验证过程,登陆过程,核心算法过程等隐藏,由于你隐藏了一些重要的程序集,一些人就算得到了你的其他代码,想要软件正确运行还是需要很大的工夫的。by Zengg
花了一点时间写了一个隐藏程序集的的小DEMO,如下图:
AssemblyControl
AssemblyWPFDemo里的AssemblyTestSource类里存放的就是我们AssemblyTest类库的二进制流,这个二进制流是通过我写的这个DEMO转换来的,可看上图,里面有个“转换代码”的按钮,当你打开了一个DLL后就可以把它转换为C#代码,通过加载这个数据流就能获得AssemblyTest的程序集,有了程序集你就能使用程序集里的功能。由于AssemblyTestSource的代码比较多,贴上来会影响排版,大家自行下载DEMO来看。
其他的就是一些简单的逻辑处理了,不一一贴上来,我这里只是起着抛砖引玉的作用,写得比较粗糙,大家要注意的是,程序集的二进制流要存放的隐蔽,要有艺术,不然别人还是能把二进制流取出来存入文件,这就又变成DLL了,有心研究的可以去研究一下把这些二进制数据进行个加密,尽量增加反编译的难度。
这里我又要唠叨一下破解者和软件开发者的关系,我们写软件保护就是和破解者斗智斗勇的过程,这两个是良性的竞争关系,如果你输了只能说明你技不如人,回去回炉一下卷土再来,一味的指责并不能使你的技术提高,你得了解破解人的思路是怎么想的才能设计出更好的保护手段,我相信一个高明的破解者,也一定是一个高明的软件开发者,这两个关系并没有什么分明的界限。。。另提前祝大家国庆快乐。。。下篇博客不知道什么时候才能出来了。。。以后的几篇我可能会围绕着保护这个主题来写..
源码:http://pan.baidu.com/s/1xc9aW
如果您看了本篇博客,觉得对您有所收获,请点击右下角的 [推荐]
如果您想转载本博客,请注明出处
如果您对本文有意见或者建议,欢迎留言
感谢您的阅读,请关注我的后续博客 Zengg
作者:Zengg 出处:http://www.cnblogs.com/01codeworld/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
我们都知道.NET的代码容易被反编译出来,站在破解者的角度来看,破解一个软件情况可分为几种:
1.修改注册验证的代码,达到绕过注册的效果;
2.破解出注册核心算法,写出注册机;
3.完全复制代码,做成一个可编译修改的项目;
从危害是上来看,第三种是最严重的,如果你的软件被实力更强的竞争对手复制了,那简直是毁灭性的打击,理论上.NET没有什么软件是不能破解复制的,只要有高手死了心要破你的软件,保护再好也是无意义的,那时只能认命,当然一般高手也不屑于破解一些没意义的东西。我们虽然做不到完全保护代码,但是我们可以增加他们的破解难度,防不了高手,至少我们要防住像我这种普通的程序员,不能随便什么阿猫阿狗都能染指我们的代码,这简直是对程序员智商的侮辱嘛。
一般我们保护软件的几个重要过程:
1.设计机器码;
2.根据机器码生成注册码;
3.验证注册码(本地+远程验证);
4.给程序集加强命名;
5.对程序集进行代码混淆;
当然这么多步骤一次性也说不完,当前我主要就说说怎么隐藏自己的核心程序集,也就是.DLL动态库。我们平时写项目的时候,里面肯定会有各种各样的动态库出现,当我们编译的时候都会有一个*.DLL的动态库出现,DLL里包含了许多元数据,这就很容易被人用反编译软件完全看到里面的代码,所以隐藏程序集就很重要了,思路是:把程序集存入内存中,到该用的时候才会去用它,这样反编译软件就不能轻易的看到我们的代码了,但是一个比较大的项目,把全部程序集存入内存是不现实的,我们只能把几个比较核心的程序集,如注册验证过程,登陆过程,核心算法过程等隐藏,由于你隐藏了一些重要的程序集,一些人就算得到了你的其他代码,想要软件正确运行还是需要很大的工夫的。by Zengg
花了一点时间写了一个隐藏程序集的的小DEMO,如下图:
// *********************************************************************** // Assembly : AssemblyWPFDemo // Author : 曾意恒 // Created : 09-25-2013 // // Last Modified By : 曾意恒 // Last Modified On : 09-25-2013 // *********************************************************************** // <copyright file="AssemblyControl.cs" company=""> // Copyright 2013(c) . All rights reserved. // </copyright> // <summary>程序集操作类</summary> // *********************************************************************** using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; namespace AssemblyWPFDemo { /// <summary> /// Class AssemblyControl /// </summary> public class AssemblyControl { /// <summary> /// 把指定程序集转化为二进制流 /// </summary> /// <param name="assemblyFileName">路径程序集</param> /// <returns>二进制源</returns> public byte[] GetAssemblyToByte(string assemblyFileName) { byte[] assemblySource=null; if (File.Exists(assemblyFileName)) { FileStream fStream = new FileStream(assemblyFileName, FileMode.Open); BinaryReader bReader = new BinaryReader(fStream); assemblySource = bReader.ReadBytes(Convert.ToInt32(fStream.Length)); fStream.Close(); bReader.Close(); } return assemblySource; } /// <summary> /// 二进制源转换为C#代码,方便我们新建一个静态类存入数据 /// </summary> /// <param name="memberNmae">字段名</param> /// <param name="assemblySource">二进制源</param> /// <returns>System.String.</returns> public string ByteConverToString(string memberNmae, byte[] assemblySource) { string strAssemblySource = "public byte[] " + memberNmae + "={"; foreach (byte b in assemblySource) { strAssemblySource += b.ToString() + ","; } strAssemblySource = strAssemblySource.Substring(0, strAssemblySource.Length - 1); strAssemblySource += "};\n"; return strAssemblySource; } /// <summary> /// 通过二进制数据源转换为程序集 /// </summary> /// <param name="assemblySource">二进制源</param> /// <returns>程序集</returns> /// <exception cref="System.NullReferenceException">assembly为空,请检查二进制数据源</exception> public Assembly GetAssemblyBySource(byte[] assemblySource) { Assembly assembly = Assembly.Load(assemblySource); if (assembly == null) throw new NullReferenceException("assembly为空,请检查二进制数据源"); return assembly; } /// <summary> /// 获取该程序集里有多少个类 /// </summary> /// <param name="assembly">程序集</param> /// <returns>类列表</returns> public Type[] GetTypesByAssembly(Assembly assembly) { if (assembly == null) return null; Type[] types = assembly.GetTypes(); return types; } /// <summary> /// 获取类名 /// </summary> /// <param name="type">类</param> /// <returns>类名</returns> public string GetTypeName(Type type) { if (type == null) return ""; return type.Name; } /// <summary> /// 获取类里的所有公开方法的信息 /// </summary> /// <param name="type">The type.</param> /// <returns>MemberInfo[][].</returns> public MemberInfo[] GetMemberInfosByType(Type type) { if (type == null) return null; return type.GetMethods(); } /// <summary> /// 获取当前方法的名称 /// </summary> /// <param name="menberInfo">The menber info.</param> /// <returns>System.String.</returns> public string GetMemberInfoName(MemberInfo menberInfo) { return menberInfo.Name; } /// <summary> /// 执行无返回值的方法 /// </summary> /// <param name="menberInfo">方法体</param> /// <param name="obj">类实体</param> public void InvokeMember(MemberInfo menberInfo,object obj) { obj.GetType().InvokeMember(menberInfo.Name, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, obj, null); } /// <summary> /// 执行有返回值的方法 /// </summary> /// <param name="menberInfo">方法体</param> /// <param name="obj">类实体</param> /// <returns>返回结果</returns> public object InvokeMemberHaveResult(MemberInfo menberInfo, object obj) { return obj.GetType().InvokeMember(menberInfo.Name, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, obj, null); } } }
AssemblyControl
AssemblyWPFDemo里的AssemblyTestSource类里存放的就是我们AssemblyTest类库的二进制流,这个二进制流是通过我写的这个DEMO转换来的,可看上图,里面有个“转换代码”的按钮,当你打开了一个DLL后就可以把它转换为C#代码,通过加载这个数据流就能获得AssemblyTest的程序集,有了程序集你就能使用程序集里的功能。由于AssemblyTestSource的代码比较多,贴上来会影响排版,大家自行下载DEMO来看。
其他的就是一些简单的逻辑处理了,不一一贴上来,我这里只是起着抛砖引玉的作用,写得比较粗糙,大家要注意的是,程序集的二进制流要存放的隐蔽,要有艺术,不然别人还是能把二进制流取出来存入文件,这就又变成DLL了,有心研究的可以去研究一下把这些二进制数据进行个加密,尽量增加反编译的难度。
这里我又要唠叨一下破解者和软件开发者的关系,我们写软件保护就是和破解者斗智斗勇的过程,这两个是良性的竞争关系,如果你输了只能说明你技不如人,回去回炉一下卷土再来,一味的指责并不能使你的技术提高,你得了解破解人的思路是怎么想的才能设计出更好的保护手段,我相信一个高明的破解者,也一定是一个高明的软件开发者,这两个关系并没有什么分明的界限。。。另提前祝大家国庆快乐。。。下篇博客不知道什么时候才能出来了。。。以后的几篇我可能会围绕着保护这个主题来写..
源码:http://pan.baidu.com/s/1xc9aW
如果您看了本篇博客,觉得对您有所收获,请点击右下角的 [推荐]
如果您想转载本博客,请注明出处
如果您对本文有意见或者建议,欢迎留言
感谢您的阅读,请关注我的后续博客 Zengg
作者:Zengg 出处:http://www.cnblogs.com/01codeworld/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章推荐
- .NET核心代码保护策略:隐藏核心程序集
- .NET核心代码保护策略
- Delphi 灵活运用接口(interface), 隐藏核心代码, 设计低耦合程序.
- Delphi 灵活运用接口(interface), 隐藏核心代码, 设计低耦合程序.
- Bullet核心类介绍(Bullet 2.82 HelloWorld程序及其详解,附程序代码)
- 揭开.NET程序保护的秘密
- mscorwks.dll在DotNet中的地位以及在.Net代码保护方面的应用
- .Net 下的保护和逆向工程,时代决定我们必须破解NET程序
- 基于visual c++之windows核心编程代码分析 保持程序单实例运行
- .net程序中资源文件的保护办法探讨
- mscorwks.dll在DotNet中的地位以及在.Net代码保护方面的应用
- 怎样保护你的.NET程序
- SAP ABAP如何隐藏你写的程序代码(危险,请小心谨慎)
- mscorwks.dll在.net中的地位以及在.net代码保护方面的应...
- 2003年的代码-隐藏任意文件/目录-禁止访问任意文件/目录-隐藏任意注册表子键-禁止访问任意注册表子键-隐藏任意进程[NT系列]-自启动任意进程[95系列]-自定义可信赖进程(可以访问被保护的文件/目录,和/或者子键),并采用CRC32校验
- .NET程序的代码混淆、加壳与脱壳
- 在Delphi中隐藏程序进程的方法[2]--纯DELPHI代码方式
- .NET程序的代码混淆、加壳与脱壳
- python批量同步web服务器代码核心程序
- .NET程序中常用的28种代码