以前有人问过我Dotfuscator的原理,我对其做了比较详细的测试和讲解:
"Principles of Obfuscation"
http://www.simonrobinson.com/DotNET/Articles/Security/Obfuscation1.aspx
Dotfuscator里面是可以设置将哪些符号改名的。默认情况下,它会将assembly里面的所有符号都改名,你可以在Dotfuscator的"Rename"选项卡处设定你所想要禁止Rename的符号,具体使用方法请参考Dotfuscator的帮助文档。
如果你使用默认设置Rename所有的符号,这会导致外面想要使用此assembly的代码出问题,可以证明如下:
我的工程里面有一个公有的方法
public void testmethod()
{
MessageBox.Show("testmethod");
}
将其生成的assembly使用Dotfuscator改变后。如果你使用以下Reflection代码调用原来assembly里面的testmethod方法,你将会成功,但是如果调用混淆后的assembly,你将会得到异常。
private void button1_Click(object sender, System.EventArgs e)
{
Assembly ass=Assembly.LoadFrom(@"reflectiontest.exe");
Type t=ass.GetType("reflectiontest.Form1");
object obj=Activator.CreateInstance(t);
MethodInfo mi=t.GetMethod("testmethod");
mi.Invoke(obj, new object[]{});
}
你可以试试再次混淆,但是将Form1和testmethod的复选框给选中(testmethod在Form1这个类中),你的Reflection代码将会成功。
下面我要证明Dotfuscator没有足够的智能改变Reflection代码中的参数字符串,所以在混淆后,运行将会出错:
在一个Winform工程里面使用Reflection代码调用自己这个Assembly里面的一个方法testmethod
public void testmethod()
{
MessageBox.Show("testmethod");
}
private void button1_Click(object sender, System.EventArgs e)
{
Assembly ass=Assembly.LoadFrom(@"reflectiontest.exe");
Type t=ass.GetType("reflectiontest.Form1");
object obj=Activator.CreateInstance(t);
MethodInfo mi=t.GetMethod("testmethod");
mi.Invoke(obj, new object[]{});
}
在混淆前,你的Assembly将会执行成功。在混淆后(注意,使用默认设置,将public的方法也混淆掉),你点击Button1你将会得到运行时的UnhandledException,内部就是System.ArgumentNullException: Value cannot be null.
这个证明代码中的"reflectiontest.Form1"和"testmethod"并没有被混淆掉。
对于在VS.net IDE里面添加对这个Assembly的引用,它基本跟Reflection没有什么区别,只不过一个是在运行时动态绑定类型信息和调用,而另一个是在设计时就从Assembly里面调用提取了类型信息。Assembly的类型信息是存放在Metadata里面的,这两种方式都需要提取Metadata的信息,所以在IDE里面添加公有类名,命名空间名被混淆过的Assembly是会失败的,你可以将一个默认混淆过的Assembly添加到Toolbar中试试。但是,你可以控制Dotfuscator保留所有的公有符号不混淆,这样你的Assembly就可以正常添加,而不会出问题。具体,你可以这样保留不混淆Public符号:
在Rename选项卡里面点击"Add Type",然后Name写上"*",然后在右边的Spec列表框中选择"+Public"。