In depth analysis of Caphaw/Shylock from “FirefoxUpdate.exe” campaign – Part 1

In this essay we will perform an in-depth analysis (from the unpacking to explorer.exe code injection) of the most recent version of Caphaw/Shylock, a banking malware that, at the time of discovery, was ranked as FUD (Fully UnDetected) by VirusTotal. The article will cover the following topics:

  • Analysis of the packer and related unpacking.
  • Reverse engineering and dropper’s functional analysis.
  • Reverse engineering and functional analysis of explorer.exe injected code.
  • Overview of the associated botnet configuration and webinjects.
  • Intelligence about the sample and involved domains.

How we’ve found it

Before starting with the sample’s direct analysis, let’s talk about how the first binary was discovered in order to add some initial intelligence. While looking for Blackhole EK on urlquery we came across the following entry:

As you can see the URL has the following structure:*.php – after a quick analysis, it emerged that the Exploit Kit was serving a low detection ZeroAccess sample. The most interesting thing happened when we removed the path /ngen/controlling/ in order to get the full domain,

Screen Shot 2013-08-25 at 2.49.54 PM

A fake Firefox critical update page popped up and served as a download vector towards another executable named “FirefoxUpdate.exe” that appeared to be completed undetected on VirusTotal. By gathering information about the IP of the involved domain, we were able to find out that the following domains were also involved in the same campaign:

Additional research revealed that all domains used Blackhole with /ngen/controlling path and the following variations of FirefoxUpdate.exe:



Evilcry (@Blackmond) and Cthulhu(@0s0urce).

PE overview

Let’s start with a general inspection of FirefoxUpdate.exe binary.

SHA256:  35ccf0e051fb0ff61e52ff4130eb38521f954f90ad9c97be59af1e7901974557
SHA1:   8d6d3522daaf4bba74153f9a738d776b4a7d1d6d
MD5:    dcc876357354acaf2b61ee3e839154ad
File size:      292.0 KB ( 299008 bytes )
File type:      Win32 EXE
Detection ratio:        0 / 46
Analysis date:  2013-08-25 10:48:11 UTC

The executable shows the following Section Header (PE inspection done with Profiler):


We have a considerable number of Sections, some of them with “weird” names like “E1″,”E2″,”B/0″ – please note that we can use the following names to identify other similar samples. As marked in the screenshot, .rdata section contains the ImportTable. According to the Import Table content shown below:


We have some “usually uncommon” imported module, which is WinSCard.dll and its related function SCardAccessStartedEvent, further observations on a larger set of similar samples revealed that the majority of Caphaw variants related to this campaign are using this import entry. Obviously this peculiarity cannot be considered a key factor in the identification of this specific threat, but it can help to identify a specific subset.

Finally let’s take a look at the entropy plot of the whole binary file:


Here we have high entropy levels, this implies that the executable could be packed.

The Analysis

We can start the reversing of the sample with a static analysis approach, by disassembling and watching code starting at the EntryPoint:

.text:004044B0                 sub     esp, 150h
.text:004044B6                 push    edi
.text:004044B7                 lea     eax, [esp+154h+StartupInfo]
.text:004044BB                 push    eax             ; lpStartupInfo
.text:004044BC                 call    ds:GetStartupInfoA
.text:004044C2                 mov     edi, ds:GetProcessHeap
.text:004044C8                 call    edi ; GetProcessHeap
.text:004044CA                 test    eax, eax
.text:004044CC                 jz      Exit_Process
.text:004044D2                 push    esi
.text:004044D3                 push    1000h           ; dwBytes
.text:004044D8                 push    8               ; dwFlags
.text:004044DA                 push    eax             ; hHeap
.text:004044DB                 call    ds:HeapAlloc
.text:004044E1                 call    ds:GetCommandLineA
.text:004044E7                 mov     esi, eax
.text:004044E9                 mov     eax, [esp+158h+StartupInfo.cb]
.text:004044ED                 test    eax, eax
.text:004044EF                 jnz     short getCurrentDirectory

This piece of code should be pretty easy to understand, if GetProcessHeap (the function retrieves a handle to the default heap of the calling process) fails, execution terminates and no infection takes place, otherwise the command-line string is retrieved together with the current directory.

.text:004045AE                 push    0              
.text:004045B0                 call    ds:GetModuleHandleA
.text:004045B6                 mov     ecx, [eax+3Ch]  
.text:004045B9                 lea     edx, [esp+158h+flOldProtect]
.text:004045BD                 push    edx             ; lpflOldProtect
.text:004045BE                 add     ecx, eax
.text:004045C0                 mov     ecx, [ecx+50h]
.text:004045C3                 push    PAGE_EXECUTE_READWRITE ; flNewProtect
.text:004045C5                 push    ecx             ; dwSize
.text:004045C6                 push    eax             ; lpAddress
.text:004045C7                 call    ds:VirtualProtect
.text:004045DF                 push    0
.text:004045E1                 push    0
.text:004045E3                 push    0
.text:004045E5                 call    sub_4014D0

The above piece of code uses GetModuleHandleA to get the base address of the calling process (the malicious process itself), later on it changes the permission map of the committed memory via VirtualProtect, in our case the permission is PAGE_EXECUTE_READWRITE, this is a typical behaviour of packed code: the malware needs to decrypt (WRITE) blocks of encrypted code before executing them. Soon after we can inspect the call 004014d0.

.text:004014D0                 push    ebp
.text:004014D1                 mov     ebp, esp
.text:004014DB                 push    edi
.text:004014DC                 push    0               ; lpModuleName
.text:004014DE                 call    ds:GetModuleHandleA	;Get executable base address
.text:004014E4                 mov     esi, ds:GetTickCount
.text:004014EA                 mov     ebx, eax
.text:004014EE                 test    al, 0C8h
.text:004014F0                 jnz     short get_processversion
.text:00401500 get_processversion:                     ; CODE XREF: sub_4014D0+20j
.text:00401500                 mov     esi, [ebx+3Ch]
.text:00401503                 push    0               ; ProcessId
.text:00401505                 add     esi, ebx
.text:00401507                 call    ds:GetProcessVersion
.text:0040150D                 test    eax, eax
.text:0040150F                 jnz     short next_step
.text:00401511                 push    eax             ; uExitCode
.text:00401512                 call    ds:ExitProcess
.text:00401518 next_step:
.text:00401534                 push    ebx             ; FirefoxUpdate Base Address
.text:00401535                 fstp    [ebp+var_10]
.text:00401538                 call    Get_PE_section_address
.text:00401549                 jnz     short previous_section ; eax - 0x28 (previous section)
.text:00401586 previous_section: 
.text:00401586                 add     eax, 0FFFFFFD8h ; eax - 0x28 (previous section)

