首页
社区
课程
招聘
[原创]虎符第三题 -vm 虚拟机逆向
发表于: 2020-4-24 16:16 17645

[原创]虎符第三题 -vm 虚拟机逆向

2020-4-24 16:16
17645

虎符ctf -- vm

一个 调了好久好久的虚拟机题目

原本比赛的时候是上午做了个pyc, 下午开始调vm, 调到结束也没弄出来个道道,tcl, 就开始等待大佬们的wp, 好几天过去, 似乎没有???

走投无路的菜鸡只好自己慢慢逆。。然后写下这个题目的wp。 欢迎围观

虎符ctf, vm题目, 个人觉得还是一个比较不错的虚拟机,指令好多,不太好调。

几个简单的虚拟机题目, 我的博客有一个整理, 对应的文件应该是在里面有,没有的话,博客主页转csdn里对应文章肯定有(这,是个历史遗留问题...)

似乎也没怎么找到比较好的方法,对于虚拟机的题目,就看虚拟机指令然后去还原, 再逆吧,不过发现还是要注意下栈堆机器和寄存器机器是不一样,

这个题目给出的就是一个栈堆机器,所以里面有一部分处理栈的指令,用了python字节码去标注,(pyc字节码:"哈哈,没想到吧!还是我!"),

首先题目的main函数比较简单:


注意下打开文件是用的参数。即运行时要指定参数./vm code , ida调试要在debugger -> process options -> parameters写上参数code,

重点在于函数vm(code):

比较典型的一个while(1)switch(opcode)的结构做的虚拟机,

然后运行的大体情况, 如下示:

对于详细的可以看附件中的code.py文件, 本文简单写下data架构体和opcode, 和一部分循环的结构。

一个bss段的一个结构体, 主要我们运行的时候储存信息:

vm_eip一个数字, 代表偏移量,使用这个配合code地址检索到opcode,opcode = *(&code + vm_eip)

vm_sp: 代表栈内数据数目,也配合栈地址形成指向栈顶的指针,

code: 这个就是储存code, 没啥要说的,

vm_stack: 这个是这个栈堆机器操作的栈,

vm_arr: 一片内存空间,主要用于储存三个数组, 一个预定义好了的arr1(在50-91), 一个用户输入的arr2(在100-141), 一个由arr2处理成的arr3(在0-41),对arr的处理是重点

vm_block: 主要是用于储存循环时的计数器。

比如题目中在for i in range(7): for j in range(6)的里面, bolck就储存着ij, 还有后面循环的i也都是在block中储存的,

记录下用到了的 一些指令, 格式, 简单的标记,
后面有参数的标注已经写了参数的意义(如index,var啥的), 在代码中的*(&code + vm_eip + 1), 就是获取到指令后面的参数了

opcode(0x1) ==> 0x1, ==> push input, 接收一个用户输入字节并压入栈中,

opcode(0x4) ==> 0x4, var, ==> push var;

opcode(0x7) ==> 0x7, index, ==> push vm_arr[index],

opcode(0x5) ==> 0x5, index, ==> push vm_block[index]

opcode(0x12) ==> 0x12, ==> vm_stack[vm_sp] = ~vm_stack[vm_sp] 对栈顶数值取反。

opcode(0x19) ==> 0x19, ==> vm_stack[vm_sp-1] = vm_arr[vm_stack[vm_sp-1]]

opcode(9) ==> 9 ==> binary_add 加法 +

opcode(0xa) ==> 0xa ==> binary_subtract 减法-

opcode(0xb) ==> 0xb ==> binary_multiply乘法 ×

opcode(0xd) ==> 0xd ==> binary_modulo 取余 %

opcode(0xf) ==> 0xf ==> binary_and 按位与 &

opcode(0x10) ==> 0x10 ==> binary_or 按位或 |

opcode(0x1d) ==> 0x1d, tar, ==>jump $+tar, 直接跳转到参数指定的位置,但是要注意,有时候这个参数其实是负数, 回跳,形成一个循环结构。

剩下几个都是,判断栈顶两个值,决定是否跳转到参数指定的位置,

opcode(0x18) ==> 0x18, tar, ==> if vm_stack[vm_sp] < vm_stack[vm_sp-1]: jump $+tar

opcode(0x16) ==> 0x16, tar, ==> if vm_stack[vm_sp] > vm_stack[vm_sp-1]: jump $+tar

opcode(0x14) ==> 0x14, tar, ==> if vm_stack[vm_sp] == vm_stack[vm_sp-1]: jump $+tar,

opcode(8) ==> 8, index, ==> vm_arr[index] = vm_stack[vm_sp];

opcode(0x1a) ==> 0x1a, ==> vm_arr[vm_stack[vm_sp]] = vm_stack[vm_sp-1]

opcode(0x5) ==> 0x5, index, ==> push vm_block[index]

opcode(0x6) ==> 0x6, ==> vm_block[var] = vm_stack[vm_sp]

