0x00 前言
之前网鼎杯的逆向题,说实话,这是我第一次见虚拟机的逆向
现在已经深夜了,害怕第二天就忘了,所以赶紧记下来
已经第二天了,刚刚写出脚本,回来接着写
说实话第一次见虚拟机的题目还挺有新鲜感的
不过真正吃透一道题也不容易(还是自己太菜)
本题三种解法我了解的差不多了,当作笔记好好记录一下
0x01 程序分析
主函数:
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
不管别的,把&unk_403040
的值扣下来再说
主函数做的是先把&unk_403040
的值赋给&v4
,然后进入vm_operad
函数
1 | int __cdecl vm_operad(int *a1, int a2) |
第一次见,感觉这么多数一定很麻烦,但其实如果理解了其中的操作并不难
粗略的看一下,有 what a shame 这样的字符串,所以应该是要比较字符
再仔细分析程序,switch 这里用的参数是 a1(0x403040的值),v10 相当于是索引,从0开始递增,
进而遍历 0x403040之后的所有数(四字节为单位)。
所以说 0x403040 这里面储存的都是操作数,然后一个一个取出来,找相应的case进行操作。
##特别要注意的是case7,操作码最后部分的07H都是进行比较用的
接下来只要根据相应的操作数一步一步分析,
首先通过分析知道,a1是存入的操作数,v3是你输入的字符,v4,v5用于暂存数据
1 | case1:进行赋值操作,将v5的值赋给v4,标号索引全加1 |
了解了全部操作,那么就可以分析它的实现流程了
0x02 实现流程
对照着0x403040
的数据可以一步一步摸清它的脉络
首先第一个操作码是10,是输入15位数据(也就是要求的flag)
下一个操作码是4,flag[0]与a1的下一个数值(16)进行异或,索引加2
下一个操作码是8,保存当前状态。
下一个操作码是3,当前值减去a1下一个数据(5)
下一个操作码是1,将现在的数据赋值给v4,各个索引均加1
进行对下一位flag[1]的运算操作
所以可以从中找出规律,对于每一位数据的操作都结束于case1,也就是说,程序是将flag[0~14]这15位数据依次作运算,存入v4中,最后将v4的数值分别与对应的数值进行比较
0x03 脚本
1.手撕程序
那么可以动笔来算一下,写的有点乱,无伤大雅,勉强能冲。
由于题目的位数不多,逻辑不难,所以手撕还是挺快(乐)的,贴上代码
1 | print (chr((34+5)^16),end='') |
2.高级脚本
基本的逆向思维
找出v4的值,分别反向做逆运算就可以找出flag
1 | v4 = [34,63,52,50,114,51,24,167,49,241,40,132,193,30,122] |
为了写的通俗易懂,脚本可能会存在考虑不周的地方,不过解出本题还是可以的
附上队里一位Han Xu小姐姐的脚本,比赛时就解出来是真的强,
1 | v1=[0xa,4,0x10,8,3,5,1,4,0x20,8,5,3,1,3,2,8,0xb, |
3.Angr
angr也叫符号执行暴力破解,用于解CTF题目,emmm实战中应该作用不大
这一块是我的知识盲区,直接贴上学习资源1、学习资源2、学习资源3…….学习资源N,先记下来,以后慢慢看(咕咕咕)
贴上大佬们的脚本
1 | import angr |
运行结果:
0x04 小结
这可能是我赛后复现过的第一题,还是时隔了这么久。。。
之前总感觉要从基础学起,从入门题慢慢进阶,后来发现进步速度实在缓慢,
小结做一下简单的反思
去翻一下炜哥的博客,发现他每次赛后都会写一篇博客复现一下当时没解出来的题目,
我们英语课经常会讨论一些逆向的话题,他说必须要逼着自己做一些难题,大家一开始都不会,就是通过每一次复现题目来强制自己学习新的知识,否则会一直停留在入门水平。
我目前的状态确实不像想学习的态度,比如说比赛题目只要没见过、或者很复杂,我很难静下心来解题,一般这种情况我会直接关掉网页,然后安慰自己,嗯…这题不是给我做的。
逆向大佬子洋、炜哥遇到巨难的题目会慢慢地啃,就算一道题目花费几天的时间,真正搞懂原理和逻辑也是值得的,说实话,这道signal题难度远不及他们的博客的平均水平,可以说是最简单的虚拟机题目(炜哥比赛手撕半个小时解决),虽然花了几个小时才搞懂,但还是很有成就感的
张老师说过比赛和题目都不是关键,关键是你能从中学到什么,分清主次,明确学习规划才是当前最重要的
好好学逆向,争取比赛不再只是去纠结MISC