原先是在这版某讨论帖写的. 之前这版块管制.
稍稍整理独立出来. 己看过的就飘过吧.
讲一下 VMP, 及还原代码的可行性.
VMP其实不复杂, 反而是他的太单纯导致复杂化
万用闸有二种, 一种叫 NOR Gate, 一种叫 NAND Gate.
即称万用, 就表示单靠他自己, 就能变换出 OR ' NOT ' AND ' XOR
VMP在VM内的运算选择了 NOR Gate 去实现 NOT'AND'OR'XOR
(实现图我列在最后)
致于加法, VMP内部自有这种指令(直接用 intel ADD 指令)
add(w,w) EFL,Result
add(d,d) ELF,Result
addb(wb,wb) ELF,Result
VMP内部也有 shl(d,w) EFL,Result 及 FS:[d0]:= d1
等等一些较为有目的性的指令.
所以还原成可视(或称类asm)个人认为并没想像中的难.
-----------------------------------------------------------------------------
VM 的条件跳转
条件跳转跟我们平常的观念不太一样.
这是 jmp : #delta=0
vm.jmp(d+#delta) ;ESI=[EBP]+[EBP+4]
上面的#delta的值将决定所谓的跳或不跳.
通常 d=Target, #delta=0 为跳 jmp(d+#d)
若 #delta=-d 则 ESI 的值不会变, 也就是不跳(继续执行)的意思了.
-----------------------------------------------------------------------------
为何说没想像中的那么难呢?
下列是很常见的一连3个VM指令
原 VM.ESP: *** 注: VM.ESP 是由 EBP 所表示 ***
12FFB0 00000286
12FFB4 0012FFB8
1.经过 VM.push_esp , 变成:
12FFAC 0012FFB0
12FFB0 00000286
12FFB4 0012FFB8
2.再经过 VM.pushd([d]) , 变成:
12FFAC 00000286 <- 复制一份了
12FFB0 00000286
12FFB4 0012FFB8
3.再经过 VM.nor(d,d) EFL,Result 变成: 注: nor is NOR 闸
12FFAC 00000282 <- ELF
12FFB0 FFFFFD79 <- Result
12FFB4 0012FFB8
这3个步骤其实就是 NOT 0286h = FFFFFD79

紧接着上列3个步骤后, 常见下列的动作:
4. VM.pop 丢掉ELF, 变成:
12FFB0 FFFFFD79 <- Result
12FFB4 0012FFB8
5. pushd(decode(followWord)) <- 从opcode处取2 byte当数据, 符号扩展PUSHD
12FFAC FFFFF7EA <- 数据 (亦即 0815的not)
12FFB0 FFFFFD79 <- Result
12FFB4 0012FFB8
6. VM.nor(d,d) EFL,Result 变成:
12FFAC 00000202 <- ELF
12FFB0 00000004 <- Result
12FFB4 0012FFB8
7. VM.pop 丢掉ELF, 变成:
12FFB0 00000004 <- Result
12FFB4 0012FFB8
1~7 其实实现的就是 00000286 & 00000815 = 00000004
(00000815被以NOT的型式硬编在OPCode)

所以 VMP 的 VM 是很正规的.
一个简单的80x86指令 : and reg, 00000815h
被分解成 (假设reg的值已入Stack)
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!