Shifting yourself to space

March 6, 2012

First thoughts on Purple Haze

I just finished unpacking PurpleHaze a couple of hours ago
I got the sample from Contagio (thank you, once again)

The packer seems really amazing, as it didn’t use any VirtualAlloc*,SetWindowsHookEx,etc functions, which got me a be insane about it, although I didn’t work much on it.

I will try writing about it soon, TDLn rocks, although the kernel driver is poorly written.
When I finished unpacking it and started skimming it in IDA I was quite suprised to see no antidebug stuff,
however I did see some usage of LoadLibrary + GetProcAddress to some functions which reminded me a bit of Spyeye

BTW, my queue has a few more posts which are not started (read: written in my head but not in wordpress ) which most reside about the old hardworking LD (runtime relocation of functions, loading, unloading, etc) and loading ELF on the fly (as nowadays I started fiddling around w/ generating ELFs from scratch ( btw, libelf sucks ) )

the packer, btw, used a really nice technique for calling functions, a simple

push func addr
pop eax
label: jmp label+1
call eax

so, Olly couldn’t disassemble it correctly, nor IDA btw.

A few more fun fragments where the loop_inc_check_false-call_inc_loop

.text:00415400                 jmp     loc_415410
.text:00415405 ; ---------------------------------------------------------------------------
.text:00415405 loc_415405:                             ; CODE XREF: .text:loc_415460j
.text:00415405                 xor     eax, eax
.text:00415407                 xor     eax, [ebp-2Ch]
.text:0041540B                 inc     eax
.text:0041540C                 mov     [ebp-2Ch], eax
.text:00415410 loc_415410:                             ; CODE XREF: .text:00415400j
.text:00415410                 cmp     dword ptr [ebp-2Ch], 19h
.text:00415418                 jnb     loc_415465
.text:0041541E                 cmp     dword ptr [ebp-2Ch], 8
.text:00415426                 jnz     loc_415449
.text:0041542C                 mov     eax, 645h
.text:00415431                 sub     eax, 292h
.text:00415436                 push    dword ptr [ebp-28h]
.text:00415439                 push    0
.text:0041543B                 push    offset dword_4020B4
.text:00415440                 push    dword ptr [ebp-1Ch]
.text:00415443                 call    ds:WaitForMultipleObjects
.text:00415449 loc_415449:                             ; CODE XREF: .text:00415426j
.text:00415449                 cmp     dword ptr [ebp-2Ch], 7
.text:00415451                 jnz     loc_415460
.text:00415457                 mov     eax, [ebp-2Ch]
.text:0041545B                 inc     eax
.text:0041545C                 mov     [ebp-2Ch], eax
.text:00415460 loc_415460:                             ; CODE XREF: .text:00415451j
.text:00415460                 jmp     loc_415405

The function there will be never be executed, it is only a false positive call

This is a smart move imho, it add more imports not to make the binary suspicious and also makes the debugger more frustrated of why this superficial call is made

I think however that the fun will be when I’ll start messing around the drivers themselves and understanding the packer in a more brief way.
I still want to know(after skimming the unpacked exe though) how the actual unpacking process works in depth other than the decryption part.
Diving in

I ran the malware on vbox, using Olly w/ phant0m, OD and OllyDump, other plugins like ollysync weren’t usable, as the malware has several encrypted portions which are only decrypted later on.

So a quick look on peid shows it’s encrypted/packed/protected, the fist thing I’ve done was to step the code a bit, this is how the packed entry point looked like :

.text:0041514B start:
.text:0041514B                 sub     eax, 50FBh
.text:00415150                 push    ebp
.text:00415151                 mov     ebp, esp
.text:00415153                 sub     esp, 0CCh
.text:00415159                 push    ebx
.text:0041515A                 mov     ebx, 44CE26Ah
.text:0041515F                 mov     [ebp-4], ebx
.text:00415162                 push    offset aKdsiiuduikjdkl ; "KDSIiuduiKJDkljDYUOdOYHD"
.text:00415167                 mov     dword ptr [ebp-8], 44CE269h
.text:0041516E                 call    ds:GetModuleHandleW
.text:00415174                 cmp     esi, ds:sz._cx
.text:0041517A                 sub     ds:dword_4020C4, offset dword_402104
.text:00415184                 xor     ds:dword_4020C4, offset dword_4020EC
.text:0041518E                 sbb     ds:dword_4020C4, offset dword_402110
.text:00415198                 test    eax, eax
.text:0041519A                 jz      loc_41537C
.text:004151A0 loc_4151A0:                             ; CODE XREF: .text:0041538Aj
.text:004151A0                 xor     eax, eax
.text:004151A2                 inc     eax
.text:004151A3                 jmp     loc_4158CA

For a reason which is not known at this, the malware checks for the existence of the “KDSIiuduiKJDkljDYUOdOYHD” module
if it exists, the malware exits

.text:004158CA loc_4158CA:                             ; CODE XREF: .text:004151A3j
.text:004158CA                 pop     ebx
.text:004158CB                 leave
.text:004158CC                 retn    0Ch

