Visual Studio提供的Dotfuscator保護程序,可以對用戶代碼中包含的字符串進行加密。比如下面的例子,為了找到這個程序的注冊算法,用.NET Reflector加載程序集后,發現代碼中的字符串,都變成這種形式的:
Assembly executingAssembly = Assembly.GetExecutingAssembly(); ArrayList list = new ArrayList(); string str = Class64.smethod_0("ᓊᓜᓙᒷᓎᓝᒶᒱᒽ"); string fullName = executingAssembly.FullName; Version version = new Version(); bool flag = false; int index = fullName.ToLower().IndexOf(Class64.smethod_0("ᓟᓎᓛᓜᓒᓘᓗᒦ"));
注意到這幾行代碼中的方法調用的參數,已經完全不是我們熟悉的English,我把它放到Google翻譯中去尋找它的語言,結果是一種東歐的國家的語言,為了得到它對應的英語,我得找這方面的翻譯資料。如何將這種語言,翻譯成英語,結果只有專門做翻譯的公司才可以做,而且報價不便宜,按字數來收費。這一條路似乎走不通……
意識到自己走錯方向之后,馬上把自己的想法,翻譯成英語,用Google來搜索。Google翻譯的質量,確實不錯。
很快,我就得到這篇文章Decrypting strings in obfuscated assemblies,它告訴我,這個程序集應用了字符串混淆算法,同樣的例子是這樣的
int num = 19; if (args.Length < 1) { Console.WriteLine(a("昞傳圢䐤弦न個弬崮帰䄲༴᜶稸吺似䴾⑀⁂ㅄ桿㩈㉊⍌㭎ぐ⭒畔㹖⩘篳♜潞ᱠ䍢奤ቦ᭨ݪ卬佮⩰ᱲtͶॸॼuda86", num), a("東瘞䰠匢䤤䈦洨䐪娬䄮崰尲吳匶屍䤺", num)); Console.ReadKey(); }
老外一看到這些方塊的文字,第一想到的就是Chinese,呵呵,中文語言在世界上還真有點名氣。難怪Windows的安裝程序中,專門有一項是Aisan Language是專門用來安裝東方語言文字字符集的。
解決方案也比較簡單,調用加密的辦法,獲取它的運行時的值:
string encryptedString = "東瘞䰠匢䤤䈦洨䐪娬䄮崰尲吳匶屍䤺"; int key = 19; Assembly assembly = Assembly.LoadFile(assemblyPath); // Okay, It’s sample code.. what do you expect! :) MethodInfo secretMethod = assembly.GetModules()[0] .GetMethods(BindingFlags.NonPublic| BindingFlags.Public| BindingFlags.Static)[0]; string decryptedString = secretMethod.Invoke(null, new object[] {encryptedString, key}) as string;
這樣就解決了字符串的反混淆。如果需要對程序中的每個字符串進行調用,需要寫一個GUI,用來批量的解決反混淆。
做到這里,基本上可以理解被混淆的程序集中的字符串的含義,然而,網上的一篇文章介紹的工具DotNetStringSearch,引起了我的注意,我確實是在找這樣的工具,也一直想做一個一勞永逸的工作,就是我需要一個工具程序,打開一個應用過字符串混淆的程序,點一個按鈕,它馬上可以為我顯示原文字符串和混淆后的字符串。
可細DotNetStringSearch的作者並沒有公布這個軟件的細節,源代碼也沒有開放,唯一提到的Rainst.net這個網站中的一篇文章,現在已經打不開,無從得知它應用的技術。這一條路似乎也走不下去……
一個偶然的原因,看到CodeProject上面的一篇文章,講解如何應用Mono.Cecil實現.NET代碼注入,這一下子引起了我的注意。與我們通常用的反射不同,它實現的是直接修改程序集的代碼,比起16進制工具修改EXE/DLL的二進制文件要高級得多,畢竟是原來的.NET代碼,可以直接調試,觀察實現過程。一下小心,找到SystemInternal上面的一個實用工具,Strings,這個程序可以提取PE文件中的字符串內容。
思路一下就打開了,原來不是反射,是直接對PE文件格式進行讀取,運行Strings程序,果然它順利的讀取了PE格式中的字符串資源,而且源代碼是開放的,里面的例子程序是這樣的
static void Main(string[] args) { try { string exePath = args[0]; List<string> allUserStrings = ReadAllUserStrings(exePath); File.WriteAllLines(exePath + ".txt", allUserStrings.Select(str => CSStringConverter.Convert(str))); Console.WriteLine("hotovo... "); } catch (Exception ex) { Console.WriteLine("Exception: " + ex.ToString()); Console.WriteLine("press a key..."); Console.ReadKey(); } }
通過上面的一段代碼,你可以很容易的找到它的源代碼文件,於是可以解決我說的目標:做一個通用的字符串反混淆程序,可以對當前流行的加密工具加密后的字符串進行反混淆。

