Shifting yourself to space

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.

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

May 21, 2011

Push `n call

Filed under: Uncategorized — shift32 @ 8:43 pm
Tags: , , ,

I’m no glorious reverser, however I’m always glad to learn some cool new technique to
detect interesting behaviour
As my journey reversing for fun and non-profit I got into different methods to call a function
in an “obfuscated” way

Such way that in most cases you won’t be able to know where the call would actually go to
The actual value of the call is decided upon runtime and is based on the value of a few things
The actualy value of the call is decided upon runtime and is based on usually one of things below:

1.The value of the register
For example – let’s take a look at this simple method

mov eax,[ebp-22]
shl eax,3
call eax

in this example below the value of ebp-22 can be calculated upon runtime
but if we’d try to statically analyse the function it will be quite hard to follow the stack changes and call
as this example is quite abstract, most malware add different kind of obduscation methods
such as different calls to useless function and register manipulation

2. push `n ret

push 5
push &amp;exit
call obfuscation_method
ret

In this example it gets a bit trickier, obfuscation_method doesn’t really interest us
since once we’ll comeback from obfuscation_method, we’ll be back to the previous stack frame
and since we’ve pushed the address of printf beforehand – we’ll return to it immidiately after calling obfuscation_method

3. nopsled, bruteforce

In this specific method we don’t really know at all (nor does the program itself) where are we going
The method is based on a simple “brute-force” loop which tries calling addresses by simple arithmetic manipluation

mov eax,&amp;base_offset
mov ecx,MAX_BASE_OFFSET
call [eax+ecx]

in this specific method we’ll have to allocate an array of MAX_BASE_OFFSET
pad it with nops or garbage instructions and add our real code in specific location for example

nop
nop
nop
nop
nop
[ ... real code goes here ... ]
ret
nop
nop
nop
nop
[ ... more real code goes here ... ]
ret
nop
nop
nop
nop

it is quite hard (and frustrating) to know where the real code is especially if don’t have nops and real garbage code the disadvantage in this specific method is that you must align you code perfectly else you’ll get an exception of an invalid instruction

this method is quite equivalent to a malware which doesn’t know it’s decryption key (same concept) and so it just bruteforce’s itself until it finds the key the disadvantage here is that you’ll need large computation power in order to get they decryption key when not dealing with the classical xor/XTEA/etc crypto

4. nanomites

I’ve read about this method in peter ferrie’s article and decided to try to implement it on my own
From Peter Ferrie’s article :

Nanomites are a more advanced method of anti-dumping.
They were introduced in Armadillo. They work by replacing
branch instructions with an “int 3” instruction, and using
tables in the unpacking code to determine the details. The
details in this case are whether or not the “int 3” is a
nanomite or a debug break; whether or not the branch
should be taken, if it is a nanomite; the address of the
destination, if the branch is taken; and how large the
instruction is, if the branch is not taken.
A process that is protected by nanomites requires selfdebugging
(known as “Debug Blocker” in Armadillo, see Anti-Debugging:Self-Debugging
section below), which uses a copy of the same process.
This allows the debugger to intercept the exceptions that are
generated by the debuggee when the nanomite is hit.
When the exception occurs in the debuggee, the debugger recovers
the exception address and searches for it in an address table. If a match is found, then
the nanomite type is retrieved from a type table. If the CPU
flags match the type, then the branch will be taken. When
that happens, the destination address is retrieved from a
destination table, and execution resumes from that address.
Otherwise, the size of the branch is retrieved from the size
table, in order to skip the instruction.

This method however adds much more complication to the code you’re writing
and divides it into separate projects:

One is your original project which has all the code you’ve written originally

The other is a “stub” ( those who ever wrote a packer would know this acronym better than I do) that keeps track of the nanomites and knows when a real nanomite is hit and not a regular int 3 instruction caused by the debugger / compiler.

The third is a project that injects the stub ( PE/ELF file manipulation, adding a new section if necessary ) and replaces the calls/jmps
with nanomites (int 3 instructions)

This is a whole new level of complication and it really frustrates the reversing process, not talking about that it is really hard to statically reverse such binary
without having all the instructions in your hand….

April 28, 2011

Dwelling into ZwSetSystemInformation

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

As things got a bit out of control with my simple driver, I have decided to debug and see what’s going on really inside ZwSetSystemInformation.
Perplexed by the windows architecture (so far I was used to good old Linux 2.6.x ), I’ve plugged windbg
into a session an


kd> uf nt!ZwSetSystemInformation
nt!ZwSetSystemInformation:
804fe534 b8f0000000      mov     eax,0F0h
804fe539 8d542404        lea     edx,[esp+4]
804fe53d 9c              pushfd
804fe53e 6a08            push    8
804fe540 e80ce10300      call    nt!KiSystemService (8053c651)
804fe545 c20c00          ret     0Ch
kd> x nt!ZwSetSystemInformation
804fe534 nt!ZwSetSystemInformation = <no type information>

