1 Востаннє редагувалося 0xDADA11C7 (23.09.2014 00:45:53)

Тема: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Ця ВМ використовувалася в моєму пакувальнику-крипторі, тому вона має деякі спецефічні властивості, продиктовані антиантивірусним ринком. Мушу зауважити, що коли я кажу про віртуальну машину, то маю на увазі родину подібних віртуальних машин, бо для кожного вхідного файла генерувалася власна віртуальна машина, яка відрізналася від подібних деякими властивостями. Нижченаведена ВМ є офіційно затвердженим "ірідієвим" зразком у вакуумі для використання в прикладах.

  • параметри одержує в регістрах

  • розмір коливається в межах 700-750 байтів

  • номера функцій, опкоди команд і розташування полів в структурі в кожної ВМ свої

  • виконано у вигляді шеллкоду

Нижче наведений код однієї з віртуальних машин. Попереджаю, в деяких місцях код схожий на страшні темні чари.

Докладний опис архітектури віртуальної машини

  • Два 32-розрядні стеки - даних і викликів.

  • Власний адресний простір відсутній, тобто використовується адресний простір "хоста" (в даному випадку x86 IA-32).

  • Формат зберігання цілих чисел подібний до інтелівського (англ. little-endian, дослівно: «гострокінцевий»)

  • Доступ до комірок пам’яті можливий байтами (Byte), словами (2 байти - Word) і подвійними словами (4 байти - DWord)

Джерельний код віртуальної машини

Файл заголовків picovm.inc

struct PICOVM_CONTEXT
_dstack_size            db ?
_instruction_pointer    dd ?
_dstack_begin           dd ?
_rstack_size            db ?
_rstack_begin           dd ?
_rstack_top             dd ?
_dstack_top             dd ?
ends
macro PICOVM_CTX ip, dssz, rssz, rstop, dstop, rsb, dsb {  PICOVM_CONTEXT dssz, ip, dsb, rssz, rsb, rstop, dstop }

PICOVM_FNC_STEP = 0
PICOVM_FNC_DSPOP = 1
PICOVM_FNC_RUN = 2
PICOVM_FNC_RSPOP = 3
PICOVM_FNC_DSPUSH = 4
PICOVM_FNC_RSPUSH = 5
PICOVM_FNC_DEPTH = 6

PICOVM_ADD_OPCODE equ 0x0
PICOVM_PICK_OPCODE equ 0x1
PICOVM_NOT_OPCODE equ 0x2
PICOVM_STOREW_OPCODE equ 0x3
PICOVM_LOADCW_OPCODE equ 0x4
PICOVM_AND_OPCODE equ 0x5
PICOVM_OVER_OPCODE equ 0x6
PICOVM_DUP_OPCODE equ 0x7
PICOVM_LOADCB_OPCODE equ 0x8
PICOVM_XOR_OPCODE equ 0x9
PICOVM_ROLL_OPCODE equ 0xA
PICOVM_CALLN_OPCODE equ 0xB
PICOVM_LOADCD_OPCODE equ 0xC
PICOVM_CALLA_OPCODE equ 0xD
PICOVM_JMPR_OPCODE equ 0xE
PICOVM_SHR_OPCODE equ 0xF
PICOVM_BELOW_OPCODE equ 0x10
PICOVM_SHL_OPCODE equ 0x11
PICOVM_FETCHD_OPCODE equ 0x12
PICOVM_SUB_OPCODE equ 0x13
PICOVM_ROT_OPCODE equ 0x14
PICOVM_RET_OPCODE equ 0x15
PICOVM_STORED_OPCODE equ 0x16
PICOVM_DROP_OPCODE equ 0x17
PICOVM_OR_OPCODE equ 0x18
PICOVM_ROR_OPCODE equ 0x19
PICOVM_EQ_OPCODE equ 0x1A
PICOVM_ROL_OPCODE equ 0x1B
PICOVM_ABOVE_OPCODE equ 0x1C
PICOVM_SWAP_OPCODE equ 0x1D
PICOVM_CALLR_OPCODE equ 0x1E
PICOVM_FETCHW_OPCODE equ 0x1F
PICOVM_MOD_OPCODE equ 0x20
PICOVM_STOREB_OPCODE equ 0x21
PICOVM_JMPC_OPCODE equ 0x22
PICOVM_DIV_OPCODE equ 0x23
PICOVM_MUL_OPCODE equ 0x24
PICOVM_FETCHB_OPCODE equ 0x25
PICOVM_JMPA_OPCODE equ 0x26
PICOVM_HLT_OPCODE equ 0xFF

PICOVM_ERR_NONE          equ  0
PICOVM_ERR_DSOVERFLOW    equ -1
PICOVM_ERR_DSUNDERFLOW   equ -2
PICOVM_ERR_RSOVERFLOW    equ -4
PICOVM_ERR_RSUNDERFLOW   equ -5
PICOVM_ERR_UNKNOWNFNC    equ -6
PICOVM_ERR_UNKNOWNCMD    equ -7

macro PICOVM_CMD cmd, n {
  if cmd eq _LOADCW
    db PICOVM##cmd##_OPCODE
    dw n and 0xffff
  else if cmd eq _LOADCD
    db PICOVM##cmd##_OPCODE
    dd n and 0xffffffff
  else if cmd eq _LOADCB
    db PICOVM##cmd##_OPCODE
    db n and 0xff
  else
    db PICOVM##cmd##_OPCODE
  end if
}

macro PICOVM_COMMAND_ENTRY link, sz, dsinp, dsoutp {
  dw ((link-__COMMANDS_BEGIN__) shl 0x6) + (sz and 0x7) + ((dsinp and 0x3) shl 0x3) + ((dsoutp and 0x1) shl 0x5)
}

Головний файл picovm.asm

format binary 
use32
org 0x0

include '%FASMINC%\WIN32A.INC'
include 'picovm.inc'

__VM_BEGIN__:
    pusha
    call    .delta
.delta:
    sub     DWord [esp], __VM_BEGIN__.delta - __VM_BEGIN__
    pop     ebp
    cmp     eax, 0x6
    ja     .err
    call    .fnc

  db  __STEP__
  db  __DSPOP__
  db  __RUN__
  db  __RSPOP__
  db  __DSPUSH__
  db  __RSPUSH__
  db  __DEPTH__

.fnc:
    pop     ecx
    movzx   ecx, Byte [ecx+eax]
    add     ecx, ebp
    call    ecx
    jmp     short _save_eax_edx_stack_up
.err:
    mov     edx, PICOVM_ERR_UNKNOWNFNC
    jmp     short __RSPUSH__.err

__RSPUSH__:
    pusha
    mov     esi, edx
    call    __DEPTH__
    movzx   ecx, [ebx+PICOVM_CONTEXT._rstack_size]
    cmp     edx, ecx
    jb      .ok
    mov     edx, PICOVM_ERR_RSOVERFLOW
.err:
    stc
.up:
    mov     eax, edx
    jmp     short _save_eax_edx_stack_up
.ok: 
    mov     ecx, [ebx+PICOVM_CONTEXT._rstack_top]
    mov     [ecx], esi
    add     [ebx+PICOVM_CONTEXT._rstack_top], 0x4
    xor     edx, edx
    clc
    jmp     short .up

__RSPOP__:
    pusha
    call    __DEPTH__
    test    edx, edx
    jnz     .ok
    mov     edx, PICOVM_ERR_RSUNDERFLOW
    jmp     short __RSPUSH__.err
.ok: 
    mov     ecx, [ebx+PICOVM_CONTEXT._rstack_top]
    mov     eax, [ecx-0x4]
    sub     [ebx+PICOVM_CONTEXT._rstack_top], 0x4
    xor     edx, edx
    clc
_save_eax_edx_stack_up:
    jmp     short _save_eax_edx_stack

__DSPOP__:
    xor     edx, edx
    xor     eax, eax
    inc     eax
    call    __DSCheckInpOutp__
    jc      .err
    mov     ecx, [ebx+PICOVM_CONTEXT._dstack_top]
    mov     eax, [ecx-0x4]
    sub     [ebx+PICOVM_CONTEXT._dstack_top], 0x4
    clc
    ret
.err:
    xchg    edx, eax
    xor     eax, eax
    stc
    ret

__RUN__:
    test    edx, edx
    jz      .up
    mov     [ebx+PICOVM_CONTEXT._instruction_pointer], edx
.up:
    mov     edx, [ebx+PICOVM_CONTEXT._instruction_pointer]
    cmp     Byte [edx], PICOVM_HLT_OPCODE
    jz      .ok
    call    __STEP__
;    pushf
;    pusha
;    call    __DEPTH__
;    popa
;    popf
    jnc     .up
    ret
.ok:      
    xchg    edx, eax
    xor     eax, eax
    ret

__DSPUSH__:
    xor     eax, eax
    inc     ah
    call    __DSCheckInpOutp__
    jnc     .ok
    mov     eax, edx
    ret
.ok:
    mov     ecx, [ebx+PICOVM_CONTEXT._dstack_top]
    mov     DWord [ecx], edx
    add     [ebx+PICOVM_CONTEXT._dstack_top], 0x4
    xor     edx, edx
    ret

__DEPTH__:
    pusha
    mov     eax, [ebx+PICOVM_CONTEXT._dstack_top]
    mov     edx, [ebx+PICOVM_CONTEXT._rstack_top]
    sub     eax, [ebx+PICOVM_CONTEXT._dstack_begin]
    shr     eax, 0x2
    sub     edx, [ebx+PICOVM_CONTEXT._rstack_begin]
    shr     edx, 0x2
    clc
_save_eax_edx_stack:
    mov     DWord [esp+0x14], edx
_save_eax_stack:
    mov     DWord [esp+0x1C], eax
    popa
    ret

__STEP__:
    pusha
    xor     eax, eax
    push    eax
    mov     esi, [ebx+PICOVM_CONTEXT._instruction_pointer]
    lea     edi, [ebp+cmdsTable]
    movzx   ecx, Byte [esi]
    mov     eax, ecx
    shl     eax, 0x1
    add     edi, eax
    push    edi
    movzx   eax, Byte [edi]
    and     al,  0x3F
    shl     eax, 0x3
    shr     al,  0x6
    call    __DSCheckInpOutp__
    jc      .err
    movzx   eax, Word [edi]
    shr     eax, 0x6
    add     eax, ebp
    add     eax, __COMMANDS_BEGIN__
    push    ebp
    add     DWord [esp], __STEP__.return
    push    eax
    mov     edi, [ebx+PICOVM_CONTEXT._dstack_top]
    mov     edx, DWord [edi-0x8]
    mov     eax, DWord [edi-0x4]
    ret
.return:
    pop     edx
    mov     eax, DWord [esp]
    test    eax, eax
    jnz     short .err
    mov     ebx, DWord [esp+0x14]
    movzx   edx, Byte [edx]
    and     edx, 0x7
    jz      short .end
    mov     esi, [ebx+PICOVM_CONTEXT._instruction_pointer]
    add     esi, edx
    xor     edx, edx
    jmp     short .end
.err:
    xchg    edx, eax
    xchg    eax, esi
    stc
.end:
    mov     eax, esi
    pop     ecx
    mov     [ebx+PICOVM_CONTEXT._dstack_top], edi
    mov     [ebx+PICOVM_CONTEXT._instruction_pointer], esi
_save_eax_edx_stack_down:
    jmp     short _save_eax_edx_stack

__DSCheckInpOutp__:
    pusha
    xor     edi, edi
    mov     edx, eax
    shr     edx, 0x8
    xchg    esi, eax
    and     esi, 0xff
    call    __DEPTH__
    cmp     eax, esi
    jnl     .outp
    dec     edi
    jmp     short .err
.outp:
    movzx   esi, Byte [ebx+PICOVM_CONTEXT._dstack_size]
    sub     esi, eax
    cmp     esi, edx
    jnl     .ok
    dec     edi
    dec     edi
.err:
    stc
    jmp     short .end
.ok:
    clc
.end:
    xchg    edi, eax
    jmp     _save_eax_stack
__COMMANDS_BEGIN__:

_calln_:
    call    eax
    ret

;_mrtd_:
;    call    _crtd_
;    sub     [ebx + PICOVM_CONTEXT._rstack_top], 0x4
;    ret

_stored_:
    mov     [eax], edx
_drop2:
    sub     edi, 0x8
    ret

_storew_:
    mov     Word [eax], dx
    jmp     short _drop2

_storeb_:
    mov     Byte [eax], dl
    jmp     short _drop2

_jmpa_:
    mov     esi, eax
    jmp     short _drop_

_jmpr_:
    add     esi, eax
    jmp     short _drop_

_jmpc_:
    test    edx, edx
    jnz     short _jmpc_not
    add     esi, eax
    jmp     short _drop2

_jmpc_not:
    inc     esi
    jmp     short _drop2

_over_:
    xchg    ecx, edx
;    jmp     short _save_ecx_up1

;_depthr_:
;    call    __DEPTH__
;    xchg    edx, eax
;    jmp     short _save_ecx_up1

;_depthd_:
;    call    __DEPTH__
;    xchg    ecx, eax
_save_ecx_up1:
    mov     [edi], ecx
    add     edi, 0x4
    ret

_loadcb_:
    movzx   ecx, Byte [esi+0x1]
    jmp     short _save_ecx_up1
_loadcw_:
    movzx   ecx, Word [esi+0x1]
    jmp     short _save_ecx_up1
_loadcd_:
    mov     ecx, [esi+0x1]
    jmp     short _save_ecx_up1

_dup_:
    xchg    ecx, eax
    jmp     short _save_ecx_up1

_drop_:

    sub    edi, 0x4
    ret

;_mdtr_:
;    call    _cdtr_
;    jmp     short _drop_

_calla_:
    mov     ecx, eax
    mov     edx, esi
    inc     edx
    call    __RSPUSH__
    jc      _err_edx
    mov     esi, ecx
    jmp     short _drop_

_callr_:
    mov     ecx, eax
    mov     edx, esi
    inc     edx
    call    __RSPUSH__
    jc      _err_edx
    add     esi, ecx
    jmp     short _drop_

_mod_:
    mov     ecx, eax
    xchg    eax, edx
    xor     edx, edx
    div     ecx
_save_edx_down1:
    mov     [edi-0x8], edx
    jmp     short _drop_

_above_:
    xor     ecx, ecx
    cmp     eax, edx
    ja      short _save_ecx_down1
    dec     ecx
_save_ecx_down1:
    mov     [edi-0x8], ecx
    jmp     short _drop_

_below_:
    xor     ecx, ecx
    cmp     eax, edx
    jb      short _save_ecx_down1
    dec     ecx
    jmp     short _save_ecx_down1

_add_:
    add     eax, edx
    jmp     short _save_eax_down1

_sub_:
    sub     edx, eax
    jmp     short _save_edx_down1

_mul_:
    mul     edx
    jmp     short _save_eax_down1

_xor_:
    xor     eax, edx
    jmp     short _save_eax_down1

_shr_:
    xchg    eax, edx
    xchg    ecx, edx
    shr     eax, cl
    jmp     short _save_eax_down1

_ror_:
    xchg    eax, edx
    xchg    ecx, edx
    ror     eax, cl
    jmp     short _save_eax_down1

_shl_:
    xchg    eax, edx
    xchg    ecx, edx
    shl     eax, cl
    jmp     short _save_eax_down1

_eq_:
    xor     ecx, ecx
    cmp     eax, edx
    jnz     _save_ecx_down1
    dec     ecx
    jmp     short _save_ecx_down1

;_sar_:
;    xchg    eax, ecx
;    sar     edx, cl
;    xchg    edx, eax
;    jmp     short _save_eax_down1

_not_:
    not     eax
    jmp     short _save_eax

_rot_:
    mov     ecx, [edi-0xC]
    mov     [edi-0xC], edx
    mov     [edi-0x8], eax
_save_ecx_d:
    mov     [edi-0x4], ecx
    ret

;_sal_:
;    xchg    eax, ecx
;    sal     edx, cl
;    xchg    edx, eax
;    jmp     short _save_eax_down1

;_neg_:
;    neg     eax
;    jmp     short _save_eax

_div_:
    mov     ecx, eax
    xchg    eax, edx
    xor     edx, edx
    div     ecx
_save_eax_down1:
    mov     [edi-0x8], eax
    jmp     _drop_

_rol_:
    xchg    eax, edx
    xchg    ecx, edx
    rol     eax, cl
    jmp     short _save_eax_down1

_and_:
    and     eax, edx
    jmp     short _save_eax_down1

_or_:
    or      eax, edx
    jmp     short _save_eax_down1

_swap_:
    xchg    eax, edx
_save_eax_edx:
    mov     [edi-0x8], edx
_save_eax:
    xchg    ecx, eax
    jmp     short _save_ecx
_fetchb_:
    movzx   eax, Byte [eax]
    jmp     short _save_eax

_fetchw_:
    movzx   eax, Word [eax]
    jmp     short _save_eax
_fetchd_:
    mov     eax, [eax]
    jmp     short _save_eax

;_esb_:
;    cbw
;_esw_:
;    cwde
;    jmp     short _save_eax

_save_ecx:
    mov     [edi-0x4], ecx
    ret

_pick_:
    inc     eax
    inc     eax
    mov     edx, eax
    call    __DSCheckInpOutp__
    jc      _err_
    shl     edx, 0x2
    mov     eax, edi
    sub     eax, edx
    push    DWord [eax]
    pop     DWord [edi-0x4]
    ret

_roll_:
    mov     edx, eax
    inc     eax
    inc     eax
    call    __DSCheckInpOutp__
    jc      _err_
    pusha
    mov     ecx, edx
    xchg    esi, edi
    mov     ebx, ecx
    inc     ebx
    shl     ebx, 0x2
    sub     esi, ebx
    lea     edi, [esi-0x4]
    push    DWord [edi]
    cld
    rep     movsd
    pop     DWord [edi]
    popa
    sub     edi, 0x4
    ret

_drop_d:
    sub     edi, 0x4
    ret

_ret_:
    call    __RSPOP__
    jc      _err_edx
    mov     esi, eax
    ret

;_cdtr_:
;    mov     edx, eax
;    call    __RSPUSH__
;    jc      short _err_edx
;    ret

;_crtd_:
;    mov    edx, [ebx + PICOVM_CONTEXT._rstack_top]
;    mov    eax, [ebx + PICOVM_CONTEXT._rstack_begin]
;    cmp    edx, eax
;    jbe    .err
;    mov    ecx, [edx-0x4]
;    jmp    _save_ecx_up1
;.err:
;    mov    eax, PICOVM_ERR_RSUNDERFLOW
;    jmp    _err_
_err_edx:
    xchg   eax, edx
_err_:
    mov     [esp+0x8], eax
    ret


cmdsTable:
 PICOVM_COMMAND_ENTRY _add_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _pick_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _not_, 0x1, 0x1, 0x0
 PICOVM_COMMAND_ENTRY _storew_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _loadcw_, 0x3, 0x0, 0x1
 PICOVM_COMMAND_ENTRY _and_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _over_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _dup_, 0x1, 0x1, 0x1
 PICOVM_COMMAND_ENTRY _loadcb_, 0x2, 0x0, 0x1
 PICOVM_COMMAND_ENTRY _xor_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _roll_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _calln_, 0x0, 0x1, 0x0
 PICOVM_COMMAND_ENTRY _loadcd_, 0x5, 0x0, 0x1
 PICOVM_COMMAND_ENTRY _calla_, 0x0, 0x1, 0x0
 PICOVM_COMMAND_ENTRY _jmpr_, 0x0, 0x1, 0x0
 PICOVM_COMMAND_ENTRY _shr_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _below_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _shl_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _fetchd_, 0x1, 0x1, 0x0
 PICOVM_COMMAND_ENTRY _sub_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _rot_, 0x1, 0x3, 0x0
 PICOVM_COMMAND_ENTRY _ret_, 0x0, 0x0, 0x0
 PICOVM_COMMAND_ENTRY _stored_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _drop_, 0x1, 0x1, 0x0
 PICOVM_COMMAND_ENTRY _or_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _ror_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _eq_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _rol_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _above_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _swap_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _callr_, 0x0, 0x1, 0x0
 PICOVM_COMMAND_ENTRY _fetchw_, 0x1, 0x1, 0x0
 PICOVM_COMMAND_ENTRY _mod_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _storeb_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _jmpc_, 0x0, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _div_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _mul_, 0x1, 0x2, 0x0
 PICOVM_COMMAND_ENTRY _fetchb_, 0x1, 0x1, 0x0
 PICOVM_COMMAND_ENTRY _jmpa_, 0x0, 0x1, 0x0

Характеристики віртуальної машини зберігаються у JSON форматі в файлі picovm.settings.json

{"date":null,"cmds":["add","pick","not","storew","loadcw","and","over","dup","loadcb","xor","roll","calln","loadcd","calla","jmpr","shr","below","shl","fetchd","sub","rot","ret","stored","drop","or","ror","eq","rol","above","swap","callr","fetchw","mod","storeb","jmpc","div","mul","fetchb","jmpa"],"consts":["STEP","DSPOP","RUN","RSPOP","DSPUSH","RSPUSH","DEPTH"]}

Приклади використання (як закінчені приклади, так і окремі функції)

Для скорочення джерельного коду я використовую такий макрос

macro @ cmd, p {
 PICOVM_CMD cmd, p
}

Функція розкодування BASE85 з довільною абеткою:

; BASE85
;[pAlphabet, pSrc, pDst, Size]
BASE85:
@ _DUP
@ _LOADCW, 0x0
@ _EQ
@ _NOT
@ _LOADCD, .Down-.toDown
.toDown:
@ _JMPC
@ _LOADCB, 0x5
@ _SUB
@ _ROT
;[pAlphabet, pDst, Size, pSrc]
@ _LOADCW, 0x3
@ _PICK
;[pAlphabet, pDst, Size, pSrc, pAlphabet]
@ _SWAP
;[pAlphabet, pDst, Size, pAlphabet, pSrc]
@ _LOADCD, DECODE_DWORD-.toDecodeDWord
.toDecodeDWord:
@ _CALLR
;[pAlphabet, pDst, Size, pSrc, DW]
@ _LOADCW, 0x3
@ _PICK
;[pAlphabet, pDst, Size, pSrc, DW, pDst]
@ _STORED
;[pAlphabet, pDst, Size, pSrc]
@ _ROT
;[pAlphabet, Size, pSrc, pDst]
@ _LOADCD, 0x4
@ _ADD
@ _ROT
;[pAlphabet, pSrc, pDst, Size]
@ _LOADCD, BASE85-.toUp
.toUp:
@ _JMPR
.Down:
@ _DROP
@ _DROP
@ _DROP
@ _DROP
@ _RET

;[pAlphabet, pSrc] => [pSrc, DW]
DECODE_DWORD:
@ _LOADCB, 0
@ _OVER
@ _FETCHB
;[pAlphabet, pSrc, 0, [pSrc]]
@ _LOADCW, 0x3
@ _PICK
@ _SWAP
;[pAlphabet, pSrc, 0, Alphabet, [pSrc]]
@ _LOADCD, SEARCHB -.toSearchB1
.toSearchB1:
@ _CALLR
@ _ADD
@ _SWAP
@ _LOADCW, 0x1
@ _ADD
@ _SWAP
@ _OVER
@ _FETCHB
@ _LOADCD, 0x3
@ _PICK
@ _SWAP
@ _LOADCD, SEARCHB -.toSearchB2
.toSearchB2:
@ _CALLR
@ _LOADCB, 0x55
@ _MUL
@ _ADD
@ _SWAP
@ _LOADCB, 0x1
@ _ADD
@ _SWAP
@ _OVER
@ _FETCHB
@ _LOADCD, 0x3
@ _PICK
@ _SWAP
@ _LOADCD, SEARCHB -.toSearchB3
.toSearchB3:
@ _CALLR
@ _LOADCW, 85*85
@ _MUL
@ _ADD
@ _SWAP
@ _LOADCB, 0x1
@ _ADD
@ _SWAP
@ _OVER
@ _FETCHB
@ _LOADCD, 0x3
@ _PICK
@ _SWAP
@ _LOADCD, SEARCHB -.toSearchB4
.toSearchB4:
@ _CALLR
@ _LOADCD, 85*85*85
@ _MUL
@ _ADD
@ _SWAP
@ _LOADCW, 0x1
@ _ADD
@ _SWAP
@ _OVER
@ _FETCHB
@ _LOADCW, 0x3
@ _PICK
@ _SWAP
@ _LOADCD, SEARCHB -.toSearchB5
.toSearchB5:
@ _CALLR
@ _LOADCD, 85*85*85*85
@ _MUL
@ _ADD
@ _ROT
@ _DROP
@ _SWAP
@ _LOADCD, 0x1
@ _ADD
@ _SWAP
@ _RET

SEARCHB:
@ _OVER
@ _SWAP
.Up:
@ _OVER
@ _FETCHB
@ _OVER
;[pMem, pMem, bVal, [pMem], bVal]
@ _EQ
;[pMem, pMem, bVal, BOOL]
@ _NOT
@ _LOADCD, .Down-.toDown
.toDown:
@ _JMPC
@ _SWAP
@ _LOADCB, 0x1
@ _ADD
@ _SWAP
@ _LOADCD, .Up-.toUp
.toUp:
@ _JMPR
.Down:
@ _DROP
@ _SWAP
@ _SUB
@ _RET

Знаходження послідовності Фібоначчі

Криптографічна функція RC4

; [lpBuf, lpKey, dwBufLen, dwKeyLen, pS]
RC4:
@ _LOADCB, 0 ;B
@ _DUP ;A
@ _ROT
@ _SWAP
.for1_up:
@ _DUP
@ _LOADCW, 0x100;
@ _EQ
@ _NOT
@ _LOADCD, .for1_down-.tofor1_down
.tofor1_down:
@ _JMPC
@ _OVER
@ _OVER
@ _ADD
@ _OVER
@ _SWAP
@ _STOREB
@ _LOADCB, 0x1                           
@ _ADD
@ _LOADCD, .for1_up-.tofor1_up
.tofor1_up:
@ _JMPR
.for1_down:
@ _DROP
@ _LOADCB, 0x0
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0]
.for2_up:
@ _DUP
@ _LOADCW, 0x100
@ _EQ
@ _NOT
@ _LOADCD, .for2_down-.tofor2_down
.tofor2_down:
@ _JMPC
@ _OVER
@ _OVER
@ _ADD
@ _FETCHB
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0, pS[A]]
@ _LOADCB, 0x3
@ _PICK
@ _ADD 
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0, pS[A]+B]
@ _OVER
@ _LOADCB, 0x5
@ _PICK
@ _MOD
@ _LOADCB, 0x7
@ _PICK
@ _ADD
@ _FETCHB
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0, pS[A]+B, lpKey [A % dwKeyLen]]
@ _ADD
@ _LOADCB, 0xFF
@ _AND
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A=0, pS[A]+B+lpKey [A % dwKeyLen]]
@ _LOADCB, 0x3
@ _ROLL
@ _DROP
;[lpBuf, lpKey, dwBufLen, dwKeyLen, pS, A, B]
@ _ROT
;[lpBuf, lpKey, dwBufLen, dwKeyLen, A, B, pS]
@ _ROT
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A]
@ _OVER
@ _OVER
@ _ADD
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A, pS+A]
@ _LOADCB, 0x2
@ _PICK
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A, pS+A, pS]
@ _LOADCB, 0x4
@ _PICK
@ _ADD
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A, pS+A, pS+B]
@ _OVER
@ _FETCHB
@ _OVER
@ _FETCHB
@ _SWAP
@ _ROT
@ _STOREB
@ _SWAP
@ _STOREB
@ _LOADCB, 0x1
@ _ADD
@ _LOADCD, .for2_up-.tofor2_up
.tofor2_up:
@ _JMPR
.for2_down:
;[lpBuf, lpKey, dwBufLen, dwKeyLen, B, pS, A]
@ _ROT
;[lpBuf, lpKey, dwBufLen, dwKeyLen, pS, A, B]
@ _LOADCB, 0x3
@ _ROLL
@ _DROP
;[lpBuf, lpKey, dwBufLen, pS, A, B]
@ _LOADCB, 0x4
@ _ROLL
@ _DROP
@ _SWAP
;[lpBuf, dwBufLen, pS, B, A]
.for3_up:
@ _LOADCB, 0x3
@ _ROLL
@ _DUP
;[lpBuf, pS, B, A, dwBufLen, dwBufLen]
@ _LOADCD, .for3_down-.tofor3_down
.tofor3_down:
@ _JMPC
@ _LOADCB, 0x1
@ _SUB
;[lpBuf, pS, B, A, dwBufLen]
@ _SWAP
@ _LOADCB, 0x1
@ _ADD
@ _LOADCB, 0xFF
@ _AND
;[lpBuf, pS, A, dwBufLen, (A+1)%255]
@ _ROT
;[lpBuf, pS, dwBufLen, (A+1)%255, B]
@ _OVER
@ _LOADCB, 0x4
@ _PICK
@ _ADD
@ _FETCHB
@ _ADD
@ _LOADCB, 0xFF
@ _AND
@ _OVER
@ _OVER
@ _LOADCB, 0x5
@ _PICK
@ _ADD
@ _SWAP
@ _LOADCB, 0x5
@ _PICK
@ _ADD
@ _OVER
@ _OVER
;
@ _OVER
@ _FETCHB
@ _OVER
@ _FETCHB
@ _SWAP
@ _ROT
@ _STOREB
@ _SWAP
@ _STOREB
;
@ _FETCHB
@ _SWAP
@ _FETCHB
@ _ADD
@ _LOADCB, 0xFF
@ _AND
@ _LOADCB, 0x4
@ _PICK
@ _ADD
@ _FETCHB
@ _LOADCB, 0x5
@ _PICK
@ _FETCHB
@ _XOR
@ _LOADCB, 0x5
@ _PICK
@ _STOREB
@ _LOADCB, 0x4
@ _ROLL
@ _LOADCB, 0x1
@ _ADD
@ _ROT
@ _ROT
@ _LOADCB, 0x4
@ _ROLL
@ _LOADCB, 0x4
@ _ROLL
@ _LOADCB, 0x3
@ _ROLL
@ _LOADCB, 0x3
@ _ROLL
@ _LOADCB, 0x3
@ _ROLL
@ _ROT
@ _ROT
@ _SWAP
@ _LOADCD, .for3_up-.tofor3_up
.tofor3_up:
@ _JMPR
.for3_down:
@ _DROP
@ _DROP
@ _DROP
@ _DROP
@ _DROP
@ _RET

Як сказано вище, кожна віртуальна машина створюється генератором і є неповторною. Це зроблено з метою ускладнити життя антивірусним аналітикам. В ідеалі для кожного пакованого (криптованого) файла має бути унікальна сигнатура, притаманна лише йому.

Джерельний код генератора віртуальних машин на NODE JS

picovm.js

var _ = require ('underscore');
var fs = require ('fs');

Number.prototype.toHex = function() {
    return('0x'+this.toString(16).toUpperCase());};

var fncs = ['RUN', 'STEP', 'DEPTH', 'RSPOP', 'RSPUSH', 'DSPOP', 'DSPUSH'];
var cmds_array = [];
var picovm_inc_end = '\
PICOVM_ERR_NONE          equ  0\n\
PICOVM_ERR_DSOVERFLOW    equ -1\n\
PICOVM_ERR_DSUNDERFLOW   equ -2\n\
PICOVM_ERR_RSOVERFLOW    equ -4\n\
PICOVM_ERR_RSUNDERFLOW   equ -5\n\
PICOVM_ERR_UNKNOWNFNC    equ -6\n\
PICOVM_ERR_UNKNOWNCMD    equ -7\n\n\
macro PICOVM_CMD cmd, n {\n\
  if cmd eq _LOADCW\n\
    db PICOVM##cmd##_OPCODE\n\
    dw n and 0xffff\n\
  else if cmd eq _LOADCD\n\
    db PICOVM##cmd##_OPCODE\n\
    dd n and 0xffffffff\n\
  else if cmd eq _LOADCB\n\
    db PICOVM##cmd##_OPCODE\n\
    db n and 0xff\n\
  else\n\
    db PICOVM##cmd##_OPCODE\n\
  end if\n\
}\n\n\
macro PICOVM_COMMAND_ENTRY link, sz, dsinp, dsoutp {\n\
  dw ((link-__COMMANDS_BEGIN__) shl 0x6) + (sz and 0x7) + ((dsinp and 0x3) shl 0x3) + ((dsoutp and 0x1) shl 0x5)\n\
}\n\n';

var picovm_asm_begin = 'format binary\n\
use32\n\
org 0x0\n\n\
include \'%FASMINC%\\WIN32A.INC\'\n\
include \'picovm.inc\'\n\n\
__VM_BEGIN__:\n\
    pusha\n\
    call    .delta\n\
.delta:\n\
    sub     DWord [esp], __VM_BEGIN__.delta - __VM_BEGIN__\n\
    pop     ebp\n\
    cmp     eax, 0x6\n\
    ja     .err\n\
    call    .fnc\n';

var picovm_asm_body = '.fnc:\n\
    pop     ecx\n\
    movzx   ecx, Byte [ecx+eax]\n\
    add     ecx, ebp\n\
    call    ecx\n\
    jmp     short _save_eax_edx_stack_up\n\
.err:\n\
    mov     edx, PICOVM_ERR_UNKNOWNFNC\n\
    jmp     short __RSPUSH__.err\n\n\
__RSPUSH__:\n\
    pusha\n\
    mov     esi, edx\n\
    call    __DEPTH__\n\
    movzx   ecx, [ebx+PICOVM_CONTEXT._rstack_size]\n\
    cmp     edx, ecx\n\
    jb      .ok\n\
    mov     edx, PICOVM_ERR_RSOVERFLOW\n\
.err:\n\
    stc\n\
.up:\n\
    mov     eax, edx\n\
    jmp     short _save_eax_edx_stack_up\n\
.ok: \n\
    mov     ecx, [ebx+PICOVM_CONTEXT._rstack_top]\n\
    mov     [ecx], esi\n\
    add     [ebx+PICOVM_CONTEXT._rstack_top], 0x4\n\
    xor     edx, edx\n\
    clc\n\
    jmp     short .up\n\n\
__RSPOP__:\n\
    pusha\n\
    call    __DEPTH__\n\
    test    edx, edx\n\
    jnz     .ok\n\
    mov     edx, PICOVM_ERR_RSUNDERFLOW\n\
    jmp     short __RSPUSH__.err\n\
.ok: \n\
    mov     ecx, [ebx+PICOVM_CONTEXT._rstack_top]\n\
    mov     eax, [ecx-0x4]\n\
    sub     [ebx+PICOVM_CONTEXT._rstack_top], 0x4\n\
    xor     edx, edx\n\
    clc\n\
_save_eax_edx_stack_up:\n\
    jmp     short _save_eax_edx_stack\n\n\
__DSPOP__:\n\
    xor     edx, edx\n\
    xor     eax, eax\n\
    inc     eax\n\
    call    __DSCheckInpOutp__\n\
    jc      .err\n\
    mov     ecx, [ebx+PICOVM_CONTEXT._dstack_top]\n\
    mov     eax, [ecx-0x4]\n\
    sub     [ebx+PICOVM_CONTEXT._dstack_top], 0x4\n\
    clc\n\
    ret\n\
.err:\n\
    xchg    edx, eax\n\
    xor     eax, eax\n\
    stc\n\
    ret\n\n\
__RUN__:\n\
    test    edx, edx\n\
    jz      .up\n\
    mov     [ebx+PICOVM_CONTEXT._instruction_pointer], edx\n\
.up:\n\
    mov     edx, [ebx+PICOVM_CONTEXT._instruction_pointer]\n\
    cmp     Byte [edx], PICOVM_HLT_OPCODE\n\
    jz      .ok\n\
    call    __STEP__\n\
;    pushf\n\
;    pusha\n\
;    call    __DEPTH__\n\
;    popa\n\
;    popf\n\
    jnc     .up\n\
    ret\n\
.ok:      \n\
    xchg    edx, eax\n\
    xor     eax, eax\n\
    ret\n\n\
__DSPUSH__:\n\
    xor     eax, eax\n\
    inc     ah\n\
    call    __DSCheckInpOutp__\n\
    jnc     .ok\n\
    mov     eax, edx\n\
    ret\n\
.ok:\n\
    mov     ecx, [ebx+PICOVM_CONTEXT._dstack_top]\n\
    mov     DWord [ecx], edx\n\
    add     [ebx+PICOVM_CONTEXT._dstack_top], 0x4\n\
    xor     edx, edx\n\
    ret\n\n\
__DEPTH__:\n\
    pusha\n\
    mov     eax, [ebx+PICOVM_CONTEXT._dstack_top]\n\
    mov     edx, [ebx+PICOVM_CONTEXT._rstack_top]\n\
    sub     eax, [ebx+PICOVM_CONTEXT._dstack_begin]\n\
    shr     eax, 0x2\n\
    sub     edx, [ebx+PICOVM_CONTEXT._rstack_begin]\n\
    shr     edx, 0x2\n\
    clc\n\
_save_eax_edx_stack:\n\
    mov     DWord [esp+0x14], edx\n\
_save_eax_stack:\n\
    mov     DWord [esp+0x1C], eax\n\
    popa\n\
    ret\n\n\
__STEP__:\n\
    pusha\n\
    xor     eax, eax\n\
    push    eax\n\
    mov     esi, [ebx+PICOVM_CONTEXT._instruction_pointer]\n\
    lea     edi, [ebp+cmdsTable]\n\
    movzx   ecx, Byte [esi]\n\
    mov     eax, ecx\n\
    shl     eax, 0x1\n\
    add     edi, eax\n\
    push    edi\n\
    movzx   eax, Byte [edi]\n\
    and     al,  0x3F\n\
    shl     eax, 0x3\n\
    shr     al,  0x6\n\
    call    __DSCheckInpOutp__\n\
    jc      .err\n\
    movzx   eax, Word [edi]\n\
    shr     eax, 0x6\n\
    add     eax, ebp\n\
    add     eax, __COMMANDS_BEGIN__\n\
    push    ebp\n\
    add     DWord [esp], __STEP__.return\n\
    push    eax\n\
    mov     edi, [ebx+PICOVM_CONTEXT._dstack_top]\n\
    mov     edx, DWord [edi-0x8]\n\
    mov     eax, DWord [edi-0x4]\n\
    ret\n\
.return:\n\
    pop     edx\n\
    mov     eax, DWord [esp]\n\
    test    eax, eax\n\
    jnz     short .err\n\
    mov     ebx, DWord [esp+0x14]\n\
    movzx   edx, Byte [edx]\n\
    and     edx, 0x7\n\
    jz      short .end\n\
    mov     esi, [ebx+PICOVM_CONTEXT._instruction_pointer]\n\
    add     esi, edx\n\
    xor     edx, edx\n\
    jmp     short .end\n\
.err:\n\
    xchg    edx, eax\n\
    xchg    eax, esi\n\
    stc\n\
.end:\n\
    mov     eax, esi\n\
    pop     ecx\n\
    mov     [ebx+PICOVM_CONTEXT._dstack_top], edi\n\
    mov     [ebx+PICOVM_CONTEXT._instruction_pointer], esi\n\
_save_eax_edx_stack_down:\n\
    jmp     short _save_eax_edx_stack\n\n\
__DSCheckInpOutp__:\n\
    pusha\n\
    xor     edi, edi\n\
    mov     edx, eax\n\
    shr     edx, 0x8\n\
    xchg    esi, eax\n\
    and     esi, 0xff\n\
    call    __DEPTH__\n\
    cmp     eax, esi\n\
    jnl     .outp\n\
    dec     edi\n\
    jmp     short .err\n\
.outp:\n\
    movzx   esi, Byte [ebx+PICOVM_CONTEXT._dstack_size]\n\
    sub     esi, eax\n\
    cmp     esi, edx\n\
    jnl     .ok\n\
    dec     edi\n\
    dec     edi\n\
.err:\n\
    stc\n\
    jmp     short .end\n\
.ok:\n\
    clc\n\
.end:\n\
    xchg    edi, eax\n\
    jmp     _save_eax_stack\n\
__COMMANDS_BEGIN__:\n\n\
_calln_:\n\
    call    eax\n\
    ret\n\n\
;_mrtd_:\n\
;    call    _crtd_\n\
;    sub     [ebx + PICOVM_CONTEXT._rstack_top], 0x4\n\
;    ret\n\n\
_stored_:\n\
    mov     [eax], edx\n\
_drop2:\n\
    sub     edi, 0x8\n\
    ret\n\n\
_storew_:\n\
    mov     Word [eax], dx\n\
    jmp     short _drop2\n\n\
_storeb_:\n\
    mov     Byte [eax], dl\n\
    jmp     short _drop2\n\n\
_jmpa_:\n\
    mov     esi, eax\n\
    jmp     short _drop_\n\n\
_jmpr_:\n\
    add     esi, eax\n\
    jmp     short _drop_\n\n\
_jmpc_:\n\
    test    edx, edx\n\
    jnz     short _jmpc_not\n\
    add     esi, eax\n\
    jmp     short _drop2\n\n\
_jmpc_not:\n\
    inc     esi\n\
    jmp     short _drop2\n\n\
_over_:\n\
    xchg    ecx, edx\n\
;    jmp     short _save_ecx_up1\n\n\
;_depthr_:\n\
;    call    __DEPTH__\n\
;    xchg    edx, eax\n\
;    jmp     short _save_ecx_up1\n\n\
;_depthd_:\n\
;    call    __DEPTH__\n\
;    xchg    ecx, eax\n\
_save_ecx_up1:\n\
    mov     [edi], ecx\n\
    add     edi, 0x4\n\
    ret\n\n\
_loadcb_:\n\
    movzx   ecx, Byte [esi+0x1]\n\
    jmp     short _save_ecx_up1\n\
_loadcw_:\n\
    movzx   ecx, Word [esi+0x1]\n\
    jmp     short _save_ecx_up1\n\
_loadcd_:\n\
    mov     ecx, [esi+0x1]\n\
    jmp     short _save_ecx_up1\n\n\
_dup_:\n\
    xchg    ecx, eax\n\
    jmp     short _save_ecx_up1\n\n\
_drop_:\n\n\
    sub    edi, 0x4\n\
    ret\n\n\
;_mdtr_:\n\
;    call    _cdtr_\n\
;    jmp     short _drop_\n\n\
_calla_:\n\
    mov     ecx, eax\n\
    mov     edx, esi\n\
    inc     edx\n\
    call    __RSPUSH__\n\
    jc      _err_edx\n\
    mov     esi, ecx\n\
    jmp     short _drop_\n\n\
_callr_:\n\
    mov     ecx, eax\n\
    mov     edx, esi\n\
    inc     edx\n\
    call    __RSPUSH__\n\
    jc      _err_edx\n\
    add     esi, ecx\n\
    jmp     short _drop_\n\n\
_mod_:\n\
    mov     ecx, eax\n\
    xchg    eax, edx\n\
    xor     edx, edx\n\
    div     ecx\n\
_save_edx_down1:\n\
    mov     [edi-0x8], edx\n\
    jmp     short _drop_\n\n\
_above_:\n\
    xor     ecx, ecx\n\
    cmp     eax, edx\n\
    ja      short _save_ecx_down1\n\
    dec     ecx\n\
_save_ecx_down1:\n\
    mov     [edi-0x8], ecx\n\
    jmp     short _drop_\n\n\
_below_:\n\
    xor     ecx, ecx\n\
    cmp     eax, edx\n\
    jb      short _save_ecx_down1\n\
    dec     ecx\n\
    jmp     short _save_ecx_down1\n\n\
_add_:\n\
    add     eax, edx\n\
    jmp     short _save_eax_down1\n\n\
_sub_:\n\
    sub     edx, eax\n\
    jmp     short _save_edx_down1\n\n\
_mul_:\n\
    mul     edx\n\
    jmp     short _save_eax_down1\n\n\
_xor_:\n\
    xor     eax, edx\n\
    jmp     short _save_eax_down1\n\n\
_shr_:\n\
    xchg    eax, edx\n\
    xchg    ecx, edx\n\
    shr     eax, cl\n\
    jmp     short _save_eax_down1\n\n\
_ror_:\n\
    xchg    eax, edx\n\
    xchg    ecx, edx\n\
    ror     eax, cl\n\
    jmp     short _save_eax_down1\n\n\
_shl_:\n\
    xchg    eax, edx\n\
    xchg    ecx, edx\n\
    shl     eax, cl\n\
    jmp     short _save_eax_down1\n\n\
_eq_:\n\
    xor     ecx, ecx\n\
    cmp     eax, edx\n\
    jnz     _save_ecx_down1\n\
    dec     ecx\n\
    jmp     short _save_ecx_down1\n\n\
;_sar_:\n\
;    xchg    eax, ecx\n\
;    sar     edx, cl\n\
;    xchg    edx, eax\n\
;    jmp     short _save_eax_down1\n\n\
_not_:\n\
    not     eax\n\
    jmp     short _save_eax\n\n\
_rot_:\n\
    mov     ecx, [edi-0xC]\n\
    mov     [edi-0xC], edx\n\
    mov     [edi-0x8], eax\n\
_save_ecx_d:\n\
    mov     [edi-0x4], ecx\n\
    ret\n\n\
;_sal_:\n\
;    xchg    eax, ecx\n\
;    sal     edx, cl\n\
;    xchg    edx, eax\n\
;    jmp     short _save_eax_down1\n\n\
;_neg_:\n\
;    neg     eax\n\
;    jmp     short _save_eax\n\n\
_div_:\n\
    mov     ecx, eax\n\
    xchg    eax, edx\n\
    xor     edx, edx\n\
    div     ecx\n\
_save_eax_down1:\n\
    mov     [edi-0x8], eax\n\
    jmp     _drop_\n\n\
_rol_:\n\
    xchg    eax, edx\n\
    xchg    ecx, edx\n\
    rol     eax, cl\n\
    jmp     short _save_eax_down1\n\n\
_and_:\n\
    and     eax, edx\n\
    jmp     short _save_eax_down1\n\n\
_or_:\n\
    or      eax, edx\n\
    jmp     short _save_eax_down1\n\n\
_swap_:\n\
    xchg    eax, edx\n\
_save_eax_edx:\n\
    mov     [edi-0x8], edx\n\
_save_eax:\n\
    xchg    ecx, eax\n\
    jmp     short _save_ecx\n\
_fetchb_:\n\
    movzx   eax, Byte [eax]\n\
    jmp     short _save_eax\n\n\
_fetchw_:\n\
    movzx   eax, Word [eax]\n\
    jmp     short _save_eax\n\
_fetchd_:\n\
    mov     eax, [eax]\n\
    jmp     short _save_eax\n\n\
;_esb_:\n\
;    cbw\n\
;_esw_:\n\
;    cwde\n\
;    jmp     short _save_eax\n\n\
_save_ecx:\n\
    mov     [edi-0x4], ecx\n\
    ret\n\n\
_pick_:\n\
    inc     eax\n\
    inc     eax\n\
    mov     edx, eax\n\
    call    __DSCheckInpOutp__\n\
    jc      _err_\n\
    shl     edx, 0x2\n\
    mov     eax, edi\n\
    sub     eax, edx\n\
    push    DWord [eax]\n\
    pop     DWord [edi-0x4]\n\
    ret\n\n\
_roll_:\n\
    mov     edx, eax\n\
    inc     eax\n\
    inc     eax\n\
    call    __DSCheckInpOutp__\n\
    jc      _err_\n\
    pusha\n\
    mov     ecx, edx\n\
    xchg    esi, edi\n\
    mov     ebx, ecx\n\
    inc     ebx\n\
    shl     ebx, 0x2\n\
    sub     esi, ebx\n\
    lea     edi, [esi-0x4]\n\
    push    DWord [edi]\n\
    cld\n\
    rep     movsd\n\
    pop     DWord [edi]\n\
    popa\n\
    sub     edi, 0x4\n\
    ret\n\n\
_drop_d:\n\
    sub     edi, 0x4\n\
    ret\n\n\
_ret_:\n\
    call    __RSPOP__\n\
    jc      _err_edx\n\
    mov     esi, eax\n\
    ret\n\n\
;_cdtr_:\n\
;    mov     edx, eax\n\
;    call    __RSPUSH__\n\
;    jc      short _err_edx\n\
;    ret\n\n\
;_crtd_:\n\
;    mov    edx, [ebx + PICOVM_CONTEXT._rstack_top]\n\
;    mov    eax, [ebx + PICOVM_CONTEXT._rstack_begin]\n\
;    cmp    edx, eax\n\
;    jbe    .err\n\
;    mov    ecx, [edx-0x4]\n\
;    jmp    _save_ecx_up1\n\
;.err:\n\
;    mov    eax, PICOVM_ERR_RSUNDERFLOW\n\
;    jmp    _err_\n\
_err_edx:\n\
    xchg   eax, edx\n\
_err_:\n\
    mov     [esp+0x8], eax\n\
    ret\n';

var macroparams = [];
var struc = 'struct PICOVM_CONTEXT\n';
picovm_struc = _.shuffle(
[['_dstack_top             dd ?', 'dstop'], 
 ['_dstack_begin           dd ?', 'dsb'],
 ['_rstack_top             dd ?', 'rstop'],
 ['_rstack_begin           dd ?', 'rsb'],
 ['_instruction_pointer    dd ?', 'ip'],
 ['_dstack_size            db ?', 'dssz'],
 ['_rstack_size            db ?', 'rssz']]);
//picovm_struc+='';
_.each(picovm_struc, function (a){ 
  struc+=a[0]+'\n'; 
  macroparams.push(a[1]);
}, this);
struc+='\nends';
var macro = 'macro PICOVM_CTX ip, dssz, rssz, rstop, dstop, rsb, dsb {  PICOVM_CONTEXT '+ macroparams.join(', ')+' }\n';
var cmds = [
['fetchb', 0x1, 0x1, 0x0],    
['fetchw', 0x1, 0x1, 0x0],
['fetchd', 0x1, 0x1, 0x0],
['storeb', 0x1, 0x2, 0x0],
['storew', 0x1, 0x2, 0x0],
['stored', 0x1, 0x2, 0x0],
['not', 0x1, 0x1, 0x0],
['or', 0x1, 0x2, 0x0],
['and', 0x1, 0x2, 0x0],
['xor', 0x1, 0x2, 0x0],
['loadcb', 0x2, 0x0, 0x1],
['loadcw', 0x3, 0x0, 0x1],
['loadcd', 0x5, 0x0, 0x1],
['rol', 0x1, 0x2, 0x0],
['ror', 0x1, 0x2, 0x0],
['shl', 0x1, 0x2, 0x0],
['shr', 0x1, 0x2, 0x0],
['eq',  0x1, 0x2, 0x0],
['above', 0x1, 0x2, 0x0],
['below', 0x1, 0x2, 0x0],
['drop',0x1, 0x1, 0x0],
['swap',0x1, 0x2, 0x0],
['over',0x1, 0x2, 0x0],
['pick',0x1, 0x2, 0x0],
['roll',0x1, 0x2, 0x0],
['add', 0x1, 0x2, 0x0],
['sub', 0x1, 0x2, 0x0],
['mul', 0x1, 0x2, 0x0],
['div', 0x1, 0x2, 0x0],
['mod', 0x1, 0x2, 0x0],
['rot', 0x1, 0x3, 0x0],
['dup', 0x1, 0x1, 0x1],
['jmpr', 0x0, 0x1, 0x0],
['jmpa', 0x0, 0x1, 0x0],
['jmpc', 0x0, 0x2, 0x0],
['calla', 0x0, 0x1, 0x0],
['callr', 0x0, 0x1, 0x0],
['calln', 0x0, 0x1, 0x0],
['ret', 0x0, 0x0, 0x0]];

fncs=_.shuffle(fncs);
cmds=_.shuffle(cmds);
var vmconst = [];
var fncs_inc = '';
var fncs_asm = '';
var cmds_inc = '';
var cmds_asm = 'cmdsTable:\n';
var i = 0;
_.each (fncs, function(a) { fncs_inc += 'PICOVM_FNC_'+a+' = '+i+'\n'; fncs_asm += '  db  __'+a+'__\n'; i++;}, this);
i = 0;
_.each (cmds, function(a) { 
    cmds_inc += 'PICOVM_'+a[0].toUpperCase()+'_OPCODE equ '+i.toHex()+'\n'; 
    cmds_asm += ' PICOVM_COMMAND_ENTRY _'+a[0]+'_, '+a[1].toHex()+', '+a[2].toHex()+', '+a[3].toHex()+'\n';
    i++;}, this);
cmds_inc += 'PICOVM_HLT_OPCODE equ 0xFF\n';
var picovm_asm = picovm_asm_begin +'\n'+fncs_asm +'\n'+ picovm_asm_body + '\n\n'+cmds_asm;
var picovm_inc = struc +'\n'+macro+'\n'+fncs_inc +'\n' + cmds_inc +'\n' + picovm_inc_end;
var settings = JSON.stringify({date: null, cmds: _.pluck(cmds, 0), consts: fncs});
fs.writeFile(process.argv[2]+'\\picovm.settings.json', settings);
fs.writeFile(process.argv[2]+'\\picovm.asm', picovm_asm);
fs.writeFile(process.argv[2]+'\\picovm.inc', picovm_inc);

Буду поторхи правити код, дописувати доки і викладати приклади використання.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: 0x9111A, Kane, anakin, leofun01, Betterthanyou5

2

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

шукати зайві байти?  :)

Maybe a = Just a | Nothing

3 Востаннє редагувалося 0xDADA11C7 (20.09.2014 16:28:45)

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Не паліть контору (тиждень чи два), краще викладіть пошук послідовності Фібоначчі саме для цієї ВМ.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»

4 Востаннє редагувалося 0x9111A (20.09.2014 22:37:12)

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Числа Фібоначчі це послідовність де перші два елементи це 1, 1 а кожен наступний дорівнює сумі двох попередніх. (Зараз інколи беруть 0 як нульовий елемент послідовності)
Власне послідовність:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55..

algorythm.inc

@ _LOADCD, 1
@ _DUP
@ _LOADCD, fibo
@ _STORED
@ _LOADCD, fibo
@ _LOADCD, 4
@ _ADD
@ _DUP
@ _ROT
@ _ROT
@ _STORED
@ _LOADCD, 1
@ _LOADCD, 1
;[addr, 1, 1]
_calc:
@ _DUP
@ _ROT
@ _ADD
;[addr, k, k+1]
@ _ROT
@ _DUP
@ _DUP
@ _LOADCD, fibo_end 
;[k, k+1, addr, addr, addr_end]
@ _EQ
@ _NOT
@ _LOADCD, _end - _nend
_nend:
@ _JMPC
@ _DROP
@ _LOADCD, 4
@ _ADD
@ _ROT
@ _ROT
;[addr, k-1, k]
@ _DUP
@ _LOADCD, 3
@ _PICK
@ _STORED
;[addr, k-1, k] (k saved)
@ _LOADCD, _calc
@ _JMPA
_end:
@ _HLT

fibo.asm

; Приклад використання ВМ пана 0xDADA11C7
; Виводить перші 10 чисел Фібоначі

format PE console

include '%FASM%\INCLUDE\win32a.inc'
include 'picovm.inc'
entry start

macro @ cmd, p {
 PICOVM_CMD cmd, p
}

section '.data' data readable writeable

;Рядки для форматування виводу (printf)
fibo_str db "Fibonachi : ",0
pr_form db "%d ",0

;Розмір стеків для ВМ. Стек викликів і стек данних
vm_rstack_size = 20h
vm_dstack_size = 20h

;Структура для ініціалізації ВМ (див. picovm.inc)
VM_SET PICOVM_CONTEXT vm_rstack, vm_dstack_size, vm_dstack, vm_rstack_size, vm_rstack, vm_dstack, 0

;Виділення пам*яті для ВМ
vm_rstack dd vm_rstack_size dup(?)
vm_dstack dd vm_dstack_size dup(?)

;Масив чисел які порахує ВМ
fibo dd 10 dup (?)
fibo_end:
dd '0' 

;Підключення коду
vm_code:
include 'algorythm.inc'

section '.code' code readable executable
start:

;Ініціалізація і запуск ВМ
mov [VM_SET + PICOVM_CONTEXT._instruction_pointer], vm_code
mov ebx, VM_SET
xor edx, edx
mov eax, PICOVM_FNC_RUN
call picovm

;Вивід малюнку
invoke printf, hdata
;Вивід результатів
invoke printf, fibo_str
pop eax
mov ebx, fibo
@@:
cmp ebx, fibo_end
je @f
xor edx, edx
mov dl, byte [ebx]
invoke printf, pr_form, edx
pop eax
pop eax
add ebx, 4
jmp @b
@@:

invoke getchar
invoke ExitProcess, 0

;Підключення попередньо асембльованого коду ВМ. Fasm не має лінкера
picovm:
file 'picovm.bin'

;Підключення малюнку
hdata:
file 'hdata.bin'

section '.idata' import data readable
library kernel,'kernel32.dll',\
        msvcrt,'msvcrt.dll'
 
import  kernel,\
        ExitProcess,'ExitProcess'
 
import  msvcrt,\
        printf,'printf',\
        getchar,'_fgetchar'

hdata.bin

             ,'``.._   ,'``.
              :,--._:)\,:,._,.:       
              :`--,''   :`...';\      
               `,'       `---'  `.
               /                 :
              /                   \
            ,'                     :\.___,-.
           `...,---'``````-..._    |:       \
             (                 )   ;:    )   \  _,-.
              `.              (   //          `'    \
               :               `.//  )      )     , ;
             ,-|`.            _,'/       )    ) ,' ,'
            (  :`.`-..____..=:.-':     .     _,' ,'
             `,'\ ``--....-)='    `._,  \  ,') _ '``._
          _.-/ _ `.       (_)      /     )' ; / \ \`-.'
         `--(   `-:`.     `' ___..'  _,-'   |/   `.)
             `-. `.`.``-----``--,  .'
               |/`.\`'        ,','); 
                   `         (/  (/

Весь код разом з ВМ

Пароль
replace
Скріншот

http://cs617229.vk.me/v617229163/1c620/uPZYX7AihD4.jpg
Maybe a = Just a | Nothing
Подякували: 0xDADA11C7, leofun01, anakin3

5

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

;Виділення пам*яті для ВМ
vm_rstack db vm_rstack_size dup(?)
vm_dstack db vm_dstack_size dup(?)

ги-ги - комірки мають розмір 4 байти, а не 1
зробіть на основі мого "ірідієвого зразка", викладіть скріншоти і взагалі оформіть по-людські приклад використання.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»

6

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Таки 4, але кратність збереглась і по 1 крутіше виглядає :)
Але замінив.

Maybe a = Just a | Nothing

7 Востаннє редагувалося 0xDADA11C7 (06.10.2014 16:20:07)

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Я помилково гадав, що моя софтверна ВМ майже ідеально оптимізована за розміром, але зараз я зрозумів, що прикоро помилявся. В джерельних кодах FreeForth я побачив реалізацію стеків софтверної ВМ перемиканням звичайного "залізного" стеку х86 на інші ділянки пам’яті.

macro DROP1 {                   ; n --
        mov ebx,edx             ; 89D3
        xchg eax,esp            ; 94
        pop edx                 ; 5A
        xchg eax,esp            ; 94
}
Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: leofun011

8

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Ця ВМ використовувалася в моєму пакувальнику-крипторі, тому вона має деякі спецефічні властивості, продиктовані антиантивірусним ринком.

Цікава реалізація. Таким чином, вдається збити лише сигнатурний детект? З проактивним захистом, мабуть, по іншому потрібно діяти..

9 Востаннє редагувалося 0xDADA11C7 (06.10.2014 22:59:03)

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Таким чином, вдається збити лише сигнатурний детект? З проактивним захистом, мабуть, по іншому потрібно діяти..

Там все складно. Ця ВМ має подвійне призначення - збивання з пантелику сигнатурного детекту і одімкнення ав емулятора, себто останній поки дійде до власне малварі "видихається", бо має визначену глибину емуляції. Це відбувається через те, що виконання однієї команди софтверної ВМ потребує десь пів сотні машинних команд.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: Kane, leofun012

10

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

А для чого це все?

11 Востаннє редагувалося 0xDADA11C7 (16.10.2014 22:37:59)

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Ця ВМ використовувалася в моєму пакувальнику-крипторі, тому вона має деякі спецефічні властивості, продиктовані антиантивірусним ринком.

В цьому випадку для того, щоб антивіруси не бачили "звіряток". Криптор - це такий пакувальник, що ховає зловмисне програмне забезпечення від антивірусних засобів.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»

12

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Мені на думку спало наступне:

// poc.cpp

#include <iostream>

using namespace std;

enum reg {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI};

class VM {
public:
    VM();
    ~VM();
    int GetReg(reg r);
    void Mov(reg r, int i);
    void Mov(reg a, reg b);
    void Add(reg r, int i);
    void Add(reg a, reg b);
    void Xor(reg r, int i);

private:
    int reg_mem[8];
};


VM::VM() {

}

VM::~VM() {

}

int VM::GetReg(reg r) {
    return reg_mem[r];
}

void VM::Mov(reg r, int i) {
    reg_mem[r] = i;
}

void VM::Mov(reg a, reg b) {
    reg_mem[a] = reg_mem[b];
}

void VM::Add(reg r, int i) {
    reg_mem[r] += i;
}

void VM::Add(reg a, reg b) {
    reg_mem[a] += reg_mem[b];
}

void VM::Xor(reg r, int i) {
    reg_mem[r] ^= i;
}


int main() {
    VM *vm = new VM();


    vm->Mov(ECX, 1111);                 // mov ecx, 1111
    vm->Mov(EAX, ECX);                  // mov eax, ecx
    vm->Add(EAX, 5);                    // add eax, 5
    vm->Mov(ECX, 10);                   // mov ecx, 10
    vm->Add(EAX, ECX);                  // add eax, ecx
    vm->Xor(EAX, 19);                   // xor eax, 19

    cout << vm->GetReg(EAX) << endl;    // = 1141


    return 0;
}

Тобто дизасмимо тіло, та "перекладаємо" його в такий проміжок. Купа недоліків, в т.ч. статичність методів, які можна задетектити.. хоча це більше підходить для захисту кода від посторонніх очей, аніж від ав. Але все ж таки, як один із варіантів на тему реалізації VM.

Подякували: 0xDADA11C71

13

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Насправді тільки що ви винайшли "шитий код". Наступним кроком має стати його оптимізація, себто замість машинного коду нижченаведеного виду:

push 1111
push reg_mem.ecx
call MovCmd

Постане це:

DWORD ThreadedCode[] = [PUSH_CMD, 11111, PUSH_CMD, &reg_mem.ecx, MOV_CMD];

Ваш код є лише гарним початком роздумів про віртуалізацію х86 коду.

хоча це більше підходить для захисту кода від посторонніх очей, аніж від ав.

Від посторонніх очей це якраз поганенький захист, бо ця ВМ відтворює забагато особливостей х86 процесора. Насправді нас ніхто не змушує бездумно копіювати архітектуру - регістів може бути хоч 16, хоч 33. Якщо робити захист від поторонніх очей, то краще високорівневі конструкції напряму транслювати в потрібну платформу - без посередництва х86 машинного коду. Такі мої роздуми...

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: Kane1

14

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

І ще роздуми по темі vm. Бавився я тут із lua/luac, за приклад робив так: вирізав зайве, додав пару своїх функцій, описав роботу скриптом, перетворив у байт-код зашифрувавши його.. Гра здалася цікавою, але знову таки, сенс))

15

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Гра здалася цікавою, але знову таки, сенс))

Все цікаве має сенс :D Цікавість це така ж самодостатня річ, як кохання чи помста. Викладайте ваші напрацювання бо мені теж цікаво це побачити :)

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»

16

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

0xDADA11C7 написав:

в моєму пакувальнику-крипторі

Цікаво як ви .tls у ньому обробляли?

17

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Читате тут:
Власне криптор
LoadPE шеллкод, який запускає виконувані файли
Для 80% ТLS цього досить (Дельфі). Я вже й забув, так давно то було. Існує 2 відомих мені способи: шаманізм з заголовком пе файла (Джерельний код UPX вам у поміч) і запис вказівника на наново побудований ланцюжок TLS  у fs:[0x2C]

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»

18

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

0xDADA11C7 написав:

Читате тут:
[*]Власне криптор[/*]
[*]LoadPE шеллкод, який запускає виконувані файли[/*]
Для 80% ТLS цього досить (Дельфі)

Я асемблер не дуже знаю, як ви перехоплювал старт потоку для фікса вказівника у TEB ?

19

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

оновив відповідь, читайте

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»

20

Re: [FASM x86] Мініатюрна стекова софтверна віртуальна машина

Виходячи із повідомлення 9 про глибину емуляції, бачу, що це і є крутий антиемулятор, як я і гадав :)

А у вас немає розробок на тему регістрової VM?

Подякували: 0xDADA11C71