下載附件打開后就是一個32位的pe檔案,用IDA(32)打開,F5定位至主函式main處,如圖:

函式_main()就是一個初始化的函式,qmemcpy則是將unk_403040地址處的值賦給v4,再進入vm_operad()函式,可知,vm_operad()函式既是關鍵函式
進入后,如下:
1 int __cdecl vm_operad(int *a1, int a2) 2 { 3 int result; // eax 4 char Str[100]; // [esp+13h] [ebp-E5h] 5 char v4[100]; // [esp+77h] [ebp-81h] 6 char v5; // [esp+DBh] [ebp-1Dh] 7 int v6; // [esp+DCh] [ebp-1Ch] 8 int v7; // [esp+E0h] [ebp-18h] 9 int v8; // [esp+E4h] [ebp-14h] 10 int v9; // [esp+E8h] [ebp-10h] 11 int v10; // [esp+ECh] [ebp-Ch] 12 13 v10 = 0; 14 v9 = 0; 15 v8 = 0; 16 v7 = 0; 17 v6 = 0; 18 while ( 1 ) 19 { 20 result = v10; 21 if ( v10 >= a2 )//是否>=114 22 return result; 23 switch ( a1[v10] )//若a1[v10]存在 24 { 25 case 1: 26 v4[v7] = v5; 27 ++v10; 28 ++v7; 29 ++v9; 30 break; 31 case 2: 32 v5 = a1[v10 + 1] + Str[v9]; 33 v10 += 2; 34 break; 35 case 3: 36 v5 = Str[v9] - LOBYTE(a1[v10 + 1]);#這里取了a1[v10+1]的低位,資料中有FFFFFF開頭的,這里為負數,如FFFFFFF1,取它的低位,也就是F1 37 v10 += 2; 38 break; 39 case 4: 40 v5 = a1[v10 + 1] ^ Str[v9]; 41 v10 += 2; 42 break; 43 case 5: 44 v5 = a1[v10 + 1] * Str[v9]; 45 v10 += 2; 46 break; 47 case 6: 48 ++v10; 49 break; 50 case 7: 51 if ( v4[v8] != a1[v10 + 1] )//若有一個不等的情況存在,則直接退出程式 52 { 53 printf("what a shame..."); 54 exit(0); 55 } 56 ++v8; 57 v10 += 2; 58 break; 59 case 8: 60 Str[v6] = v5; 61 ++v10; 62 ++v6; 63 break; 64 case 10: 65 read(Str); 66 ++v10; 67 break; 68 case 11: 69 v5 = Str[v9] - 1; 70 ++v10; 71 break; 72 case 12: 73 v5 = Str[v9] + 1; 74 ++v10; 75 break; 76 default: 77 continue; 78 } 79 } 80 }
該函式的邏輯就是根據傳入的a1的值,遍歷進入相應的case,并執行相應的操作,但有一個我們注意的點,那就是我們要找到進行輸入的函式或者操作在哪,
觀察該函式,發現case 10中有一個read(Str)操作,進去后發現

因此我們就知道了,首先要進入case 10,我們才能進行輸入,而且,字串的大小為15位!,否則錯誤并退出程式,
回到vm_operad()函式中,我們要去查看a1(也就是傳入的v4)地址處的值,才能知道具體進行了什么操作,把資料提取后如圖:

資料第一個恰是10,也就是會執行case 10里的操作,輸入我們的資料,繼續遍歷進行操作,直至進入case 7中,v4[v8]的值等于a1[v10+1],這里我們要注意,是在a1[v10]==7的時候,我們才進入case 7 ,因此a1[v10+1]=a1中,7數字之后的數,也就是說,輸入的資料進行一系列的操作后,要與每個7之后的資料相比較,將這些資料提取出來,即為 [34, 63, 52, 50, 114, 51, 24, -89, 49,-15, 40,-124, -63, 30, 122],
到這里該函式的邏輯就清楚了,我們只需要根據遍歷傳入的值,將進行的操作逆一下就可以了,這里有幾種做法:
①動態除錯,寫出相應的操作后,直接寫出逆回去的式子
②使用c/c++或者python,根據演算法,更改資料順序,寫出逆演算法(這里可以參考https://bbs.pediy.com/thread-259595.htm)
③使用angr寫腳本直接得出
下面介紹第一種和第三種,
方法①:
使用IDA動態除錯(選擇remote windows server, 在本地運行win32_remote.exe),運行后如下:

設定好相應斷點

單步運行,寫下相應的操作,如下:
1. v4[0]=(Str[0]^0x10)-5 2. v4[1]=(Str[1]^0x20)*3 3. v4[2]=(Str[2]-2)-1 4. v4[3]=(Str[3]+1)^4 5. v4[4]=(Str[4]*3)&0xff-0x21
6. v4[5]=(Str[5]-1)-1 7. v4[6]=(Str[6]^0x9)-0x20 8. v4[7]=(Str[7]+0x51)^0x24 9. v4[8]=(Str[8]+1)-1 10.v4[9]=(Str[9]*2)+0x25 11.v4[10]=(Str[10]+0x36)^0x41 12.v4[11]=(Str[11]+0x20)*1 13.v4[12]=(Str[12]*3)+0x25 14.v4[13]=(Str[13]^9)-0x20 15.v4[14]=(Str[14]+0x41)+1
逆過去后,腳本如下:
b=[34, 63, 52, 50, 114, 51, 24, 256-89, 49,256-15, 40,256-124, 256-63, 30, 122]#(負數取了最低位,因此,直接取后面那部分) flag=[0]*15 flag[0]=(b[0]+5)^0x10 flag[1]=(b[1]//3)^0x20 flag[2]=(b[2]+3) flag[3]=(b[3]^4)-1 flag[4]=(b[4]+0x21)//3 flag[5]=b[5]+2 flag[6]=(b[6]+0x20)^9 flag[7]=(b[7]^0x24)-0x51 flag[8]=b[8] flag[9]=(b[9]-0x25)//2 flag[10]=(b[10]^0x41)-0x36 flag[11]=(b[11]-0x20) flag[12]=(b[12]-0x25)//3 flag[13]=(b[13]+0x20)^9 flag[14]=(b[14]-1)-0x41 print(flag) for i in flag: print(chr(i),end='')
運算結果如下:

方法③:
腳本如下:
import angr import sys def Go(): path_to_binary="signal.exe" project=angr.Project(path_to_binary,auto_load_libs=False) initial_state=project.factory.entry_state() simulation=project.factory.simgr(initial_state) simulation.explore(find=0x0040179E,avoid=0x004016E6) if simulation.found: solution_state=simulation.found[0] solution=solution_state.posix.dumps(0) print("[+] Success! Solution is: ",solution) else: print('Could not find the solution') if __name__ == "__main__": Go()
結果如下:

有關angr可以參考以下三篇文章:
https://www.anquanke.com/post/id/212816
https://www.anquanke.com/post/id/213423
https://www.anquanke.com/post/id/214288
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/451.html
標籤:其他