The scope of the previous snippet of code is to locate each PE Section starting at .rsrc (8th section) and moving to the previous ones by adding – 0×28. Let’s now check the next block of code:

.text:004015B1                 mov     eax, [esi+50h]	; Size of Image
.text:004015B4                 push    40h             ; PAGE_EXECUTE_READWRITE
.text:004015B6                 push    1000h           ; MEM_COMMIT
.text:004015BB                 push    eax             ; dwSize
.text:004015BC                 push    0               ; lpAddress
.text:004015BE                 call    ds:VirtualAlloc
.text:004015C4                 mov     edx, [esi+50h]  
.text:004015C7                 lea     ecx, [ebp+flOldProtect]
.text:004015CA                 push    ecx             ; lpflOldProtect
.text:004015CB                 push    40h             ; flNewProtect
.text:004015CD                 push    edx             ; dwSize
.text:004015CE                 push    ebx             ; lpAddress
.text:004015CF                 mov     [ebp+arg_0], eax
.text:004015D2                 call    edi ; VirtualProtect
.text:004015D4                 fld     ds:dbl_40B9A8
.text:004015DA                 mov     ecx, [esi+50h]  ; Size of Image
.text:004015DD                 mov     edi, [ebp+8]    ; pointer to the freshly allocated clock of memory
.text:004015E0                 mov     eax, ecx
.text:004015E2                 shr     ecx, 2
.text:004015E5                 mov     esi, ebx
.text:004015E7                 rep movsd               ; Copy PE /itself/ in allocated block of memory
.text:00401605                 push    eax             ; PE allocated in memory
.text:00401606                 call    sub_401440

This part basically allocates a block of memory of the same size of the current running PE image (esi+50h == Size of Image in the PE). The next action is to change the protection (PAGE_EXECUTE_READWRITE) of the freshly allocated chunk and copy inside it the entire PE image. Let’s now inspect call 00401440:

.text:00401440                 push    esi
.text:00401441                 mov     esi, [esp+8]
.text:00401445                 mov     eax, [esi+3Ch]
.text:00401448                 mov     ecx, [eax+esi+34h] ; PE
.text:00401455                 mov     ecx, [eax+0A0h] ; relocation directory
.text:0040145B                 test    ecx, ecx
.text:0040145D                 jz      short loc_4014C2
.text:0040145F                 push    ebx
.text:00401460                 mov     ebx, [eax+0A4h] ; relocation directory size
.text:00401466                 add     ecx, esi        ; new allocated pe + relocation directory
.text:00401468                 add     ebx, ecx        ; add relocation directory size
.text:0040146A                 cmp     ecx, ebx
.text:0040146C                 mov     [esp+10h], ebx
.text:00401470                 jnb     short loc_4014C1
.text:00401472                 push    ebp
.text:00401473 loc_401473:                             
.text:00401473                 mov     eax, [ecx+4]    ; PE address of the new allocated PE
.text:00401476                 test    eax, eax
.text:00401478                 jz      short loc_4014B9
.text:0040147A                 add     eax, 0FFFFFFF8h
.text:0040147D                 shr     eax, 1
.text:0040147F                 test    eax, eax
.text:00401481                 lea     edx, [ecx+8]
.text:00401484                 jbe     short loc_4014B9
.text:00401486                 mov     ebx, eax
.text:00401488 loc_401488:                            
.text:00401488                 xor     eax, eax
.text:0040148A                 mov     ax, [edx]       ; edx points to the beginning of the 
relocation directory
.text:0040148D                 mov     ebp, eax
.text:0040148F                 and     ebp, 0F000h
.text:00401495                 cmp     ebp, 3000h
.text:0040149B                 jnz     short loc_4014AF
.text:0040149D                 mov     ebp, [ecx]
.text:0040149F                 and     eax, 0FFFh
.text:004014A4                 add     eax, ebp
.text:004014A6                 mov     ebp, [eax+esi]  ; next imported function
.text:004014A9                 add     eax, esi
.text:004014AB                 add     ebp, edi
.text:004014AD                 mov     [eax], ebp      ; new fixed address of the import placed in the new executable

This piece of code fixes the imported APIs addresses in order to correctly call each function when the execution flow jumps into the “new” PE. In the nearby call 00401440 we meet our first “call to the next layer”:

.text:0040161B                 add     eax, esi        ; Get entrypoint in PE located in memory
.text:0040161D                 call    eax             ; Next layer

Let’s see what happens inside the new layer, we will talk about the most significant portions of code.

00D614D0    55              PUSH EBP
00D614D1    8BEC            MOV EBP,ESP
00D614D3    81EC 4C010000   SUB ESP,14C
00D614DC    6A 00           PUSH 0
00D614DE    FF15 7490D600   CALL DWORD PTR DS:[0D69074]                      ; GetModuleHandleA
00D614E4    8B35 4490D600   MOV ESI,DWORD PTR DS:[0D69044]
00D614EA    8BD8            MOV EBX,EAX
00D61500    8B73 3C         MOV ESI,DWORD PTR DS:[EBX+3C]                    ; Get PE of the main dropper
00D61518    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]                     ; Base address of the new PE
00D61631    52              PUSH EDX
00D61632    C745 FC 0001000 MOV DWORD PTR SS:[EBP-4],100
00D61639    FF15 3090D600   CALL DWORD PTR DS:[0D69030]                      ; GetComputerNameA
00D6165D    68 54D0D600     PUSH 0D6D054                                     ; ASCII "kernel32"
00D61662    FF15 7490D600   CALL DWORD PTR DS:[0D69074]                      ; GetModuleHandleA
00D61668    8B4E 50         MOV ECX,DWORD PTR DS:[ESI+50]                    ; Size of Image
00D6166B    6A 40           PUSH 40
00D6166D    68 00100000     PUSH 1000
00D61672    51              PUSH ECX                                         ; Size
00D61673    53              PUSH EBX                                         ; 0040000 (PE base address)
00D61674    8945 DC         MOV DWORD PTR SS:[EBP-24],EAX
00D61677    FF15 3C90D600   CALL DWORD PTR DS:[0D6903C]                      ; VirtualAlloc
00D6167D    8B46 50         MOV EAX,DWORD PTR DS:[ESI+50]
00D616F1    8D0485 0870E700 LEA EAX,[EAX*4+0E77008]                          ; Pointer to a block of data in EAX
00D616F8    C1E9 02         SHR ECX,2
00D616FB    8945 E4         MOV DWORD PTR SS:[EBP-1C],EAX
00D616FE    8BF0            MOV ESI,EAX
00D61700    8BFB            MOV EDI,EBX
00D61702    F3:A5           REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]   ; Base address now contains a block of DATA
00D61704    8BCA            MOV ECX,EDX
00D61706    83E1 03         AND ECX,00000003
00D61709    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
00D6170B    8B4D FC         MOV ECX,DWORD PTR SS:[EBP-4]
00D6170E    51              PUSH ECX
00D6170F    50              PUSH EAX
00D61710    50              PUSH EAX
00D61711    8945 F4         MOV DWORD PTR SS:[EBP-0C],EAX
00D61714    E8 E7F8FFFF     CALL 00D61000

