字符串反混淆實戰 Dotfuscator 4.9 字符串加密技術應對策略


因為手頭需要使用一個第三方類庫,網絡上又找不到它的可用的版本,於是只好自己動手。這個類庫使用了Dotfuscator 加密,用.NET Reflector加載程序集,

看到的字符串是亂碼,如下面的代碼例子所示:

internal class Program
{
    // Methods
    private static void Main(string[] args)
    {
        int num2 = 4;
        try
        {
            List<string> expressionStack_51_0;
            string expressionStack_51_1;
            List<string> expressionStack_3C_0;
            string expressionStack_3C_1;
            int expressionStack_12_0 = 1;
            if (expressionStack_12_0 == 0)
            {
            }
            string exePath = args[0];
            List<string> list = ReadAllUserStrings(exePath);
            if (CS$<>9__CachedAnonymousMethodDelegate1 != null)
            {
                expressionStack_51_1 = exePath + b("䱡ၣṥᱧ", num2);
                expressionStack_51_0 = list;
                goto Label_0051;
            }
            else
            {
                expressionStack_3C_1 = exePath + b("䱡ၣṥᱧ", num2);
                expressionStack_3C_0 = list;
            }
            string expressionStack_3E_1 = expressionStack_3C_1;
            List<string> expressionStack_3E_0 = expressionStack_3C_0;
            CS$<>9__CachedAnonymousMethodDelegate1 = str => CSStringConverter.Convert(str);
            expressionStack_51_1 = expressionStack_3E_1;
            expressionStack_51_0 = expressionStack_3E_0;
        Label_0051:
            File.WriteAllLines(expressionStack_51_1, expressionStack_51_0.Select<string, string>(CS$<>9__CachedAnonymousMethodDelegate1));
            Console.WriteLine(b("੡ୣብݧᱩͫ䁭幯山味", num2));
        }
        catch (Exception exception)
        {
            Console.WriteLine(b("❡ᱣե൧ᩩᡫݭὯᱱ乳噵", num2) + exception.ToString());
            Console.WriteLine(b("ቡᙣͥ᭧ᥩ䱫཭偯ᥱᅳཱུ噷呹剻", num2));
            Console.ReadKey();
        }
    }

 

初步判斷是應用了字符串混淆技術。網上可以找到的一個反加密的算法,代碼如下所示

static string GetString(string source, int salt)
 {
     int index = 0;
     char[] data = source.ToCharArray();
     salt += 0xe74d6d7; // This const data generated by dotfuscator
     while (index < data.Length)
     {
         char key = data[index];
         byte low = (byte)((key & '\x00ff') ^ salt++);
         byte high = (byte)((key >> 8) ^ salt++);
         data[index] = (char)((low << 8 | high));
         index++;
     }
     return string.Intern(new string(data));
 }

套用一下這個方法,沒有解密成功,得到的仍然是亂碼。如果你有讀過我昨天發布的文章”字符串混淆技術在.NET程序保護中的應用及如何解密被混淆的字符串“,就相當於我已經解決了這個問題。但是,我想把這個思路解釋一下,以至不忘。

第一個知識點是關於多模塊。現在Visual Studio編譯生成的程序集,一個程序集只能有一個模塊,但是用命令行的CSC可以生成有多個模塊的程序集文件。因為C#中不能給模塊添加全局方法,也不能添加全局變量,但是MSIL可以做到這一點。MSIL可以添加完全不依賴於任何類型的全局方法。下面的代碼演示了如何添加全局方法和全局變量:

.assembly extern mscorlib { auto }
.assembly MyApp {}
.module MyApp.exe

.namespace MyApp
{
  .class public auto ansi Program extends [mscorlib]System.Object
  {
    .method private static void Main(string[] args) 
    {
      .entrypoint

      call void Test()
      ret
     }
  }
}

.field assembly static int32 x

.method private hidebysig specialname rtspecialname static void .cctor()
{
  ldc.i4 1234
  stsfld int32 x
  ret
}

.method public static void Test()
{
  ldsfld int32 x
  call void [mscorlib]System.Console::WriteLine(int32)
  ret
}

MSDN論壇中有一個關於如何調用模塊中的方法的,地址是的http://social.msdn.microsoft.com/Forums/vstudio/en-US/8a48f5bb-08c3-4d80-b5fc-56cb359fca94/call-a-global-function-using-c-emit

那么,如何調用這個全局方法呢,請參看下面的代碼:

Assembly assembly = Assembly.LoadFile(file);
MethodInfo methodInfo = assembly.GetModules()[0].GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)[0];
object result = methodInfo.Invoke(null, new object[] {allUserString, key});             

 