As I’ve read beforehand, ZwSetSystemInformation is an undocumented and “stealthy” function to load drivers, so I wasn’t looking for anything special
as the “examine” command doesn’t give anything at all, I’ve kept looking a bit more – I thought about checking out where the function is defined in the official sources – aka – Microsoft
or the WDK but it seems that undocumented is indeed undocumented, the best I could find was basically the original definition I had


NSTATUS (_stdcall *ZwSetSystemInformation)(	IN DWORD functionCode,
											IN OUT PVOID driverName,
											IN LONG driverNameLength );

and nothing more than.
Well, I guess that it’s enough for a start, I’ve a set a bp in ZwSetSystemInformation and kept hoping for good.

kd> bp nt!ZwSetSystemInformation
kd> bl
 0 e 804fe534     0001 (0001) nt!ZwSetSystemInformation

Once I’ve hit it, I’ve disassembled the call and wasn’t too surprised to see that it was calling to nt!KiSystemService

nt!ZwSetSystemInformation:
804fe534 b8f0000000      mov     eax,0F0h
804fe539 8d542404        lea     edx,[esp+4]
804fe53d 9c              pushfd
804fe53e 6a08            push    8
804fe540 e80ce10300      call    nt!KiSystemService (8053c651)
804fe545 c20c00          ret     0Ch

The interesting arguments here are

804fe534 b8f0000000      mov     eax,0F0h
804fe539 8d542404        lea     edx,[esp+4]
804fe53d 9c              pushfd
804fe53e 6a08            push    8

I don’t know enough to understand what each one of them means, but it’s worth a shot investigating deeper in order to understand

Trying to figure what is the address which gets into edx didn’t give much results beside archaic thoughts


kd> dw 81dc4068 
81dc4068  0006 0070 0000 0000 4070 81dc 4070 81dc
81dc4078  4078 81dc 4078 81dc 6000 f4ca 2000 f4ca
81dc4088  d000 7ffd 0000 0000 5b10 f4ca 0200 0000
81dc4098  0a00 0800 409c 81dc 409c 81dc 40a4 81dc
81dc40a8  40a4 81dc 2da0 8201 0000 0000 076e 0000
81dc40b8  0000 0000 0000 0000 0000 0000 40d8 81dc
81dc40c8  0000 0000 8db8 8054 5c6b 0001 0008 0400
81dc40d8  bbf8 81f2 bbf8 81f2 4068 81dc 3a60 f72a
kd> db 81dc4068 
81dc4068  06 00 70 00 00 00 00 00-70 40 dc 81 70 40 dc 81  ..p.....p@..p@..
81dc4078  78 40 dc 81 78 40 dc 81-00 60 ca f4 00 20 ca f4  x@..x@...`... ..
81dc4088  00 d0 fd 7f 00 00 00 00-10 5b ca f4 00 02 00 00  .........[......
81dc4098  00 0a 00 08 9c 40 dc 81-9c 40 dc 81 a4 40 dc 81  .....@...@...@..
81dc40a8  a4 40 dc 81 a0 2d 01 82-00 00 00 00 6e 07 00 00  .@...-......n...
81dc40b8  00 00 00 00 00 00 00 00-00 00 00 00 d8 40 dc 81  .............@..
81dc40c8  00 00 00 00 b8 8d 54 80-6b 5c 01 00 08 00 00 04  ......T.k\......
81dc40d8  f8 bb f2 81 f8 bb f2 81-68 40 dc 81 60 3a 2a f7  ........h@..`:*.
kd> 
81dc4068  06 00 70 00 00 00 00 00-70 40 dc 81 70 40 dc 81  ..p.....p@..p@..
81dc4078  78 40 dc 81 78 40 dc 81-00 60 ca f4 00 20 ca f4  x@..x@...`... ..
81dc4088  00 d0 fd 7f 00 00 00 00-10 5b ca f4 00 02 00 00  .........[......
81dc4098  00 0a 00 08 9c 40 dc 81-9c 40 dc 81 a4 40 dc 81  .....@...@...@..
81dc40a8  a4 40 dc 81 a0 2d 01 82-00 00 00 00 6e 07 00 00  .@...-......n...
81dc40b8  00 00 00 00 00 00 00 00-00 00 00 00 d8 40 dc 81  .............@..
81dc40c8  00 00 00 00 b8 8d 54 80-6b 5c 01 00 08 00 00 04  ......T.k\......
81dc40d8  f8 bb f2 81 f8 bb f2 81-68 40 dc 81 60 3a 2a f7  ........h@..`:*.
kd> u 81dc4068 
81dc4068 06              push    es
81dc4069 007000          add     byte ptr [eax],dh
81dc406c 0000            add     byte ptr [eax],al
81dc406e 0000            add     byte ptr [eax],al
81dc4070 7040            jo      81dc40b2
81dc4072 dc817040dc81    fadd    qword ptr [ecx-7E23BF90h]
81dc4078 7840            js      81dc40ba
81dc407a dc817840dc81    fadd    qword ptr [ecx-7E23BF88h]
kd>

