Cerber is a popular ransomware that it's still active. In this blogpost, we will analyze and dump Cerber's config using the Cuckoo Sandbox for it.

Prior analysis of Cerber already exist (like this one by Hasherezade).
As state by Hasherezade, Cerber stores it's configuration in an RCDATA resource bundled in the PE header. This RCDATA resource is encrypted and cerber uses a dedicated function to decrypt it.

It is clear that it is loading a resource (and we know config is stored as a resource), then allocating some memory, decrypting a string (the string decryption function was identified by Hasherezade in it's analysis) and using that decrypted string as a key to decrypt the config resource. Now, the configKey is a global variable in a fixed location, but as suggested by the code it will be encrypted. We can also set a breakpoint in the call to rc4 and observe the key (decrypted) value (which, in this case is "cerber" - big surprise).

Again, thanks to Hasherezade we know the decrypt_string function has the following parameters:

We can gather that cerber is checking some memory locations and, if certain conditions are met, it is calling the rc4 function over the string. If we do further dynamic analysis we can gather that when Cerber decrypts a string it is moved to a particular zone, so it does not need to decrypt it again, but in the end, strings are also RC4 encrypted.

Other variants

Let's explore other Cerber 1 samples and see how much they change, if any.

The sample is packed using the Nullsoft Scriptable Install System (NSIS), this is quite common for cerber samples. Unpacking instructions are available here. Once unpacked we are left with the payload.

Now we need to identify something that looks like the configuration decryption function in the new binary. I tried to use Diaphora for it, but the config decrypt function had a very bad match. Upon examination, we can conclude that Diaphora's match is not what we are after as it does use any resource-loading functions.

With that in mind, we can look for usages of FindResource in order to identify the configuration decryption function. Said function is called in two different places (sub_403742 and sub_401000). Both usages look somewhat alike to the first sample (they fetch a resource, lock it and measure size, then they call unnamed functions). We can set a breakpoint in both and see if any of the two does configutation handling.

As a result of setting up the breakpoints we can conclude that sub_403742 does not get called (at least not in normal execution) and sub_401000 gets called once. As reading the configuration seems like something you should always do let's go for the second one.

Everything is pretty clear but sub_4088BD. Upon initial examination it is a function that allocates heap and copies what it is given to it to that heap zone. We can conclude that this is a function to copy a resource to heap, not much to do with decryption though. We'll name it rscCopy.

The configuration decryption must be in some way related to this function as it is the only call to FindResource in the whole sample. If we check for calling functions we get only one - sub_401068.

This function copies a resource into a new memory zone and then does lot of XOR, AND and displacement operations over the memory zone (which is why I wanted to remark with the name XORsStuff). This is begining to look a lot more like config decryption. Let's set a breakpoint on XORsStuff.

Bingo! We can observe how XORsStuff is returning a pointer to the begining of the decrypted configuration.

Common ground

Although decryption mechanisms are different on both samples, they both load the configuration in heap and then free it using HeapFree (this was pointed by Hugo Gascón), so we can hook the HeapFree system call to dump the configuration.

One caveat though, if we check the pointer given to HeapFree we will notice that there are 8 weird bytes on the beginning and end of the heap. This is because HeapFree and HeapAlloc are wrapped on custom functions that insert / check this padding.

In this case the 0xABBABABA constant gets inserted in every beginning and end of allocated heap memory. This is probably for overflow/integrity checking, but we don't care much as everything we need is start reading at ptr + 8 and read size - 16.

This is the case for sample 17FCD7A7162298225B06D85D1D5A90EA (the second one).

Moar samples

This sample is also NSIS packed but could not be extracted by the same methods I used to unpack other NSIS-packed samples. Seems like it is packed by a modified NSIS. Anyhow, Hasherezade helped me unpacking it (credits to her - once again) and it turns to be an exact copy of sample #2 (as far as the configuration handling goes).