Users of the net dread this screen. They feel when they see it all hope is lost.
In the case of this ransomware dropper, the same holds true.
In fact, in running this, I lost my downloads folder >:(
Indeed, a risk all malware reverse engineers take. Live and learn right? Anywho, let’s dive into this bastard already.
First things first, here’s what the thing looks like on VirusTotal:
A pretty dinky file to be honest, barely scratching 40 KB.
A quick peek in IDA shows us what its like under the hood:
Memory packed. How the hell do I know that just peeking real quick? Whenever there’s a bunch of uninitialized data (yellow) that looks like garbage, its most likely its memory packed. This most likely means they’re gonna try the either the RunPE method, or some sort of code injection. Looking through the thing in IDA, I’m not seeing the prerequisites for RunPE, but I do however see one function that stands out for code injection:
See the ‘jmp dword ptr[esi]’ sequence? This is where the malware will make its process leap to another section after preparing the loader. Also note the VirtualAllocEx call for used for allocating some space in another region. The code sequence appears to loop through code and inject it into the region returned by the VirtualAlloc call, then when its done, jumps to it.
That said, let’s load this thing into the debugger and get to work. I start by setting my breakpoints on the usual malware fare (Process creations, file, memory, thread manipulation, etc), and start, breaking at the code space mentioned in IDA:
As I suspected, the malware is injecting the code in ECX into the space pointed to by ESI or in this case 003E0000. We see our jump and more (new) instructions. Let’s hit F9 and continue on through.
There’s a lot going on in this picture. As I said in red, we got a hit, a VirtualProtect call that’s modifying the address space of the original byte space 00400000 from outside (003F00FB). Casual observation shows us an exe header in our registers pointing us to another address space at 008f0000. What does this mean? It means the malware dumped its loader into 008f0000 and is attempting to write the contents into itself in 00400000 (original address space). A form of self modifying code. This also means I was wrong with my RunPE guess. Oh well, can’t win em all right?
Let’s dump the exe in 008f0000 (right click dump, choose save file) and peek in IDA.
That’s a bit more like it. Note the URL’s hard coded inside. This seems to be our stage 2. There are few functions (thank GOD) which makes reversing this much easier.
Further down from main, we see a function that attempts to grab something from the resources section (FindResource).
There’s something there when we load the thing up with CFF Explorer:
A cab file? Sure ok, whatever. What’s in the cab file?
RTF document. My guess is file is shown to the user so they don’t think anything is up / wrong.
The other functions are responsible for downloading the stage2, and decrypting / running it. For that, let’s step through. In this case, I used ollydump after the process changed its original bytes with the newly loaded sequence. Skipping past the part where it launches the RTF doc we just dissected with ShellExecute, we see a number of functions and a sleep.
The sub routine at 00401a8a just downloads a file. In this case, the malware is downloading the index page from Windows update I guess in an attempt to fool heuristics? After the long sleep, the malware goes through its stage2 loop and attempts to download the encrypted file.
Recall that 00401A8A is for downloading files and takes 1 argument. The value pushed is ‘evalero.com/img/cario.tar.gz’.
If the file is non existent / no good, then the malware continues after sleeping for 5 seconds with the next address in the list.
Since the first few links are dead ends, it takes a few iterations before finding a payload:
This link actually worked.
Here’s what it looks like:
Encrypted of course….
After downloading the file, the malware stores the contents in EDI and decrypts via the function 0040179E.
Let’s step on through
Looking at the code, it looks like it looks like simple XOR, but with a few extra steps. It also appears to write the contents after decryption into EAX. Let’s be lazy and run until return:
Sure enough, at address 01760000 we have our decrypted file complete with exe header. After returning, the code then writes the file, runs it with ShellExecute, sleeps for 10 seconds and deletes the file, exiting.
So what’s in this new file we just decrypted? It’s slightly larger than the original file and has a generic looking icon too:
Peeking in IDA shows us its packed (OF COURSE IT IS).
Note the FindResource call, and the long red section. This is actually garbage. Most of this binary is like this just to anger me. The only code I’m interested in is at 00402A80 with ‘jmp dword ptr [edx]’.
Look familiar? it should, it’s the same code injection jump from the previous binary. How does the thing inject the code after decrypting it? Beats the heck outta me, but there’s a lot of jumping around involved:
.text:0040294B cmp ebx, 0 .text:0040294E jz loc_402A57 .text:00402954 sbb ecx, 0FFFFFF86h .text:00402957 sub ecx, 0FFFFFFDFh .text:0040295A sub eax, eax .text:0040295C dec eax .text:0040295D and eax, [esi] .text:0040295F mov cl, byte ptr unk_4070F1 .text:00402965 sub dword_4071BE+2, ecx .text:0040296B add dword_4070EC+1, ecx .text:00402971 sub dword_407030, ecx .text:00402977 sbb ecx, 0FFFFFFA5h .text:0040297A add esi, 4 .text:0040297D add ecx, ecx .text:0040297F add dword_407030+3, ecx .text:00402985 not eax .text:00402987 sub ch, cl .text:00402989 sbb ecx, ecx .text:0040298B or ecx, 0FFFFFFA7h .text:0040298E mov byte ptr dword_407116+2, 0D5h .text:00402995 sbb dword ptr unk_4070AC, ecx .text:0040299B lea eax, [eax-11h] .text:0040299E xor ecx, 10h .text:004029A1 mov ecx, dword_4070BA .text:004029A7 mov dword_407017, ecx .text:004029AD mov byte ptr dword_40710D, 8Dh .text:004029B4 xor eax, edi .text:004029B6 sub ecx, 0FFFFFFDBh .text:004029B9 mov byte ptr dword_407012+2, 4 .text:004029C0 adc ecx, ecx .text:004029C2 clc .text:004029C3 sbb eax, 0FFFFFFFFh .text:004029C6 mov byte_407029, 37h .text:004029CD sbb ecx, 57h .text:004029D0 xor dword_4071FA+1, ecx .text:004029D6 add ecx, ecx .text:004029D8 xor edi, edi .text:004029DA sub edi, eax .text:004029DC neg edi .text:004029DE mov byte ptr dword_40706F+2, 42h .text:004029E5 sbb ecx, ecx .text:004029E7 mov byte ptr dword_4070C1, 0C4h .text:004029EE or ecx, 52h .text:004029F1 rol edi, 2 .text:004029F4 mov byte ptr dword_407121+1, 0FFh .text:004029FB mov ecx, dword_407162+2 .text:00402A01 add cl, ch .text:00402A03 mov byte ptr dword_4070C7+2, 77h .text:00402A0A rol edi, 6 .text:00402A0D adc ecx, 0FFFFFF9Fh .text:00402A10 sbb ecx, ecx .text:00402A12 push eax .text:00402A13 pop dword ptr [edx] .text:00402A15 mov byte ptr dword_40706F, 0CEh .text:00402A1C xor dword_4070F6+1, ecx .text:00402A22 sub edx, 0FFFFFFFCh .text:00402A25 mov ecx, dword_4071FA .text:00402A2B sub dword_40711D+1, ecx .text:00402A31 and ecx, 55h .text:00402A34 or dword_407135, ecx .text:00402A3A mov byte ptr dword_40701B+2, 7Bh .text:00402A41 lea ebx, [ebx-4] .text:00402A44 mov byte_407069, 0EDh .text:00402A4B sbb dword_407104, ecx .text:00402A51 push offset loc_40294B .text:00402A56 retn .text:00402A57 ; --------------------------------------------------------------------------- .text:00402A57 .text:00402A57 loc_402A57: ; CODE XREF: .text:0040294Ej .text:00402A57 mov edx, esp .text:00402A59 mov esi, ds:GetModuleHandleA .text:00402A5F push esi .text:00402A60 mov dword ptr byte_40707D, edi .text:00402A66 sub dword_4071F5, ebx .text:00402A6C push offset loc_4028F0 .text:00402A71 mov ah, byte ptr dword_40710D+2 .text:00402A77 mov byte_407195, 0DCh .text:00402A7E xor al, 46h .text:00402A80 jmp dword ptr [edx]
Let’s dive right in and break on this jump like last time shall we? Stepping into the function brings me into the area of 00A90000:
Peeking through shows a lot of dynamic address resolution and unpacking. Instead of simply just calling functions, the malware dynamically builds a string of a function and then calls it. Weird right?
Like before in stage1, it also replaces the bytes in itself before running. It took some time to find the decryption sequence, but here it is and yes its XOR:
See the STOS instruction? That instruction copies the value of EAX and places it in the location ES:[EDI] or 00AB0010. This is basic self modifying code with encryption. The LOOPD instruction tells it to loop and jump X number of times (657910 or so). Executing until return and checking in the dump the address 00AB0000 shows us what we want:
Dumping the file and loading it into IDA shows us its packed. Of course. Why wouldn’t it be packed?
Which means once again I have to dive in to see what it does. I mean I could continue the program, but this is a good stopping point. Immunity complains that its packed (DUH). The first thing I encounter is a call to VirtualAlloc, most likely to free up some space and mark it RWE.
0012FF8C 00495D50 P]I. /CALL to VirtualAlloc from _00AB000.00495D4D
0012FF90 00000000 …. |Address = NULL
0012FF94 001FC000 .À. |Size = 1FC000 (2080768.)
0012FF98 00001000 ... |AllocationType = MEM_COMMIT
0012FF9C 00000004 … \Protect = PAGE_READWRITE
In an effort to save time, I need to wrap this up. The thing calls VirtualProtect next to set the range, it jumps around a lot before eventually unpacking fully and calling its main function in another address 00690000.
Eventually in the unpacked portion, the malware starts looking for files via the FindFirstFile api with a *.* wildcard. It loops through every file in the user’s working directory and base directory (nice enough to skip the system directory and program files folder), inspecting each file extension for MDF, XLS, DOC, PDF, ZIP, 7Zip, etc, but it doesn’t encrypt them yet. Only on the second run.
0012C5B8 00743D5D ]=t. /CALL to CreateFileW from 00743D57
0012C5BC 00869418 ”†. |FileName = “C:\Documents and Settings\All Users\Application Data\Adobe\usnpcde”
0012C5C0 80000000 …€ |Access = GENERIC_READ
0012C5C4 00000000 …. |ShareMode = 0
0012C5C8 00000000 …. |pSecurity = NULL
0012C5CC 00000003 … |Mode = OPEN_EXISTING
0012C5D0 00000002 … |Attributes = HIDDEN
0012C5D4 00000000 …. \hTemplateFile = NULL
It then checks for AV’s ekrn.exe and avp.exe (Kaspersky and Eset). Why now and not at the beginning? Who knows?
After this it copies itself to the temp folder:
Copies itself to temp
0012C850 0074309C œ0t. /CALL to CreateFileW from 0074309A
0012C854 0012D2A0 Ò. |FileName = “C:\DOCUME~1\Joe\LOCALS~1\Temp\ityksxm.exe”
0012C858 40000000 …@ |Access = GENERIC_WRITE
0012C85C 00000003 … |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
0012C860 00000000 …. |pSecurity = NULL
0012C864 00000002 … |Mode = CREATE_ALWAYS
0012C868 00000000 …. |Attributes = 0
0012C86C 00000000 …. \hTemplateFile = NULL
Creates a task for persistence:
0012CB30 7583B76D m·ƒu /CALL to CreateFileW from mstask.7583B767
0012CB34 00D173A0 sÑ. |FileName = “C:\WINDOWS\Tasks\ilhorge.job”
0012CB38 00000000 …. |Access = 0
0012CB3C 00000003 … |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
0012CB40 00000000 …. |pSecurity = NULL
0012CB44 00000003 … |Mode = OPEN_EXISTING
0012CB48 00000000 …. |Attributes = 0
0012CB4C 00000000 …. \hTemplateFile = NULL
Then it sleeps for a little while, before finally exiting:
When it runs again from the scheduled task, that’s when it changes your background and asks you to read its nice little message, informing you how to get your files back:
Never once does the malware’s second stage write its unencrypted contents to disk, its all contained in RAM making scraping more difficult. I was able to pull the asm contents of the main unpacked function into an IDB file and a text file. There are over 405 THOUSAND lines of assembly code in this bitch. Sure, some of it is data, and most of it is statically linked crap like crypto algorithms, but still, lots of shit to go through.
Have a peek. If you want the IDB file, have at it.
When I have time to revisit (Workshop in 1 month!!!!) I will go into more detail about the encryption used, but its pretty tight stuff – RSA Public key encryption. Block ciphers for large files.
For now though, it seems someone else beat me to the punch.
Until then, stay safe and don’t trust anyone / anything from email.