zoukankan      html  css  js  c++  java
  • 字符串反混淆实战 Dotfuscator 4.9 字符串加密技术应对策略

    字符串反混淆实战 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:CLRSourceExtractExeNetStringsinDebugDotfuscatedMap.xml to G:CLRSourceExtractExeNetStringsinDebugDotfuscatedMap.1.xml 
    Loading Assemblies...

    Running C:Program Files (x86)Microsoft SDKsWindowsv7.0AinNETFX 4.0 Toolsx64ildasm.exe /OUT=C:UsersAdministratorAppDataLocalTemp~Extract.0ExtractExeNetStrings.exe.il /TEXT /NOBAR /RAWEH /QUOTEALLNAMES /UTF8 /FORWARD G:CLRSourceExtractExeNetStringsinDebugExtractExeNetStrings.exe

    Processing instrumentation attributes...

    Analyzing Markup...

    Removal is disabled 
    Linking is disabled 
    Analyzing Code...

    Renaming...

    Encrypting Strings...

    Updating Markup...

    Writing map file to G:CLRSourceExtractExeNetStringsinDebugDotfuscatedMap.xml

    Writing Assemblies...

    Running C:WindowsMicrosoft.NETFrameworkv4.0.30319ilasm.exe /OUTPUT=C:UsersAdministratorDesktopCPPExtractExeNetStrings.exe /nologo /quiet /resource=C:UsersAdministratorAppDataLocalTemp~Extract.0ExtractExeNetStrings.exe.res  C:UsersAdministratorAppDataLocalTemp~Extract.0ExtractExeNetStrings.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

     
     
  • 相关阅读:
    MongoDB数据库新建数据库用户
    Grafana部署
    k8s ingress及ingress controller
    Rabbitmq如何安装插件
    RabbitMQ手册之rabbitmq-plugins
    RabbitMQ运行在Docker容器中
    K8S资源限制
    System类
    Runtime类
    StringBuffer类
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3166300.html
Copyright © 2011-2022 走看看