VirtualAlloc allocates a new block of memory with PAGE_EXECUTE_READWRITE permissions, which will be used to host some portion of code to be executed, then a rep movs instruction copies a new block of code. Here’s what happens in synthesis inside call 00D61000:

00D61035    66:3306         XOR AX,WORD PTR DS:[ESI]                         ; XOR based data decryption
00D61038    83C6 02         ADD ESI,2
00D6103B    4B              DEC EBX
00D6103C    66:894437 FE    MOV WORD PTR DS:[ESI+EDI-2],AX                   ; copy decrypted data
00D61041  ^ 75 ED           JNE SHORT 00D61030
00D61043    5F              POP EDI
00D61044    5B              POP EBX
00D61045    5E              POP ESI
00D61046    C3              RETN

A block of data is decrypted by using a simple XOR, by inspecting the destination buffer we can observe the following memory layout:


A new executable has been decrypted, you can also see that PE seems packed with UPX. Immediately after call 00D61000 the freshly decrypted PE will be copied in the corresponding 0040000 Base Address, in other words the previous PE as been exchanged with this “new” one.

00D617D6    E8 35F9FFFF     CALL 00D61110                     ; Build a minimal IAT for UPX executable
00D617DB    8B53 3C         MOV EDX,DWORD PTR DS:[EBX+3C]     ; New UPX executable PE
00D617DE    8B4413 28       MOV EAX,DWORD PTR DS:[EDX+EBX+28] ; AddressOfEntryPoint = baseaddress+PE+0x28
00D617E2    03C3            ADD EAX,EBX
00D617E4    83C4 04         ADD ESP,4
00D617E7    8945 F0         MOV DWORD PTR SS:[EBP-10],EAX
00D617EA    FFD0            CALL EAX		               ; Jump to the UPX executable

Call EAX confirms that we’ve reached the second layer, EAX will contain the EntryPoint address of the UPX executable. Let’s see what happens in the second block of code:

0044C0B0    8A06            MOV AL,BYTE PTR DS:[ESI]
0044C0B2    46              INC ESI
0044C0B3    8807            MOV BYTE PTR DS:[EDI],AL
0044C0B5    47              INC EDI
0044C0B6    01DB            ADD EBX,EBX
0044C0B8    75 07           JNE SHORT 0044C0C1
0044C0BA    8B1E            MOV EBX,DWORD PTR DS:[ESI]
0044C0BC    83EE FC         SUB ESI,-4
0044C0BF    11DB            ADC EBX,EBX
0044C0C1  ^ 72 ED           JB SHORT 0044C0B0

This part transfers a block of code pointed by ESI into the location pointed by EDI (that initially points to 00401000), once the code has been transferred it will be decrypted. After decryption we have the following routine:

0044C172    8A07            MOV AL,BYTE PTR DS:[EDI]	; Move the one byte pointed by EDI in AL
0044C174    47              INC EDI			; Next byte
0044C175    2C E8           SUB AL,0E8			; Byte - 0xE8
0044C177    3C 01           CMP AL,1			; Result is 1  ?
0044C179  ^ 77 F7           JA SHORT 0044C172		; Next byte
0044C17B    803F 00         CMP BYTE PTR DS:[EDI],0	; Is byte after equal to 0 ?
0044C17E  ^ 75 F2           JNE SHORT 0044C172
0044C180    8B07            MOV EAX,DWORD PTR DS:[EDI]  ; Move DWORD pointed by EDI in EAX
0044C182    8A5F 04         MOV BL,BYTE PTR DS:[EDI+4]	; Next DWORD
0044C185    66:C1E8 08      SHR AX,8
0044C189    C1C0 10         ROL EAX,10
0044C18C    86C4            XCHG AH,AL
0044C18E    29F8            SUB EAX,EDI
0044C190    80EB E8         SUB BL,0E8
0044C193    01F0            ADD EAX,ESI
0044C195    8907            MOV DWORD PTR DS:[EDI],EAX   ; Substitute fixed address

EDI initially points to 00401000 (where freshly decrypted code is placed), the routine takes one byte (we are dealing with code, so we need to consider these bytes as Opcodes) at a time and subtracts 0xE8 to it. This is a simple way to check if the opcode pointed by EDI is a Call. When the code meets a call, it takes the adjacent DWORD (which is the address pointed by the call) and places it in EAX (instruction 0044C180) then it applies a fix and finally, at instruction 0044C195, replaces the old address pointed by the call with the new one. The picture below shows the code before the fix:


You can clearly see an incoherent address (8340101A), here’s the situation after the fix:


Looks definitely coherent now.

After the call fix we land here:

0044C21C    39C4            CMP ESP,EAX
0044C21E  ^ 75 FA           JNE SHORT 0044C21A
0044C220    83EC 80         SUB ESP,-80
0044C223  ^ E9 D84DFBFF     JMP 00401000

Last instruction represent the jump to the third layer. After landing into the third layer the first important operation is shown below:

004011B9   FFD0          CALL EAX                                  ; VirtualAlloc
004011BB   8945 F8       MOV DWORD PTR SS:[EBP-8],EAX
004011BE   85C0          TEST EAX,EAX
004011C0   74 5B         JZ SHORT 0040121D
004011D0   4D            DEC EBP
004011D1   FC            CLD
004011D2   FC            CLD
004011D3   F3:A4         REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ; Copy a 
new portion of data into the new block of memory

This is the classical scheme we have already seen: VirtualAlloc builds a new block of memory and finally a block of data is copied inside it, by taking a look at this data we discover that there is (again!) a new executable:

