Introduction

de4dot is a wonderful tool for deobfuscating known and unknown .NET protections. Dealing with known and supported protections is easy – drag&drop executable on de4dot and it will create deobfuscated assembly. Removing unknown protections is a little bit harder and requires supplying correct command-line parameters to de4dot.

In this article I’ll show how de4dot can be used to deobfuscate strings in almost any .NET assembly, some undocumented features of de4dot, and a few bugs in de4dot too. smile

Basics of string encryption/decryption

To show how string encryption works, let’s start with a simple C# program.

Hint – you don’t have to copy-paste all the code, sample files are available in the archive at the bottom of the post.

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System;
 
namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, world!");
            Console.Write("Please enter password: ");
            string pass = Console.ReadLine();
            if (pass == "secret")
            {
               Console.WriteLine("Password accepted");
            }
            else
            {
               Console.WriteLine("Bad password");
            }
            Console.ReadKey();
        }
    }
}

As you can see, all the strings are in the clear view and it’s obvious that correct password is “secret”. No protection whatsoever.

To slow down reversing efforts, obfuscators offer to encrypt user strings. They locate all strings in assembly, encode them somehow, and replace access to string with call to obfuscator code. To keep the code simple, I’ll just encode all strings using Base64 – however, the same approach would work for almost any string encryption method (xor, Rijndael, or anything else).

New code looks like this:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
using System.Text;
 
namespace Demo
{
    static class Obfuscator
    {
       static string[] hiddenStrings = {
         "SGVsbG8sIHdvcmxkIQ==",
         "UGxlYXNlIGVudGVyIHBhc3N3b3JkOiA=",
         "c2VjcmV0",
         "UGFzc3dvcmQgYWNjZXB0ZWQ=",
         "QmFkIHBhc3N3b3Jk"
       };
 
       public static string DecryptString(int index)
       {
          return Encoding.UTF8.GetString(Convert.FromBase64String(hiddenStrings[index]));
       }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Obfuscator.DecryptString(0));
            Console.Write(Obfuscator.DecryptString(1));
            string pass = Console.ReadLine();
            if (pass == Obfuscator.DecryptString(2))
            {
               Console.WriteLine(Obfuscator.DecryptString(3));
            }
            else
            {
               Console.WriteLine(Obfuscator.DecryptString(4));
            }
            Console.ReadKey();
        }
    }
}

No more obvious strings! smile Let’s see how we can decrypt them using de4dot..

de4dot and basic string decryption

If you check de4dot help, you’ll see that you need to supply 2 command line options for a string decryption to work. First, you need to choose a string decrypter type using –strtyp option: staticdelegateemulate. Then you need to tell de4dot which is string decrypter method using –strtok option.

Let’s find which method is responsible for string decryption. Good decompiler can show method tokens, for example,SAE shows it as a tooltip, when you hover over the method:

So, for our very basic protection we could run de4dot with commandline:

 
1
de4dot hello-2.exe --strtyp delegate --strtok 0x06000001

and the result will look like this:

So far, so good!

Advanced string decryption

But what happens if obfuscator uses more than one string decryptor? Let’s change the code a little bit:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Text;
 
namespace Demo
{
    static class Obfuscator
    {
       static string[] hiddenStrings = {
         "SGVsbG8sIHdvcmxkIQ==",
         "UGxlYXNlIGVudGVyIHBhc3N3b3JkOiA=",
         "c2VjcmV0",
         "UGFzc3dvcmQgYWNjZXB0ZWQ=",
         "QmFkIHBhc3N3b3Jk"
       };
 
       public static string DecryptStringA(int key)
       {
          return Encoding.UTF8.GetString(Convert.FromBase64String(hiddenStrings[key ^ 0x666]));
       }
 
       public static string DecryptStringB(int key)
       {
          return Encoding.UTF8.GetString(Convert.FromBase64String(hiddenStrings[key + 0xDEAD]));
       }
 
