CTB-Locker and Dropper

Users of the net dread this screen. They feel when they see it all hope is lost.
zomg no2
In the case of this ransomware dropper, the same holds true.
ZOMG NOOO
In fact, in running this, I lost my downloads folder >:(
damnit
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:
virus_total
A pretty dinky file to be honest, barely scratching 40 KB.
dinkyfile

A quick peek in IDA shows us what its like under the hood:
quickidapeek
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:
code_injection_point
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:
start1_2
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.
start2
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.

quickidapeek_2
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).
resource_section
There’s something there when we load the thing up with CFF Explorer:
findresource2
A cab file? Sure ok, whatever. What’s in the cab file?
findresource3
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.
making_rounds
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.
download_stage2
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.
sleep5seconds_tryagain

Since the first few links are dead ends, it takes a few iterations before finding a payload:
hardcoded_next

This link actually worked.
Here’s what it looks like:
cairo_tar_gz
Encrypted of course….

After downloading the file, the malware stores the contents in EDI and decrypts via the function 0040179E.
cryptedfile1
Let’s step on through
cryptedfile2

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:
cryptedfile4

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.
write_it_run_it_delete_it

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:
_17

Peeking in IDA shows us its packed (OF COURSE IT IS).
quickidapeek_3

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:
crypto_unpacked1
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?
function_unpacking

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:
decryption_sequence_again

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:
crypto_unpacked3

Dumping the file and loading it into IDA shows us its packed. Of course. Why wouldn’t it be packed?
packedagain

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.
findfile
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?
av_check

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:
final_sleep

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:
kek

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.
1247938871381

Leave a Reply