The machine I ran it on wasn’t virgin it all, it was an unpatched winxp-sp2, running on virtualbox, along with virtualbox tools etc
I didn’t see any efforts at detecting virtualization but I haven’t tried enough.
Either way, the classical CreateToolhelp32Snapshot would easily defeat my box.

When I started debugging it I made Olly stop every time a new module is being loaded, so in case I’ll lose any stealthy API call
I’ve set a bp on VirtualAlloc and on FS:[0x30] aka PEB.

VirtualAlloc seems to be the main functions which might help unpacking, having any sort of fast phase to try finding how does it know the addresses failed (PEB trick is not used directly, anywho)

I have seen at least 4 allocations which one of them was a PE being written into memory, others were just data which I didn’t manage to parse yet, some of it gets freed so I assume it’s not used in unpacking and probably manipulated with other sections.
One thing I really liked about the dropper is that it doesn’t use any direct manipulations of the segments modifiers, something which was a for me in order to detect different behavior, all segments which need to be written are already RWX’ed, so it makes finding the sweet spots a bit harder.

A small note to the debugger would be to also add a breakpoint on VirtualFree to locate memory regions which were free()’ed
After a few VirtualAlloc’s there will be another PE which is dumped to memory , my lucky address was 0xA30000 , it is a bit important to note that the PE header will be “corrupted” with the filename at the beginning (mine was php.dll, thanks Contagio, again, for the sample), so I just removed the first few bytes until I got the classical 4D5A w/ hex workshop

After a quick look at this PE it looks like a dll, perhaps the dropper is planning to inject it to some processes ? let’s skim the DLL in one byte look

.text:10003D05                 push    ebp
.text:10003D06                 mov     ebp, esp
.text:10003D08                 sub     esp, 124h
.text:10003D0E                 cmp     [ebp+Str1], 1
.text:10003D12                 push    ebx
.text:10003D13                 push    esi
.text:10003D14                 push    edi
.text:10003D15                 jnz     ret_loc_10003E23
.text:10003D1B                 xor     ebx, ebx
.text:10003D1D                 push    ebx             ; dwMaximumSize
.text:10003D1E                 push    ebx             ; dwInitialSize
.text:10003D1F                 push    ebx             ; flOptions
.text:10003D20                 call    ds:HeapCreate
.text:10003D26                 mov     hHeap, eax
.text:10003D2B                 call    ds:GetTickCount
.text:10003D31                 mov     edi, ds:PathFindFileNameA
.text:10003D37                 mov     GetTickCount_dword_10008264, eax
.text:10003D3C                 mov     [ebp+Str1], ebx ; zero
.text:10003D3F                 cmp     [ebp+Source], ebx
.text:10003D42                 jz      short loc_10003D6A
.text:10003D44                 push    [ebp+Source]    ; pszPath
.text:10003D47                 call    edi ; PathFindFileNameA
.text:10003D49                 push    104h            ; Count
.text:10003D4E                 push    [ebp+Source]    ; Source
.text:10003D51                 mov     esi, offset byte_10008268
.text:10003D56                 push    esi             ; Dest
.text:10003D57                 mov     [ebp+Str1], eax
.text:10003D5A                 call    ds:strncpy
.text:10003D60                 add     esp, 0Ch
.text:10003D63                 push    esi             ; pszPath
.text:10003D64                 call    ds:PathRemoveFileSpecA

I don’t know the value of Str1, but it’s likely to not contain1 as if not the DLL would exit/return
We see a small dummy call to HeapCreate w/ zero values and then GetTickCount.
I didn’t analyze the whole DLL at all, just dumped it and gave a quick look but it is quite important to know this address
As timing attacks are the debugger’s worst enemy, and no plugin can detect them so easily.

A few more calls are made but the actual “meat” which really goes is starts from a sequence of several “strcmp” for interesting values
such as – svchost.exe netcvs jp2launcher and java

Another interesting thing is the CreateEvent call which is made here :

xor     eax, eax
mov     [ebp+var_20], 1
lea     edi, [ebp+var_1F]
push    4
lea     eax, [ebp+var_20]
mov     [ebp+EventAttributes.lpSecurityDescriptor], eax
pop     eax
push    offset aPh0     ; "ph0"
push    offset aGlobal  ; "Global"
mov     [ebp+var_1E], ax
lea     eax, [ebp+Name]
push    offset aSS      ; "%s\\%s"
push    eax             ; Dest
mov     [ebp+EventAttributes.nLength], 0Ch
mov     [ebp+EventAttributes.bInheritHandle], ebx
call    ds:sprintf
add     esp, 10h
lea     eax, [ebp+Name]
push    eax             ; lpName
push    ebx             ; bInitialState
push    ebx             ; bManualReset
lea     eax, [ebp+EventAttributes]
push    eax             ; lpEventAttributes
call    ds:CreateEventA
mov     esi, eax
cmp     esi, ebx
jz      short ret_loc_10003E23

If you skim a bit in msdn you’ll obviously understand that this is some sort of way to communicate to the outside world.
There is another call which creates a local event

