ESET researchers reveal details about a prevalent cryptor, operating as a cryptor-as-a-service used by tens of malware families
In this blogpost we examine the operation of AceCryptor, originally documented by Avast. This cryptor has been around since 2016 and because – throughout its existence – it has been used to pack tens of malware families, many technical parts of this malware have already been described. You might already have read about this cryptor, which is variously known as the DJVU obfuscation, SmokeLoader’s stage 1, RedLine stealer’s stage 1, 2 and 3, simple and popular packer, and so on… Many (but not all) of the published blogposts don’t even recognize this cryptor as a separate malware family, so let us connect all the dots for you, providing not only a technical analysis of its variants but also an overview of the malware families that can be found packed by it and how prevalent AceCryptor is in the wild.
For malware authors, protecting their creations against detection is a challenging task. Cryptors are the first layer of defense for malware that gets distributed. Even though threat actors can create and maintain their own custom cryptors, for crimeware threat actors it often may be a time-consuming or technically difficult task to maintain their cryptor in a so-called FUD (fully undetectable) state. Demand for such protection has created multiple cryptor-as–a-service (CaaS) options that pack malware. These cryptors can include multiple anti-VM, anti-debugging ,and anti-analysis techniques combined to achieve concealment of the payload.
Statistics and packed families overview
Since the first known appearances of AceCryptor back in 2016, many malware authors have used the services of this cryptor, even the best-known crimeware like Emotet, back when it didn’t use its own cryptor. During 2021– 2022 ESET detected more than 80,000 unique samples of AceCryptor. Because of the high number of different malware families packed inside, we assume that AceCryptor is sold somewhere as a CaaS. If we take into consideration the number of unique files detected: even though we don’t know the exact pricing of this service, we assume that the gains to the AceCryptor authors aren’t negligible.
Because of the high volume of samples over past years, the following stats are based only on samples detected during 2021 and 2022. As can be seen in Figure 1, detection hits were distributed quite evenly throughout these two years, which is to be expected from malware used by a large number of threat actors who don’t synchronize their campaigns.
After looking at the malware packed by AceCryptor, we found over 200 ESET detection names. Now, of course one malware family may have several detection names across the individual variants, because of updates or changes in obfuscation – e.g., MSIL/Spy.RedLine.A and MSIL/Spy.RedLine.B are both detections for the RedLine Stealer malware. Detection names for some other malware are not by family, but by class (e.g., ClipBanker or Agent), because a lot of unpacked malware samples are generic clipboard stealers, trojans, and so on that are not that widespread and/or are just slightly modified variants of other known malware published in various public repositories. After grouping, we can conclude that after unpacking, among the malware families found are SmokeLoader, RedLine Stealer, RanumBot, Raccoon Stealer, STOP ransomware, Amadey, Fareit, Pitou, Tofsee, Taurus, Phobos, Formbook, Danabot, Warzone, and many more… Figure 2 shows an overview of the quantities of samples belonging to some of the well-known and prevalent malware families packed by AceCryptor.
Monitoring activities of CaaS providers such as AceCryptor is helpful for monitoring of malware that uses their services. As an example, consider a RedLine Stealer that was first seen in Q1 2022. As can be seen in Figure 3, RedLine Stealer distributors used AceCryptor since the beginning of RedLine Stealer’s existence and still continue to do so. Thus, being able to reliably detect AceCryptor (and other CaaS) not only helps us with visibility of new emerging threats, but also with monitoring the activities of threat actors.
As should be expected from the variety of malware packed inside AceCryptor and the diversity of interests of different malware authors, AceCryptor is seen everywhere in the world. During 2021 and 2022, ESET telemetry detected over 240,000 detection hits of this malware, which amounts to over 10,000 hits every month. In Figure 4 you can see the countries with the highest numbers of detections during 2021 and 2022.
During 2021 and 2022, ESET products detected and blocked malware variants packed by AceCryptor on more than 80,000 customers’ computers. We also discovered over 80,000 unique samples of AceCryptor. Now, of course that any sample could be detected at multiple computers or one computer was protected multiple times by ESET software, but the number of unique hashes just shows how actively the authors of AceCryptor work on its obfuscation and detection evasion. We will dive deeper into the technical details of AceCryptor’s obfuscations in the Technical analysis part of this blogpost.
What’s worth mentioning here is that even though the number of unique samples of AceCryptor is very high, the number of unique samples packed inside is fewer than 7,000. This shows the degree to which many malware authors rely on the services of a cryptor and how convenient it is for them to pay for this kind of service rather than invest their time and resources to implement their own cryptor solution.
Because AceCryptor is used by multiple threat actors, malware packed by it is also distributed in multiple different ways. According to ESET telemetry, devices were exposed to AceCryptor-packed malware mainly via trojanized installers of pirated software, or spam emails containing malicious attachments.
Another way that someone may be exposed to AceCryptor-packed malware is via other malware that downloaded new malware protected by AceCryptor. An example is the Amadey botnet, which we have observed downloading an AceCryptor-packed RedLine Stealer.
We’d like to note that this works both ways and some of the malware families protected by AceCryptor can also download new, additional malware.
Currently AceCryptor uses a multistage, three-layer architecture. There are two known versions of the first layer that are currently in use – a version that uses TEA (Tiny Encryption Algorithm) to decrypt the second layer and a version that uses a linear congruential generator (LCG) from Microsoft Visual/Quick/C++ to decrypt the second layer. The second layer is shellcode that performs defensive tricks, then decrypts and launches the third layer. Finally, the third layer is more shellcode that also performs some anti-investigation tricks, and its task is to launch the payload. There are two known versions of the third layer: one version performs process hollowing, while the other uses a reflective loader and overwrites its own image with the PE of the final payload.
Even though there are two versions of Layer 1, they work very similarly. Their main tasks can be summarized as follows:
- Load encrypted Layer 2 into allocated memory.
- Decrypt Layer 2.
- Call or jump to Layer 2.
The most important part of this stage is the obfuscations. Throughout the years, new obfuscations have been added – to the point where almost every part of the binary is somehow randomized and obfuscated. This will cause big problems for someone trying to come up with YARA rules or static detections.
The authors leverage loops for multiple obfuscations. The first and most straightforward technique is to use loops with junk code just to make analysis more difficult. We have seen usage of junk code since 2016 when we registered the first samples of AceCryptor. These loops are filled with many API calls that not only slow down analysts who don’t know what is happening, but also overwhelm the logs of sandboxes that hook API calls, thereby making them useless. The loops may contain many MOV instructions and math operations, again just to confuse analysts and thereby lengthen the time of analysis.
The second usage of loops is to achieve delay. We have observed that some versions of AceCryptor launch Layer 2 almost immediately, but others contain loops that are so time demanding that it can slow down the execution even for tens of minutes: delaying the execution of some parts of malware is a known technique, but usage of API calls like Sleep may already raise some flags. Even if not, some sandboxes like Cuckoo Sandbox implement sleep-skipping techniques to avoid the delay and proceed to the interesting parts. Implementing delays via loops and execution of junk code is also a complication during dynamic analysis, because the analyst has to identify which loops are junk loops and thus can be skipped.
A third obfuscation technique using loops consists of hiding important operations in them. Among the junk loops, there are some that wait for a certain iteration and just during that iteration something happens. Usually, an API is loaded using GetProcAddress, which is later used or some constant like the offset of the encrypted data is unmasked. If that particular iteration of a loop doesn’t happen, the sample will later crash. This, in combination with junk code, means that to dynamically analyze the malware, one first has to analyze which loops or iterations of loops can be skipped, and which cannot. This means that the analyst can either spend time analyzing junk code or waiting until all the junk code is executed. In Figure 6 you can see two loops where the first contains an operation important for subsequent execution, and the other is just full of junk code. Of course, this may not be (and it is not in the majority of the samples) that easily visible among all the loops, especially if the loops with the important operations also contain junk code.
Randomization – Thou shalt not YARA
Another important part of the first layer is randomization. Junk code and the loops mentioned previously are randomized in each sample, in such a way that:
- the number of iterations changes,
- API calls change,
- the number of API calls change, and
- junk arithmetic or MOV instructions change.
All this randomization can also quite complicate identification of the decryption algorithm and keys. In Figure 7 and Figure 8 you can see the original, unobfuscated and the obfuscated version of the TEA algorithm. In the obfuscated version there are not only junk arithmetic instructions, but also some parts of the algorithm are outlined into subroutines and known constants (sum and delta in Figure 7) are masked, just to make correct identification of the algorithm unlikely or certainly more difficult.
Code is not the only thing that is randomized. The encrypted Layer 2 and its decryption key are currently usually stored in the .text or .data section, but they are hidden using some offsets that change between the samples. Also, after successfully decrypting Layer 2: in some samples the code of Layer 2 is at the beginning of the decrypted data, but there are samples where you end up with a block of random data at the beginning and you need to know the correct offset to find the beginning of Layer 2’s code.
AceCryptor authors also randomize the following characteristics:
- The PDB path always starts with C:\, but the rest of the path is random.
- Resources with random names and content, as can be seen in Figure 9. The authors of AceCryptor fill samples with randomly generated resources containing randomly generated data. We assume that this is done to make samples less suspicious and make locating the actual encrypted data more difficult. Resources can contain:
- String tables
- Binary data
- Strings used in the code.
- Icons – even though icons that are used in many samples look similar, they are just slightly modified/randomized to be unique.
- Random dummy section names.
- Memory allocation functions for Layer 2 data – GlobalAlloc, LocalAlloc, and VirtualAlloc.
- Usage of some APIs important to code execution – they may be statically imported or obtained via GetModuleHandleA and GetProcAddress.
Over the years, the authors of AceCryptor got more proficient at developing malware and the cryptor changed and evolved. Even though there were many smaller changes, updates, and improvements, some of the interesting features of the older versions of Layer 1 included the following:
- During 2016 AceCryptor used a version of Layer 1 with XTEA encryption algorithm.
- During 2017–2018 AceCryptor used one more Layer 1 version, where the encryption algorithm used was RC4.
- The first (X)TEA and LCG versions of Layer 1 appeared in 2016. Unlike the LCG version, the XTEA version quickly fell into disuse and was replaced with the TEA version.
- In older versions, the encrypted Layer 2 was in the resources hidden in a BMP image. This image was randomly generated with random width and height, and the middle of the image was cut out and replaced with encrypted data. Data had to be found at the correct offset.
Layer 2 of AceCryptor appeared in 2019. Until then, AceCryptor launched Layer 3 directly from Layer 1. This layer serves as additional encryption and protection of Layer 3 and, as Figure 11 illustrates, consists of three parts:
- position-independent code,
- a custom structure that we named L2_INFO_STRUCT, containing information about Layer 3, and
- the data of Layer 3
As the first step, AceCryptor uses a common technique to obtain some API function addresses. It resolves the GetProcAddress and LoadLibraryA functions by using the PEB_LDR_DATA to traverse through loaded modules, and by comparing the hash values of their export names against hardcoded values. As a checksum function, AceCryptor uses a shl1_add function, already implemented in hashDb, which can make identification of resolved APIs faster.
val = 0
for i in data:
b = i
b = 0xff & (b | 0x60)
val = val + b
val = val << 1
val = 0xffffffff & val
Figure 12. shl1_add hash implemented in Python
Then AceCryptor obtains a handle for kernel32.dll using LoadLibraryA and uses that and GetProcAddress to resolve more APIs.
For the next steps, AceCryptor uses information from its custom structure L2_INFO_STRUCT (shown in Figure 13), which can be found right at the end of the position-independent code, as can be seen in Figure 11.
Struct __unaligned __declspec(align(1)) L2_INFO_STRUCT
… //empty fields (padding or reserved for future use) filled with zeros
Figure 13. Overview of the L2_INFO_STRUCT from Layer 2
In the next steps, AceCryptor decrypts Layer 3, which is encrypted using LCG from Microsoft Visual/QuickC/C++. Decryption happens in place. If the compressionFlag is set, AceCryptor allocates memory with the VirtualAlloc API and decompresses the decrypted data with the LZO_1Z decompression algorithm. After this, execution jumps into the decrypted and optionally decompressed Layer 3.
Layer 3 – Process hollowing
As the first step, AceCryptor obtains the addresses of LoadLibraryA and GetProcAddress APIs the same way as in ` 2 – traverse loaded modules, traverse exports, and use shl1_add checksums. Then AceCryptor obtains multiple API function addresses and DLL handles.
In the next step, AceCryptor uses the API GetFileAttributesA and checks for file system attributes of a file called apfHQ. Attributes are compared to a non-existing combination of flags 0x637ADF and if they are equal, the program will end up in an infinite loop. Because this is used in the last layer, which is already well hidden, and because this is not the only trick here, we assume that this is not another obfuscation technique, but rather an undocumented anti-sandbox/anti-emulator trick against an unknown but specific sandbox/emulator that returns this value.
If the program continues successfully, there is yet another anti-sandbox/anti-emulator check. Now AceCryptor uses the API RegisterClassExA to register a class with the class name saodkfnosa9uin. Then it tries to create a window with the name mfoaskdfnoa using the CreateWindowExA API. In the last step of this check, AceCryptor tries to use the APIs PostMessageA and GetMessageA to pass a message. Because these APIs are not used that frequently, this check helps to dodge sandboxes/emulators that have not implemented these APIs or where the emulated APIs don’t function properly.
After passing these checks successfully, AceCryptor uses the process hollowing technique where it creates a new instance of the current process (GetCommandLineA, CreateProcessA), maps the final payload into the newly created process, and launches it.
Anti-investigation trick using RegisterClassExA, CreateWindowExA, PostMessageA, GetMessageA was in previous versions (e.g., SHA-1: 01906C1B73ECFFD72F98E729D8EDEDD8A716B7E3) seen used at Layer 1 and later (when it was tested out and the architecture of the cryptor evolved) it was moved to Layer 3.
Layer 3 – Reflective loader
The first stephis layer, similar to Layer 2 and Layer 3 – Process hollowing, obtains addresses of the GetProcAddress and LoadLibraryA API functions. The difference is that this time, for some reason, the authors didn’t use the shl1_add checksum function, but they obtain first the GetProcAddress via traversing loaded modules, traversing exports, and comparing strings. Then using GetProcAddress they obtain the LoadLibraryA function. Using those two APIs, AceCryptor loads addresses of some more API functions and a handle to kernel32.dll.
In the code, there is a trick (shown in Figure 17) where AceCryptor mixes code with data. AceCryptor controls a value that is on return address after one call. This value is by default set to zero and later AceCryptor writes there an address of the entry point of the final payload. If the program gets patched and the value is set to a non-zero value, the program will jump to the address pointed to by that value and crash.
In the next step, AceCryptor performs a known anti-VM check aimed against Cuckoo sandbox, IDA Pro+Bochs, and Norman SandBox. In Figure 19 can be seen that flag SEM_NOALIGNMENTFAULTEXCEPT with the value 0x04 always gets set by the Cuckoo sandbox, and because of that, the second call of SetErrorMode in the code from Figure 18 won’t return the same value as the one that was set by the previous call.
In the last steps, AceCryptor first checks if the final payload has been compressed (again) and if so, it uses LZO_1Z decompression. Similar to Layer 2, the Layer 3 reflective loader uses a custom structure, which we named ENCRYPTED_DATA_INFO_STRUCT (Figure 16), that can be found right between the position-independent code and final payload, containing information like compression flag, number of sections of payload, (de)compressed size of payload, entry point address, addresses of some directories, image relocation table address, and so on. AceCryptor uses this information (unlike Layer 3 – Process hollowing, which parses the PE of the final payload) to do a reflective code loading technique where it remaps (map sections, rebase image, …) its own image with the image of the final payload and launches the payload by calling its entry point.
AceCryptor is a long-lasting and prevalent cryptor-malware, distributed all around the world. We expect that it is sold somewhere on dark web/underground forums as a CaaS. Services of this malware have been used by tens of different malware families and many of them rely on this cryptor as their main protection against static detections.
Since the malware is used by many threat actors, anyone can be affected. Because of the diversity of packed malware, it is difficult to estimate how severe the consequences are for a compromised victim. AceCryptor may have been dropped by other malware, already running on a victim’s machine, or if victim got directly afflicted by, for example, opening a malicious email attachment, any malware inside might have downloaded additional malware; thus it may be very difficult to clean the compromised machine.
Even though for now an attribution of AceCryptor to a particular threat actor is not possible and we expect that AceCryptor will continue to be widely used, closer monitoring will help with prevention and discovery of new campaigns of malware families packed with this cryptor.
ESET Research offers private APT intelligence reports and data feeds. For any inquiries about this service, visit the ESET Threat Intelligence page.
ESET Research offers private APT intelligence reports and data feeds. For any inquiries about this service, visit the ESET Threat Intelligence page.
Note: Listed files are a reasonable selection of samples throughout time, covering different versions of AceCryptor or packing different malware.
|SHA-1||Filename||ESET detection name||Description|
|0BE8F44F5351A6CBEF1A54A6DE7674E1219D65B6||N/A||Win32/Kryptik.HPKJ||TEA version of Layer 1, with SmokeLoader packed inside.|
|0BE56A8C0D0DE11E0E97B563CAE6D1EE164F3317||N/A||Win32/Kryptik.GOFF||LCG version of Layer 1, with SmokeLoader packed inside, anti-investigation trick on Layer 2.|
|1E3D4230655411CB5F7C6885D7F947072B8F9F0F||N/A||Win32/Emotet.AW||RC4 version of Layer 1, with Emotet packed inside.|
|2FDD49A3F7D06FFFD32B40D35ABD69DEC851EB77||N/A||Win32/Smokeloader.F||TEA version of Layer 1, with SmokeLoader packed inside.|
|3AC205BE62806A90072524C193B731A1423D5DFD||N/A||Win32/Kryptik.GPCG||TEA version of Layer 1, with SmokeLoader packed inside.|
|6ABF731B90C11FFBD3406AA6B89261CC9596FEFD||N/A||Win32/Kryptik.HRHP||TEA version of Layer 1, with RedLine stealer packed inside.|
|8E99A5EC8C173033941F5E00A3FC38B7DEA9DCB3||N/A||Win32/Kryptik.FKYH||TEA version of Layer 1, with Filecoder.Q packed inside, next layer in BMP image.|
|15ADFFDA49C07946D4BD41AB44846EB673C22B2B||N/A||WinGo/RanumBot.B||TEA version of Layer 1, with RanumBot packed inside, obfuscation – random PDB path.|
|47DB52AB94B9A303E85ED1AA1DD949605157417E||N/A||Win32/Smokeloader.A||TEA version of Layer 1, with SmokeLoader packed inside, anti-emulator trick on Layer 1.|
|70BC8C2DC62CF894E765950DE60EC5BD2128D55B||N/A||Win32/Smokeloader.F||TEA version of Layer 1, with SmokeLoader packed inside.|
|88B125DDA928462FDB00C459131B232A3CD21887||N/A||Win32/Kryptik.GDTA||TEA version of Layer 1, with Hermes packed inside, obfuscation – masking values.|
|90A443787B464877AD9EB57536F51556B5BA8117||N/A||Win32/Kovter.C||XTEA version of Layer 1, with Kovter packed inside.|
|249BED77C1349BE7EC1FC182AFCCB1234ADFACDF||N/A||Win32/Smokeloader.F||TEA version of Layer 1, with SmokeLoader packed inside.|
|3101B17D73031384F555AE3ACD7139BBBAB3F525||N/A||Win32/TrojanDownloader.Amadey.A||TEA version of Layer 1, with Amadey packed inside.|
|8946E40255B57E95BAB041687A2F0F0E15F5FFCE||N/A||Win32/Kryptik.GKIN||LCG version of Layer 1, with GandCrab packed inside, obfuscation – named sections.|
|946082F225C76F2FFBE92235F0FAF9FB9E33B784||N/A||Win32/Filecoder.Locky.C||LCG version of Layer 1, with Locky packed inside.|
|A8ACF307EA747B24D7C405DEEF70B50B2B3F2186||N/A||MSIL/Spy.RedLine.B||LCG version of Layer 1, with RedLine Stealer packed inside.|
|F8039D04FF310CEF9CA47AC03025BD38A3587D10||N/A||Win32/Smokeloader.F||TEA version of Layer 1, with SmokeLoader packed inside.|
|Object Type||Object name|
MITRE ATT&CK techniques
This table was built using version 12 of the MITRE ATT&CK enterprise techniques.
|Execution||T1106||Native API||AceCryptor is able to launch a process using the CreateProcessA API.|
|Defense Evasion||T1497.003||Virtualization/Sandbox Evasion: Time Based Evasion||AceCryptor uses loops with arbitrary code to delay the execution of core functionality.|
|T1497.001||Virtualization/Sandbox Evasion: System Checks||AceCryptor uses multiple techniques to detect sandboxes and emulators.|
|T1140||Deobfuscate/Decode Files or Information||AceCryptor uses TEA, LCG, XTEA, or RC4 encryption and LZO_1Z compression to extract position-independent code and payloads.|
|T1027||Obfuscated Files or Information||AceCryptor masks values like length of payload, known constants of decryption algorithms, or decryption key.|
|T1055.012||Process Injection: Process Hollowing||AceCryptor can create a new process in a suspended state to unmap its memory and replace it with the hidden payload.|
|T1620||Reflective Code Loading||AceCryptor can use a reflective loader to rewrite its image and replace it with a hidden payload (Windows PE).|