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. 【嵌入式硬件Esp32】ESP32 正确下载姿势

    程序的正确下载步骤,以8M flash为例子: 一.硬件连接 ESP32 的运行状态主要由 GPIO0 决定 二.ESP32 Flash 地址配置 ESP32 在编译时,通过 make menucon ...

  2. feign学习笔记

    使用:

  3. springmvc流程 struts2 spring Hibernate 优缺点 使用场景介绍

    为什么使用HandlerAdapter? SpringMVC使用一个Servlet(DispacherServlet)代理所有的请求 , SpringMVC中的处理器是方法级别的处理器,而非类级别的处 ...

  4. [ERROR] /D:/IDEA文件/travel/src/main/java/cn/itcast/travel/util/MailUtils.java:[1,1] 非法字符: '\ufeff'

    报错: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (defau ...

  5. Django框架2——模板

    django框架2--模板 直接将HTML硬编码到你的视图里却并不是一个好主意: 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改. 站点设计的修改往往比底层 Python 代码的修 ...

  6. PAT(B) 1094 谷歌的招聘(Java)

    题目链接:1094 谷歌的招聘 (20 point(s)) 题目描述 2004 年 7 月,谷歌在硅谷的 101 号公路边竖立了一块巨大的广告牌(如下图)用于招聘.内容超级简单,就是一个以 .com ...

  7. git出现Invalid path

    今天换了电脑,我直接把整个仓库从电脑A复制到了电脑B,包括仓库下面的 .git 文件夹. 修改代码后我执行了一下 git add . 出现了一个报错 fatal: Invalid path 'D:/S ...

  8. C++ 异步编程:Boost.Asio

    Boost.Asio 是一个用于网络和低级 I/O 编程的跨平台 C++ 库,它使用现代 C++ 方法为开发人员提供一致的异步模型 一个异步使用计时器的样例 #include <iostream ...

  9. windows Git Bash 无法运行python文件的解决方法(转)

    https://blog.csdn.net/xie_0723/article/details/51958243

  10. SQL case when 遇到null值

    case  when f.FPH is  NULL then a.HSJE else f.KPHSJE  end    yes case f.FPH  when   NULL then a.HSJE ...