Section names clearly indicates that this PE is different from the others (like the UPX) previously seen. Finally we land here:

00401077      8B40 10       MOV EAX,DWORD PTR DS:[EAX+10]		
0040107A      03C6          ADD EAX,ESI 		;EAX points to the new EntryPoint 		
0040107C      FFD0          CALL EAX

Exploring the core

With this final call we finally reach the unpacked code, as is shown below:

00EF615D    55              PUSH EBP
00EF615E    8BEC            MOV EBP,ESP
00EF6160    8B45 0C         MOV EAX,DWORD PTR SS:[EBP+0C]
00EF6163    83E8 00         SUB EAX,0
00EF6166    74 15           JE SHORT 00EF617D
00EF6168    48              DEC EAX
00EF6169    74 0D           JE SHORT 00EF6178
00EF616B    48              DEC EAX
00EF616C    74 0F           JE SHORT 00EF617D
00EF616E    48              DEC EAX
00EF616F    74 0C           JE SHORT 00EF617D
00EF6171    E8 C1FAFFFF     CALL 00EF5C37
00EF6176    EB 05           JMP SHORT 00EF617D
00EF6178    E8 19F5FFFF     CALL 00EF5696
00EF617D    33C0            XOR EAX,EAX
00EF617F    40              INC EAX
00EF6180    5D              POP EBP
00EF6181    C2 0C00         RETN 0C

The full dropper/injector code is concentrated into the call 00EF5C37. Before starting with dynamic analysis (debugging approach) it’s important to specify that we will deal with a lot of redundant pieces of code that won’t be reported here for obvious reasons.

00EF5C37    55              PUSH EBP
00EF5C38    8BEC            MOV EBP,ESP
00EF5C3A    83E4 F8         AND ESP,FFFFFFF8
00EF5C3D    81EC DC010000   SUB ESP,1DC
00EF5C43    53              PUSH EBX
00EF5C44    56              PUSH ESI
00EF5C45    57              PUSH EDI
00EF5C46    8D7424 18       LEA ESI,[ESP+18]
00EF5C4A    E8 FEFEFDFF     CALL 00ED5B4D                  ; Allocate Heap
00EF5C5C    E8 B237FEFF     CALL 00ED9413	           ; GetCommandLineA
00EF5C61    8BF0            MOV ESI,EAX                    ; ASCII "c:\FirefoxUpdate.exe"

As you can see we have marked call 00ED9413 as “GetCommandLineA”, this happens because Caphaw/Shylock does not call directly the required API but uses the following schema:

00ED9413    56              PUSH ESI
00ED9414    68 2E1D6AC6     PUSH C66A1D2E
00ED9419    E8 8AECFFFF     CALL 00ED80A8	; retrieve module address
00ED941E    8BF0            MOV ESI,EAX
00ED9420    E8 DFECFFFF     CALL 00ED8104       ; retrieve API address
00ED9425    59              POP ECX
00ED9426    5E              POP ESI
00ED9427    FFE0            JMP EAX		; GetCommandLineA

Now let’s see another common function (call 00EEBC31) widely used to decrypt strings.

00EEBC96    E8 C1BFFEFF     CALL 00ED7C5C	;RtlAllocateHeap
00EEBC9B    59              POP ECX
00EEBC9C    59              POP ECX
00EEBC9D    8945 F8         MOV DWORD PTR SS:[EBP-8],EAX
00EEBCA0    85C0            TEST EAX,EAX
00EEBCA2    74 37           JE SHORT 00EEBCDB
00EEBCA4    8365 F4 00      AND DWORD PTR SS:[EBP-0C],00000000
00EEBCA8    8975 EC         MOV DWORD PTR SS:[EBP-14],ESI
00EEBCAB    8B7D F8         MOV EDI,DWORD PTR SS:[EBP-8]
00EEBCAE    8B75 EC         MOV ESI,DWORD PTR SS:[EBP-14]
00EEBCB1    8B4D F0         MOV ECX,DWORD PTR SS:[EBP-10]
00EEBCB4    FC              CLD
00EEBCB5    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ;Copy the 
encrypted string in the recently allocated heap
00EEBCB7    897D F4         MOV DWORD PTR SS:[EBP-0C],EDI
00EEBCBA    6A 01           PUSH 1
00EEBCBC    FF33            PUSH DWORD PTR DS:[EBX]
00EEBCBE    8BC8            MOV ECX,EAX
00EEBCC0    E8 7B19FFFF     CALL 00EDD640	;Decrypt string
00EEBCC5    59              POP ECX

Let’s see how 00EDD640 works:

00EDD640    55              PUSH EBP
00EDD641    8BEC            MOV EBP,ESP
00EDD643    85C9            TEST ECX,ECX
00EDD645    74 3A           JE SHORT 00EDD681
00EDD647    56              PUSH ESI
00EDD648    8A11            MOV DL,BYTE PTR DS:[ECX]   ;Encrypted byte pointed by ECX in AL
00EDD64A    8AC2            MOV AL,DL
00EDD64C    3245 08         XOR AL,BYTE PTR SS:[EBP+8] ;XOR Encrypted byte with a key 
byte pointed by EBP+8	
00EDD64F    837D 0C 01      CMP DWORD PTR SS:[EBP+0C],1
00EDD653    8801            MOV BYTE PTR DS:[ECX],AL
00EDD655    75 04           JNE SHORT 00EDD65B
00EDD657    84C0            TEST AL,AL
00EDD659    EB 08           JMP SHORT 00EDD663
00EDD65B    837D 0C 00      CMP DWORD PTR SS:[EBP+0C],0
00EDD65F    75 04           JNE SHORT 00EDD665
00EDD661    84D2            TEST DL,DL
00EDD663    74 1B           JE SHORT 00EDD680
00EDD665    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]
00EDD668    69C0 4D030000   IMUL EAX,EAX,34D
00EDD66E    05 41020000     ADD EAX,241
00EDD673    33D2            XOR EDX,EDX
00EDD675    83CE FF         OR ESI,FFFFFFFF
00EDD678    F7F6            DIV ESI
00EDD67A    41              INC ECX
00EDD67B    8955 08         MOV DWORD PTR SS:[EBP+8],EDX
00EDD67E  ^ EB C8           JMP SHORT 00EDD648		;Decrypt next byte

Finally, the encrypted string placed in the allocated piece of heap will be replaced by the decrypted one. Back to the main (inside the Call 00EF5C37), whe have ‘ -test’ as decrypted string. The stages of infection are marked by a series of strings, the first one we meet is:

00EF5CF7    50              PUSH EAX
00EF5CF8    B8 48ADEB00     MOV EAX,0EBAD48
00EF5CFD    E8 2F5FFFFF     CALL 00EEBC31				; "HSE::Step 1 START VERSION %s"
00EF5D02    8B00            MOV EAX,DWORD PTR DS:[EAX]
00EF5D04    C70424 38ADEB00 MOV DWORD PTR SS:[ESP],0EBAD38                 ; ASCII ""

that, once decrypted, becomes: HSE::Step 1 START VERSION

00EF5D2A    68 CC010000     PUSH 1CC
00EF5D2F    E8 A526FEFF     CALL 00ED83D9		; Allocate Heap
00EF5D34    59              POP ECX
00EF5D35    85C0            TEST EAX,EAX
00EF5D37    74 08           JE SHORT 00EF5D41
00EF5D39    50              PUSH EAX  			; Pointer to the allocated heap
00EF5D3A    E8 684CFFFF     CALL 00EEA9A7

Call 00EEA9A7 contains the features that characterise the HSE:: Step 1 phase, we will see a synthesis of these operations.

A security descriptor is initialised via InitializeSecurityDescriptor and consequently we have:

SetSecurityDescriptorDacl with the following arguments 
Arg1 = 0F7F77C 
Arg2 = 1
Arg3 = 0
Arg4 = 0

The second parameter is set to TRUE, the function sets the SE_DACL_PRESENT flag in the SECURITY_DESCRIPTOR_CONTROL structure and uses the values in the pDacl and bDaclDefaulted parameters. Third parameter is pDacl, this parameter is NULL, a NULL DACL is assigned to the security descriptor, which allows all access to the object.

Immediately after we have a call to GetVersionExA, in order to get the OS version of the victim. Here’s a quick summary of the information gathered:

GetEnvironmentVariableA -> with argument SYSTEMDRIVE which returns the current System Drive 
(C: in our case).

Call GetComputerNameA -> Retrieves the name of the local computer

Call GetUsernameA -> Retrieves the name of the user associated with the current thread.

Call LookupAccountNameA -> The LookupAccountName function accepts the name of a system and 
an account as input. It retrieves a security identifier (SID) for the account and the name 
of the domain on which the account was found.

This information will be used to build the string that will be sent to the Command&Control server. Another important piece is given by the MD5 hash of data+ComputerName, which in our case is:


Caphaw/Shylock implements also a quite trivial check (carried out via Process enumeration via CreateToolhelp32Snapshot) for the presence of Trusteer’s Rapport product. Immediately after Rapport check we can see the decryption of a list of strings:


_EVT_ clearly suggests us the term Event, these strings will be indeed used as  name parameter for CreateEvent function. Once the strings are decrypted we’ll get something like this:


We have MD5(previously computed)_EVT_*, as we have seen we also have _MTX_ string that clearly indicates that it will be used as a name for a Mutex. The usage of an infection dependent value (our MD5 which is computed by using the Computer Name) allows the trojan to bypass some easy detection (a static event name or mutex could became a good Indicator of Compromise), especially in this case were the string MD5_EVT_* is encrypted as shown in the following image:


Finally we have the following self explaining piece of code applied to each event:

00EEB4AC    FF75 F4         PUSH DWORD PTR SS:[EBP-0C] ; ASCII "5nwfKpA{1mHQ`lcRE
00EEB4AF    E8 47CBFFFF     CALL 00EE7FFB	;CreateEventA with the encrypted event string above

Here it ends the long Call 00EEA9A7 and we are ready to enter in the second stage of the trojan as we can infer by the string HSE::Step 2 (FIREFOXUPDATE.EXE:1312) where FIREFOXUPDATE.EXE is the malicious executable name and 1312 the PID. This phase does not include substantial operations, except for the creation of an executable name: “ipconfig.exe”.

00EF5DF8    E8 345EFFFF     CALL 00EEBC31		; HSE::Step 3 Guid=%s
00EF5DFD    8B00            MOV EAX,DWORD PTR DS:[EAX]
00EF5DFF    59              POP ECX
00EF5E00    56              PUSH ESI
00EF5E01    50              PUSH EAX
00EF5E02    8D7424 18       LEA ESI,[ESP+18]
00EF5E06    E8 42FDFDFF     CALL 00ED5B4D
00EF5E0B    E8 0F02FEFF     CALL 00ED601F		; HSE::Step 3 Guid=ipconfig.exe

We land quickly to the Step 3 identified by the string HSE::Step 3 Guid=ipconfig.exe, where Guid is equal to the previously decrypted executable name. Additionally we have the following core operations:

00EF5E62    E8 3E2DFFFF     CALL 00EE8BA5	; CreateMutex with previously computed MD5		
00EF5E67    85C0            TEST EAX,EAX
00EF5E69    0F84 D6020000   JE 00EF6145
00EF5E6F    8D4424 58       LEA EAX,[ESP+58]
00EF5E73    50              PUSH EAX
00EF5E74    E8 96ECFDFF     CALL 00ED4B0F	; WSAStartup

We have now a mutex named 571C8ECED4FAF69E4A38507B4417257B571C8571C8ECE and a call to WSAStartup which initiates the use of Winsock DLL, this means that soon we will deal with  communication between the client (our malware) and the Command and Control server.

00EF5E8C    E8 A05DFFFF     CALL 00EEBC31		; HSE::Step 4
00EF5E91    59              POP ECX
00EF5E92    8D7424 10       LEA ESI,[ESP+10]
00EF5E96    E8 CDFCFDFF     CALL 00ED5B68
00EF5E9B    8D7C24 10       LEA EDI,[ESP+10]
00EF5E9F    E8 913AFFFF     CALL 00EE9935		; Look for ipconfig.exe in CurrentVersion\Run

HSE::Step 4 is characterised mainly by the call 00EE9935 which is reported below in our usual synthetic language:

RegQueryValueExA with the following arguments

hKey = [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run]
Name = "ipconfig.exe"


Executables listed in Software\Microsoft\Windows\CurrentVersion\Run will be executed during system’s startup, this is the most common way to grant persistence on the system. In our specific case the trojan checks if there is already an entry named “ipconfig.exe”.