opcode(0x1c) ==> 0x1c, ==> vm_block[vm_stack[vm_sp]] = vm_stack[vm_sp-1]

opcode(0x2) ==> 0x2, ==> print vm_stack[vm_sp]打印栈顶的数值对应字符。

opcode(0x1) ==> 0x1, ==> push input, 接收一个用户输入字节并压入栈中,

其中的语句构成一些结构,我们需要注意,

压栈,然后将栈顶弹出到arr中,其实就相当于是向arr里面赋值,一开始大片的0x4 -0x8 是赋值arr1, 接着就是0x1-0x8是设置好arr2,

0x4-0x6是设置block内的值,0x5-0x4-0x16是判断block里的值和0x4参数的大小, 在code中出现过三次,都是循环的开头部分,

0x1d 后面的参数有负数的情况,其实就是相当于减法,回跳,一般配合前面这个0x5-0x4-0x16,形成一个循环结构,

最后可以得到的还原出来大致是:

该文件在附件中,在附件中有,

可以点下右侧那个箭头,展开代码块, 里面是比较详细的标注和对应的opcode,

注:

那个 var * 0x6b 的位置可以print下, 爆破每个都是只爆破出来一个数,直接爆破即可。

设置了另一个arr的原因是,arr1[i] - arr1[i-1], 减的时候arr[i-1]已经是arr[i]*0x6b处理了, 要逆得倒着写, 写了下没成功,弄起来感觉有点麻烦(其实是菜),直接设置另一个就直接用就好了 (看起来就比较优雅)。

然后后面的那个异或是对于前面那个花里胡稍的操作, 其实就是个异或关系,即a ^ b = (~a & b) | (a & ~b)

然后得到flag:

最后

附件中是整个的压缩包,题目的bin和code文件,一个solver.py文件,code.py是代码还原的文件,里面注释还是比较多,

剩下还有一堆vm.*是...ida分析的文件,emmmm manjaro-kde的wine跑ida, 因为qt的原因会在打包的时候ida卡死崩溃, 又一个历史遗留问题? 还没找到啥办法,(好丢人),

 
 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-5-2 02:43 被令则编辑 ,原因: 修改关于block的位置
上传的附件:
收藏
免费 4
支持
分享
最新回复 (12)
雪    币: 977
活跃值: (435)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2020-4-24 16:40
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
感谢分享 :)
2020-4-24 23:03
0
雪    币: 1485
活跃值: (1135)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
楼主vm这方面有相关书籍学习吗
2020-4-25 11:38
0
雪    币: 1129
活跃值: (2756)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2020-4-25 12:14
0
雪    币: 3735
活跃值: (1188)
能力值: ( LV5,RANK:65 )
在线值:
发帖
回帖
粉丝
6

我记得加密解密里面有个虚拟机构造的一章, 讲的是寄存器机器,我之前有个关于python解释器的帖子,也算是讲的一个栈堆机器。有关于两种机器的底层运行原理啥的,应该会是对虚拟机的理解有些帮助。最近发现, 看雪大佬整理的一个专题帖子

最后于 2020-4-30 22:42 被令则编辑 ,原因: tcl
2020-4-25 12:27
0
雪    币: 425
活跃值: (2886)
能力值: ( LV11,RANK:185 )
在线值:
发帖
回帖
粉丝
7
挺好
2020-4-25 21:21
0
雪    币: 259
活跃值: (283)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
vm_block: 这个储存另一部分数据,主要是用于储存循环时的计数器,是一个python解释器中block_stack的地位,vm_block到底是啥 没看懂
2020-4-26 09:52
0
雪    币: 3735
活跃值: (1188)
能力值: ( LV5,RANK:65 )
在线值:
发帖
回帖
粉丝
9
ZwCopyAll vm_block: 这个储存另一部分数据,主要是用于储存循环时的计数器,是一个python解释器中block_stack的地位,vm_block到底是啥 没看懂

在循环结构中保存循环计数器。比如题目中在for i in range(7): for j in range(6)的里面, bolck就储存着i和j, 还有后面循环的i也都是在block中储存的, (在python中循环都会使用一个block_stack,用来处理循环中的计数器,也就因此命名了),就是这个意思啦,文章已修改

2020-4-26 12:30
0
雪    币: 8186
活跃值: (6404)
能力值: ( LV12,RANK:207 )
在线值:
发帖
回帖
粉丝
10
感谢分享
2020-4-26 17:52
0
雪    币: 2620
活跃值: (1965)
能力值: ( LV8,RANK:121 )
在线值:
发帖
回帖
粉丝
11
感谢令则师傅,第一次接触基于栈的vm,看了两天,终于做出来了
2020-4-28 19:08
0
雪    币: 31
活跃值: (24)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
12
感谢分享
2020-4-28 22:42
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13

我的ida调试不太好用。

2021-7-3 23:24
0
游客
登录 | 注册 方可回帖
返回
//