第一次脱壳,vmp+xor
前几天的“恶意软件分析”课程作业,附加题是个elf格式的VMP文件,说是装了虚拟机壳,写个反汇编器就可以解出来。目标是输对密码,让它报告congratulations。但是放进我的linux虚拟机就是不运行,查了后是缺头文件,于是装好环境,运行了。
破解的工具是IDA,main函数调用个函数,进去后是一片变量声明,后面就是文档里说的一堆switch,也就是虚拟机壳接收指令集的方式。通过阅读和变量重命名,终于看会了它的原理。真正的代码被放在某个数据段中,这个函数的作用只是把它读出来,然后根据代码中的第一位判断指令,后面几位是对应的参数,基本就是mov ax, bx这类汇编指令的二进制版本。我的初步目标很简单,就是把这些代码翻译出来,至少翻译成逐句的文字版汇编指令。
我这段时间以来用的最多的是C++,考虑到不练就生疏的问题,决定练练python。Python是可以读取二进制文件的,一开始做感觉不适应,代码却很短,也是with open这些,然后写反汇编的时候就发现没有switch,于是费劲写了一堆elif。于是分屏对比着写反汇编码,由于其中有不少跳转指令,所以额外添加了行号的显示,其中4154到7899是从59开始(大概?)往后的代码段地址,我已经做了反xor处理,否则59往后都是乱码。可以看到其中还有很多不完善的地方,不过基本的指令已经可以看出来了,有能力的读者可以从最后硬编码的一些数据中恢复出30位的ascii码密码。
1: mov ds[0], 4154
8: mov ds[1], 7899
15: mov ds[3], ds[0]
19: mov ds[5], 24432450
26: mov ds[4], [ds[3]]
29: ds[4] = ds[5] xor ds[4]
34: mov [ds[3]], ds[4]
37: ds[3] = ds[3] + 4
45: cmp ds[1], ds[3]
49: jge not jumping
54: jmp to 58 (40fa)
59: jmp to 3008 (4c80)
3009: push
3012: push
3015: push
3018: call 2669
2670: mov ds[0], 80
2677: call 63
64: io: put_char
66: ret (2681)
2682: mov ds[0], 108
2689: call 63
64: io: put_char
66: ret (2693)
2694: mov ds[0], 101
2701: call 63
64: io: put_char
66: ret (2705)
2706: mov ds[0], 97
2713: call 63
64: io: put_char
66: ret (2717)
2718: mov ds[0], 115
2725: call 63
64: io: put_char
66: ret (2729)
2730: mov ds[0], 101
2737: call 63
64: io: put_char
66: ret (2741)
2742: mov ds[0], 32
2749: call 63
64: io: put_char
66: ret (2753)
2754: mov ds[0], 101
2761: call 63
64: io: put_char
66: ret (2765)
2766: mov ds[0], 110
2773: call 63
64: io: put_char
66: ret (2777)
2778: mov ds[0], 116
2785: call 63
64: io: put_char
66: ret (2789)
2790: mov ds[0], 101
2797: call 63
64: io: put_char
66: ret (2801)
2802: mov ds[0], 114
2809: call 63
64: io: put_char
66: ret (2813)
2814: mov ds[0], 32
2821: call 63
64: io: put_char
66: ret (2825)
2826: mov ds[0], 121
2833: call 63
64: io: put_char
66: ret (2837)
2838: mov ds[0], 111
2845: call 63
64: io: put_char
66: ret (2849)
2850: mov ds[0], 117
2857: call 63
64: io: put_char
66: ret (2861)
2862: mov ds[0], 114
2869: call 63
64: io: put_char
66: ret (2873)
2874: mov ds[0], 32