       public static string DecryptStringC(int key)
       {
          return Encoding.UTF8.GetString(Convert.FromBase64String(hiddenStrings[key - 0xC0DE]));
       }
 
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Obfuscator.DecryptStringC(0xC0DE));
            Console.Write(Obfuscator.DecryptStringA(0x667));
            string pass = Console.ReadLine();
            if (pass == Obfuscator.DecryptStringB(-57003))
            {
               Console.WriteLine(Obfuscator.DecryptStringA(0x665));
            }
            else
            {
               Console.WriteLine(Obfuscator.DecryptStringC(0xC0E2));
            }
            Console.ReadKey();
        }
    }
}

Now there are 3 methods that decrypt strings, and each of them is slightly different. Of course you could run de4dot 3 times, but it’s just a pain-in-the-butt.

de4dot help doesn’t tell you this, but it is possible to to specify more than one string decryption method:

 
1
de4dot hello-3.exe --strtyp delegate --strtok 0x06000001 --strtok 0x06000002 --strtok 0x06000003

This is a little bit awkward, but works.

But what to do if there are hundreds of methods – specifying each of them by token is time-consuming and command-line might get too long.

de4dot has solution for that too. Hidden in the middle of help file, is this little gem:

–strtok METHOD String decrypter method token or [type::][name][(args,…)]

It turns out that you can tell de4dot the name of obfuscator class/methods responsible for string decryption and it will resolve tokens automatically. smile

So, the following command-lines will work:

  •  
    1
    de4dot hello-2.exe --strtyp delegate --strtok "Demo.Obfuscator::DecryptString"

    This tells de4dot that string decryptor is method with full name Demo.Obfuscator::DecryptString.

  •  
    1
    de4dot hello-3.exe --strtyp delegate --strtok "Demo.Obfuscator::"

    This tells de4dot to check all methods in class Demo.Obfuscator and pick the ones which look like string decryptors.

  •  
    1
    de4dot hello-3.exe --strtyp delegate --strtok "Demo.Obfuscator::(System.Int32)"

    This tells de4dot which class to look at and what kind of parameters string decryption method has.

  •  
    1
    de4dot hello-3.exe --strtyp delegate --strtok "::DecryptStringA"

    This tells de4dot to look at all classes for a method called DecryptStringA and use that as string decryptor.

If you want to know more about possible options and the combinations, I suggest that you look at de4dot source code, file de4dot.code\ObfuscatedFile.cs, lines 454-511.

You said something about bugs?

Ok, ok, there are few issues here.. It still works 99% of the time, so no complaining!

First bug is in the checking of string decryptor parameters. When I said that –strtok “Demo.Obfuscator::(System.Int32)” will select only methods that take Int32 as a parameter, I lied. smile

Look at the source:

 
1
2
3
4
for (int i = 0; i < argsStrings.Length; i++) {
   if (argsStrings[i] != sig.Params[i].FullName)
      continue;
}

The continue instruction here does nothing, it just goes on to check next parameter. I guess 0xd4d wanted to stop evaluating this method and go to next one, but got it wrong.

Second bug is in selecting string decryptors – you cannot select a method which takes no parameters. Sample code showing this type of protection is in hello-4.cs (see below).

