What is VM
different from virtualbox…
这种虚拟机类似于自己用一套自己定义的操作码实现了完整的逻辑,当然用的指令不太多,不然会很困难且效率很低,显得没有必要。必要的定义有
- 虚拟机的初始化
- 一套自己定义的操作码
- 对应各个操作码的解释器
初次接触也许很生疏,我们从一套题目看起,这是2018NCTF WcyVM,网上wp很多,我在这里通过这道题来详细说明一下虚拟机在逆向方面的各种思路
Analysis
Some differences
1 | __int64 __fastcall main(__int64 a1, char **a2, char **a3) |
看到主函数逻辑极其简单,我们跟sub_400DAB()
,会发现是一个while
嵌套switch
的一套代码,先看循环以上本函数的初始化
1 | v11 = __readfsqword(0x28u); |
定义了许多变量,我们只需要注意v8即可,这是一个堆栈指针,在以后有大用,我们看一下后边的case
指令,例如下方
1 | case 8: |
我们看下这个函数,它做的便是把a2的值赋给了a1,然后把指针向后移,所以可以简单理解为mov a1,a2
,而堆栈指针的使用在下边,我们举例说明
1 | case 9: |
可以看到函数在直接把a2的值给了a1,之后a2自增,之后与之前的函数类似,这显然就是一个典型的pop a1
操作,而且v8正是我们是我们假定的栈顶指针
这题就是这样需要一步一步逆出指令集即可进行解题,没有别的自动化方法,我们把我们要做的操作码用idc搞出来
1 | auto i,start,end,num; |
然后硬着头皮,像转换一样把它填进去就行,例如根据得到的数据
1 | 8,1,0,8,3,70,14,21,10,1,9,2,11,10,1,10,2,9,1,17,1,13,1,3,15,8,8,1,0,8,3,71,14,70,10,1,26,2,6,29,1,4,20,2,1,25,1,2,27,1,1,29,1,110,19,1,99,21,1,116,19,1,102,28,2,1,9,1,17,1,13,1,3,15,34,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
8,1,0
就是mov (&v4)[v10[1] - 1],0
9,1
就是pop (&v4)[v10[1] - 1]
很难受的题,不过这种逆向确实很有趣
正向出题
下面自己完成一套虚拟机,通过正向来看一下 vm 层面需要什么