00EF5ECE    E8 5E5DFFFF     CALL 00EEBC31	;"HSE::Step 5 (It's the first starting)."
00EF5ED3    59              POP ECX
00EF5ED4    8D7424 10       LEA ESI,[ESP+10]
00EF5ED8    E8 8BFCFDFF     CALL 00ED5B68	; nothing
00EF5EDD    68 74030000     PUSH 374
00EF5EE2    E8 F224FEFF     CALL 00ED83D9	; allocate heap
00EF5EE7    59              POP ECX
00EF5EE8    85C0            TEST EAX,EAX
00EF5EEA    74 0C           JE SHORT 00EF5EF8
00EF5EEC    57              PUSH EDI
00EF5EED    8BC8            MOV ECX,EAX
00EF5EEF    E8 E7E9FEFF     CALL 00EE48DB	; Decrypt strings and gather victim's information

Despite previous Steps, the 5th “HSE::Step 5 (It’s the first starting).“, performs some very interesting actions located into call 00EE48DB.This call can be divided in two main sub-functionalities:

  • Decrypt bot dependent strings.
  • Victim information gathering.

At the begin of this call we have some very interesting string, decrypted on-the-fly:

  • Decrypt string: ‘net2‘ -> The name of the botnet.
  • Decrypt string: “2013.08.23 12:55:38” -> This is the build time.
  • Decrypt string: “/files/hidden7770777.jpg” -> This is the httpinject configuration.

The following URL strings are also decrypted:

  • “”
  • “”
  • “”
  • “”
  • “”

Now let’s take a look at the victim information gathering functionalities.
System memory information

00EEC8C1    50              PUSH EAX
00EEC8C2    E8 9433FFFF     CALL 00EDFC5B	; Call GlobalMemoryStatusEx
00EEC8C7    59              POP ECX
00EEC8CC    50              PUSH EAX
00EEC8CD    B8 D89CEB00     MOV EAX,0EB9CD8	; decrypt RAM=
00EEC8D2    E8 5AF3FFFF     CALL 00EEBC31
00EEC8D7    59              POP ECX

GlobalMemoryStatusEx retrieves information about the system’s current usage of both physical and virtual memory, these details goes into RAM= string.
System hardware information

00EF09F1    FF75 FC         PUSH DWORD PTR SS:[EBP-4]
00EF09F4    E8 6EC2FCFF     CALL 00EBCC67	; get ProcessorNameString
00EF09F9    5B              POP EBX

Hardware information is taken via registry key as follows:

Decrypt string: ProcessorNameString
Decrypt string: "HARDWARE\DESCRIPTION\System\CentralProcessor\0"

RegQueryValueExA with parameters:
Name = "ProcessorNameString"

00EE081E    895D F8         MOV DWORD PTR SS:[EBP-8],EBX
00EE0821    E8 0BB40000     CALL 00EEBC31		; Decrypt string "~MHz"
00EE0826    8B30            MOV ESI,DWORD PTR DS:[EAX]
00EE087C    8BC6            MOV EAX,ESI
00EE087E    E8 9C57FFFF     CALL 00ED601F		; 2492 MHz
00EE0883    83C4 0C         ADD ESP,0C

Finally the following string is assembled:

CPU= Intel(R) Core(TM) i5-3210M CPU @ 2.50GHz  2492 MHz RAM=572Mb

Windows information

Via SOFTWARE\Microsoft\Windows NT\CurrentVersion registry query Caphaw collects victim’s data as follows:

00EE3F27    50              PUSH EAX
00EE3F28    E8 45CC0000     CALL 00EF0B72	; Get ProductId
00EE3F2D    83C4 14         ADD ESP,14

RegOpenKeyExA("SOFTWARE\Microsoft\Windows NT\CurrentVersion")
hKey = [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion]
Name = "ProductId"

We will meet a certain number of call 00EF0B72 where the only parameter that varies is Name. Here’s a quick list of entries called:

  • “RegisteredOwner”
  • “RegisteredOrganization”
  • “CurrentVersion”
  • “CurrentBuild”
  • “CurrentBuildNumber”
  • “InstallDate”

Final information gathered can be summarised as follows:

InstallData=28.07.2013 14:09

XXX = we have removed our serials, hope you won’t mind :).

00EECA81    E8 E534FFFF     CALL 00EDFF6B	; Determine if we are via SID check

This call uses AllocateAndInitializeSid and CheckTokenMembership in order to determine if the caller’s process is a member of the Administrators local group. More information can be found here: IsUserAdmin via CheckTokenMembership.

Final string:


FileSystem information

Next step involves collection of details about the FileSystem geometry of the victim:

00EDFA44    E8 EB8AFFFF     CALL 00ED8534	; GetLogicalDrives
00EDFA49    6A 02           PUSH 2
00EDFAF5    8D45 F8         LEA EAX,[EBP-8]
00EDFAF8    8D7D E8         LEA EDI,[EBP-18]
00EDFAFB    E8 9DFDFFFF     CALL 00EDF89D	; GetDriveTypeA

Here we have a loop that iterates each logical drive and finally builds a synthesis of the gathered geometry, as reported below:

FS=C: [LOCAL,NTFS,T=9GB:U=2GB(25%)]D: [CD-ROM,CDFS,E: [REMOTE,VBoxSharedFolderFS,T=464GB:U=86GB(18%)]

Browser information gathering

Trojan now looks for installed browser(s) and version.

Decrypt string: "SOFTWARE\Microsoft\Internet Explorer"

RegOpenKeyA("SOFTWARE\Microsoft\Internet Explorer")
RegQueryValueExA with the following parameters:
hKey = [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer]
Name = "Version"

Final string:


In the same way via “SOFTWARE\Mozilla\Mozilla Firefox” Shylock determines the presence and version of Firefox.

Final string:

“FF=3.6.28 (en-GB)”

We have also the following browsers and version checks:

  • Software\Google\Update\Client -> Chrome.
  • Software\Opera Software -> Opera.
  • Software\Apple Computer, Inc.\Safari -> Safari.

The trojan looks also for Maxthon browser presence, but in this case the check is performed by attempting to reach the following paths:

  1. get ProgramFiles path via GetEnvironmentVariable
  2. decrypts “%s\Maxthon%u\Bin\maxthon.exe” string
  3. concatenates ProgramFiles with .2
  4. Builds the following string: “C:\Program Files\Maxthon10\Bin\maxthon.exe”
  5. Check presence and version via GetFileVersionInfoSizeA, GetFileVersionInfoA
  6. Next iteration – jump to .2

This loop goes from Maxthon 10 to Maxthon 1.

Antivirus information gathering

In the next information extraction stage we meet the Antivirus awareness routine performed with the aim of determining the presence of AV software.

00EE19E6    E8 46A20000     CALL 00EEBC31	; Decrypt the AV Name: Agava Firewall
00EE19F9    B8 6C6FEB00     MOV EAX,0EB6F6C
00EE19FE    E8 2EA20000     CALL 00EEBC31	; Fwservice.exe
00EE1A03    59              POP ECX

We have a long sequence of string decryption calls, which exposes AV Name and their Executable Filenames. In the following list we reported the full set of AV strings:

"Agava firewall"
"AtGuard firewall"
"Comodo firewall"
"Comcast Spyware Scan"
"Doctor Web"
"Kerio firewall"
"NeT firewall"
"MS Firewall Client"
"Lavasoft Ad-Aware"
"OnlineArmor firewall"
"Outpost firewall"
"Panda firewall"
"PC Cleaner"
"PC Tools"
"SoftPerfect Personal Firewall"
"Spyware Doctor"
"Trend Micro"
"Windows Defender"
"Virgin Media"

After the string decryption we can find the AV awareness routine:

00EE3979    E8 C053FFFF     CALL 00ED8D3E                              ; CreateToolhelp32Snapshot
00EE397E    8945 D4         MOV DWORD PTR SS:[EBP-2C],EAX
00EE3981    83F8 FF         CMP EAX,-1
00EE3984    0F84 72010000   JE 00EE3AFC
00EE398A    BE 28010000     MOV ESI,128
00EE398F    56              PUSH ESI
00EE3990    8D85 A4FEFFFF   LEA EAX,[EBP-15C]
00EE3996    6A 00           PUSH 0
00EE3998    50              PUSH EAX
00EE3999    E8 E6270100     CALL <JMP.memset>                          
00EE399E    83C4 0C         ADD ESP,0C
00EE39A1    8D85 A4FEFFFF   LEA EAX,[EBP-15C]
00EE39A7    50              PUSH EAX
00EE39A8    FF75 D4         PUSH DWORD PTR SS:[EBP-2C]
00EE39B1    E8 6557FFFF     CALL 00ED911B                              ; Process32First
00EE39B6    E9 2E010000     JMP 00EE3AE9
00EE39BB    8365 DC 00      AND DWORD PTR SS:[EBP-24],00000000
00EE39BF    837D E8 00      CMP DWORD PTR SS:[EBP-18],0
00EE39C3    0F86 11010000   JBE 00EE3ADA
00EE39C9    8B45 E4         MOV EAX,DWORD PTR SS:[EBP-1C]
00EE39CC    8945 E0         MOV DWORD PTR SS:[EBP-20],EAX
00EE39CF    8D85 C8FEFFFF   LEA EAX,[EBP-138]
00EE39D5    50              PUSH EAX                                   ; Current running process item
00EE39D6    8D75 D8         LEA ESI,[EBP-28]
00EE39D9    E8 0F21FFFF     CALL 00ED5AED                              ; Compare running process name with AV list

This code is pretty easy, Caphaw enumerates the running processes and compares each one against the previously decrypted AV list.

VM Awareness and characterisation

Caphaw also tries to determine if the malware is being executed in a Virtual Environment and determines what is the virtualization solution in use.
We will show here the two methods adopted:

  1. Via running processes
  2. Via system files.

Let’s see the first one.

00ED6570    E8 C9270000     CALL 00ED8D3E                              ; CreateToolhelp32Snapshot
00ED6575    8BF8            MOV EDI,EAX
00ED6577    83FF FF         CMP EDI,-1
00ED657A    74 62           JE SHORT 00ED65DE
00ED657C    68 28010000     PUSH 128
00ED6581    8D85 D4FEFFFF   LEA EAX,[EBP-12C]
00ED6587    53              PUSH EBX
00ED6588    50              PUSH EAX
00ED6589    E8 F6FB0100     CALL <JMP.memset>                          ; Jump to msvcrt.memset
00ED658E    8D85 D4FEFFFF   LEA EAX,[EBP-12C]
00ED6594    50              PUSH EAX
00ED6595    57              PUSH EDI
00ED6596    C785 D4FEFFFF 2 MOV DWORD PTR SS:[EBP-12C],128
00ED65A0    E8 762B0000     CALL 00ED911B                              ; Process32First
00ED65A5    83C4 14         ADD ESP,14
00ED65A8    EB 21           JMP SHORT 00ED65CB
00ED65AA    8D85 F8FEFFFF   LEA EAX,[EBP-108]
00ED65B0    50              PUSH EAX                                   ; EAX points to the process name
00ED65B1    E8 3D720000     CALL 00EDD7F3
00ED65B6    59              POP ECX
00ED65B7    3B45 08         CMP EAX,DWORD PTR SS:[EBP+8]               ; compare computed dword with a list of dwords
00ED65BA    74 15           JE SHORT 00ED65D1
00ED65BC    8D85 D4FEFFFF   LEA EAX,[EBP-12C]
00ED65C2    50              PUSH EAX
00ED65C3    57              PUSH EDI
00ED65C4    E8 232B0000     CALL 00ED90EC                              ; Process32Next
00ED65C9    59              POP ECX
00ED65CA    59              POP ECX
00ED65CB    85C0            TEST EAX,EAX
00ED65CD  ^ 75 DB           JNE SHORT 00ED65AA                         ; Next process name

Inside call 00EDD7F3

00EDD51F    8B75 08         MOV ESI,DWORD PTR SS:[EBP+8]               ; Process name in uppercase
00EDD522    33D2            XOR EDX,EDX
00EDD524    FC              CLD
00EDD525    33C0            XOR EAX,EAX
00EDD527    AC              LODS BYTE PTR DS:[ESI]                     ; Place in AL one character of the process name
00EDD528    0BC0            OR EAX,EAX
00EDD52A    74 07           JE SHORT 00EDD533
00EDD52C    33D0            XOR EDX,EAX
00EDD52E    C1CA 03         ROR EDX,3
00EDD531  ^ EB F2           JMP SHORT 00EDD525
00EDD533    8955 FC         MOV DWORD PTR SS:[EBP-4],EDX               ; Computed DWORD in EDX is placed in EBP-4
00EDD536    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]               ; then moved in EAX

This is a way to check for the presence of a certain running process, instead of using a classical string compare between two names, it computes an encoded DWORD and checks it against a list of precomputed encoded DWORDs. The immediate effect is to perform a check without disclosing the process that Caphaw is looking for.

Via system files

