前话
本来我是不喜欢去写wp的…因为懒()…就算有做出来题目也是在文档中简单写一下就好了…这道题目之所以去写,可能不是因为它出的很好(由于VM题我做的太少了,这才算是第一道完整做掉的题目),而是我在接触这个题目的时候,对逆VM的经验或是看法有了自己的见解,这点比起我后来成功做出这道题更令我开心,希望下次遇到VM的题目时我能成功解出)
程序大体流程以及题解
程序流程还是比较简单易读的。用IDA打开后,差不多这个模样
这里调用了三个函数,由一个函数表进行调用。
调用的三个函数是最后三个,分别做了虚拟寄存器/栈的分配以及初始化,VM的调用以及最后赋值的还原。重点在于中间这一 步,
一点都不花里胡哨,也没有混淆。就是这里用虚函数表做调用也太烦了= =翻得翻半天。再后面就是正常的VM流程了。逆出每个操作,然后打log,读汇编就可以解决…其实这一点都不算难题。要是以前有经验我觉得一小时到两小时就可以做完了= =还是输在too young。。打log的脚本如下
1 | opcode = [79, 0, 0, 0, 47, 85, 5, 84, 48, 70, 0, 71, 34, 72, 2, 75, 51, 73, 79, 0, 0, 0, 70, 84, 16, 72, 1, 77, 39, 79, 0, 0, 0, 48, 84, 16, 72, 1, 68, 22, 79, 0, 0, 0, 57, 84, 16, 72, 1, 68, 11, 79, 0, 0, 0, 65, 84, 1, 72, 1, 68, 6, 71, 0, 72, 0, 75, 5, 71, 0, 80, 0, 67, 85, 64, 79, 0, 0, 0, 7, 84, 48, 71, 17, 86, 70, 0, 79, 0, 0, 0, 48, 84, 32, 89, 2, 79, 0, 0, 0, 10, 84, 32, 72, 2, 68, 9, 79, 0, 0, 0, 7, 84, 32, 89, 2, 79, 0, 0, 0, 16, 84, 32, 88, 18, 83, 16, 85, 43, 79, 51, 180, 136, 172, 84, 32, 72, 18, 71, 0, 75, 3, 80, 0, 67, 79, 0, 0, 0, 7, 84, 48, 71, 17, 86, 70, 0, 79, 0, 0, 0, 48, 84, 32, 89, 2, 79, 0, 0, 0, 10, 84, 32, 72, 2, 68, 9, 79, 0, 0, 0, 7, 84, 32, 89, 2, 79, 0, 0, 0, 16, 84, 32, 88, 18, 83, 16, 85, 43, 79, 74, 11, 148, 63, 84, 32, 72, 18, 71, 0, 75, 3, 80, 0, 67, 79, 0, 0, 0, 7, 84, 48, 71, 17, 86, 70, 0, 79, 0, 0, 0, 48, 84, 32, 89, 2, 79, 0, 0, 0, 10, 84, 32, 72, 2, 68, 9, 79, 0, 0, 0, 7, 84, 32, 89, 2, 79, 0, 0, 0, 16, 84, 32, 88, 18, 83, 16, 85, 43, 79, 124, 92, 220, 236, 84, 32, 72, 18, 71, 0, 75, 3, 80, 0, 67, 79, 0, 0, 0, 7, 84, 48, 71, 17, 86, 70, 0, 79, 0, 0, 0, 48, 84, 32, 89, 2, 79, 0, 0, 0, 10, 84, 32, 72, 2, 68, 9, 79, 0, 0, 0, 7, 84, 32, 89, 2, 79, 0, 0, 0, 16, 84, 32, 88, 18, 83, 16, 85, 43, 79, 57, 41, 117, 27, 84, 32, 72, 18, 71, 0, 75, 3, 80, 0, 67, 79, 0, 0, 0, 7, 84, 48, 71, 17, 86, 70, 0, 79, 0, 0, 0, 48, 84, 32, 89, 2, 79, 0, 0, 0, 10, 84, 32, 72, 2, 68, 9, 79, 0, 0, 0, 7, 84, 32, 89, 2, 79, 0, 0, 0, 16, 84, 32, 88, 18, 83, 16, 85, 43, 79, 30, 242, 107, 45, 84, 32, 72, 18, 71, 0, 75, 3, 80, 0, 67, 79, 0, 0, 0, 7, 84, 48, 71, 17, 86, 70, 0, 79, 0, 0, 0, 48, 84, 32, 89, 2, 79, 0, 0, 0, 10, 84, 32, 72, 2, 68, 9, 79, 0, 0, 0, 7, 84, 32, 89, 2, 79, 0, 0, 0, 16, 84, 32, 88, 18, 83, 16, 85, 43, 79, 131, 141, 181, 46, 84, 32, 72, 18, 71, 0, 75, 2, 80, 0, 67] |
最后打出来的log长这样,里面有一些重要的注释
1 | 0 push 47 |
最后就只要将这些字符倒序再大写就可以拿到flag
至此,本题就结束了。
对VM的看法
由于以前对于VM只有粗浅的认识,导致一开始我在打log的时候非常吃力。。我只关心指令本身,而对操作数的分析直接忽视了。。导致打出来的log非常奇怪。。我还很担心中间数字对于程序流的影响,毕竟有je,jmp,jg这些跳转。。还不知道输入该怎么处理,全部置’a’还是啥。。经验的缺乏导致做题缺乏自信,中间很多指令分析都有问题,逻辑越来越乱。。今天去复现才慢慢理解到,跳转指令只要分析出来就好了,你不需要去完整的走一遍程序流,寄存器值也不需要太过担心,唯一要去担心的是立即数,所以你需要将这些数字还原。。VM作为机器的模拟是非常有趣的,对reg的选择方法真是惊到我了233,一个字节分别4位作为选择子也太帅了吧!有机会我想看看机器指令的操作数是怎么配合的hhh
后记
逆VM也太JB有趣了!
政博学长说的一些操作有空会去尝试一波。
立个flag…下周要把锅全done了!