混淆代码的编码注意事项
有些客户端的.net代码,在完成编码后需要用一些工具(如dotfuscator)进行混淆。
一般“混淆”有2个比较明显的改变:成员名称的改变(命名空间、类名、方法名、属性名等);混淆代码过程(当然是在不改变原实现的情况下)。
正常而言,工具的混淆是不会影响代码运行;但是这里要说一下,“成员的名称的改变”会在有的情况下,让混淆后的程序异常。
因此在这里总结一些经验,避免由“成员的名称的改变”造成的错误。
1、Serializable的类
如果有用.net自带的配置文件做序列化的,比如XmlSerializer,这种类就要注意不要混淆。
因为.net的自带序列化都会使用反射属性的名称,做配置文件的值;这样一混淆之后,就会出现配置文件的值跟混淆后的对应不上,容易出错。
我们可以在混淆时,剔除这些类;或者在序列化设置的时候,使用XmlElementAttribute等明确他们的名称。
2、反射功能
我们会用一些工厂模式等代码,不免会用带反射的机制。反射需要指定字符串去获取指定程序集、实例化、获取属性等。有时候还是某些框架内部用了反射机制,这些也要考虑在内。
这类型的代码在混淆后,所有成员名称都改变了,因此用指定当初的字符串去获取,肯定面目全非了,异常就在所难免。
3、资源文件自动生成代码
如果有用到.net的资源文件(如*.resx),这些代码自动生成代码中,就用到了很多用字符串指定类型、获取属性等。
这些在混淆后也会产生异常,要剔除混淆这些类。
4、命名要规范
有时候需要一类型的类遵循一些混淆规范,比如,在一个Winform程序中需要所有继承Form类中的私有实例变量都不要被混淆(不希望混淆控件变量名)。
dotfuscator的例外规则只是根据类名来判断执行,那么如果Winform中的Form命名杂乱无章,那这样的剔除就很难完成,需要人工一个一个筛选。
因此在开发前期,定义好命名规范比较重要;比如Winform的Form就要以Form结尾(如MainForm、OptionForm等)。
5、DllImport要显式指定EntryPoint
一般我们使用DllImport的时候都直接这么写了。
[DllImport("kernel32.dll")]
public static extern bool Beep(int frequency, int duration);
不会指定DllImport的EntryPoint,因此按上面的写法,DllImport的EntryPoint直接就是方法名Beep。
如果混淆把Beep修改了,那当然这个声明就错误了;因此最好显式指定EntryPoint。
PS:dotfuscator会智能地不混淆DllImport的声明,因此不会有这个问题。但还是建议显式指定EntryPoint为好。