Friday, August 17, 2012

FinFish's trick... not so legendary!

This post is about a trick that Finfish uses to appear (well, at least, "to try to appear"!) as a normal, non malicious program. 
First of all you can immediately notice that this sample is a simple loader: you can have a look at the IDA navigation bar to spot a tiny code section in contrast to a huge resource section. 




This tells us that something is hidden somewhere in the resources. The payloads, in fact, are encrypted and stored in the dialog type resources. 
Here's a quick verification test, that shows that something is wrong in the dialog data: 




But let's go back to the curious trick we mentioned, and let's begin by analyzing the code. If we start looking from the entry point we notice... absolutely nothing! 
At a first glance nothing suggests that we are analyzing a malware, as we only go through some common APIs.




Of course, a deeper reading reveals the trick: in the middle of some legitimate calls we find a suspicious function. The thing that more captured my attention is that it makes use of the VirtualProtect API different times, apparently without any good reason, as we will see later. 

For now let's start from the beginning:


.text:004011F5                 push    0               ; lpModuleName
.text:004011F7                 call    ds:GetModuleHandleW
.text:004011FD                 mov     ebp, eax        ; MZ header
.text:004011FF                 mov     eax, [ebp+3Ch]  ; MZ.elfanew = PE offset
.text:00401202                 mov     esi, [eax+ebp+80h] ; import table RVA
.text:00401209                 mov     eax, [esi+ebp+0Ch] ; import name RVA


This code gets the handle of the application itself and then it reads: the MZ header; the PE offset; the import table RVA; the first import name RVA.

.text:0040120D                 add     esi, ebp ; virtual address of the image import descriptor
...
.text:00401223                 add     eax, ebp
.text:00401225                 push    offset aUser32_dll_0 ; "user32.dll"
.text:0040122A                 push    eax             ; char *
.text:0040122B                 call    __stricmp
.text:00401230                 add     esp, 8
...
.text:00401237                 add     esi, 14h
.text:0040123A                 mov     [esp+18h+var_4], esi
.text:0040123E                 jmp     loc_4012E6
...
.text:004012E6                 mov     eax, [esi+0Ch]
.text:004012E9                 test    eax, eax
.text:004012EB                 jnz     loc_401223


Then the malware calculates the virtual addresses of the first image import descriptor, its import name address, and begins a loop over the import names looking for "user32.dll".

.text:00401243                 mov     edi, [esi]
.text:00401245                 mov     esi, [esi+10h]
.text:00401248                 mov     eax, [edi+ebp]
.text:0040124B                 add     edi, ebp
.text:0040124D                 add     esi, ebp
...
.text:00401257                 jmp     short loc_401260
...
.text:00401260                 lea     ecx, [eax+ebp+2] ; Name
.text:00401264                 push    offset aRegisterclasse ; "RegisterClassExW"
.text:00401269                 push    ecx             ; char *
.text:0040126A                 call    __stricmp
.text:0040126F                 add     esp, 8
.text:00401272                 test    eax, eax
.text:00401274                 jnz     short loc_401297
...
.text:00401297                 mov     edx, [edi]
.text:00401299                 lea     eax, [edx+ebp+2]
.text:0040129D                 push    offset aCreatewindowex ; "CreateWindowExW"
.text:004012A2                 push    eax             ; char *
.text:004012A3                 call    __stricmp
.text:004012A8                 add     esp, 8
.text:004012AB                 test    eax, eax
.text:004012AD                 jnz     short loc_4012D0
...
.text:004012D0                 mov     eax, [edi+4]
.text:004012D3                 add     edi, 4
.text:004012D6                 add     esi, 4
.text:004012D9                 test    eax, eax
.text:004012DB                 jnz     short loc_401260


Here the code saves the content of the OriginalFirstThunk and the FirstThunk fields of the IMAGE_IMPORT_DESCRIPTOR. Then, it loops over every IMAGE_IMPORT_BY_NAME.Name looking for the RegisterClassExW and the CreateWindowExW APIs.

Once they are found it does the following:


[RegisterClassExW]


.text:00401276                 lea     edx, [esp+18h+flOldProtect]
.text:0040127A                 push    edx             ; lpflOldProtect
.text:0040127B                 push    40h             ; flNewProtect
.text:0040127D                 push    4               ; dwSize
.text:0040127F                 push    esi             ; lpAddress
.text:00401280                 call    ebx ; VirtualProtect
.text:00401282                 lea     eax, [esp+18h+flOldProtect]
.text:00401286                 push    eax             ; lpflOldProtect
.text:00401287                 mov     dword ptr [esi], offset BadFunc1 ; FirstThunk overwrite
.text:0040128D                 mov     ecx, [esp+1Ch+flOldProtect]
.text:00401291                 push    ecx             ; flNewProtect
.text:00401292                 push    4               ; dwSize
.text:00401294                 push    esi             ; lpAddress
.text:00401295                 call    ebx ; VirtualProtect


[CreateWindowExW]


.text:004012AF                 lea     ecx, [esp+18h+flOldProtect]
.text:004012B3                 push    ecx             ; lpflOldProtect
.text:004012B4                 push    40h             ; flNewProtect
.text:004012B6                 push    4               ; dwSize
.text:004012B8                 push    esi             ; lpAddress
.text:004012B9                 call    ebx ; VirtualProtect
.text:004012BB                 lea     edx, [esp+18h+flOldProtect]
.text:004012BF                 push    edx             ; lpflOldProtect
.text:004012C0                 mov     dword ptr [esi], offset BadFunc2 ; FirstThunk overwrite
.text:004012C6                 mov     eax, [esp+1Ch+flOldProtect]
.text:004012CA                 push    eax             ; flNewProtect
.text:004012CB                 push    4               ; dwSize
.text:004012CD                 push    esi             ; lpAddress
.text:004012CE                 call    ebx ; VirtualProtect


Basically, it changes the protection of the memory containing the import addresses, using the VirtualProtect API; then it overwrites the FirstThunk entry, related to the RegisterClassExW and CreateWindowExW APIs, with a malicious offset.

In this way, every time one of these APIs is called it won't be executed and, instead, the code located at the malicious offset will be run. Even debugging the code, if we don't step into the calls, nothing will suggest that the code is being hijacked.






As we can see the ones above seem to be normal, legitimate, calls, but they are really hijacked to the malicious routines. And here is the trick in action in the debugger:







Note that this is not API hooking, but only a simple trick that works in the executable itself: it's not the API code being overwritten, it is the FirstThunk of the malicious executable.

What can I say... It's not a very advanced deception trick, but a curious one at least: come on guys, you can do better!

2 comments:

  1. A good finding. I saw a similar approach in virus.win32.ninmul.e variant(KAV). But it was a API hook. May be they think as a anti debug/emul trick!

    ReplyDelete
  2. Yes, I think it may fool weaker emulators... or a distracted analyst ;)

    ReplyDelete