【CTF】看雪CTF第一題 流浪者


下載題目,從圖標初步判斷是一個MFC程序,其它也沒什么好看的,直接拖入虛擬機雙擊運行看下顯示效果。

雙擊后程序顯示一個輸入框,提示輸入passwod,並驗證。

首先什么都不輸入,直接驗證,程序彈窗輸出提示字符串:“請輸入pass!”。

而隨意輸入pass,則彈窗輸出提示字符串:“錯了! 加油!”,並且程序退出。

從以上信息我們猜測:

1、如果pass正確,程序應該會和失敗時一樣彈窗,並且提示相關字符串,我們可以從搜索錯誤或者正確時提示的字符串入手,也可以從彈窗API入手。

2、既然程序需要用戶輸入,那我們就從輸入控件,或者獲取控件字符串的API入手。

3、假如程序是MFC程序,並且用戶輸入后需要點擊按鈕驗證,我們可以從OD搜索MFC按鈕事件代碼入手。

4、輸入pass錯誤后,程序會退出,搜索退出函數或API下斷,然后代碼回溯。

有了以上4個破解思路,我們就可以打開IDA開始分析了。

待IDA分析完代碼后,按快捷鍵Shift+F12查看字符串。

雙擊可疑字符串,查看代碼交叉引用。

F5查看偽代碼。

 1 int __thiscall sub_401890(CWnd *this)
 2 {
 3   struct CString *v1; 
 4   CWnd *v2; 
 5   int v3; 
 6   int result; 
 7   int v5[26]; 
 8   int i;
 9   char *Str; 
10   CWnd *v8; 
11 
12   v8 = this;
13   v1 = (CWnd *)((char *)this + 100);
14   v2 = CWnd::GetDlgItem(this, 1002);
15   CWnd::GetWindowTextA(v2, v1);
16   v3 = sub_401A30((char *)v8 + 100);
17   Str = CString::GetBuffer((CWnd *)((char *)v8 + 100), v3);
18   if ( strlen(Str) )
19   {
20     for ( i = 0; Str[i]; ++i )
21     {
22       if ( Str[i] > 57 || Str[i] < 48 )
23       {
24         if ( Str[i] > 122 || Str[i] < 97 )
25         {
26           if ( Str[i] > 90 || Str[i] < 65 )
27             sub_4017B0();
28           else
29             v5[i] = Str[i] - 29;
30         }
31         else
32         {
33           v5[i] = Str[i] - 87;
34         }
35       }
36       else
37       {
38         v5[i] = Str[i] - 48;
39       }
40     }
41     result = sub_4017F0(v5);
42   }
43   else
44   {
45     result = CWnd::MessageBoxA(v8, "請輸入pass!", 0, 0);
46   }
47   return result;
48 }

第15、17行代碼將用戶輸入的pass保存到Str。

第18行代碼使用strlen函數檢測pass長度,如果為空,則第45行代碼彈窗提示重新輸入。

第22、24、26行代碼通過循環比較來判斷pass每個字符是否在0-9,a-z,A-Z范圍之間。通過IDA快捷鍵“R”可以將比較數值轉換為字符顯示。

第29、33、38行代碼則對不同范圍內的字符進行減法操作:

0-9:Str[i] -= 48

a-z:Str[i] -= 87

A-Z:Str[i] -= 29

第41行程序將處理后的pass交由“sub_4017F0”函數進行驗證處理。

 1 int __cdecl sub_4017F0(int a1)
 2 {
 3   int result; 
 4   char Str1[28]; 
 5   int v3; 
 6   int v4; 
 7 
 8   v4 = 0;
 9   v3 = 0;
10   while ( *(_DWORD *)(a1 + 4 * v4) < 62 && *(_DWORD *)(a1 + 4 * v4) >= 0 )
11   {
12     Str1[v4] = aAbcdefghiabcde[*(_DWORD *)(a1 + 4 * v4)];
13     ++v4;
14   }
15   Str1[v4] = 0;
16   if ( !strcmp(Str1, "KanXueCTF2019JustForhappy") )
17     result = sub_401770();
18   else
19     result = sub_4017B0();
20   return result;
21 }

第10行代碼循環遍歷pass字符,判斷pass[i]是否>=0並且<62。

第12行代碼如果以上條件滿足,程序將pass[i]的值當做下標索引來獲取“aAbcdefghiabcde”字符數組對應索引位置的字符,保存到Str1。

第16行代碼使用“strcmp”函數比較Str1是否等於“KanXueCTF2019JustForhappy”字符串,如果等於則調用第17行函數,否則調用第19行函數。

第17行代碼:pass正確!

第19行代碼:pass錯誤!

假設:

字符串1 = "KanXueCTF2019JustForhappy"。

字符串2 = "abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQR"。

通過以上分析我們知道,正確的pass在經過一系列減法操作后,最終應該等於字符串1。

而字符串1是通過字符串2得到的。所以通過反向思維,我們首先獲取字符串1每個字符在字符串2中的下標索引。

然后根據每一個索引值的范圍加上不同的數,最終就是輸入時正確的pass!

 1 void deCode()
 2 {
 3     char* key1 = "KanXueCTF2019JustForhappy";
 4     char* key2 = "abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ";
 5 
 6     for (int i = 0; i < strlen(key1); i++)
 7     {
 8         char* s = strchr(key2, key1[i]);
 9         char c = s - key2;
10         if ((c + 48 >= '0') && (c + 48 <= '9'))
11         {
12             printf("%c", c + 48);
13         }
14         else if ((c + 87 >= 'a') && (c + 87 <= 'z'))
15         {
16             printf("%c", c + 87);
17         }
18         else if ((c+29 >= 'A') && (c+29 <= 'Z'))
19         {
20             printf("%c", c + 29);
21         }
22     }
23     printf("\n");
24 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM