今天在公司看一个软件注册验证机制,由于没有源代码,只能通过反编译工具看了。当看到下边这段代码的时候,就觉得有点奇怪。
Assembly assembly = Assembly. Load (Resource.Register); object obj = assembly. CreateInstance ("DCommon.Register" ); Type type = obj. GetType (); MethodInfo method = type. GetMethod ("Register" );
什么情况,反射我是见过的,但貌似没见过反射Resource里的东西,请教了一下老大,原来是有些软件为了防止别人看到它的代码,就把它编成一个DLL,然后做为项目资源文件,添加到主程序的资源中。这样做的好处是你没办法看到它的源代码。老大说这种情况要想看它的原代码,就只有想办法把Resource中的内容读出来,写到一个文件中,就可以还原出原来的类库了。思路有了,具体怎么操作,还得我自己想办法。
我首先想到的是能不能找到一种方法将它的私有属性调出来,在网上搜索到了如下代码,可以在没有代码的情况下,直接读取和修改它的私有属性、字段。
public static class PrivateExtension { public static T GetPrivateField <T >( this object instance , string fieldname ) { BindingFlags flag = BindingFlags. Instance | BindingFlags . NonPublic; Type type = instance. GetType (); FieldInfo field = type. GetField (fieldname , flag); return (T ) field. GetValue (instance ); } public static T GetPrivateProperty <T >( this object instance , string propertyname ) { BindingFlags flag = BindingFlags. Instance | BindingFlags . NonPublic; Type type = instance. GetType (); PropertyInfo field = type. GetProperty (propertyname , flag); return (T ) field. GetValue (instance , null); } public static void SetPrivateField (this object instance , string fieldname, object value ) { BindingFlags flag = BindingFlags. Instance | BindingFlags . NonPublic; Type type = instance. GetType (); FieldInfo field = type. GetField (fieldname , flag); field .SetValue ( instance, value ); } public static void SetPrivateProperty (this object instance , string propertyname, object value ) { BindingFlags flag = BindingFlags. Instance | BindingFlags . NonPublic; Type type = instance. GetType (); PropertyInfo field = type. GetProperty (propertyname , flag); field .SetValue ( instance, value , null ); } public static T CallPrivateMethod <T >( this object instance , string name , params object[] param ) { BindingFlags flag = BindingFlags. Instance | BindingFlags . NonPublic; Type type = instance. GetType (); MethodInfo method = type. GetMethod (name , flag); return (T ) method. Invoke (instance , param); } }
拷到项目中试了一下,不行,因为Resource是Interal的,在我的外部程序中引用它的Resource都无法通过编译。
看来这个办法不行了,还得想想别的办法,记得以前看过一种方法,可以在不动原类的情况下给它加一个扩展方法。
public static class ExtendProperty { public static String Connect (this String s ,string a) { return s + a; } } public class Test { public void Test1() { String s = "aa"; s .Connect ( "cc"); } }
像这样,我就可以给Resource类加一个扩展方法,然后就可以做我想做的事了,试验下来,还是因为Internal的问题,不能用。该想的办法都想了,还有什么办法呢?有,但只剩下最后一招了,不行我就打算放弃了。最后一招就是www.google.com,搜了一下,有网友说可以用反射调用私有类,那就在试试了,代码如下。
private void GetResource() { Assembly assembly = Assembly. LoadFile (@"d:\test.exe" ); ResourceManager resourceManager = new ResourceManager ("Test.Resource" , assembly); object obj = resourceManager. GetObject ("Register" ); byte [] byetes = ( byte[]) obj ; FileStream fs = new FileStream (@"d:\result.dll" , FileMode. CreateNew ); BinaryWriter bw = new BinaryWriter (fs ); bw .Write ( byetes); bw .Flush (); bw .Close (); fs .Close (); }
写好后,运行起来试了一下,奇迹出现了,这个类库被我导出来了,剩下的工作就好办了,只要反编译就可以看到它的实现了。