Look again at the source:

 
1
2
3
4
5
6
7
if (argsStrings == null) {
    if (sig.Params.Count == 0)
        continue;
else {
    if (argsStrings.Length != sig.Params.Count)
        continue;
}

If you don’t supply hints about parameters, then methods with 0 parameters will be ignored because of 2nd if. If you do supply hints – then no method with 0 parameters can pass the 3rd if.

Fixing these 2 bugs is left as an exercise to the reader.

Conclusion

In this article explained how to use de4dot to decrypt strings in any .NET assembly, including some lesser known options. Hope this helps you next time you encounter .NET protection that’s not directly supported by de4dot. smile

All sample files and their source code: https://www.mediafire.com/?2kwnf7d7vre4uv8

String decryption with de4dot的更多相关文章

  1. java 多线程编程三种实现方式

    一种是继承Thread类,一种是实现Runable接口,还有一种是实现callable接口: 有博主说只有前面2种方式,我个人愚见是三种,主要详细介绍下callable的使用: 三种线程的我的个人理解 ...

  2. WisDom.Net 框架设计(四) 用户安全

    WisDom.Net  ----用户安全 1.用户单机登录 正如其名这里要求其实就是显示用户只能在一台电脑上登录.防止多处登录,这里简单的说一下实现原理,我们在这里使用session +cookie ...

  3. jquery实现登录加密的几种方法以及cookie存放加密/解密

    本篇文章的所有操作都是在jsp页面上进行的,完全与后台分离 part 1:加密方式 这个加密方式网上基本都有很多人总结,我在此也就抛砖引玉一下: 1.base64加密 在页面中引入base64.js文 ...

  4. 加密算法--->对称加密与非对称加密算举例说明

    目前主流的加密方式有:(对称加密)AES.DES        (非对称加密)RSA.DSA 对称加密例子:des对称加密 des对称加密,对称加密,是一种比较传统的加密方式,其加密运算.解密运算使用 ...

  5. 3DES加密算法32个字节

    简介 最近开发的一个项目,使用到了3DES加密算法,加密socket服务端和客户端通信的报文,因为加密秘钥是32个字节,结果折腾了一番,现在记录下来分享! 1.Des3EncryptUtils.jav ...

  6. rsa实现js前台加密java后台解密

    前段时间写了一个rsa前台加密到后台用java解密,下面共享下实现思路: 准备工作:第三方包是必须的 bcprov-jdk15on-148.jar commons-codec-1.7.jar comm ...

  7. ASP.NET web.config 配置里部分参数详细说明

    Session配置 <!-- <identity impersonate = "false" [true|false] userName = "" ...

  8. C# PKCS7加密解密

    //加密字符串 public string Encryption(string toE) { //加密和解密必须采用相同的key,具体自己填写,但是必须为32位 "); RijndaelMa ...

  9. c# wpf 加密文本

    可以加密人们的内容,文本加密. 界面 <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation& ...

随机推荐

  1. pickle.load EOFError: Ran out of input

    错误原因:pickle.loads()的次数超过了pickle.dumps()的次数 https://www.cnblogs.com/cmnz/p/6986667.html

  2. 记录一下vue slot

    使用步骤: 1.在组件(panda)当中建立一个slot,定义好name.(<slot name='myname'></slot>)    2.引用组件的时候如果需要补充内容, ...

  3. 使用jmeter HTTP代理服务器录制APP脚本

    使用jmeter HTTP代理服务器录制APP脚本 步骤一.jemter设置 1.启动JMeter,双击运行jmeter.bat,启动jmeter jmeter运行主界面 2.添加线程组:右键测试计划 ...

  4. pandas对时间列分组求diff遇到的问题

    例子: df = pd.DataFrame() df['A'] = [1, 1, 2] df['B'] = [datetime.date(2018, 1, 2), datetime.date(2018 ...

  5. Rust零碎总结

    1.Rust里没有null的概念,但是实际上有很多地方是需要null的概念的,这个时候就可以用Option来代替,它是泛型T的一个包装类,就是C#里的int?或Java里的Optional: [但反序 ...

  6. 使用redis调用lua脚本的方式对接口进行限流

    java端实现: //初始化一个redis可执行的lua DefaultRedisScript<List> defaultRedisScript = new DefaultRedisScr ...

  7. 剑指offer22:从上往下打印出二叉树的每个节点,同层节点从左至右打印。

    1 题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 2 思路和方法 使用一个队列存放节点.先将根节点加入到队列中,然后循环遍历队列中的元素,遍历过程中,访问该节点的左右子节点,再将左 ...

  8. python 之 re模块、hashlib模块

    6.16 re模块 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法.或者说:正则就是用来描述一类事物的规则.(在Python中)它内嵌在Python中,并通过 ...

  9. PAT(A) 1144 The Missing Number(C)统计

    题目链接:1144 The Missing Number (20 point(s)) Description Given N integers, you are supposed to find th ...

  10. MRR,BKA,ICP相关

    MRR Multi-Range Read,多范围读,5.6以上版本开始支持 工作原理&优化效果: 将查询到的辅助索引结果放在一个缓冲(read_rnd_buffer_size = 4M)中 将 ...