2018/12/03-NCTF-WcyVM
題目連結: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}“。