網鼎杯-re-signal

下載附件打開後就是一個32位的pe文件,用IDA(32)打開,F5定位至主函數main處,如圖:python

 函數_main()就是一個初始化的函數,qmemcpy則是將unk_403040地址處的值賦給v4,再進入vm_operad()函數,可知,vm_operad()函數既是關鍵函數c++

進入後,以下:算法

 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,並執行相應的操做。但有一個咱們注意的點,那就是咱們要找到進行輸入的函數或者操做在哪。windows

觀察該函數,發現case 10中有一個read(Str)操做,進去後發現函數

 

 所以咱們就知道了,首先要進入case 10,咱們才能進行輸入,並且,字符串的大小爲15位!,不然錯誤並退出程序。post

回到vm_operad()函數中,咱們要去查看a1(也就是傳入的v4)地址處的值,才能知道具體進行了什麼操做。把數據提取後如圖:spa

 

 數據第一個恰是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]。3d

到這裏該函數的邏輯就清楚了,咱們只須要根據遍歷傳入的值,將進行的操做逆一下就能夠了。這裏有幾種作法:調試

①動態調試,寫出相應的操做後,直接寫出逆回去的式子code

②使用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

相關文章
相關標籤/搜索