Lingze's blog Lingze's blog
timeline
about
friends
categories
tags

lingze

bin不是垃圾桶的意思!
timeline
about
friends
categories
tags
  • book
  • reverse
  • vm和符号执行
lingze
2020-07-14
目录

vm

# 虚拟化混淆

虚拟混淆手段整理。

这里整理下目前对于虚拟混淆的一些想法,

大多数的想法和思路来自ctf赛题和tigress挑战。

# vm

首先是vm本身开始说, 虚拟机的设计本身,牵扯到虚拟机本身对于opcode->handler的调度, 和虚拟机内部对于循环判断函数调用的调度。

# vm机器和应对思路

主要来说有寄存器机器和栈机器两类,

如果说手动编写反汇编脚本,然后一点点处理的话,两者的区别不太大,

如果使用miasm等符号执行/动态符号执行框架处理的话, 目前寄存器机器的反汇编脚本,直接把每个寄存器都设置为符号值, 处理起来会比较舒服, 栈机器目前我没学到啥手段。

但是两者都可以通过这些框架获取类似反编译脚本,也区别不算太大。

这是简单的虚拟机相关结构,

设置好的虚拟指令,opcode/bytecode的指令流, 虚拟栈, 虚拟pc指针,虚拟sp指针,

指令对应的解释器, 最上面的调度器,每个指令对应的handler,


details

简单说下两个机器区别在于对于运算的实现,比如1+2

寄存器机器:

regA = 1
regB = 2
regA += regB
1
2
3

栈机器:

push 1
push 2
add 
1
2
3

其中的add是, 将栈顶两个值弹出,相加后结果压栈。

# 对vm的调度

对于opcode -> handler的映射关系。

一般比较常见的是while + switch组合的虚拟机, 在tigress-challenge中设置了六种对vm的调度。这里也简单笔记。

switch :

转换/分发, 最常见的方式, 一般opcode->handler会一对一,而且映射比较简单,

while (1){
	switch (prog[pc]) {
            opcode1: 
                handler1;
                break;
            opcode2:
                handler2;
                break;
            .......
    }
}
1
2
3
4
5
6
7
8
9
10
11

ifnest :

连续if-else, 这个类似switch的方式:

while (1) {
	if (prog[pc]==op1) 
        handler1;
    else if (prog[pc]==op2) 
        handler2;
    else if …
}
1
2
3
4
5
6
7

direct :

直接跳转, 分成一个个小段, 然后运行最后直接跳转到下一个应该的handler去运行。

goto *prog[pc];

opcode1: 
	handler1; 
goto *prog[pc];

opcode2: 
	handler2; 
goto *prog[pc];

....
1
2
3
4
5
6
7
8
9
10
11

warning

对这个模式存在一些小疑惑,目前只是在tigress中看到相关思路, 但是没看到对应的实现。

indirect :

间接跳转, 比上个直接跳转增加了个表, 通过表进行跳转,这样的情况下,opcode->handler会因为表的原因打乱,也可能存在多对一情况。

goto *jtab[prog[pc]];

handler1; 
goto *jtab[prog[pc]];

handler2;
goto *jtab[prog[pc]];
1
2
3
4
5
6
7

call :

情况每个handler设置一个函数,检索和函数调用的方式对opcode调用不同的函数,应该也是opcode->handler一对一映射,

void op1fun(){handler1}
void op2fun(){handler2}
.....
    
call *prog[pc]();
1
2
3
4
5

linear, binary, interpolation :

线性运算 插入值, 这里是在top做一个opcode->handler映射,然后跳转到对应handler运行,运行后跳转回到top继续。这种情况因为映射的关系,很容易造成多对一的情况,并且对应的位置比前面几个情况更难把握。

top: 
   goto *(searchalg(map,prog[pc]));

handler1; 
goto top;

handler2; 
goto top;
1
2
3
4
5
6
7
8

tip

tigress-challenge0-0就是这样的处理,应该是比较复杂的方式,

当时的反汇编脚本先写了对应的映射,然后又写对应handler。

# vm内的调度

vm内的调度主要是修正pc指针,实现跳转,通过跳转和比较实现if和for,

通过引入简单的帧等结构保存和修复, pc指针,虚拟栈,sp指针等,实现函数调用。

# 特殊手段

这些手段都是在tigress项目中看到的,其中的一些目前还不能理解,但有一些类似于普通的小混淆手段在vm中的表现, 在这里记录下。

# vm内的opcode自修改

每次调用进入vm都会修正一部分opcode然后返回,并在最后

# vm调度器的花指令

插入不透明谓词, 对调度器位置进行混淆。

#vm#混淆
上次更新: 6/24/2025, 5:07:55 AM
Theme by Vdoing | Copyright © 2019-2025 lingze | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式