1. 程式人生 > >20181020學習筆記——解決的第一個Reverse題目

20181020學習筆記——解決的第一個Reverse題目

解決的第一個Reverse題目

題目描述

題目給了一個名為rev1的檔案,沒有後綴。

檔案的下載地址:

結題過程

第一次做Reverse題目,一臉矇蔽,我首先嚐試把字尾改為.exe,結果,不能執行。。。。可能不是Windows系統檔案。

我轉到虛擬機器裡,開啟Linux系統,執行“file rev1”,結果,果然是Linux下的可執行檔案,是ELF檔案。

然後我在終端執行“./rev1”,結果拒絕訪問。

修改許可權,在終端執行“chmod 777 rev1”

再次執行“./rev1”,執行成功了,終端顯示"Please input your flag:",隨便輸入,結果果然是wrong。

好吧,其實,上述步驟和解決這道題沒有半毛錢關係,這是我在完全小白的情況下對此題的摸索,接下來進入正題。

Windows下逆向分析強有力的工具是OD+IDA,我之前的部落格中提供了下載連結。題目提供的是ELF檔案,是無法使用OD的,好在這道題僅僅使用IDA就可以了。

  1. 把檔案拖入IDA中,執行ctrl+F5,得到程式的虛擬碼。
  2. 開啟虛擬碼檢視。虛擬碼的核心內容如下:
    //這是main函式
    
    __int64 __fastcall main(__int64 a1, char **a2, char **a3)
    {
      __int64 result; // [email protected]
      __int64 v4; // 
    [email protected]
    char s; // [sp+0h] [bp-30h]@1 __int64 v6; // [sp+28h] [bp-8h]@1 v6 = *MK_FP(__FS__, 40LL); printf("Please input your flag:", a2, a3); __isoc99_scanf("%32s", &s); if ( strlen(&s) == 32 ) { if ( (unsigned int)sub_400686((__int64)&s) ) puts("Right!"); else puts("Wrong!"); result = 0LL; } else { puts("Wrong!"); result = 0LL; } v4 = *MK_FP(__FS__, 40LL) ^ v6; return result; } //main函式中呼叫的子函式 signed __int64 __fastcall sub_400686(__int64 a1) { signed int i; // [sp+Ch] [bp-Ch]@1 for ( i = 0; i <= 31; ++i ) { if ( (char)(*(_BYTE *)(i + a1) ^ byte_400818[i]) != i ) return 0LL; } return 1LL; } //定義的全域性變數 _BYTE byte_400818[33] = { 102, 109, 99, 100, 127, 60, 54, 114, 87, 66, 100, 59, 123, 82, 124, 60, 102, 84, 96, 96, 39, 74, 73, 127, 113, 88, 82, 114, 125, 117, 42, 98, 0 }; // idb

    分析得到,主函式中輸入了一個長度為32的字串,然後呼叫子函式對字串進行處理(子函式返回一個判斷),所以最關鍵的部分就是分析子函式到底幹了啥。

  3. 我們來分析一下子函式到底幹了啥。子函式的虛擬碼如下:

    signed __int64 __fastcall sub_400686(__int64 a1)
    {
      signed int i; // [sp+Ch] [bp-Ch]@1
    
      for ( i = 0; i <= 31; ++i )
      {
        if ( (char)(*(_BYTE *)(i + a1) ^ byte_400818[i]) != i )
          return 0LL;
      }
      return 1LL;
    }

    定義了一個變數i(i用來控制迴圈),然後進入了一個for迴圈。觀察for迴圈中if語句的條件,“^”是異或運算,(i+a1)實際上就是在從傳入的字串變數中一次取值(第1個字元、第2個字元、第3個字元......一直到第31個字元),取出來以後和byte_400818[i](是定義的全域性變數)進行了異或運算,判斷異或運算的結果,滿足條件,則繼續迴圈,不滿足,則返回false。所以,每個字元的值怎麼求呢?其實很簡單,a^b = c,那麼b^c =a,所以(a1+i)=byte_400818[i]^i。

  4. 最後程式設計求出flag就行了。

    #include<stdio.h>
    
    int a[]={102,109,99,100,127,60,54,114,87,66,100,59,123,82,124,60,102,84,96,96,39,74,73,127,113,88,82,114,125,117,42,98,0};
    
    void test(){
    	int i;
    	for(i=0;i<32;i++){
    		printf("%c",a[i]^i);
    	}
    	printf("\n");
    }
    
    int main(){
        test();
        return 0;
    }

    flag{90u_Kn0w_r3vErs3__hiAHiah4}