Recently on Malekal.com forum, I came across a challenge. Some people got infected by a brand new ransomware having the particularity to encrypt documents (based on extension, .jpg, .doc, and so on). Having a dropper, I decided to have a look into it and find a way to decrypt those files (if possible)…
The dropper is detected as Win32.Symmi on Virus Total:
https://www.virustotal.com/file/2aca300b45371b3e01e1ab044798bc6777e11345435713027bc8cae6292dda0f/analysis/
Static analysis – What has changed on files?
After launched the dropper, I looked at the modified files. After a little wait, the infection showed up a window saying lots of documents where compromised. The infection is self restarted by a registry key (RUN).
It looked like the very first 100 bytes where overwritten, with no kind of logical (the null bytes where randomly overwritten). No basic encryption here then. I’ll have to go further.
Dropping the Paypload
The dropper uses basic tricks to avoid debugging. It’s not packed nor protected, but does massive usage of GetProcAddress to make the routine detection more difficult. I found nothing useful by first looking at the dropper in OllyDbg, so I went to APIMonitor.
What APIMonitor showed is fun 🙂
The dropper was indeed trying to escape of debugging by also create threads and new processes:
– First, It creates new thread and quit the main thread
– Then, the second thread fires a new process
Let’s see this in OllyDB!
After setting a breakpoint into GetProcAddress (kernel32.dll), I found the place where CreateThread was called.
I could then place a breakpoint into the StartAddress (0x00C70000) of the thread to break into it.
In this new Thread, I’ve done the same to find the place where CreateProcess was called.
It was recreating a new process over the same file! (quite unusual, as we could expect some infinite loop).
In fact, the process is created using the flag CREATE_SUSPENDED (see the “PUSH 4” before the call), and later we will see a WriteProcessMemory, and then a ResumeThread.
The WriteProcessMemory routine is indeed writing a whole new PE at StartAddress (0x400000) of our new process, completely overwriting itself. I’ve made a dump of this code section, it’s a standalone PE (our Payload). We will analyse it right after.
To finish ResumeThread resumes the new process (which is now a brand new one, with nothing in common with our dropper).
The Paypload is detected as Generic (quite bad) in Virus Total :
https://www.virustotal.com/file/8387e5d7e76a3c36708ca50eed438245a5906fa4ed07c6229621b1798a13bced/analysis/
Analysing the Payload
Once the payload dumped, and loaded into OllyDbg, we can have a quick overview by looking into the strings and intermodular calls. And this is indeed our encrypter 🙂
What is remarkable is the calls to the APIs : FindFirstFile, FindNextFile (files enumeration), CreateFile (file opening), and WriteFile (file overwriting).
After loading it into API Monitor, we have a dynamic overview of the scheme of file overwriting. This will be useful to understand where to search for a way to decrypt them. We can see the scheme: SetFileAttributes, CreateFile, ReadFile, and then WriteFile (with 100 bytes)
In OllyDBG, I quickly found where the ReadFile and WriteFile were performed. WriteFile was indeed done on the firsts 100 bytes (0x64), as expected (see API Monitor capture above).
Interesting thing, this malware was doing a Sleep of 180 seconds to evade some sandboxes. For debugging purposes, I’ve nopped this call to avoid waiting for nothing 🙂
To finish, I found where the file was encrypted, and how. It was a “simple” XOR routine, with a key of -1398550687 (ASCII), on my VM.
I suspected the key to be dynamically build, and not hardcoded.
Let’s find the key!
In my tale to find the key, I ran into the fact that the malware was calling an API called GetVolumeInformation right before the call to the routine to XOR the file. My little finger told me it was important in order to get the key, so I put a breakpoint on the return buffer of this API.
Indeed, it was important. Once the routine responsible for key’s computing found, I saw that the Volume serial number was the only thing able to change the key’s content.In the main loop, the “Push EDI” was pushing the volume serial number onto the stack for later use.
The key’s routine is displayed above. This is not very clear, but nevermind.
I’ve translated it into C++ code below to able to restore the files.
The keys also needs another parameter to find the first ASCII character (here, a “-“). It’s the buffer size (0x64), which is hardcoded in the data section. I’ll hardcode myself too then.
Let’s restore the files!
I’ve made a little program able to retrieve the key corresponding to a hard drive (the program must be on the same drive than the file to restore), and apply a XOR with this key on the 100 first bytes of a given file (it does the same as the malware, but as XOR is reversible, it restores the file).
Here’s the routine to get the key. It’s a basic algorithm, but not trivial to reverse…
void GetKey(char* & key)
{
DWORD volumeSerial = 0, modifiedSerial = 0;
DWORD initial = 0, tmp = 0, tmp2 = 0, result = 0;
DWORD operand = 0x0A;
TCHAR buff[1024];
char keytmp[1024];
int count = 0;
// Volume info
GetVolumeInformation(L"\\", NULL, 0, &volumeSerial, NULL, NULL, NULL, NULL);
// Modified
modifiedSerial = -volumeSerial;
memset(keytmp, '\0', 1024);
initial = modifiedSerial;
while(initial != 0)
{
tmp = initial / operand;
tmp2 = tmp * operand;
result = - (tmp2 - initial);
result += 0x30; //go to ACSII
initial = tmp;
keytmp[count] = (char)result;
count++;
}
// Invert buffer, add -
key = (char*)malloc(count + 1 + 1); //1 for -, 1 for null byte
memset(key, '\0', count + 1 + 1);
key[0] = 0x2D; // - char
for (u_int i = 0 ; i < count ; i++)
{
key[count - i] = keytmp[i];
}
}
The program to restore your files is available here :
To use it, simply move a file to restore on the program’s icon, it will trigger the program with its path on parameter, and restore the file. It works also by selecting multiple files at once.