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

loc_10003E2C:
xor     eax, eax
mov     [ebp+var_20], 1
lea     edi, [ebp+var_1F]
stosd
stosd
stosd
stosd
stosw
stosb
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,

October 14, 2011

Inside KiSystemService

Preface

I wanted to write this post for over a week and couldn’t find a decent way to start writing it well.KiSystemService is one of the interesting functions I ran into while reversing ntoskrnl.exe and I have always wanted to understand it from top to bottom, I took myself a copy of Windows Internals but they did not seem to draw a complete
flow of how things go from userland to kernel land and how the actual function gets executed.I hope this post would fill some blank objects for those who are interested in understanding the actual mechanism.

To start our post I will use winxp sp2 on vbox to test it, among with IDA, calc.exe, ollydbg and windbg to ease up reversing, I’m lazy- yes, I can’t be arsed to start looking for different symbols/struct when I got both windbg’s dt/dds and IDA’s flowgraph,
for userland debugging I’ll use olly, and for kernel I’ll use windbg, IDA is only used for the flowgraph.

For this post I had chosen a random function to follow which is CloseHandle,
I will not dive into the actual code of what it does and how CloseHandle works, I will only explain how things are working in order to get the actual execution.
I will try describing things at my best, however I’m not a Windows guru so be aware of some mistakes I might do, most of the material I will be writing here is pieces of information written in several (many) places, the purpose of this post would probably be to gather most of them into one post.

Introduction

KiSystemService is a kernel function which provides system services, what does that mean you might ask ? and why would I want to know about it ?

KiSystemService is a function in kernel land which is triggered after a system service request is called. It is actually the last gateway between the actual function in kernel land the usermode process which wants to call (in our case, CloseHandle inside calc.exe).

“Wait a second”, someone might say, “but I got CloseHandle inside a dll in usermode!”

That is correct 🙂 but if we look carefully enough, we will see that the actual function which does the “real thing” is not in userland (e.g not in kernel32.dll or in ntdll.dll).
NTDLL or KERNEL32.dll only deal with error handling and parameter verification so the kernel could deal with the real thing – which is in our case close the specified handle.

Let’s take a quick look about how things are going inside calc.exe
I found where CloseHandle is imported from (kernel32.dll) and looked for any references to it, then I just printed out the function which calls it,
it does not really matter what this function does, let’s see what’s going on there.

/*100436C*/  PUSH ESI
/*100436D*/  PUSH DWORD PTR DS:[1014EFC]
/*1004373*/  MOV ESI,DWORD PTR DS:[<&KERNEL32.SetEvent>]
/*1004379*/  MOV DWORD PTR DS:[1014EF8],1
/*1004383*/  CALL ESI
/*1004385*/  PUSH DWORD PTR DS:[1014F00]
/*100438B*/  CALL ESI
/*100438D*/  PUSH 9C40
/*1004392*/  PUSH DWORD PTR DS:[1014F04]
/*1004398*/  CALL DWORD PTR DS:[<&KERNEL32.WaitForSingleObject>]
/*100439E*/  PUSH DWORD PTR DS:[1014EFC]
/*10043A4*/  MOV ESI,DWORD PTR DS:[<&KERNEL32.CloseHandle>]
/*10043AA*/  CALL ESI
/*10043AC*/  PUSH DWORD PTR DS:[1014F00]
/*10043B2*/  CALL ESI
/*10043B4*/  PUSH DWORD PTR DS:[1014F04]
/*10043BA*/  CALL ESI
/*10043BC*/  POP ESI
/*10043BD*/  RETN

Looks quite simple right ? CloseHandle only gets one argument, according to it’s prototype on msdn

BOOL WINAPI CloseHandle(
  __in  HANDLE hObject
);

I hope this clears things a bit.
Now let’s dive into Kernel32.CloseHandle

.text:7C809B77                 mov     edi, edi
.text:7C809B79                 push    ebp
.text:7C809B7A                 mov     ebp, esp
.text:7C809B7C                 mov     eax, large fs:18h ; TEB
.text:7C809B82                 mov     ecx, [eax+30h]  ; TEB->PEB
.text:7C809B85                 mov     eax, [ebp+hObject] ; userparam
.text:7C809B88                 cmp     eax, STD_ERROR_HANDLE
.text:7C809B8B                 jz      std_error_handle_res ; PEB->ProcessParameters->StandardError
.text:7C809B91                 cmp     eax, STD_OUTPUT_HANDLE
.text:7C809B94                 jz      std_output_handle ; PEB->ProcessParameters->StandardOutput
.text:7C809B9A                 cmp     eax, STD_INPUT_HANDLE
.text:7C809B9D                 jz      std_input_handle_res ; PEB->ProcessParameters->StandardInput
.text:7C809BA3
.text:7C809BA3 do_NtClose:                             ; CODE XREF: CloseHandle+1456Ej
.text:7C809BA3                                         ; CloseHandle+14579j ...
.text:7C809BA3                 mov     ecx, eax        ; hObject
.text:7C809BA5                 and     ecx, 10000003h
.text:7C809BAB                 cmp     ecx, 3
.text:7C809BAE                 push    eax
.text:7C809BAF                 jz      loc_7C81D937
.text:7C809BB5                 call    ds:NtClose
.text:7C809BBB                 test    eax, eax
.text:7C809BBD                 jl      loc_7C81E0D2
.text:7C809BC3                 xor     eax, eax
.text:7C809BC5                 inc     eax

Let’s try to understand what is going on there

.text:7C809B7C                 mov     eax, large fs:18h ; TEB

FS:[18] is the Thread Environment Block,

.text:7C809B82                 mov     ecx, [eax+30h]  ; TEB->PEB

lkd> dt ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : Ptr32 Void
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle  : Ptr32 Void
   +0x02c ThreadLocalStoragePointer : Ptr32 Void
   +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
   +0x034 LastErrorValue   : Uint4B
   +0x038 CountOfOwnedCriticalSections : Uint4B
   +0x03c CsrClientThread  : Ptr32 Void
   +0x040 Win32ThreadInfo  : Ptr32 Void
   +0x044 User32Reserved   : [26] Uint4B

CloseHandle first checks the values in the parameter passed to see if they are some sort of errors, it prepares for 3 conditions
std_error_handle_res
std_output_handle
std_input_handle_res

which both eventually access TEB->PEB->ProcessParameter param, each with their own unique value.
Eventually, or if none of the above conditions did not happen,

.text:7C809BB5                 call    ds:NtClose

NtClose is called.

just a quick note regarding anyone who is following my post and is not
using winxp, the PEB structure has changed across different versions of Windows,
I have tried looking at from kd and it didn’t look the same, so you have two choices
either fetch the right .h file or use a vm and debug it correctly to get the same results I got

NtClose is not part of kernel32.dll but it is part of ntdll.dll which is actually the core dll that all system service function eventually dwell into.

I had a slight problem to find NtClose in ntdll.dll but eventually realized that I should look for ZwClose, in order not to go outside the barriers of this post, there is a really good post on osronline which explains it briefly why Zw and not Nt (or vice versa).

.text:7C95D586 ZwClose         proc near               ; CODE XREF: RtlFormatCurrentUserKeyPath+6Cp
.text:7C95D586                                         ; RtlDosSearchPath_U+23Ap ...
.text:7C95D586                 mov     eax, 19h        ; NtClose
.text:7C95D58B                 mov     edx, 7FFE0300h
.text:7C95D590                 call    dword ptr [edx]
.text:7C95D592                 retn    4
.text:7C95D592 ZwClose         endp

0x7FFE0300 is a pointer to the system call stub, basically it consists of a simple 3 instruction code block, for more information about it (there is a short description of why we can’t disassemble 0x7FFE0300 directly) see here, or look at Nynaeve’spost (ironically, I found his post while writing this post, and he also wrote about NtClose, hehe, although he’s speaking about int 2eh, and we’re dealing with the newer version, the only difference (that I know of), is that the trap frames differs, but nothing more than that, if you lost me here it’s cool, more on this later )

.text:7C95EB8B KiFastSystemCall proc near              ; DATA XREF: .text:off_7C95395Co
.text:7C95EB8B                 mov     edx, esp
.text:7C95EB8D                 sysenter

There are two important things I almost forgot to mention here.
The first is the transfer of 19h to eax in ZwClose,
this is an index number which is quite important for us while we’ll be in kernel land.
The second thing is the mov edx,esp – we move the stack arguments – aka hObject of CloseHandle to kernel so it would know what to close.

Inside sysenter

Phew, wicked, we’ve now got to our first barrier, after we passed from calc.exe to kernel32.dll and into ntdll.dll and into SystemCallStub, we’ve finally managed to get into kernel land, let’s try to summarize it with a short chart (sorry for not owning visio :/ )

Phew 🙂 Finally, we got to the actual sysenter call which transfers to the kernel and does the actual call.
Before we continue again I would like quote from Intel’s Developer’s Manual about the sysenter instruction to see what it actually does and how it know to contact the right function

Executes a fast call to a level 0 system procedure or routine.
SYSENTER is a companion instruction to SYSEXIT.

The instruction is optimized to provide the maximum performance for system calls from user code running at privilege level 3 to operating system or executive procedures running at privilege level 0.

Prior to executing the SYSENTER instruction, software must specify the privilege level 0 code segment and code entry point, and the privilege level 0 stack segment and stack pointer by writing values to the following MSRs:

•IA32_SYSENTER_CS — Contains a 32-bit value, of which the lower 16 bits are the segment selector for the privilege level 0 code segment. This value is also used to compute the segment selector of the privilege level 0 stack segment.
•IA32_SYSENTER_EIP — Contains the 32-bit offset into the privilege level 0 code segment to the first instruction of the selected operating procedure or routine.
•IA32_SYSENTER_ESP — Contains the 32-bit stack pointer for the privilege level 0 stack.These MSRs can be read from and written to using RDMSR/WRMSR. Register addresses are listed in Table 4-17. The addresses are defined to remain fixed for future Intel 64 and IA-32 processors.

Traps taps traps taps

