cover image for post 'The DGA of PadCrypt'

The DGA of PadCrypt

Versions and
Table of Contents

These are just unpolished notes. The content likely lacks clarity and structure; and the results might not be adequately verified and/or incomplete.


For more information about the malware in this blog post see the Malpedia entry on PadCrypt.

EDIT 2016-03-06: I completely missed that Lawrence Abrams of not only reversed the DGA of PadCrypt long before me, but also tweeted an updated version of the DGA. Many thanks to MalwareHunterTeam for letting me know, and apologies to Lawrence Abrams for my redundant post. I updated the post and my reimplementation to reflect the second DGA too.

EDIT 2: Someone asked me on Twitter how to reverse the DGA. See the Appendix for a short tutorial how to very easily decompile PadCrypt.

PadCrypt is a Ransomware first mentioned in a tweet of @abuse_ch. wrote two articles articles on PadCrypt. The MalwareHunterTeam mentioned the Domain Generation Algorithm (DGA) PadCrypt version in a tweet: tweeted version

Here are the 24 distinct domains generated on March 6, 2016 for version

And these are the 72 distinct domains generated on March 6, 2016 for version

To get a reimplementation of the DGA, I looked at this sample of PadCrypt from Hybrid-Analysis:

upload date
2015-03-01 10:55:57 (CST)
PadCrypt version
1.3 MB

The following sample of PadCrypt was provided by Lawrence Abrams here, you can download it for example from The sample features a modified version of the DGA with subtle changes (see tweet above).

upload date
2016-03-06 19:52:54
PadCrypt version
1.4 MB

DGA Design

The DGA of PadCrypt generates 24 domains per day, the DGA of version three times that (72). The DGAs use SHA256 hashing as generation scheme. Other malware families that are based on hashing include Bamital, Murofet, Gameover, Pushdo (all MD5) and Dyre (SHA-256).

PadCrypt does not use magic numbers for seeding, only the current date along with the domain number (0 to 23) are hashed. The only difference between and is the separator between date and domain number. For the older version they are separated by : (e.g., 6-3-2016:17); the newer version uses | (e.g., 6-3-2017|17)

The last nibble of the hash value determines the top level domain. The 4 bit value is used as an index into a hard-coded list of top level domains. The list only has 11 domains and for greater indices the first top level domain is used instead. This makes “.com” — the first domain — much more common than the rest. The nibbles 3 to 18 determine the 16 second level characters. The second level characters are picked by mapping 0000 to 1001 to a hard-coded list of characters:

The remaining values 1010 to 1111 are mapped to the corresponding hex representation, i.e., “a” to “f”. Because the letters a, b, c, d and f are also in the hard-coded mapping they occur twice as common as the remaining letters “enolmk”.


I reimplemented the DGA in Python. Use the -d or --date argument to set the date. If no date is provided then the domains for the current day are generated. You can select the DGA version with -v or --version. You also find the reimplementation with potential future improvements on my Github page.

    The DGA of PadCrypt 



import argparse
import hashlib
from datetime import datetime

configs = {
    "" : {
        'nr_domains': 24,
        'tlds': ['com', '', 'de', 'org', 'net', 'eu', 'info', 'online',
            'co', 'cc', 'website'],
        'digit_mapping': "abcdnfolmk",
        'separator': ':',
    "" : {
        'nr_domains': 24*3,
        'tlds': ['com', '', 'de', 'org', 'net', 'eu', 'info', 'online',
            'co', 'cc', 'website'],
        'digit_mapping': "abcdnfolmk",
        'separator': '|'

def dga(date, config_nr):
    config = configs[config_nr]
    dm = config['digit_mapping']
    tlds = config['tlds']
    for i in range(config['nr_domains']):
        seed_str = "{}-{}-{}{}{}".format(, date.month, date.year,
                config['separator'], i)
        h = hashlib.sha256(seed_str.encode('ascii')).hexdigest()
        domain = ""
        for hh in h[3:16+3]:
            domain += dm[int(hh)] if '0' <= hh <= '9' else hh
        tld_index = int(h[-1], 16)
        tld_index = 0 if tld_index >= len(tlds) else tld_index
        domain += "." + config['tlds'][tld_index]
        yield domain

if __name__=="__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-d", "--date", help="date for which to generate domains")
    parser.add_argument("-v", "--version", help="dga version", 
            choices=["", ""], default="")
    args = parser.parse_args()
        d = datetime.strptime(, "%Y-%m-%d")
        d =
    for domain in dga(d, args.version): 


Those are the characteristics of the PadCrypt DGA:

typeTDD (time-dependent deterministic)
generation schemehashing
seedcurrent date
domain change frequency1 day
domains per day24 (version, 72 (version
wait time between domainsnone
top level domainscom,, de, org, net, eu, info, online, co, cc, website
second level charactersletters: “abcdefnolmk”
second level domain length16

Only 11 characters make up the character set of the second level domains. Together with the fixed length of 16 characters, this makes the domain easy to attribute to PadCrypt. The distribution is:

a: 12.5 % 
b: 12.5 %
c: 12.5 %
d: 12.5 %
e:  6.25 %
f: 12.5 %
k:  6.25 %
l:  6.25 %
m:  6.25 %
n:  6.25 %
o:  6.25 %

Among the top level domains, .com is picked 37.5% of the time. The remaining 10 tlds are picked with probability 6.25%.

Appendix - How to Reverse

Since I got asked by private message on Twitter, here’s how to easily reverse PadCrypt.

PadCrypt is written for .NET version 4.5. This allows us to open the binary in a .NET decompiler. I’m using the excellent and free dnSpy. Naturally, the authors of PadCrypt are aware that decompiling intermediate languages is easy, so they use a protector. Both PadCrypt, and later version use DeepSea 4.1. Opening the obfuscated binary in dnSpy gives you very messy code. The following screenshot shows the obfuscated DGA:

obfuscated DGA

The decompiled routine takes up 268 lines and is impossible to read. Fortunately, there are deobfuscators for many known obfuscators. I’m relying on the free and open soure de4dot. It comes with 21 deobfuscators and often works out of the box. I ran the following command on PadCrypt:

de4dot.exe padcrypt_2.2.97.0.exe -o padcrypt_2.2.97.0_deobf.exe

Again looking at the DGA routine reveals a much shorter, very easy to ready C# code:

deobfuscated DGA

Or, if you prefer, Visual Basic:

deobfuscated DGA