用.NET Reflector加載程序集,可以看到,模塊下面有一個靜態方法

image

 

於是,要借助於MSIL的知識才可以做到生產多模塊的程序集,來看一下Dotfuscator的日志文件:

Backed up existing renaming map file G:\CLR\Source\ExtractExeNetStrings\bin\Debug\Dotfuscated\Map.xml to G:\CLR\Source\ExtractExeNetStrings\bin\Debug\Dotfuscated\Map.1.xml
Loading Assemblies...

Running C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\x64\ildasm.exe /OUT=C:\Users\Administrator\AppData\Local\Temp\~Extract.0\ExtractExeNetStrings.exe.il /TEXT /NOBAR /RAWEH /QUOTEALLNAMES /UTF8 /FORWARD G:\CLR\Source\ExtractExeNetStrings\bin\Debug\ExtractExeNetStrings.exe

Processing instrumentation attributes...

Analyzing Markup...

Removal is disabled
Linking is disabled
Analyzing Code...

Renaming...

Encrypting Strings...

Updating Markup...

Writing map file to G:\CLR\Source\ExtractExeNetStrings\bin\Debug\Dotfuscated\Map.xml

Writing Assemblies...

Running C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe /OUTPUT=C:\Users\Administrator\Desktop\CPP\ExtractExeNetStrings.exe /nologo /quiet /resource=C:\Users\Administrator\AppData\Local\Temp\~Extract.0\ExtractExeNetStrings.exe.res  C:\Users\Administrator\AppData\Local\Temp\~Extract.0\ExtractExeNetStrings.exe.il

Build Finished.

 

可以看到一點,它先用ildasm把程序集文件反編譯成源代碼,把得到的IL源代碼經過修改后,再編譯成執行文件。

Dotfuscator本身也是用.NET語言開發的,要修改程序集文件,目前常見的技術是調用MONO.Cecil開源類庫,以面向對象的方法直接修改.NET程序集。

一個有趣的現象是,Dotfuscator本身卻不用字符串混淆技術加密,原因可能是性能。經過混淆的字符串在被調用時,要解密,性能上有損失。如果有幾百個,

上千個字符串都要被解密,這樣要耗費很多資源。

image

如上圖所示,Dotfuscator 4.9本身的程序集沒有使用字符串混淆技術。

 

第三個知識點是關於如何搜索一個程序集中的字符串。這要理解PE文件結構,可直接參考源代碼對照理解。

源代碼下載: http://files.cnblogs.com/JamesLi2015/ExtractExeNetStrings.zip

最后,我把它集成到一起,做一個通用的程序界面,用來解密混淆過的程序集。

image

代碼不復雜,點擊按鈕,打開程序集文件:

private void btnOpen_Click(object sender, EventArgs e)
{
            OpenFileDialog dlg=new OpenFileDialog();
            dlg.Filter = "All File (*.*)|*.*|Library File (*.dll)|*.dll|Application File(*.exe)|*.exe";
            if (dlg.ShowDialog() != DialogResult.OK)
                return;

            OpenLibrayFile(dlg.FileName);
}
 
 

接着是分解程序集中的字符串,把到提取到一個List<string> ,調用上面的methodIn.Invoke即可解密。

有一個缺陷是對有密匙(key)的字符串,多數時候會有亂碼,因為所傳入的key不一樣,解密時需要的key不同,無法做到自動化解密,需要手工調整key的值。

這篇文章中被加密的代碼,我使用的是Dotfuscator 版本號是4.9.6005.29054。

 

源代碼下載: http://files.cnblogs.com/JamesLi2015/ExtractExeNetStrings.zip


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM