Тема: [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
Як сказано вище, кожна віртуальна машина створюється генератором і є неповторною. Це зроблено з метою ускладнити життя антивірусним аналітикам. В ідеалі для кожного пакованого (криптованого) файла має бути унікальна сигнатура, притаманна лише йому.
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);
Буду поторхи правити код, дописувати доки і викладати приклади використання.