上期文章:虚拟指令和Handler设计
从指令集的设计上来看,经过前面转换和指令拆分的到一行中间代码虚拟化过程中可能对应了一条或者多条的虚拟指令,如下图所示,一个加法操作“r2=r1+3;”经过虚拟化后,得到4条虚拟指令分别是两条加载指令,一个加法指令和一个存储指令。
代码虚拟化保护最终会将目标代码转换成一种字节码的形式并最终以这种形式保存,这样便于隐藏指令中的包含的可读信息,同时也便于虚拟解释器的读取和解释。在编码过程中,将虚拟指令分成两个部分:操作码和操作数(部分指令没有操作数)。每个虚拟指令都有一个关联的解释程序负责实现指令所代表的功能,因此我们可以给每个虚拟指令设定一个编号,这个编号即是虚拟指令的操作码也是它的解释程序的索引ID。同时,我们将操作对象寄存器等存储单元也进行编号,这样我们就可以将虚拟指令通过编码转换成特定字节码程序,如图中示例,第一列是虚拟指令的操作码,第二列是其参数。并且在实际保护中,可以通过修改编码规则来改变虚拟指令和字节码的映射关系,如上图中所示的两种字节码编码结果,每次保护时,随机的替换虚拟指令和字节码的映射关系,这样可以使不同次保护的结果呈现不同的映射规则,增加逆向分析虚拟化保护的难度。同时我们还可以进一步对字节码进行加密保存,在执行时,解释器先对读取的字节码进行解密得到真实的操作码,然后根据解码调度相应的Handler进行解释,还原指令的语义和功能。
JS一键VMP加密 jsvmp.com