Another way to reach the same goal is by looking for some specific system file left by the virtualization solution. In first instance Caphaw builds a list of interesting system files, then we find the following piece of code:

00EE1387    8B45 E0         MOV EAX,DWORD PTR SS:[EBP-20]
00EE138A    3BC7            CMP EAX,EDI
00EE138C    75 04           JNE SHORT 00EE1392
00EE138E    33C0            XOR EAX,EAX
00EE1390    EB 03           JMP SHORT 00EE1395
00EE1392    8D04B0          LEA EAX,[ESI*4+EAX]
00EE1395    FF30            PUSH DWORD PTR DS:[EAX]  ; EAX points to the system filename
00EE1397    E8 57C4FFFF     CALL 00EDD7F3	     	 ; build DWORD from the filename (same algorithm of case .1)
00EE139C    59              POP ECX
00EE139D    3D 8822ED23     CMP EAX,23ED2288		
00EE13A2    0F84 D3000000   JE 00EE147B			
00EE13A8    3D 1346FA2F     CMP EAX,2FFA4613
00EE13AD    0F84 C8000000   JE 00EE147B
00EE13B3    3D 10C656F0     CMP EAX,F056C610
00EE13B8    0F84 BD000000   JE 00EE147B
00EE13BE    3D E82FFC23     CMP EAX,23FC2FE8
00EE13C3    0F84 B2000000   JE 00EE147B
00EE13C9    3D A8B4DE23     CMP EAX,23DEB4A8
00EE13CE    0F84 A7000000   JE 00EE147B
00EE13D4    46              INC ESI
00EE13D5    3B75 E4         CMP ESI,DWORD PTR SS:[EBP-1C]
00EE13D8  ^ 72 AD           JB SHORT 00EE1387

The concept is pretty similar to the method 1 (same DWORD value build algorithm) but this time it is applied to the system’s
filenames. We can place a breakpoint on 00EE147B and check what happens. In our case we are running VirtualBox and situation
at address 00EE147B is:

EAX = 23DEB4A8
ECX = points to ‘VBoxGuest.sys’

Caphaw correctly spotted the presence of VBoxGuest.sys which is a specific VirtualBox driver.

Finally at the end we have the following strings:


Immediately after we get the assembled bot specific strings:

BuildTime=2013.08.23 12:55:38

0EED05D    50              PUSH EAX
00EED05E    E8 5B35FFFF     CALL 00EE05BE	; get specific userinit.exe informations
00EED063    59              POP ECX

Below we reported the collected details:
Installed software:

0EED12D    50              PUSH EAX
00EED12E    E8 763FFFFF     CALL 00EE10A9	; build a list of the installed programs
00EED133    59              POP ECX

Installed=HKEY_LOCAL_MACHINE Cerbero Profilerversion 0.7Explorer Suite IV Mozilla Firefox (3.6.28) Oracle VMVirtualBox Guest Additions 4.2.16 WinPcap 4.1.3 Wireshark 1.10.1 (32-bit)

Processes list

00EED18D    50              PUSH EAX
00EED18E    E8 5C2BFFFF     CALL 00EDFCEF	; get processes list
00EED193    83C4 08         ADD ESP,8

Here how look at the end of gathering process:

[System Process]System smss.exe ==> \SystemRoot\System32\smss.exe csrss.exe == \??\C:\WINDOWS\system32\csrss.exe winlogon.exe ==> \??\C:\WINDOWS\system32\winlogon.exe services.exe ==> C:\WINDOWS\system32\services.exe

We have running_process_filename ==> path_of_the_executable

Get CPU status

00EED1E8    8D45 DC         LEA EAX,[EBP-24]
00EED1EB    E8 DF0EFFFF     CALL 00EDE0CF	; Dump Registry and other CPU current status
00EED1F0    8D4D D8         LEA ECX,[EBP-28]

In sythesis we have :

crc=C913#00000000 EAX=00000005 EBX=756E6547 ECX=6C65746E EDX=49656E69
#00000001 EAX=000306A9 EBX=00000800 ECX=00000209 EDX=078BF9FF
#00000002EAX=76035A01 EBX=00F0B2FF ECX=00000000 EDX=00CA0000
#80000002 EAX=20202020 EBX=49202020 ECX=6C65746E EDX=20295228
#80000003 EAX=65726F43 EBX=294D5428 ECX=2D356920 EDX=30313233
#80000004 EAX=5043204D EBX=20402055 ECX=30352E32 EDX=007A4847

Get current timestamp values

00EED22D    8BF8            MOV EDI,EAX
00EED22F    E8 93300000     CALL 00EF02C7
00EED234    8B30            MOV ESI,DWORD PTR DS:[EAX]                 ; ASCII "2013.10.01+12%3a56%3a52.577"

Bot specific POST data

00EED274    B8 449EEB00     MOV EAX,0EB9E44
00EED279    E8 B3E9FFFF     CALL 00EEBC31 ; Decrypt "&net=%s&cmd=log&w=cmpinfo&bt=%s&ver=%s&time=%s&t="
00EED27E    59              POP ECX

Finally we have:


please note that net’s value is equal to the previously seen Botnet=net2.

00EED2EB    E8 EE9DFFFF     CALL 00EE70DE	; build final Bot specific string
00EED2F0    8D45 EC         LEA EAX,[EBP-14]

The most important element of this call is given by “key=”, we reported below how this value is build:

MD5('85085085085') = "77487c28cbc78c457a3413a3cae1ac29"
Get first 10 bytes of the hash '77487c28cb'
MD5('77487c28cb') = "a323e7d52db72c389f4a804f2361639d"
Get first 10 bytes of the hash 'a323e7d52d'

Finally we have:


The end of this phase is decreed by the following call which assembles ALL information collected until now.

00EED2C6    8D7D FC         LEA EDI,[EBP-4]
00EED2C9    E8 F92F0000     CALL 00EF02C7
00EED2CE    59              POP ECX		;ECX points to the build data buffer

Conclusions for the first episode

Here it ends the first chapter of Caphaw/Shylock analysis, stay tuned for the other two.

In this episode we have observed the malware from its dropping zone and after we went through static and dynamic analysis of PE and unpacking. Once we’ve reached the unpacked core we have analysed its first functional steps up to the HSE::Step 5. In the next episodes we will see:

  • how the collected information will be used.
  • network interactions Bot <-> C&C Server.
  • explorer.exe code injection.
  • what “master” (code injected) does inside explorer.exe



  1. Excellent analysis! Would you please tell me what is the name of the tool you used make the entropy graph? Great thanks!