So, sysenter reads it’s information from the MSR registers to know where KiSystemService is, it also gets the stack and makes sure that the segment is executable (Intel specifies that the page must be readable, and executable )
The MSR registers are filled upon boot with the appropriate values, there must be a small note here about different types of Processors, as some processors do not support the sysenter opcode, Windows upon boot time detects the processor type and then chooses which values and which interrupt types to use,
whether it should use int 2eh, syscall, epc (IA-64) or sysenter, nix users will remember the good old int 0x80 or \xcd\x80 from nifty shellcodes (;

Before we continue to dive directly into KiSystemService some theory is required to understand the actual internals of it.
When calling a service function (in our case CloseHandle), the SYSENTER instruction makes transition to the kernel land and once it has finished executing the function it calls SYSEXIT to back to the user.
The user continues it’s work as if nothing happened and it does not have to restore any values or anything like it. This might be quite trivial for most of you, as those who code in usermode know that they never needed any sort of special adjustment to the stack, or to save any sort of values.
The coder (or the program/process/etc), just needs to check for the returned value and then continue it’s execution prior to the result (if there was an error, handle it, if everything worked, continue to the next task etc etc).
In other words – the kernel takes care of everything for the usermode process to continue it’s execution as if the actual function was in ntdll.dll.

How can this be ? some might ask, well we’re here to find out 😛
There is no magic here, the kernel does so by building a “trap frame” to save
all the important things it needs in order to restore execution back to usermode

Short note though – Windows changes it’s trap frame from version to version, and from call to call, sysenter’s trap frame is different from int 2eh’s trap frame ,
however this is the only difference between these two functions,

Short note though, before dive into the trap frame, depending on the call type, the trap frame also changes, what does it mean ?
It means that if your processor does not support the SYSENTER instruction, and uses int 2eh it means that the trap frame generated by int 2eh will be different from the trap frame of SYSENTER’s.
Eventually, however, both will jmp into KiSystemService (no call, but a simple jmp).
That is the only difference that I know of between different call mechanisms (sysenter, syscall, int 2eh, epc, etc , but I’d be fond to know if there is anything else ).

So what is exactly a trap frame ? I’ll try quoting from Windows Internals and I hope it will give a satisfying answers.

When a hardware exception or interrupt is generated, the processor records enough machine state on the kernel stack of the thread that’s interrupt so that is can return that point in the control flow and continue execution as if nothing had happened. If the thread was executing in user mode, Windows switches to the thread’s kernel-mode stack. Windows then creates as trap frame on the kernel stack of the interrupted thread into which it stores the execution state of the thread. The trap is a subset of a thread’s complete context, and you can view its definition by typing dt nt!_ktrap_frame in the kernel debugger.

So, the trap frame keeps information about the current thread context so it could restore it with SYSEXIT instruction, that is (;
This is winxp’s trap frame from windbg :

lkd> dt nt!_KTRAP_FRAME
   +0x000 DbgEbp           : Uint4B
   +0x004 DbgEip           : Uint4B
   +0x008 DbgArgMark       : Uint4B
   +0x00c DbgArgPointer    : Uint4B
   +0x010 TempSegCs        : Uint4B
   +0x014 TempEsp          : Uint4B
   +0x018 Dr0              : Uint4B
   +0x01c Dr1              : Uint4B
   +0x020 Dr2              : Uint4B
   +0x024 Dr3              : Uint4B
   +0x028 Dr6              : Uint4B
   +0x02c Dr7              : Uint4B
   +0x030 SegGs            : Uint4B
   +0x034 SegEs            : Uint4B
   +0x038 SegDs            : Uint4B
   +0x03c Edx              : Uint4B
   +0x040 Ecx              : Uint4B
   +0x044 Eax              : Uint4B
   +0x048 PreviousPreviousMode : Uint4B
   +0x04c ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x050 SegFs            : Uint4B
   +0x054 Edi              : Uint4B
   +0x058 Esi              : Uint4B
   +0x05c Ebx              : Uint4B
   +0x060 Ebp              : Uint4B
   +0x064 ErrCode          : Uint4B
   +0x068 Eip              : Uint4B
   +0x06c SegCs            : Uint4B
   +0x070 EFlags           : Uint4B
   +0x074 HardwareEsp      : Uint4B
   +0x078 HardwareSegSs    : Uint4B
   +0x07c V86Es            : Uint4B
   +0x080 V86Ds            : Uint4B
   +0x084 V86Fs            : Uint4B
   +0x088 V86Gs            : Uint4B

hum, woot, now let’s dive into the actual KiSystemService function

KiSystemService is quite a simple function, it is divided into several parts
that once you understand all of them it’s quite easy to understand the whole concept.
Eventually, the function does two main things:
1. Setup a trap frame to save all the information required to restore to usermode
without any special treatment from the usermode process which takes control.
2. Locate the system service function in the System Service Descriptor Table and call it.

Setting up the trap frame

.text:00407EA6                 push    0
.text:00407EA8                 push    ebp
.text:00407EA9                 push    ebx
.text:00407EAA                 push    esi
.text:00407EAB                 push    edi
.text:00407EAC                 push    fs
.text:00407EAE                 mov     ebx, 30h        ; KGDT_R0_PCR
.text:00407EB3                 db      66h
.text:00407EB3                 mov     fs, bx          ; push fs actually, IDA fuckup
.text:00407EB3                                         ; save and set FS to PCR
.text:00407EB3                                         ; set PCR segment number
.text:00407EB6                 push    dword ptr ds:0FFDFF000h ; KGDT_R3_TEB | RPL_MASK
.text:00407EBC                 mov     dword ptr ds:0FFDFF000h, 0FFFFFFFFh
.text:00407EC6                 mov     esi, ds:0FFDFF124h ; get current thread address from PCR[PcPrcbData + PbCurrentThread ]
.text:00407EC6                                         ;
.text:00407EC6                                         ; PcPrcbData and PbCurrentThread are constant values
.text:00407ECC                 push    dword ptr [esi+140h] ; save old exception list
.text:00407ED2                 sub     esp, 48h        ; Start a new exception list, calculate the value and put it in PCR[PcExceptionList]
.text:00407ED5                 mov     ebx, [esp+68h+arg_0]
.text:00407ED9                 and     ebx, 1          ; Logical AND
.text:00407EDC                 mov     [esi+140h], bl  ; bl = EXCEPTION_CHAIN_END
.text:00407EE2                 mov     ebp, esp        ; new stack
.text:00407EE4                 mov     ebx, [esi+134h] ; Save the current trap frame addr
.text:00407EEA                 mov     [ebp+3Ch], ebx
.text:00407EED                 mov     [esi+134h], ebp
.text:00407EF3                 cld                     ; Clear Direction Flag
.text:00407EF4                 mov     ebx, [ebp+60h]
.text:00407EF7                 mov     edi, [ebp+68h]
.text:00407EFA                 mov     [ebp+0Ch], edx
.text:00407EFD                 mov     dword ptr [ebp+8], 0BADB0D00h
.text:00407F04                 mov     [ebp+0], ebx
.text:00407F07                 mov     [ebp+4], edi
.text:00407F0A                 test    byte ptr [esi+2Ch], 0FFh ; Logical Compare
.text:00407F0E                 jnz     nt_Dr_kss_a     ; if zero we're currently debugging

The first few lines are only pushing arguments in order to save them, 0 is pushed for padding reasons or error or anything like, please do not hate me, I do not know the frame by my heart.

esi is playing a key point here, it points to the PCR (Processor Control Region)
by looking at the correct offsets (and with some great help from WRK), it is possible to
understand most of the code.
There’s one important thing to note here is that the PreviousMode is saved in order to distinguish between whether we’ve came from usermode or kernelmode,
this is quite important to know, so we’ll know how to get the parameters.

kd> dt ntkrnlpa!_KPCR
   +0x000 NtTib            : _NT_TIB
   +0x01c SelfPcr          : Ptr32 _KPCR
   +0x020 Prcb             : Ptr32 _KPRCB
   +0x024 Irql             : UChar
   +0x028 IRR              : Uint4B
   +0x02c IrrActive        : Uint4B
   +0x030 IDR              : Uint4B
   +0x034 KdVersionBlock   : Ptr32 Void
   +0x038 IDT              : Ptr32 _KIDTENTRY
   +0x03c GDT              : Ptr32 _KGDTENTRY
   +0x040 TSS              : Ptr32 _KTSS
   +0x044 MajorVersion     : Uint2B
   +0x046 MinorVersion     : Uint2B
   +0x048 SetMember        : Uint4B
   +0x04c StallScaleFactor : Uint4B
   +0x050 DebugActive      : UChar
   +0x051 Number           : UChar
   +0x052 Spare0           : UChar
   +0x053 SecondLevelCacheAssociativity : UChar
   +0x054 VdmAlert         : Uint4B
   +0x058 KernelReserved   : [14] Uint4B
   +0x090 SecondLevelCacheSize : Uint4B
   +0x094 HalReserved      : [16] Uint4B
   +0x0d4 InterruptMode    : Uint4B
   +0x0d8 Spare1           : UChar
   +0x0dc KernelReserved2  : [17] Uint4B
   +0x120 PrcbData         : _KPRCB

 dt ntkrnlpa!_KPRCB
   +0x000 MinorVersion     : Uint2B
   +0x002 MajorVersion     : Uint2B
   +0x004 CurrentThread    : Ptr32 _KTHREAD
   +0x008 NextThread       : Ptr32 _KTHREAD
   +0x00c IdleThread       : Ptr32 _KTHREAD
   +0x010 Number           : Char
   +0x011 Reserved         : Char
   +0x012 BuildType        : Uint2B
   +0x014 SetMember        : Uint4B
   +0x018 CpuType          : Char
   +0x019 CpuID            : Char
   +0x01a CpuStep          : Uint2B
   +0x01c ProcessorState   : _KPROCESSOR_STATE
   +0x33c KernelReserved   : [16] Uint4B
   +0x37c HalReserved      : [16] Uint4B
   +0x3bc PrcbPad0         : [92] UChar
   +0x418 LockQueue        : [16] _KSPIN_LOCK_QUEUE
   +0x498 PrcbPad1         : [8] UChar
   +0x4a0 NpxThread        : Ptr32 _KTHREAD
   +0x4a4 InterruptCount   : Uint4B
   +0x4a8 KernelTime       : Uint4B
   +0x4ac UserTime         : Uint4B
   +0x4b0 DpcTime          : Uint4B
   +0x4b4 DebugDpcTime     : Uint4B
   +0x4b8 InterruptTime    : Uint4B
   +0x4bc AdjustDpcThreshold : Uint4B
   +0x4c0 PageColor        : Uint4B
   +0x4c4 SkipTick         : Uint4B
   +0x4c8 MultiThreadSetBusy : UChar
   +0x4c9 Spare2           : [3] UChar
   +0x4cc ParentNode       : Ptr32 _KNODE
   +0x4d0 MultiThreadProcessorSet : Uint4B
   +0x4d4 MultiThreadSetMaster : Ptr32 _KPRCB
   +0x4d8 ThreadStartCount : [2] Uint4B
   +0x4e0 CcFastReadNoWait : Uint4B
   +0x4e4 CcFastReadWait   : Uint4B
   +0x4e8 CcFastReadNotPossible : Uint4B
   +0x4ec CcCopyReadNoWait : Uint4B
   +0x4f0 CcCopyReadWait   : Uint4B
   +0x4f4 CcCopyReadNoWaitMiss : Uint4B
   +0x4f8 KeAlignmentFixupCount : Uint4B
   +0x4fc KeContextSwitches : Uint4B
   +0x500 KeDcacheFlushCount : Uint4B
   +0x504 KeExceptionDispatchCount : Uint4B
   +0x508 KeFirstLevelTbFills : Uint4B
   +0x50c KeFloatingEmulationCount : Uint4B
   +0x510 KeIcacheFlushCount : Uint4B
   +0x514 KeSecondLevelTbFills : Uint4B
   +0x518 KeSystemCalls    : Uint4B
   +0x51c SpareCounter0    : [1] Uint4B
   +0x520 PPLookasideList  : [16] _PP_LOOKASIDE_LIST
   +0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x7a0 PacketBarrier    : Uint4B
   +0x7a4 ReverseStall     : Uint4B
   +0x7a8 IpiFrame         : Ptr32 Void
   +0x7ac PrcbPad2         : [52] UChar
   +0x7e0 CurrentPacket    : [3] Ptr32 Void
   +0x7ec TargetSet        : Uint4B
   +0x7f0 WorkerRoutine    : Ptr32     void 
   +0x7f4 IpiFrozen        : Uint4B
   +0x7f8 PrcbPad3         : [40] UChar
   +0x820 RequestSummary   : Uint4B
   +0x824 SignalDone       : Ptr32 _KPRCB
   +0x828 PrcbPad4         : [56] UChar
   +0x860 DpcListHead      : _LIST_ENTRY
   +0x868 DpcStack         : Ptr32 Void
   +0x86c DpcCount         : Uint4B
   +0x870 DpcQueueDepth    : Uint4B
   +0x874 DpcRoutineActive : Uint4B
   +0x878 DpcInterruptRequested : Uint4B
   +0x87c DpcLastCount     : Uint4B
   +0x880 DpcRequestRate   : Uint4B
   +0x884 MaximumDpcQueueDepth : Uint4B
   +0x888 MinimumDpcRate   : Uint4B
   +0x88c QuantumEnd       : Uint4B
   +0x890 PrcbPad5         : [16] UChar
   +0x8a0 DpcLock          : Uint4B
   +0x8a4 PrcbPad6         : [28] UChar
   +0x8c0 CallDpc          : _KDPC
   +0x8e0 ChainedInterruptList : Ptr32 Void
   +0x8e4 LookasideIrpFloat : Int4B
   +0x8e8 SpareFields0     : [6] Uint4B
   +0x900 VendorString     : [13] UChar
   +0x90d InitialApicId    : UChar
   +0x90e LogicalProcessorsPerPhysicalProcessor : UChar
   +0x910 MHz              : Uint4B
   +0x914 FeatureBits      : Uint4B
   +0x918 UpdateSignature  : _LARGE_INTEGER
   +0x920 NpxSaveArea      : _FX_SAVE_AREA
   +0xb30 PowerState       : _PROCESSOR_POWER_STATE

Now that we’ve finished setting up the frame, we can get to the actual calling mechanism

.text:00408000 nt_KiFastCallEntry_0x8d:                ; CODE XREF: KiSystemService?-13Cj
.text:00408000                                         ; KiSystemService?+6Fj
.text:00408000                 mov     edi, eax        ; jmp from set_ints
.text:00408000                                         ; eax = service number
.text:00408000                                         ; edx = stack caller
.text:00408000                                         ; esi = current thread
.text:00408002                 shr     edi, 8          ; extract the actual value to check
.text:00408002                                         ; which table it should be shadow or regular
.text:00408002                                         ; and also check whether it's in the right range
.text:00408005                 and     edi, 30h        ; Logical AND
.text:00408008                 mov     ecx, edi        ; ecx now has the actual index for the SSDT
.text:0040800A                 add     edi, [esi+0E0h] ; Add
.text:00408010                 mov     ebx, eax
.text:00408012                 and     eax, 0FFFh      ; Logical AND

This is the prologue for all the juicy part, eax holds the service number function (in our case, IIRC, 0x19 ), it gets saved into edi which is unused, as you probably remember
esi points to our current thread using the _KPCR array/struct

.text:0040800A                 add     edi, [esi+0E0h] ; Add

in 0040800A we actually compute the address of the SSDT table, to the specific index we need

.text:00408020                 cmp     ecx, 10h        ; Are we going to access the Shadow table
.text:00408020                                         ; or the "regular "table ?
.text:00408023                 jnz     short nt_KiFastCallEntry_0xcc ; Jump if Not Zero (ZF=0)
.text:00408025                 mov     ecx, ds:0FFDFF018h
.text:0040802B                 xor     ebx, ebx        ; Logical Exclusive OR
.text:0040802D
.text:0040802D loc_40802D:                             ; DATA XREF: .text:0040B038o
.text:0040802D                 or      ebx, [ecx+0F70h] ; Logical Inclusive OR
.text:00408033                 jz      short nt_KiFastCallEntry_0xcc ; Jump if Zero (ZF=1)

We the continue to check whether we should access the Shadow Table or the “Regular” SSDT table (I do not know how to call it actually, sorry)

CloseHandle isn’t a GDI service function, and therefore it is not part of the Shadow SSDT, therefore we’ll jmp here and continue

.text:0040803F nt_KiFastCallEntry_0xcc:                ; CODE XREF: KiSystemService?+17Dj
.text:0040803F                                         ; KiSystemService?+18Dj
.text:0040803F                 inc     dword ptr ds:0FFDFF638h ; Increment by 1
.text:00408045                 mov     esi, edx        ; esi now points to user arguments
.text:00408047                 mov     ebx, [edi+0Ch]  ; args table address
.text:0040804A                 xor     ecx, ecx        ; Logical Exclusive OR
.text:0040804C                 mov     cl, [eax+ebx]   ; argument size
.text:0040804F                 mov     edi, [edi]
.text:00408051                 mov     ebx, [edi+eax*4] ; ebx points to the actual service routine,
.text:00408051                                         ; in our case CloseHandle
.text:00408051                                         ; finally :P:P
.text:00408054                 sub     esp, ecx        ; Integer Subtraction
.text:00408056                 shr     ecx, 2          ; Shift Logical Right
.text:00408059                 mov     edi, esp
.text:0040805B                 cmp     esi, ds:MmUserProbeAddress ; Do our args are in kernel address
.text:0040805B                                         ; space or user address space ?
.text:00408061                 jnb     loc_408210      ; > kernel
.text:00408061                                         ; < user

at this point the actual service function address is calculated and we’re currently also
checking whether our arguments are already copied to kernel space,
in usual cases, and if I am not mistaken, our args are not yet copied to kernel space
and therefore we will not go through this jmp,
I just gotta give a small note here, upon analysis I got quite confused by this jmp,
I had a few cases when I did make this jmp and some cases when I was left in the dark,
so I might be mistaken here,
eitherway – the jmp leads to check what was our PreviousMode set to – user or kernel,
and sets the current error to ACCESS_VIOLATION no matter what into eax, since some fuckup
has occured, and the arguments should’ve been copied already.

iddqdkssdoit:                           ; CODE XREF: KiSystemService?+36Ej
.text:00408067                                         ; DATA XREF: .text:0040B02Eo
.text:00408067                 rep movsd               ; Move Byte(s) from String to String
.text:00408069                 call    ebx             ; Indirect Call Near Procedure

That’s it.
All the args are copied to the top of the stack, in our case only one argument and ebx
contains the address to the actual service function, if all goes well the
function will return and a restoration process of the frame will occur,
along with a SYSEXIT instruction or IRET instruction, depending whether you’re
debugging it or not.

I hope you have enjoyed or got to learn a few things, I know I have a few inaccurate things but it was hella fun journey.

September 10, 2011

Hum, Mebromi

Filed under: Uncategorized — shift32 @ 7:32 pm
Tags: , , , , , , , , , , ,

So I was reading twitter this week and got around dozen twits per day about
this malware which infects bios and pwns award BIOSes, a friend also mentioned “some Chinese malware which infects BIOS” so I started looking for a sample, and found

I started reversing it and this is my progress, the reader should note that I wrote everything while I reversed it, this is only part one as it got a bit long.
Another part will be released in a while, once I’ll finish reversing it.

The malware doesn’t come packed with any protections, beside two XOR operations on the .text section and .rodata, from a first look it didn’t seem scary or anything like it, but I still haven’t got to a phase where I can actually say what it does.

The malware starts with a few simple steps:
* gets base address of the pe header
* changes page permissions into rwx
* decrypts a 0x500 long .text section with a simple xor byte ptr [esi+edx],98

.text:00402585 sub_402585      proc near               ; CODE XREF: startp
.text:00402585                 push    esi
.text:00402586                 call    fn_change_page_perms
.text:0040258B                 push    0               ; lpModuleName
.text:0040258D                 call    ds:GetModuleHandleA
.text:00402593                 mov     ecx, [eax+3Ch]
.text:00402596                 add     ecx, eax
.text:00402598                 movzx   edx, word ptr [ecx+14h]
.text:0040259C                 lea     ecx, [edx+ecx+18h]
.text:004025A0                 mov     edx, [ecx+0Ch]
.text:004025A3                 add     edx, eax
.text:004025A5                 xor     esi, esi
.text:004025A7
.text:004025A7 decrypt_text_loop:                      ; CODE XREF: sub_402585+2Dj
.text:004025A7                 xor     byte ptr [esi+edx], 98h
.text:004025AB                 inc     esi
.text:004025AC                 cmp     esi, 500h
.text:004025B2                 jl      short decrypt_text_loop

nothing fancy goes here, after we changed the page permissions we can freely write anywhere we wish

we then proceed into .rdata section to decrypt another portion of code
base address is at 0x404000 with a 0x400 length

.text:004025B4                 mov     edx, [ecx+5Ch]
.text:004025B7                 add     ecx, 50h
.text:004025BA                 add     edx, eax
.text:004025BC                 xor     eax, eax
.text:004025BE                 mov     ecx, [ecx+10h]
.text:004025C1                 pop     esi
.text:004025C2                 test    ecx, ecx
.text:004025C4                 jbe     short locret_4025CF
.text:004025C6
.text:004025C6 decrypt_rdata_loop:                     ; CODE XREF: sub_402585+48j
.text:004025C6                 xor     byte ptr [eax+edx], 89h
.text:004025CA                 inc     eax
.text:004025CB                 cmp     eax, ecx
.text:004025CD                 jb      short decrypt_rdata_loop
.text:004025CF
.text:004025CF locret_4025CF:                          ; CODE XREF: sub_402585+3Fj
.text:004025CF                 retn

nothing interesting in here.
I was a bit suprised to see that after olly analyzed it I saw text strings instead of code,amongst the string we see a lot of “bios” related things, from what I’ve read, the malware/rootkit seem to reflash the bios
but we’ll have to see it ourselves, seeing is believing 😉

we fetched the process path and got a process snapshot we called CreateToolhelp32Snapshot to fetch a process list and called Process32Firstץ
Two strings were pushed into to the stack, to look for RSTray.exe and KVMon
these processes could be the malware’s process or some av that it wishes to monitor or eradicate the code is quite simple and fully understandableץ

.text:00402D56                 push    TH32CS_SNAPPROCESS ; dwFlags
.text:00402D58                 call    CreateToolhelp32Snapshot
.text:00402D5D                 mov     edi, eax        ; save the handle
.text:00402D5F                 lea     eax, [ebp+pe]
.text:00402D65                 push    eax             ; lppe
.text:00402D66                 push    edi             ; hSnapshot
.text:00402D67                 mov     [ebp+pe.dwSize], 128h
.text:00402D71                 call    Process32First
.text:00402D76                 push    [ebp+lpString2] ; lpString2
.text:00402D79                 mov     esi, ds:lstrcmpiA
.text:00402D7F                 lea     eax, [ebp+pe.szExeFile]
.text:00402D85                 push    eax             ; lpString1
.text:00402D86
.text:00402D86 find_process_loop:                      ; CODE XREF: fn_find_process+60j
.text:00402D86                 call    esi ; lstrcmpiA
.text:00402D88                 test    eax, eax
.text:00402D8A                 jz      short loc_402DA9
.text:00402D8C                 lea     eax, [ebp+pe]
.text:00402D92                 push    eax             ; lppe
.text:00402D93                 push    edi             ; hSnapshot
.text:00402D94                 call    Process32Next
.text:00402D99                 test    eax, eax
.text:00402D9B                 jz      short loc_402DAF
.text:00402D9D                 push    [ebp+lpString2]
.text:00402DA0                 lea     eax, [ebp+pe.szExeFile]
.text:00402DA6                 push    eax
.text:00402DA7                 jmp     short find_process_loop
.text:00402DA9 loc_402DA9:                             ; CODE XREF: fn_find_process+43j
.text:00402DA9                 mov     ebx, [ebp+pe.th32ProcessID]
.text:00402DAF
.text:00402DAF loc_402DAF:                             ; CODE XREF: fn_find_process+54j
.text:00402DAF                 push    edi             ; hObject
.text:00402DB0                 call    ds:CloseHandle
.text:00402DB6                 pop     edi
.text:00402DB7                 mov     eax, ebx
.text:00402DB9                 pop     esi
.text:00402DBA                 pop     ebx
.text:00402DBB                 leave
.text:00402DBC                 retn

for those who can’t understand much – here is a short summary
we first call Createtoolhelp32Snapshot to get a handle so we could call Process32First
then we go over all of the processes which we recvd from Createtoolhelp32Snapshot to look for them if we found the process, we save it in loc_402DA9 (I think) else we just call CloseHandle return zero

My system didn’t have those processes so I never hit loc_402DA9, in my next analysis series I will create such processes and see what happens (or not…depends how lazy I am and how interesting this kit/malware is).

The malware continues and calls GetCommandLineArgs. GetCommandLineArgs is called and the arguments are parsed and saved into a list based on a char array, I don’t know whether it’s some internal function or something the author wrote himself, but I found it quite frustrating, I’m no windows internals expert but the good old va_arg list could’ve fit here really good instead of looking for spaces, tabs, etc.

the malware calls GetVersionExA and starts looking goes through a switch case to handle
properly the OS, this is a very weird case which I didn’t bother reversing at all, there’s a big case which does some basic math which i cba to reverse, it tries to determine the major build of the OS.
I recall seeing some Microsoft video about how there are 12 ways to determine the Windows build but only one of them is actually true…you can guess whether or not the author used the right one (:

Once we parse the arguments it seems that the malware has 3 switches,
which I yet know their meaning, the switches are -u, -d and -w.
If the os version has no support (eax = 6) we just return, still nothing fancy : /

A simple side note btw –
the malware has a nice way to call methods by

push eax
retn

this tricked IDA into thinking that we haven’t reached into any new function
and made me click a few clicks ;p

Afterwards we load a resource, I don’t know what it does or what’s it’s purpose, but I think it has to do with bios.sys which we’ve seem before or some tmp file.
The resource size is 8D7 located at 420F8C in global memory
it doesn’t seem like a pe, or any sort of flat disassembly file
there doesn’t seem to be any sort magic or text at the start
hum, no fun here, beside loading the resource nothing happened
we’re now looking for the %TmP% file to see if it exists and if so delete it

after a few new operators and some c++ vooodoo (damn you c++ 😦 ) which I got lost in we finally write the %TMP% file which is a .sys driver (you can recognize it by the INIT section and import from ntoskrnl.exe and HAL.dll).
I don’t know the driver’s purpose but it had debugging symbols (when would come the time that kernel drivers also have protectors and packers ? )
/* edit: and from further analysis it also had DbgPrints 😀 */

d:\vc++\projects\mbr\bios\bios_operate\i386\bios.pdb 

this gotta give us some hint 😉

I copied the tmp file and named it with a sys extension and hooked
up IDA to see a bit of it, at this stage I stopped debugging the main exe and move to the sys, I kept olly open to continue the debugging session to continue it later on but started my static analysis journey with IDA.

When opening the driver in IDA, you can see that it’s quite small and has only 11 functions.
4 of them are are only for initialization (DriverEntry,UnloadDriver,initialize_MajorFunctions and MF_do_nothing)
the rest are unknown for now, but looking at the graph we can see that only 3 functions are calling other functions, which makes the analysis a lot more simple.

The most frustrating part when reversing the driver would probably be (from a very quick look) to find which major function the driver is using

.text:000115A1 loc_115A1:                              ; CODE XREF: initialize_MajorFunctions+56j
.text:000115A1                 mov     eax, offset MF_do_nothing
.text:000115A6                 mov     [edi+38h], eax
.text:000115A9                 mov     [edi+40h], eax
.text:000115AC                 mov     dword ptr [edi+70h], offset unknown_interesting_0
.text:000115B3                 mov     dword ptr [edi+34h], offset UnloadDriver?
.text:000115BA                 xor     eax, eax
.text:000115BC
0:000> dt nt!_DRIVER_OBJECT
ntdll!_DRIVER_OBJECT
   +0x000 Type             : Int2B
   +0x002 Size             : Int2B
   +0x004 DeviceObject     : Ptr32 _DEVICE_OBJECT
   +0x008 Flags            : Uint4B
   +0x00c DriverStart      : Ptr32 Void
   +0x010 DriverSize       : Uint4B
   +0x014 DriverSection    : Ptr32 Void
   +0x018 DriverExtension  : Ptr32 _DRIVER_EXTENSION
   +0x01c DriverName       : _UNICODE_STRING
   +0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
   +0x028 FastIoDispatch   : Ptr32 _FAST_IO_DISPATCH
   +0x02c DriverInit       : Ptr32     long
   +0x030 DriverStartIo    : Ptr32     void
   +0x034 DriverUnload     : Ptr32     void
   +0x038 MajorFunction    : [28] Ptr32     long
0:000>

I already knew that we’re accessing the MajorFunction member, but having cdb around is a really good thing as IDA lacks the fucking ability to help in such critical moments

(thanks ThFabba for helping me finding the correct offsets, <3)

after resolving which IRP_MJ_* the driver uses, let's see what we end up with :

.text:000115A1 loc_115A1:                              ; CODE XREF: initialize_MajorFunctions+56j
.text:000115A1                 mov     eax, offset MF_do_nothing
.text:000115A6                 mov     [edi+38h], eax  ; IRP_MJ_CREATE
.text:000115A9                 mov     [edi+40h], eax  ; IRP_MJ_CLOSE
.text:000115AC                 mov     dword ptr [edi+70h], offset IRP_MJ_DEVICE_CONTROL
.text:000115B3                 mov     dword ptr [edi+34h], offset DriverUnload
.text:000115BA                 xor     eax, eax
.text:000115BC

the most interesting thing which comes up to my mind is the edi+70h, which I had a few issues resolving it beforehand

the function head is quite similar to any IRP_MJ head

.text:000114DA
.text:000114DA ; Attributes: bp-based frame
.text:000114DA
.text:000114DA ; int __stdcall IRP_MJ_DEVICE_CONTROL(int, PIRP Irp)
.text:000114DA IRP_MJ_DEVICE_CONTROL proc near         ; DATA XREF: initialize_MajorFunctions+70o
.text:000114DA
.text:000114DA Irp             = dword ptr  0Ch

and PIRP is

0:000> dt nt!_IRP
ntdll!_IRP
   +0x000 Type             : Int2B
   +0x002 Size             : Uint2B
   +0x004 MdlAddress       : Ptr32 _MDL
   +0x008 Flags            : Uint4B
   +0x00c AssociatedIrp    : __unnamed
   +0x010 ThreadListEntry  : _LIST_ENTRY
   +0x018 IoStatus         : _IO_STATUS_BLOCK
   +0x020 RequestorMode    : Char
   +0x021 PendingReturned  : UChar
   +0x022 StackCount       : Char
   +0x023 CurrentLocation  : Char
   +0x024 Cancel           : UChar
   +0x025 CancelIrql       : UChar
   +0x026 ApcEnvironment   : Char
   +0x027 AllocationFlags  : UChar
   +0x028 UserIosb         : Ptr32 _IO_STATUS_BLOCK
   +0x02c UserEvent        : Ptr32 _KEVENT
   +0x030 Overlay          : __unnamed
   +0x038 CancelRoutine    : Ptr32     void
   +0x03c UserBuffer       : Ptr32 Void
   +0x040 Tail             : __unnamed
0:000>

I truly thank cdb for actually printing the offset and not letting me fuck up with the offset calculation

the IRP_MJ_CONTROL function is the most interesting one, it is the one responsible to write to the bios and copy the firmware
from usermode to kernel and from there to the bios

it has 3 important functions which are quite easy to understand and are called from a case :

.text:000114DA ; int __stdcall IRP_MJ_DEVICE_CONTROL(int, PIRP Irp)
.text:000114DA IRP_MJ_DEVICE_CONTROL proc near         ; DATA XREF: initialize_MajorFunctions+70o
.text:000114DA
.text:000114DA Irp             = dword ptr  0Ch
.text:000114DA
.text:000114DA                 mov     edi, edi
.text:000114DC                 push    ebp
.text:000114DD                 mov     ebp, esp
.text:000114DF                 push    esi
.text:000114E0                 mov     esi, [ebp+Irp]
.text:000114E3                 mov     eax, [esi+60h]
.text:000114E6                 and     dword ptr [esi+18h], 0
.text:000114EA                 and     dword ptr [esi+1Ch], 0
.text:000114EE                 cmp     byte ptr [eax], 0Eh
.text:000114F1                 push    edi
.text:000114F2                 jnz     short return
.text:000114F4                 mov     eax, [eax+0Ch]
.text:000114F7                 cmp     eax, 80102180h
.text:000114FC                 jz      short write_dosdevice_c_bios_bin_case
.text:000114FE                 cmp     eax, 80102184h
.text:00011503                 jz      short loc_11513
.text:00011505                 cmp     eax, 80102188h
.text:0001150A                 jnz     short return
.text:0001150C
.text:0001150C is_award_bios_case:
.text:0001150C                 call    is_award_bios
.text:00011511                 jmp     short loc_1151F
.text:00011513 ; ---------------------------------------------------------------------------
.text:00011513
.text:00011513 loc_11513:                              ; CODE XREF: IRP_MJ_DEVICE_CONTROL+29j
.text:00011513                 call    fn_flash_bios?
.text:00011518                 jmp     short loc_1151F
.text:0001151A ; ---------------------------------------------------------------------------
.text:0001151A
.text:0001151A write_dosdevice_c_bios_bin_case:        ; CODE XREF: IRP_MJ_DEVICE_CONTROL+22j
.text:0001151A                 call    write_dosdevice_c_bios_bin
.text:0001151F

the reader would notice that I have named the fn_flash_bios? function, with a question mark, as I am not sure whether this one actually flashes the bios or the write_dosdevice_c_bios_bin_case function, from a quick look it seems that the first
one flashes the bios as it uses out instructions to into ports and has some debugging information (DbgPrints) showing some interesting strings,
but this is for later use.
The other 2 functions check whether the pc has an award bios or not and writes the actual modified bios
to the system with \\DosDevices\\Bios

Those who follow should notice that we still haven't reached from the usermode to the part where we create the C:\\bios.bin
this would be quite interesting to reverse as I have never reversed a bios in my entire life 🙂

Ok, let's quickly analyze this 3 functions which are the most interesting ones for now

we'll start with the easiest one, is_award_bios
the reader should note, however, that I lack of some bios and lowlevel oS knowledge, so I might miss a few things here

.text:000113CE                 push    edi
.text:000113CF                 xor     eax, eax
.text:000113D1                 push    eax             ; CacheType
.text:000113D2                 mov     ebx, 10000h
.text:000113D7                 push    ebx             ; NumberOfBytes
.text:000113D8                 push    eax
.text:000113D9                 mov     esi, 0F0000h
.text:000113DE                 push    esi             ; PhysicalAddress
.text:000113DF                 mov     [ebp+var_4], eax
.text:000113E2                 call    ds:MmMapIoSpace

we see that the malware tries to map a physical address at 0F0000h, after a small google search I found that the bios is mapped from that place to 0F0000h in x86 arch (that is, the top 64k part of memory).
We can see that the NumberOfBytes parameter is set to 10000h so it could hint that we're reading the bios and probably more

just a quick note, which I'd like to mention, the author was kind enough to add DbgPrints
which decreased the complexity of understanding what each function does and also to identify the error checking basic blocks

.text:000113E8                 mov     edi, eax
.text:000113EA                 test    edi, edi
.text:000113EC                 jnz     short loc_11407
.text:000113EE                 push    eax
.text:000113EF                 push    esi
.text:000113F0                 push    offset aMmmapiospacePh ; "MmMapIoSpace physics address:0x%x faile"...
.text:000113F5                 call    DbgPrint
.text:000113FA                 add     esp, 0Ch
.text:000113FD                 mov     eax, 0C0000001h
.text:00011402
.text:00011402 loc_11402:                              ; CODE XREF: is_award_bios+79j
.text:00011402                 pop     edi
.text:00011403                 pop     esi
.text:00011404                 pop     ebx
.text:00011405                 leave
.text:00011406                 retn

🙂

Now let's move onto the interesting stuff, eax points to the mapped bios area we wish to inspect

.text:00011407 loc_11407:                              ; CODE XREF: is_award_bios+26j
.text:00011407                                         ; is_award_bios+5Dj
.text:00011407                 cmp     dword ptr [eax], 57414024h
.text:0001140D                 jnz     short loc_11418
.text:0001140F                 cmp     dword ptr [eax+4], 414C4644h
.text:00011416                 jz      short loc_11441

this check looks like it's look for magic values every Award bios has to know if it could infect it or not. I do not know much about Award BIOS , an in-depth analysis of the BIOS will be made in another post

.text:00011418
.text:00011418 loc_11418:                              ; CODE XREF: is_award_bios+47j
.text:00011418                 inc     eax
.text:00011419                 inc     [ebp+var_4]
.text:0001141C                 cmp     [ebp+var_4], 0FFF5h
.text:00011423                 jb      short loc_11407
.text:00011425                 push    offset aThisIsNotAAwor ; "This is not a Aword BIOS!\n"
.text:0001142A                 call    DbgPrint
.text:0001142F                 pop     ecx
.text:00011430                 mov     esi, 0C0000001h

once again the author was kind enough to add DbgPrints to tell us whether or not it's an Award bios or not 😀

.text:00011441 find_smi_port:                          ; CODE XREF: is_award_bios+50j
.text:00011441                 mov     ax, [eax+2Ah]
.text:00011445                 mov     smi_port, ax
.text:0001144B                 movzx   eax, ax
.text:0001144E                 push    eax
.text:0001144F                 push    offset aSmi_port0xX_ ; "SMI_PORT = 0x%x.\n"
.text:00011454                 call    DbgPrint
.text:00011459                 pop     ecx
.text:0001145A                 pop     ecx
.text:0001145B                 lea     esi, [edi+18h]
.text:0001145E                 mov     [ebp+var_4], 0FFE6h
.text:00011465
.text:00011465 get_bios_size:                          ; CODE XREF: is_award_bios+D3j
.text:00011465                 cmp     dword ptr [esi-18h], 5F4D535Fh
.text:0001146C                 jnz     short loc_11495
.text:0001146E                 cmp     dword ptr [esi-8], 494D445Fh
.text:00011475                 jnz     short loc_11495
.text:00011477                 movzx   eax, word ptr [esi]
.text:0001147A                 movsx   eax, byte ptr [eax+edi+9]
.text:0001147F                 inc     eax
.text:00011480                 shl     eax, 6
.text:00011483                 push    eax
.text:00011484                 push    offset aBiossizeKb0xX_ ; "BIOSSize(KB) = 0x%x.\n"
.text:00011489                 mov     dword_13010, eax
.text:0001148E                 call    DbgPrint
.text:00011493                 pop     ecx
.text:00011494                 pop     ecx
.text:00011494                 pop     ecx

the next stages get more information about the bios itself, the bios size, the smi port, etc,

/* edit: there's a small hint here about the order of the calls, the name implies that is_award_bios is the first, and write_dosdevice_c_bios_bin is second, and the third if flash_bios?, there's an unknown case here whether write_dosdevice_c_bios_bin is called twice – once to write the actual malware and another time to backup the bios… */

it is pretty cool to see the analysis that was done in order to identify the bios
pattern matching seem like a neat approach, unfrotunately I don't know Award BIOS internals that well to explain them, I might write a more brief post after I'll finish analyzing the whole malware, but for now this is all I can give.

once we finish getting the information we need a call to MmUnmapIoSpace is called and the function returns.

.text:00011435 loc_11435:                              ; CODE XREF: is_award_bios+D7j
.text:00011435                 push    ebx             ; NumberOfBytes
.text:00011436                 push    edi             ; BaseAddress
.text:00011437                 call    ds:MmUnmapIoSpace
.text:0001143D                 mov     eax, esi
.text:0001143F                 jmp     short loc_11402

.text:00011402 loc_11402:                              ; CODE XREF: is_award_bios+79j
.text:00011402                 pop     edi
.text:00011403                 pop     esi
.text:00011404                 pop     ebx
.text:00011405                 leave
.text:00011406                 retn

The next function got me a bit confused, I know what it does, but I might have a few mistakes when I analyze
it seem to backup the current bios that we have, and then

.text:0001128A write_dosdevice_c_bios_bin proc near    ; CODE XREF: IRP_MJ_DEVICE_CONTROL:write_dosdevice_c_bios_bin_casep
.text:0001128A
.text:0001128A ObjectAttributes= OBJECT_ATTRIBUTES ptr -2Ch
.text:0001128A IoStatusBlock   = _IO_STATUS_BLOCK ptr -14h
.text:0001128A DestinationString= UNICODE_STRING ptr -0Ch
.text:0001128A Handle          = dword ptr -4

As mentioned in the previous function we first map the bios address space

.text:000112B4 loc_112B4:                              ; CODE XREF: write_dosdevice_c_bios_bin+16j
.text:000112B4                 mov     eax, dword_13010
.text:000112B9                 push    ebx
.text:000112BA                 push    edi
.text:000112BB                 xor     edi, edi
.text:000112BD                 cmp     eax, edi
.text:000112BF                 jz      return_status_unsuccess
.text:000112C5                 cmp     smi_port, di
.text:000112CC                 jz      return_status_unsuccess
.text:000112D2                 mov     esi, eax
.text:000112D4                 imul    esi, 0FFFFFC00h
.text:000112DA                 push    edi             ; 0, CacheType
.text:000112DB                 shl     eax, 0Ah
.text:000112DE                 push    eax             ; NumberOfBytes
.text:000112DF                 xor     ecx, ecx
.text:000112E1                 push    ecx
.text:000112E2                 push    esi             ; PhysicalAddress
.text:000112E3                 call    ds:MmMapIoSpace

we then move onto getting a handle to C:\bios.bin to save the bios in case anything bad will happen

.text:00011308 open_bios_bin:                          ; CODE XREF: write_dosdevice_c_bios_bin+63j
.text:00011308                 push    offset SourceString ; "\\DosDevices\\C:\\bios.bin"
.text:0001130D                 lea     eax, [ebp+DestinationString]
.text:00011310                 push    eax             ; DestinationString
.text:00011311                 call    ds:RtlInitUnicodeString
.text:00011317                 push    edi             ; EaLength
.text:00011318                 push    edi             ; EaBuffer
.text:00011319                 push    20h             ; CreateOptions
.text:0001131B                 push    5               ; CreateDisposition
.text:0001131D                 push    1               ; ShareAccess
.text:0001131F                 push    80h             ; FileAttributes
.text:00011324                 lea     eax, [ebp+DestinationString]
.text:00011327                 mov     [ebp+ObjectAttributes.ObjectName], eax
.text:0001132A                 push    edi             ; AllocationSize
.text:0001132B                 lea     eax, [ebp+IoStatusBlock]
.text:0001132E                 push    eax             ; IoStatusBlock
.text:0001132F                 lea     eax, [ebp+ObjectAttributes]
.text:00011332                 push    eax             ; ObjectAttributes
.text:00011333                 push    100023h         ; DesiredAccess
.text:00011338                 lea     eax, [ebp+Handle]
.text:0001133B                 push    eax             ; FileHandle
.text:0001133C                 mov     [ebp+ObjectAttributes.Length], 18h
.text:00011343                 mov     [ebp+ObjectAttributes.RootDirectory], edi
.text:00011346                 mov     [ebp+ObjectAttributes.Attributes], 240h
.text:0001134D                 mov     [ebp+ObjectAttributes.SecurityDescriptor], edi
.text:00011350                 mov     [ebp+ObjectAttributes.SecurityQualityOfService], edi
.text:00011353                 call    ds:ZwCreateFile
.text:00011359                 mov     esi, eax
.text:0001135B                 mov     eax, dword_13010
.text:00011360                 shl     eax, 0Ah
.text:00011363                 cmp     esi, edi

Small note – this might be windows compiler specific – edi mostly has the value zero
and is always used to check for errors etc, this makes things a bit more easier to understand but makes you wonder more about compiler specific options etc that the project was compiled with (the smart readers would also notice the mov edi,edi
to add space for patching/detouring in some functions)

The real shit goes here, where we actually save a copy of our bios, ebx points to the buffer that we mapped with MmMapIoSpace
edi is zero, and IoStatusBlock is a parameter passed on the stack

.text:0001137C loc_1137C:                              ; CODE XREF: write_dosdevice_c_bios_bin+DBj
.text:0001137C                 push    edi             ; Key
.text:0001137D                 push    edi             ; ByteOffset
.text:0001137E                 push    eax             ; Length
.text:0001137F                 push    ebx             ; Buffer
.text:00011380                 lea     eax, [ebp+IoStatusBlock]
.text:00011383                 push    eax             ; IoStatusBlock
.text:00011384                 push    edi             ; ApcContext
.text:00011385                 push    edi             ; ApcRoutine
.text:00011386                 push    edi             ; Event
.text:00011387                 push    [ebp+Handle]    ; FileHandle
.text:0001138A                 call    ds:ZwWriteFile
.text:00011390                 mov     esi, eax
.text:00011392                 cmp     esi, edi
.text:00011394                 jl      short loc_113A1
.text:00011396                 push    offset aBackupAwordBio ; "Backup Aword BIOS to disk c bios.bin su"...
.text:0001139B                 call    DbgPrint
.text:000113A0                 pop     ecx

a call to MmUnmapIoSpace is called afterwards and a return value is return upon success by mov eax, esi

what actually caught my eye was how do we get a STATUS_SUCCESS value ? since we saw on the begining of the value that esi is

.text:0001128A                 mov     edi, edi
.text:0001128C                 push    ebp
.text:0001128D                 mov     ebp, esp
.text:0001128F                 sub     esp, 2Ch
.text:00011292                 push    esi
.text:00011293                 mov     esi, STATUS_UNSUCCESSFUL

after looking a bit on the disassembly we can see that after the ZwcreateFile esi is accumulated with eax

.text:0001134D                 mov     [ebp+ObjectAttributes.SecurityDescriptor], edi
.text:00011350                 mov     [ebp+ObjectAttributes.SecurityQualityOfService], edi
.text:00011353                 call    ds:ZwCreateFile
.text:00011359                 mov     esi, eax
.text:0001135B                 mov     eax, dword_13010
.text:00011360                 shl     eax, 0Ah
.text:00011363                 cmp     esi, edi
.text:00011365                 jge     short loc_1137C
.text:00011367                 push    eax             ; NumberOfBytes
.text:00011368                 push    ebx             ; BaseAddress
.text:00011369                 call    ds:MmUnmapIoSpace

that's it 😉

Now to the real meat

.text:000110DE fn_flash_bios?  proc near               ; CODE XREF: IRP_MJ_DEVICE_CONTROL:loc_11513p
.text:000110DE
.text:000110DE ObjectAttributes= OBJECT_ATTRIBUTES ptr -40h
.text:000110DE IoStatusBlock   = _IO_STATUS_BLOCK ptr -28h
.text:000110DE DestinationString= UNICODE_STRING ptr -20h
.text:000110DE ByteOffset      = LARGE_INTEGER ptr -18h
.text:000110DE P               = dword ptr -10h
.text:000110DE var_C           = dword ptr -0Ch
.text:000110DE Handle          = dword ptr -8
.text:000110DE var_4           = dword ptr -4
.text:000110DE

there are a few things which caught my eye first when I saw this function , one of them is that I might be mistaken about
my assumptions for the previous function, does it really backup the bios or does it do anything else ? I do not know yet,
to be sure, it copies the bios and writes it into C:\bios.bin, but which bios ? the modified one written by the malware
or the true – real one

the function opens \\DosDevice\\C:\\bios.bin and read it`s contents

.text:00011104                 push    offset SourceString ; "\\DosDevices\\C:\\bios.bin"
.text:00011109                 lea     eax, [ebp+DestinationString]
.text:0001110C                 push    eax             ; DestinationString
.text:0001110D                 call    ds:RtlInitUnicodeString
.text:00011113                 push    edi             ; EaLength
.text:00011114                 push    edi             ; EaBuffer
.text:00011115                 push    20h             ; CreateOptions
.text:00011117                 push    3               ; CreateDisposition
.text:00011119                 push    1               ; ShareAccess
.text:0001111B                 push    80h             ; FileAttributes
.text:00011120                 lea     eax, [ebp+DestinationString]
.text:00011123                 mov     [ebp+ObjectAttributes.ObjectName], eax
.text:00011126                 push    edi             ; AllocationSize
.text:00011127                 lea     eax, [ebp+IoStatusBlock]
.text:0001112A                 push    eax             ; IoStatusBlock
.text:0001112B                 lea     eax, [ebp+ObjectAttributes]
.text:0001112E                 push    eax             ; ObjectAttributes
.text:0001112F                 push    100023h         ; DesiredAccess
.text:00011134                 lea     eax, [ebp+Handle]
.text:00011137                 push    eax             ; FileHandle
.text:00011138                 mov     [ebp+ObjectAttributes.Length], 18h
.text:0001113F                 mov     [ebp+ObjectAttributes.RootDirectory], edi
.text:00011142                 mov     [ebp+ObjectAttributes.Attributes], 240h
.text:00011149                 mov     [ebp+ObjectAttributes.SecurityDescriptor], edi
.text:0001114C                 mov     [ebp+ObjectAttributes.SecurityQualityOfService], edi
.text:0001114F                 call    ds:ZwCreateFile

it allocates a pool with the tag myfr, is that the author nick ? have I seen it before ? I can't honestly remember
but it rings a bell somewhere

.text:0001116C                 mov     eax, dword_13010
.text:00011171                 mov     esi, 'mfyr'
.text:00011176                 push    esi             ; Tag
.text:00011177                 shl     eax, 0Ah
.text:0001117A                 push    eax             ; NumberOfBytes
.text:0001117B                 push    edi             ; PoolType
.text:0001117C                 call    ds:ExAllocatePoolWithTag

I will split this post into two (or more ?) parts, as I that it's getting longer than I anticipated, so the real sauce will
be in the next post, sorry, stay tuned.

August 12, 2011

Not dead yet

Filed under: Uncategorized — shift32 @ 2:36 pm
Tags: , ,

I’m not dead yet….I’m still sick……it seems that my body got the infectious mononucleosis
sounds like aids eh ? well, I’ve been staying at home most of the time, doing nothing mainly

However I got sometime fiddling around with ARM assembly (I might tell the whole story once I’ll be better), and got to disassemble one tricky file
as a VIM addict, I got the disassembly with radare2 , I saved it into a file

           0x0001320c  entry0:
            0x0001320c    0    18c04fe2^[[0m         sub ip, pc, #24 ; 0x18
            0x00013210    0    060c9ce8^[[0m         ldm ip, {r1, r2, sl, fp}
            0x00013214    0    0ca08ae0^[[0m         add sl, sl, ip
            0x00013218    0    0cb08be0^[[0m         add fp, fp, ip
            0x0001321c    0    0200a0e1^[[0m         mov r0, r2
            0x00013220    0    01904ce0^[[0m         sub r9, ip, r1
            0x00013224    0    011a81e2^[[0m         add r1, r1, #4096 ; 0x1000
            0x00013228    0    013aa0e3^[[0m         mov r3, #4096 ; 0x1000
            0x0001322c    0    0f002de9^[[0m         push {r0, r1, r2, r3}
            0x00013230    0    0720a0e3^[[0m         mov r2, #7 ; 0x7
            0x00013234    0    3230a0e3^[[0m         mov r3, #50 ; 0x32
            0x00013238    0    0040e0e3^[[0m         mvn r4, #0 ; 0x0
            0x0001323c    0    c070a0e3^[[0m         mov r7, #192 ; 0xc0
            0x00013240    0    000000ef^[[0m         svc 0x00000000
                ; syscall[0x0][0]=?

I used radare since IDA unknowingly failed to disassemble it correctly,
and now to the real things, see this annoying ^[[0m characters ? well, I tried using vim’s :%s to replace it with space with a classical

:%s/\^[[0m//gc 

but apparently it did not work well at all, I started thinking I should add \ for the [ characters indeed

:%s/\^\[\[0m//gc

but it did not work either

I started getting a bit tipsy, maybe I’m doing something wrong w/ matching the correct patterns ?
I started walking around the string itself and found that the first ^[ is actually one character, which is quite stupid imho to miss something like it
so the actualy pattern to look for would be

:%s/<Ctrl-v><Ctrl-[>\[0m//gc

and the day was saved, once again (:

I hope to feel better within a few weeks and start sharing more on my previous research I’ve done

shift

June 12, 2011

OpenBSD glob ‘GLOB_APPEND’ and ‘GLOB_DOOFFS’ flags integer overflow

Filed under: bugs,stupidity,Uncategorized — shift32 @ 1:35 am
Tags: ,

I usually don’t post about vuln dev, not because it’s not interesting, but because I love reading others people post about it (e.g xorl, cr0, etc)
The bug seems to exist in OpenBSD’s glob function, it’s definition is as follows:

glob(const char *restrict pattern, int flags,
int (*errfunc)(const char *epath, int errno),
glob_t *restrict pglob

According to globs man page, the glob function “The glob() function is a pathname generator that implements the rules for file name pattern matching used by the shell.”

The glob_t structure is what caught my eye, and has the following structure :

typedef struct {
int gl_pathc; /* count of total paths so far */
int gl_matchc; /* count of paths matching pattern */
int gl_offs; /* reserved at beginning of gl_pathv */
int gl_flags; /* returned flags */
char **gl_pathv; /* list of paths matching pattern */
} glob_t;

The integer overflow seem to reside in several functions, mostly because lame bounds checking and due to the fact the
the user has full control over almost everything, for example, take a look here:


int
160: glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
161: glob_t *pglob)
162: {
163: const u_char *patnext;
164: int c;
165: Char *bufnext, *bufend, patbuf[MAXPATHLEN];
166: struct glob_lim limit = { 0, 0, 0 };
167:
168: patnext = (u_char *) pattern;
169: if (!(flags & GLOB_APPEND)) {
170: pglob->gl_pathc = 0;
171: pglob->gl_pathv = NULL;
172: pglob->gl_statv = NULL;
173: if (!(flags & GLOB_DOOFFS))
174: pglob->gl_offs = 0;
175: }
176: pglob->gl_flags = flags & ~GLOB_MAGCHAR;
177: pglob->gl_errfunc = errfunc;
178: pglob->gl_matchc = 0;
179:

Although checks are made for the initialization values of the pglob values, but no checks are made for any value less than zero or bigger than MAX_INT
Same goes for the globextend

static int
734: globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp,
735: struct stat *sb)
736: {
737: char **pathv;
738: ssize_t i;
739: size_t newn, len;
740: char *copy = NULL;
741: const Char *p;
742: struct stat **statv;
743:
744: newn = 2 + pglob->gl_pathc + pglob->gl_offs;
745: if (SIZE_MAX / sizeof(*pathv) <= newn ||
746: SIZE_MAX / sizeof(*statv) gl_offs; i gl_pathv && pglob->gl_pathv[i])
750: free(pglob->gl_pathv[i]);
751: if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
752: pglob->gl_pathv && pglob->gl_pathv[i])
753: free(pglob->gl_statv[i]);
754: }

Notice how the values of pglob->gl_pathv and pglob->gl_offs aren’t checked for any values, and since they’re transferred from globN (N represents glob1, glob0, there’re a few passes before the actual function gets called, but I’ve seen it calling this function several times in different locations), they’re possibly controlled by others.

Well, I don’t know whether or not this vuln is remotely exploitable since I haven’t seen any usage of it in code etc, but who knows, we’re not in 2001 however.

Have fun.

June 9, 2011

Nanomites – second thoughts

Filed under: Uncategorized — shift32 @ 6:05 pm
Tags: , , , ,

I’ve been fiddling around nanomites for quite a while, since I’ve first read about them
and saw them in action in different packers, I decided to write my own implementation
So far I haven’t done any breakthrough until last night me and another colleague managed to do something neat

Stay tuned for more results.

June 5, 2011

Spyeye: Father `n Son

Filed under: Uncategorized — shift32 @ 1:45 pm
Tags: , , , , ,

I do not work much on SpyEye, I only get a chance to view it on my days off nowadays, hence the slow progress, but here’s my latest progress with SpyEye.

Also, a short tip before I start digging a bit – I found that the collaboration of IDA and OllyDBG together (if you got two screen [ I don’t have two screen though 😦 ] ) is quite great, how is this possible some of you might ask ?
Well, you can use OllySync + IDA-Sync plugins in order to share comments etc
The plugin is a bit outdated and I plan to rewrite it a bit (though Pedram has done great work)
When trying to set function names in OllySync the IDA-Sync server fails to interpret it well, but comments are amazing and IDA’s analysis adds quite alot of information.

It seems that I was mistaken in my previous post , the function which I stepped into was not the decryption stub of anything, it was only an initial check of the system and grabbing some basic info about what’s what and where
basically, the function consisted of fetching the computer’s name, the windows version, and some other details which are not that interesting for us.

It seems that SpyEye’s resource section play an important role in it’s infection process, section C2 and C3 are the sections which SpyEye holds the compressed configuration and sections SC1 and SC2 (I might be mistaken here with the exact names, but they do reside under the “SC” dir in the resources) hold the parasite code

After gathering all the information SpyEye needs from the basic initialization function, SpyEye creates a mutex and constantly checks for the Volume:\algonic\ directory existence, the reason for that is because that’s where SpyEye creates it’s reboot-killer executable named algonic.exe, it also contains the config.bin which has all the juicy information and plugins one wants to obtain once SpyEye reversed.

SpyEye frequently calls RtlAdjustPrivilege in order to get max privileges and infect processes with it’s parasite (inside the resource dir).
Also – a small hint to those who fear the “600 functions spyeye contains” – the reason SpyEye holds so “many” functions is quite simple – SpyEye doesn’t import/export all the functions it uses, if the author would’ve been smarter, he would’ve used only GetProcAddress and used the PEB to get the kernel32.dll base address
SpyEye uses some sort of “special” macro which uses a classical technique to walk through the dll the function resides in and find it, it has a hardcoded value of the hash it’s looking for and whenever someone wants to call any function it just wraps it around some wrapper function
This could be easily evaded by writing some sort of pattern matching function
Since the function which finds the dll and walks through it is the same, and the push order is always the same to find the function – a simple pattern matching procedure could name all those functions by simple instrumentation

Another thing I wanted to discuss is the infection process, which I found a bit nice,
SpyEye calls CreateToolhelp32Snapshot to get a list of all running processes and walks through them using Process32Next, each time it finds a process which isn’t csrss, smss, or System (which are critical system processes :/) it injects itself into, the parasite injection process is as follows:


1. Spyeye Calls OpenProcess(CREATE_THREAD | VM_READ | VM_WRITE | QUERY_INFORMATION,FALSE,1144 /* explorer.exe */);
2. Called NtAllocateVirtualMemory in the remote process at address 0F60000 (RWE)
3. I started debugging explorer.exe and found the page spyeye is going to inject itself into and set a memory on access breakpoint
4. Spyeye Calls NtWriteProcessMemory
5. Called CreateRemoteThread to create a new thread for spyeye malicious parasite
6. Called WaitForSingleObject to figure out that the thread was injected correctly (?)
7. Called GetExitCodeThread to see if it was injected successfully

After that, the parasite SpyEye injected has finished executing or is executing at the moment, the parasite, from what I’ve seen so far does the following things:


1. open Volume:\algonic\
2. write Volume:\algonic\algonic.exe
3. execute Volume:\algonic\algonic.exe
4. delete the original malware executable using DeleteFileA
5. sleep
6. call ExitThread

I might be missing the whole hooking part, as while I’m writing this document seems to be part I’m currently debugging
As I’ve written previously – SpyEye has a loop which walks through all the processes and injects itself into them, somewhere inside it it performs the hooking process

I hope you’ve enjoyed this although it lacked assembly information, I’ll however try to edit the post and add some assembly code too.

May 31, 2011

The case of the spying eyes: blizzard stubs

Filed under: Uncategorized — shift32 @ 11:17 pm
Tags: , , , , ,

So I finally managed to unpack SpyEye this Saturday, and only today (Thursday) had the time to start actually exploring what it does,
I’ve heard and read from friends and the net that SpyEye got some several interesting modules
also it’s module load – use – unload technique seemed interesting. I’ve also heard that it steals money and performs different kind of phising attacks, all of this seemed quite interesting to research.

I’ve hooked up olly and opened the unpacked version of spyeye, opened the names bar and looked for interesting function to set breakpoints on, I’ve also searched for all intermodular calls and found some (even more) interesting functions

As it seems, SpyEye doesn’t import all the function it’s using in it’s IAT, as when inspecting it with PEiD or anything else you see not many functions

To my humble guess it’s using a simple (yet, known), “trick” of dynamic libary loading, I have first seen it in uninformed and the technique is quite nice (originally by lsd-pl folks)

As olly shown in the “show all intermodular calls” window, it seems

However, be mistaken not – the calls repeat themselves, what really caught my eye was the unresolved call here, I’ve set bp on every possible call outside and started my static analysis journey

I started stepping the code, not running it, to see if there are any interesting things and it seems that the start of the code had some nice spots

The first thing which caught my eye was that SpyEye looks for kernel32.dll by first getting it’s address from the PEB, by walking through it’s linked list, this method is quite known as i mentioned earlier by uninformed ,however, spyeye doesn’t use a loop to look for kernel32.dll it
goes through two values and hopes for the best – if someone put kernel32.dll in a different place in the linked list – SpyEye is a bit doomed (;

The other thing which caught my eye was that SpyEye accesses its .rsrsrc section (resource), it gets a handle to them, changes their permissions and continues onward – this is something which might be pretty interesting

the find.resource calls are to find the specified resource with GetModuleFilenameA function
and the rsrsrc.alter.perm are to alternate the permissions the resource has probably to FFFFF, or something like it, it is still unknown what their purpose is, so I don’t know what to look for

One of the resources starts with a string “!EYE” which hints for some propriatery struct for SpyEye (or perhaps something different ? we don’t know yet)

There’re basically three resource section I got my eye on – C1 C2 and C3, but I didn’t find any usage with/of them for now, so we’ll leave them for now.

Also I found several strings which got my eye glitchy

Remember “algonic” from the previous posts ? this is the name of the child process that our malware creates, as for config.bin – well the name answers for everything, it seems to be some sort of configuration SpyEye has, perhaps it contains C&C IPs and passwords to communicate with our big brother

After stepping more code I’ve found some small jackpot, I remember when I was unpacking SpyEye I got really frustrated when I didn’t know which functions SpyEye was using in order to allocate space for itself, and once I’ve found them – everything went alot easier,
So after stepping some code I found that SpyEye calls NtAllocateVirtualMemory to allocate space for something…something big, as of writing now I have a few clues of what it might be, but I still can’t be sure,
however my guesses go from
1. a huge decryption stub to decrypt the configuration and other resource section
2. a huge decompression/compression stub to de/compress something else
3. something else I have no clue yet (always leave room for the unexpected, hehe)

Why am I not thinking about hooking processes ? because as it seems SpyEye is only going through the tasklist at later stages of the code, I’ve seen a few calls to GetCurrentProcessId, and you are right if you said that it doesn’t prove anything, this is only a guess…I’m writing this while still disassembling everything..
However in order to prove more that I’m right I’ve scrolled down with olly a bit more and found this little interesting (yet, exciting) block :

See the comments olly adds on the side ? see smss.exe, csrss.exe, services.exe, etc ? does this look to you like something that would’ve done after we hook things up ? This looks like a prologue to something…something interesting (:

I kept stepping the code until I reached the copy of a resource section, however, the rest seems to be like a topic for another post,
To be continued(:

May 28, 2011

The case of the spying eyes: The third eye

Filed under: Uncategorized — shift32 @ 4:52 pm
Tags: , , , , , , ,

About an hour ago I managed to fully unpack SpyEye, my work was stopped due to other commitments but this morning I promised myself that I’ll try finishing the initial analysis.

The sample I have of SpyEye is triple packed with three layers of known packers, the configuration stub crypto and probably anything else is totally different topic

UPX is quite easy to unpack, basically when you hook up olly you begin at the regular “pusha” instruction

The first thing you gotta do is just scroll down until you meet lots of “db 00”
and set a breakpoint at

sub esp,-80
jmp entryPoint

This would be the last jump before you hit the entry point of the executable, in our case – we’ll hit the ep of ASPack, since my sample is triple packed

In order to get the decryptor stub, we’ll be setting a breakpoint at VirtualAlloc, as this is the function which is used to allocate the space for the function,

Once we hit VirtualAlloc, we’ll step over and return to the caller, we could see where the decryption stub will be written to by the return value of eax

So we set a memory bp on the address eax points to and run –
we hit one rep stos instrcution which copies the decrypted stub into the location and hit step over to complete the copy process

Right now we have the function which decrypt the real (packed with UPX) exectuable code, I’ll try to analyze it once I’ll finish the global analysis, in order to get to the real entrypoint, we have two possibilities:
1. Step the code and look for interesting writes and reads
2. Set a bp at the function which allocates space for the EP

The first option would work if we didn’t know which function is used to allocate the EP, however it would be tedious work.
The second option is quite easier, as assuming we don’t know which function actually writes the EP code, we set a bp on every interesting allocation function, this includes – (amongst others) – VirtualAlloc, VirtualAllocEx, NtAllocateVirtualMemory, GlobalAlloc, HeapAlloc, etc
I’ve had a few hints from friends and managed to figured that the function is ZwAllocateVirtualMemory

I’ve set a bp on ZwAllocateVirtualMemory and hit F9 in olly, the first occurrence was the routine which copies the decrypted PE.

Once the PE was written to it’s original place just hit twice “execute till return” and you’ll hit a ret that get you into ZwFreeVirtualMemory, return there and you’ll hit the EP
You’re now in the EP of the UPX packed code, as this is – once again – quite easy to unpack –
just jump to the real EP and have fun

To be continued.

Edit: the post is a bit messy, I’ll rewrite it later on

May 25, 2011

The case of the spying eyes

Filed under: Uncategorized — shift32 @ 10:48 pm
Tags: , , , , , ,

I found this sample of an interesting spyeye malware packed with UPX and ASPack,
and decided to reverse it on my own.
As I’ve never unpacked ASPack I decided to look around and found two interesting anchors,
both are interesting win32-api memory allocation functions which are called VirtualAlloc and ZwAllocateVirtualMemory

But before reversing the malware itself I wanted to see what goes “on the hood”, as Mark Russinovich documents in his blog
In other words – before dwelling into an unpacking nightmare I want to see what sort of files it adds to the system, what registry keys it modifies, what sort of hooks it adds etc

So onward my small journey I’ve hooked up several processes (sysinternals + rku, rootkitRevealer)
I’ve set a snapshot on the vm to return to my initial status after executing and executed the binary

And there I’ve had it, after just executing it everything remained the same, I’ve looked at procmon and regmon to see what sort changes in their process tree and started investigating.

Before running the malware I’ve used shellrunas to first run the malware in a Guest user restricted mode, just to see how it handles things, and I saw that the malware forks itself to a new process called “algonic.exe”,

I’ve set the process in suspended mode and started looking at the log of procmon to see which values it tried modifying

Considering that the malware doesn’t have any zerodays it couldn’t leave Guest user, and execute code in ring0, this helps a bit as I know I’m dealing with any kernelmode malware

Now onto the interesting part, I’ve looked at procmon and saw that the process fork itself and looks for certain specific registry values such as ComputerName,
“HKU\S-1-5-21-1547161642-152049171-839522115-501\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders” ,
“HKU\S-1-5-21-1547161642-152049171-839522115-501\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Cache” , “HKLM\SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers\Paths\{dda3f824-d8cb-441b-834d-be2efd2c1a33}” etc,

it tries to lower down the security attributes ie has, open different know dlls (ntdll, wininet, usp01 (??), windows Shell manifest etc),

At this time of writing I do not know the purpose of all those, I can only think it wants to hide itself (with hooks, though), and add different malicious things
I can also ponder that it tries to collect information about the system, if the malware is smart enough it will detect that it’s running inside VirtualBox ( as vbox has two main processes with *vbox* initials inside them, though there are other ways to detect you’re inside a vm like timing-attacks etc )

One interesting thing my eyes caught was that the malware tries to read the

E:\Documents and Settings\Guest\Application Data\Microsoft\SystemCertificates\My\CRLs

This path is quite important as it includes the local system certificates the user has, adding the virus’s certificate to the trusted path will probably break any av or scanner that tries to look for malicious things automagically

Aight, enough for that now –
Let’s move onto the real binary – the algonic.exe which seems to do all the dirty job
[btw, as this time of writing, since no dynamic/static analysis of the binary is done, it is quite unknown what the malware is looking for, I can only assume that I’m missing alot of under the hood stuff, but that’s only an assumption which must be analyzed and faced ]

The algonic.exe is located in the same root drive the malware was originally located, in my own situation it’s located in

 E:\algonic 

The folder is secret and probably well protected if ran with administrator privileges.
The folder contains to files – algonic.exe and config.bin

I’ve hit PEiD on algonic.exe and I wasn’t surprised to see that it is indeed also packed with UPX and
probably also with ASPack,
at this point I’ve unpacked the UPX packing protection by simply putting a bp at 497F3 which is probably the most classical way to unpack most UPX versions

I’ve set also two hardware breakpoints – one for each unique function I was hint’ed, one for VirtualAlloc and one for ZwAllocateVirtualMemory,

Once I’ve hit both bp’s I’ve managed to get the decryption stub, and also the function which calls the EP, I’ve seen the real PE header (at 0x4000000) and currently I’m reversing the last part of the loop before reaching the last popad + ret part.
(I do want to apologize for not writing too much about this phase, but since it’s incomplete I’m still unsure what I am missing and what’s not)
Wish me luck.

To be continued

Next Page »

Blog at WordPress.com.