So I kept on debugging .. to be continued for now….

Short tips: Debugging a vm with a named pipe

Filed under: Uncategorized — shift32 @ 12:59 pm
Tags: , ,

I recently started writing drivers with windows, so far I’ve only written one and you can see the results down below, however I tried loading the driver in a non-traditional way using the undocumented ZwSetSystemInformation

For some unknown reason, the driver halts the system and I get an exception of an invalid instruction
However this is not the case of this post

In order to debug things correctly, I’m using VirtualBox winxp-sp2 as a guest machine to run my code and my host machine runs a windbg session
VirtualBox’s support in com ports sucks and I didn’t make it at configurating a com port for my debugging session so I decided to use named pipes

In order to do so, go to the Settings -> Serial Ports – >
Check the “Enable serial port” and create “Host Pipe”

It is quite crucial that you’ll name your pipe as \\.\pipe\ since if not you’ll get an error while running the vm

Once you’ve created a named pipe, run

kdsrv.exe -t npipe:pipe=\\.\pipe\<pipe_name> in your guest machine

within the host machine go to File -> Kernel Debug ->
and choose “Port” within the COM box write your named pipe name, Check “Pipe” and you’re done.
You can also check “Reconnect” too, it saves a few things

Once you load up the os in debug mode (bcdedit etc) be sure to hit ctrl+break to halt the system and get control
It’s also noted to use the symbol server that ms offers in order not to fuck symbols up (it’s quite a nightmare setting things up imho)

enjoy.

April 17, 2011

The case of video.exe

Filed under: Uncategorized — shift32 @ 5:46 pm
Tags: , , ,

The case of video.exe

Just another day without much work and I wanted to do some fun reversing. I fetched some malware from malc0de.com database and started investigating.

The malware is packed, and from the begining it has a few annoying anti-debugging stuff, however IDA knows how to deal with them and with a little bit of editting in olly
everything can be overrun

loc_49C8F4:                            ; CODE XREF: start+9A7B6_j
.data:0049C8F4                 jmp     loc_49C8FD
.data:0049C8F4 ; END OF FUNCTION CHUNK FOR start
.data:0049C8F4 ; ---------------------------------------------------------------------------
.data:0049C8F9                 db 22h, 9Eh, 8Dh
.data:0049C8FC ; ---------------------------------------------------------------------------
.data:0049C8FC                 sahf
.data:0049C8FD ; START OF FUNCTION CHUNK FOR start
.data:0049C8FD

Notice the db 22h, 9eh and 8dh which resolve to

simple assembly obfuscation

Olly gets a little bit crazy when hitting the single step button, these anti-debuggin tricks appear all along the way

I’m writing this documentation while still disassembling the malware and so far I’ve ran into several xor-loop decryption
It seems that the crucial parts of this malware are encrypted with a simple xorl-loop encryption method, which is quite easy to spot

simple xor decryption loop of a code chunk

EAX seems to hold the address that will be decrypted, EBP holds the relative address and makes it a true virtual address
DL/EDX seems to hold the decryption key (70h) and ECX as always has the len

The malware continues it’s journey and allocate space at 0x00BEE00, without any known reasons (for now ? : )

It seems that every decryption method is quite similar to the other, only they’re written over and over
DST address is always in either EAX or EDX (depending on the size word,dword,byte, etc),
KEY is always in either EAX or DL which seems to be 0 most times
LEN is always in ECX

after these arguments are pushed onto the stack they’re moved into the registers and a simple mov-xor-dec-jnz loop begins

Next there’s an interesting PE header deobfuscation method, the method is very long and I still haven’t fully understood how it works
but the main thing it does is copy an obfuscated PE header from ESI to EDI using AL as the register holding the chars and DL as the state machine
The method consists of MANY JNB/JNZ and ADD/ADC’s with DL which makes it even harder to understand what’s going on and why

Once the DOS stub header is reconstructed, the basic PE header is copied along with the section names, size, and virtual addresses of the real executable
They’re all located from 0x00EB000.
There’s an interesting side note here to say, if you’ve been disassembling the binary with me, you’d notice that EB0000 plays an important role here, it is chunk we’ve allocated
somewhile ago with VirtualAlloc in 0x49C436

I didn’t follow all of it, I just ran through it managed to copy all the DOS header and the PE header,
once we return – the packer starts fixing regular jmps (E8,E9) and JMP DWORD (25FF), the loop itself is quite easy
it starts from the DOS stub looking for these bytes, if they exist, it just changes their values

fix jmps

Afterwards another PE header is parsed and copied, this time it’s a DLL type PE header, all the sections are copied into the executable and the original PE header is freed with VirtualFree (00BEE0000)

This is probably the end of part I in this series, I hope to continue and reverse this malware and actually see what it is doing

Blog at WordPress.com.