push    offset aPh0     ; "ph0"
push    offset aLocal   ; "Local"
lea     eax, [ebp+Name]
push    offset aSS      ; "%s\\%s"
push    eax             ; Dest
call    ds:sprintf
add     esp, 10h
lea     eax, [ebp+Name]
push    eax             ; lpName
push    ebx             ; bInitialState
push    ebx             ; bManualReset
push    ebx             ; lpEventAttributes
call    ds:CreateEventA
test    eax, eax
jz      short ret_loc_10003E23

I have seen some Thread interaction and my guess is that this DLL is either a module or gets injected to other processes (as the interaction w/ the many strcmp’s of java/jp2launcher/etc)
Another interesting string I encountered was

<body><a id=link href='%s'></body><script>document.getElementById('link').click()</script>

Hum, a clicker ? Botnet ? hum hum hum who knows.
I got a bit tripped off the unpacking stage, as this DLL got my attention
Finding Kernel32.dll

One thing which got my attention while skimming the packed EXE was the fact that all calls to external (aka DLL) functions were made from something like

call [ebp+8]

An arithmetic manipulation was done in order to keep the actual value on the stack secret until the real call is made, a short XOR,ADD,SBB calls were made in order
to reveal the real value, but , how do they know the actual value of the function they wish to call ?

My journey actually began while I was debugging the VirtualAlloc/VirtualProtect calls, I knew who’s calling them ( all I had to do was to return from the call, as no special
push’s were made before the call ) but I didn’t know how they retrieve the address.
So I set my side on VirtualAlloc to try demonstrate the process I’ve done in order to reveal it

Let’s see:

7C809A7E                                            90                         NOP
7C809A7F                                            90                         NOP
7C809A80                                            90                         NOP
7C809A81 kernel32.VirtualAlloc                      8BFF                       MOV EDI,EDI
7C809A83                                            55                         PUSH EBP
7C809A84                                            8BEC                       MOV EBP,ESP
7C809A86                                            FF75 14                    PUSH DWORD PTR SS:[EBP+14]
7C809A89                                            FF75 10                    PUSH DWORD PTR SS:[EBP+10]
7C809A8C                                            FF75 0C                    PUSH DWORD PTR SS:[EBP+C]
7C809A8F                                            FF75 08                    PUSH DWORD PTR SS:[EBP+8]                                               ; ntdll.7C960738
7C809A92                                            6A FF                      PUSH -1
7C809A94                                            E8 09000000                CALL kernel32.VirtualAllocEx
7C809A99                                            5D                         POP EBP                                                                 ; ntdll.7C960738
7C809A9A                                            C2 1000                    RETN 10
7C809A9D                                            90                         NOP
7C809A9E                                            90                         NOP

This is the classical VirtualAlloc inside kernel32.dll as the EXE had tremendous API it was trivial to find the base of it w/ a simple lea eax, VirtualAlloc and then just looking for MZ and parsing the imports.
However, this is not the case, there are many ways to  get kernel32.dll base in an environment where you don’t have GetProc and LoadLibrary , but none of them were used here, at least from what I’ve seen.
I tried setting breakpoints both at FS:[0x18],FS:[0] (SEH), FS:[0x30] but none worked, I always stopped at different DLL locations, which didn’t really find my interest

The call was made, a memory region was created and the function returned here :

004102FB                                           .^\E0 C3                    LOOPDNE SHORT w_php.004102C0
004102FD                                           >  FF55 08                  CALL DWORD PTR SS:[EBP+8]                                               ;  kernel32.VirtualAlloc
00410300                                           .  837D 10 00               CMP DWORD PTR SS:[EBP+10],0
00410304                                           .  8945 14                  MOV DWORD PTR SS:[EBP+14],EAX
00410307                                           .  0F84 24000000            JE w_php.00410331
0041030D                                           .  837D 0C 00               CMP DWORD PTR SS:[EBP+C],0
00410311                                           .  0F85 1A000000            JNZ w_php.00410331

Remember the call [ebp+8] I mentioned earlier ? exactly.
Be no mistaken about the loopdne here, it’s just a call +ret to make olly think otherwise

So stepping a bit back leads us to

00410189                                           .  55                       PUSH EBP
0041018A                                           .  8BEC                     MOV EBP,ESP
0041018C                                           .  83EC 54                  SUB ESP,54
0041018F                                           .  8D45 10                  LEA EAX,DWORD PTR SS:[EBP+10]
00410192                                           .  C745 F4 04000000         MOV DWORD PTR SS:[EBP-C],4
00410199                                           .  8945 F0                  MOV DWORD PTR SS:[EBP-10],EAX
0041019C                                           .  8B45 F0                  MOV EAX,DWORD PTR SS:[EBP-10]
0041019F                                           .  8138 6AE24C04            CMP DWORD PTR DS:[EAX],44CE26A
004101A5                                           .  53                       PUSH EBX
004101A6                                           .  56                       PUSH ESI
004101A7                                           .  0F84 50010000            JE w_php.004102FD

which is the start of the function,


Create a free website or blog at