Category : Files from Magazines
Archive   : PCTV1N3.ZIP
Filename : ANTIVENM.ASM

 
Output of file : ANTIVENM.ASM contained in archive : PCTV1N3.ZIP
;***********************************************************************
; Listing 1 - ANTIVENM.ASM
;
; Written by Kevin D. Weeks 10-8-89
; Released to the Public Domain.
;
; int anti_venom(int buf_size,char* buffer)
;
; Description:
; This collection of routines performs a Cyclic Redundancy Check on
; the program they are a part of and compares the resulting value
; with a value known to be correct. A descrepancy in these two num-
; bers indicates the program has been modified and may be infected
; by a virus.
;
; Returns:
; -1 Program has been modified and may be infected.
; 0 No problems detected.
; +1 Execution error (file not found, PSP not found, etc.)
;
.MODEL small
if @codesize
bp_ofs equ 6
else
bp_ofs equ 4
endif

FOUND equ 0
EXECUTION_ERR equ 1
VIRUS_DETECTED equ -1

.DATA
state dw ? ; current state of valid_crc search
cur_crc dw ? ; current crc value

;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
.CODE
public _anti_venom

;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The _anti_venom function performs the initial setup (such as ac-
; quiring the file name) and then successively calls READ_FILE and
; CALC_CRC until the entire file has been processed.
;
if @codesize ; if large code memory model
_anti_venom proc far
else ; else, small code memory model
_anti_venom proc near
endif
push bp ; save the caller's stack frame
mov bp,sp
push bx
push cx
push dx
push di
push si
push es
push ds
jmp STEP_1 ; jump over the CRC and signature

; the signature and validation crc are stored here to guarantee they'll
; be contiguous and not subject to compiler startup manipulation.
signature db 'ANTIV'
valid_crc dw 0

; the first step is to get the psp of this process.
STEP_1:
call GET_PSP ; returns with BX = PSP
cmp bx,0 ; check for a 0 return
je ERROR_OUT

; from the psp we get the address of the environment block which con-
; tains the path and name of this program.
call SCAN_ENVIRONMENT

; SCAN_ENVIRONMENT returns with DS:DX pointing to file path and name
; ready for a call to DOS to open the file.
mov ax,3d00h ; Open File function - read only
int 21h ; call DOS
jc ERROR_OUT

; get the buffer address form the stack. NOTE: this is language specific!
mov bx,ax ; move file handle to bx
mov cx,[bp + bp_ofs] ; get buffer size
mov dx,[bp + bp_ofs + 2] ; get offset address of buffer
if @datasize ; if large data model
mov ds,[bp + bp_ofs + 4] ; get segment address of buffer
else ; else small data model
pop ds ; restore original data segment
push ds ; keep stack accurate
endif
call CLEAR_OUT ; initialize the state

; this is where the real work gets done. we read to the end of the file
; calling CALC_CRC after each read.
MAIN_LOOP:
call READ_FILE ; read the file
jc ERROR_OUT ; bailout if read error
cmp ax,0 ; check for EOF
jz COMPARE_CRC ; if so, complete testing
; else
push cx ; save buffer size
mov cx,ax ; place bytes actually read in cx
call CALC_CRC ; calculate CRC
pop cx ; restore buffer size
jmp MAIN_LOOP ; and repeat
; end of MAIN_LOOP

; test the crc just calculated by subtracting it from the valid crc. if
; the result is 0 then we have our return code, otherwise we indicate a
; virus was detected
COMPARE_CRC:
mov ax,cs:valid_crc ; move the correct crc to ax
sub ax,cs:cur_crc ; and subtract the new crc
jz CLOSE ; if the result is 0 they're equal
; else
mov ax,VIRUS_DETECTED ; indicate crc error
jmp short CLOSE ; and bailout

ERROR_OUT:
mov ax,EXECUTION_ERR ; indicate execution error

CLOSE:
push ax ; save the return code
mov ax,3e00h ; Close File function
int 21h ; call DOS
pop ax ; restore the return code

EXIT:
pop ds ; restore the caller's environment
pop es
pop si
pop di
pop dx
pop cx
pop bx
mov sp,bp
pop bp
ret
_anti_venom endp

; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; GET_PSP
; First we issue a call to DOS function 62h, Get PSP. this function only
; exists in DOS 3.xx but IS documented. If we get a 0 back in register bx
; then we assume we're running under DOS 2.xx and issue a call to the UN-
; documented DOS function 51h.
;
GET_PSP proc near
mov ax,6200h ; DOS Get PSP function
int 21h ; call DOS
cmp bx,0 ; check for a 0 return
jz GET_PSP2
ret ; if not, return
GET_PSP2:
mov ax,5100h ; undocumented Get PSP function
int 21h ; call DOS
ret
GET_PSP endp

; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; SCAN_ENVIRONMENT
; The DOS environment blocks consist of a series of ASCIIz strings. The
; last string is double terminated, followed by the number of additional
; strings(?), followed by the ASCIIz path and filename of the current
; process, which is what we want.
;
SCAN_ENVIRONMENT proc near
mov si,002ch ; offset of pointer to environment block
mov es,bx ; move psp segment into es
mov ds,es:[si] ; move environment segment into ds
mov si,0 ; set index to beginning
mov cx,0 ; use cx to count NUL-terminators
SCAN_0:
cmp byte ptr [si],0 ; check for a zero
jnz SCAN_1 ; no zero so check next character
; else
inc cx ; increment cx
inc si ; point to next character
cmp cx,2 ; check to see if we've got two 0's
je SCAN_2 ; we do so exit loop
; else
jmp SCAN_0 ; loop again
SCAN_1:
inc si ; point to next character
mov cx,0 ; re-initialize cx
jmp SCAN_0 ; and loop again

SCAN_2: ; we've found the double NUL
inc si ; skip over the string count
inc si
mov dx,si ; ds:dx = pointer to this program's
; path and name
ret ; return
SCAN_ENVIRONMENT endp

; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; READ_FILE
;
READ_FILE proc near
mov ax,3f00h ; Read File function
int 21h ; call DOS
ret ; return immediately
READ_FILE endp

; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; CALC_CRC
; This routine consists of two loops. The outer one processes the input
; buffer byte-by-byte while the inner loop calculates the crc on each
; byte.
;
CALC_CRC proc near
mov si,dx ; move pointer to buffer to si
FOR_1:
push cx ; save buffer count
mov ah,[si] ; move character to ah
mov al,0 ; clear low byte of ax
xor ax,cs:cur_crc ; combine character with crc
mov cx,8 ; set cx to 8 for 'for' loop
FOR_2:
test ax,8000h ; see if MSB is on
jz CCRC_2 ; if not, perform else
shl ax,1 ; shift left one
xor ax,1021h ; and incorporate prime
loop FOR_2 ; loop back
jmp short CCRC_3 ; we finished the crc calculation
CCRC_2: ; else
shl ax,1 ; shift left one
loop FOR_2 ; and loop

CCRC_3:
pop cx ; restore buffer length to cx
cmp cs:state,FOUND ; see if we've found the signature
je END_OF_FOR2 ; if so, go on
call FIND_VALID_CRC ; else, check this character
END_OF_FOR2:
inc si ; point to next byte
mov cs:cur_crc,ax ; save current crc
loop FOR_1 ; and loop

ret
CALC_CRC endp

; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; FIND_VALID_CRC
; This is implemented as a finite state machine (I use these things ALL
; the time) where each state is represented by the address of the state
; processor. This would of course have to be modified for a different
; signature. Alternatively, it could be handled the way SETCRC.C does it
; which is more general but less clear. My feeling is that since you
; should change the signature for each program you use this in you might
; as well change this routine also. It's simple enough to do.
;
FIND_VALID_CRC proc near
jmp cs:state
FIND_A:
cmp byte ptr [si],'A' ; if target value not seen
jne CLEAR_OUT ; go back to beginning
mov cs:state,offset FIND_N ; else, change state
ret
FIND_N:
cmp byte ptr [si],'N'
jne CLEAR_OUT
mov cs:state,offset FIND_T
ret
FIND_T:
cmp byte ptr [si],'T'
jne CLEAR_OUT
mov cs:state,offset FIND_I
ret

FIND_I:
cmp byte ptr [si],'I'
jne CLEAR_OUT
mov cs:state,offset FIND_V
ret
FIND_V:
cmp byte ptr [si],'V'
jne CLEAR_OUT
mov cs:state,FOUND ; we've found the signature
dec cx ; so increment the byte counter
dec cx ; past it
inc si ; and increment the pointer
inc si ; past it
ret
CLEAR_OUT:
mov cs:state,offset FIND_A
ret
FIND_VALID_CRC endp

END


  3 Responses to “Category : Files from Magazines
Archive   : PCTV1N3.ZIP
Filename : ANTIVENM.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/