题目链接:https://pan.baidu.com/s/17upwsge3pVrAbANqkeGkwA 密码:30b4
如果对VM题不太了解的话,可以先看看这一篇文章(https://www.52pojie.cn/forum.php?mod=viewthread&tid=713219),基本上有汇编功底的话很快就能入门的。
分析vm首先先找到这四个。
我们来看这个题,函数sub_400DAB()里有一个虚拟机,dword_6021C0处存放的即是VM_data,进行分析后可以初步确定VM_data,VM_IP,VM_context,VM_stack。
下面就是逐条分析每个Handler,有汇编功底的话基本能根据脚本去理解过程,就不具体分析了,只简单说明一下。
这三个是虚拟机寄存器数组,可以理解为R0,R1,R2。
每个Handler都要传入VM_EIP,因为执行完 Handler 后,VM_EIP 需要向后移动,指向下一条指令。在函数中VM_EIP会增加,增加一个字节就+4。
关于mov指令有不少,要注意它们引用的区别,如果不太清楚可以通过脚本来理解。
关于Handler13和Handler15的伪代码比较麻烦,可以看汇编指令来写。
其他的可以看脚本来理解。
arr = \ [0x8,0x1,0x0,0x8,0x3,0x46,0xe,0x15,0xa,0x1, 0x9,0x2,0xb,0xa,0x1,0xa,0x2,0x9,0x1,0x11, 0x1,0xd,0x1,0x3,0xf,0x8,0x8,0x1,0x0,0x8,0x3, 0x47,0xe,0x46,0xa,0x1,0x1a,0x2,0x6,0x1d, 0x1,0x4,0x14,0x2,0x1,0x19,0x1,0x2,0x1b, 0x1,0x1,0x1d,0x1,0x6e,0x13,0x1,0x63,0x15, 0x1,0x74,0x13,0x1,0x66,0x1c,0x2,0x1,0x9, 0x1,0x11,0x1,0xd,0x1,0x3,0xf,0x22,0x64] i = 0 while(i < len(arr)): if(arr[i] == 8): print('%d mov R%d, %d'%(i, arr[i+1]-1, arr[i+2])) i += 3 if(arr[i] == 9): print('%d pop R%d'%(i, arr[i+1]-1)) i += 2 if(arr[i] == 10): print('%d push R%d'%(i, arr[i+1]-1)) i += 2 if(arr[i] == 11): print('%d R0 = getchar()'%i) i += 1 if(arr[i] == 12): print('%d R0 = putchar()'%i) i += 1 if(arr[i] == 13): print(" cmp R%d, R%d\n"%(arr[i+1]-1, arr[i+2]-1), " jnz %d\n"%(i+3), " mov a, 80") i += 3 if(arr[i] == 14): print('%d jmp %d'%(i,arr[i+1])) i +=2 if(arr[i] == 15): print("%d"%i, " and a, 0x80\n" " test a\n" " jnz %d"%arr[i+1]) i += 2 if(arr[i] == 17): print('%d inc R%d'%(i,arr[i+1]-1)) i += 2 if(arr[i] == 18): print('%d dec R%d'%(i,arr[i+1]-1)) i += 2 if(arr[i] == 19): print("%d add R%d, %d"%(i, arr[i+1]-1, arr[i+2])) i += 3 if(arr[i] == 20): print('%d sub R%d, R%d'%(i, arr[i+1]-1, arr[i+2] - 1)) i += 3 if(arr[i] == 21): print('%d xor R%d, %d'%(i, arr[i+1]-1, arr[i+2])) i += 3 if(arr[i] == 22): print('%d and R%d, R%d'%(i, arr[i+1]-1, arr[i+2]-1)) i += 3 if(arr[i] == 23): print('%d or R%d, R%d'%(i, arr[i+1]-1, arr[i+2]-1)) i += 3 if(arr[i] == 25): print('%d mov R%d, R%d'%(i, arr[i+1]-1, arr[i+2]-1)) i += 3 if(arr[i] == 26): print('%d mov R%d, R%d'%(i, arr[i+1]-1, arr[i+2]-1)) i += 3 if(arr[i] == 27): print('%d mov R%d, [R%d]'%(i, arr[i+1]-1, arr[i+2]-1)) i += 3 if(arr[i] == 28): print('%d mov [R%d], R%d'%(i, arr[i+1]-1, arr[i+2]-1)) i += 3 if(arr[i] == 29): print('%d mul R%d, %d'%(i, arr[i+1]-1, arr[i+2])) i += 3
运行结果如下,加上简单注释:
0 mov R0, 0
3 mov R2, 70
6 jmp 21
//获取70个字符的输入
8 push R0
10 pop R1
12 R0 = getchar()
13 push R0
15 push R1
17 pop R0
19 inc R0
cmp R0, R2
jnz 24
mov a, 80
24 and a, 0x80
test a
jnz 8
26 mov R0, 0
29 mov R2, 71
32 jmp 70
//进行70个字符的流加密,加*为运算
34 push R0
36 mov R1, 5
39 mul R0, 4
42 sub R1, R0
45 mov R0, R1
48 mov R0, [R0]
51 mul R0, 110 *
54 add R0, 99 *
57 xor R0, 116 *
60 add R0, 102 *
63 mov [R1], R0
66 pop R0
68 inc R0
cmp R0, R2
jnz 73
mov a, 80
73 and a, 0x80
test a
jnz 34
可以分析得到运算为 ((a*110)+99)^116+102,最后再调用函数和数据比较,我们把比较数据dump下来然后写脚本即可。
arr = [ 0x36D3, 0x2AFF, 0x2ACB, 0x2B95, 0x2B95, 0x2B95, 0x169F, 0x186D, 0x18D7, 0x1611, 0x18D7, 0x2B95, 0x2C23, 0x2CA9, 0x1611, 0x1611, 0x18D7, 0x2AFF, 0x1849, 0x18FB, 0x2ACB, 0x2A71, 0x1735, 0x18D7, 0x1611, 0x2ACB, 0x15DD, 0x18D7, 0x2C23, 0x169F, 0x15DD, 0x2B95, 0x169F, 0x156B, 0x186D, 0x2AFF, 0x1611, 0x1611, 0x15DD, 0x2AFF, 0x2C23, 0x2ACB, 0x15DD, 0x15DD, 0x186D, 0x1849, 0x2B95, 0x156B, 0x1735, 0x18FB, 0x18FB, 0x2A71, 0x2AFF, 0x1735, 0x2C23, 0x15DD, 0x18D7, 0x2A71, 0x18D7, 0x18D7, 0x2C23, 0x2AFF, 0x156B, 0x2C23, 0x169F, 0x35AF, 0x2CA9, 0x32B5, 0x2AFF, 0x3039 ] flag = [0 for i in range(70)] for i in range(70): flag[i] = int((((arr[i] - 102) ^ 116) - 99) / 110) flag.reverse() print(''.join(map(chr,flag)))
运行可得flag为”nctf{3e1ce77b70e4cb9941d6800aec022c813d03e70a274ba96c722fed72783dddac}“。