1. 程式人生 > 實用技巧 >[逆向學習] BUUOJ 第二彈

[逆向學習] BUUOJ 第二彈

1.Java逆向解密

工具:jd-gui

拖入jd-gui得到加密函式 public static void Encrypt(char[] arr)

易得出是將使用者輸入加上‘@’^0x20的值再與KEY比較是否相等。

0x20為16進位制,異或時要轉換為10進位制即32

可寫出指令碼:

key=[180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65]
a=''
for i in key:
    a += chr(i - ord('@')^32)
print (a)

解得 This_is_the_flag_!

2.[BJDCTF2020]BJD hamburger competition

工具:dnSpy,C#線上ide

下載開啟壓縮包,發現是以unity為框架的小遊戲,直接搜尋Assembly-CSharp.dll檔案,拖入dnspy進行反編譯,找到關鍵類函式 ButtonSpawnFruit .發現關鍵程式碼

找個網站解密雜湊值得:

接著就是進行MD5加密,跟進函式。

一開始看不太懂,直接就用c#線上ide把這段程式碼搬上去。

後來查到是呼叫系統md5加密函式後將字母全部轉換為大寫,再取前20個字元作為結果返回.得到md5加密後的結果,注意是用flag{}包上,而不是BJDCTF{} 。

3.[HDCTF2019]Maze

工具:Exeinfo pe,upx,IDA

拖入Exeinfo pe,發現是一個加了upx殼的32位程式,走個流程脫殼。

拖入IDA中尋找start函式,跟進main。

發現main沒有被ida識別成函式,看樣子是被加花指令了。

注意到_mian中有個jnz跳轉,前面有個cmp,且跳轉地址和與指令相鄰的下一地址相同,所以相當於沒跳轉,把他nop掉。

因為下面call另一個不是地址的地址,所以將反編譯程式碼轉換成機器碼來看看。

其中
E8 對應指令為 call
58 對應指令為 pop

當ida把E8識別為call時,58 C7 45 EC便會被看作地址,此地址不存在便會無法反彙編,因此真正的指令應該是pop,所以把db 0E8h

nop掉後,IDA就可以自動轉換出彙編指令了

接著按p將_mian轉換為函式再進行反彙編。跟進 dword_408078和 dword_40807C檢視到初始狀態:dword_408078=7 dword_40807C=0,然後經過14次移動後要使 dword_408078=5 dword_40807C=-4才能解出答案。

結合程式碼和題目名字Maze可得是一道迷宮題,但是程式好像沒有判斷迷宮。只要滿足兩個a和四個s就可以得到Congratulations!

用ida搜尋一下字串,處理一下得到資料

整理一下

*******+**
******* **
****    **
**   *****
** **F****
**    ****
**********

因為dword_408078=7 dword_40807C=0,所以是+為起點,F為中點,且ad控制左右,ws控制上下。又因為

a --dword_408078
d ++dword_408078
s --dword_40807C
w ++dword_40807C

所以s是上,w是下,a是右,d是左。

若迷宮為正向,則行走路徑為wwdddwddwwaaas;若迷宮為反向,則行走路徑為ssaaasaassdddw。

先驗證一下.

排除正向迷宮,提交一下:flag{ssaaasaassdddw}

4.[GKCTF2020]BabyDriver

工具:IDA

根據題目描述,拖入IDA64中。看來看去沒有頭緒,搜下字串,估計是個迷宮題

跟進字串,發現一共有224個字元,猜測是16*14 或 14*16,寫個指令碼驗證一下

list = '****************o.*..*......*..**.**...**.*.*.***.****.**.*.*.***...**....*.*.*****..***.**.*..**.**.***.**.**.**.**.******.**.**.**....***.**.**.*****.***....**...***.**********..***......#****.***************************** '
a = 0
for i in range(len(list)):
    a = a + 1
    print(list[i], end='')
    if a % 16 == 0:
        print('\n', end='')

得到

****************
o.*..*......*..*
*.**...**.*.*.**
*.****.**.*.*.**
*...**....*.*.**
***..***.**.*..*
*.**.***.**.**.*
*.**.******.**.*
*.**....***.**.*
*.*****.***....*
*...***.********
**..***......#**
**.*************
****************

跟進a0,並檢視交叉引用列表。

跟進sub_140001380進行反編譯。得到關鍵程式碼,先分析好分析。

      v9 = aO[v5];
      if ( v9 == '*' )
      {
        v10 = "failed!\n";
      }
      else
      {
        if ( v9 != '#' )
        {
LABEL_27:
          aO[v5] = 'o';                   //更新位置
          goto LABEL_28;
        }
        v10 = "success! flag is flag{md5(input)}\n";
      }
      dword_1400030E4 = 16;
      DbgPrint(v10);
      v5 = dword_1400030E4;
      goto LABEL_27;
    }
  }

可知當碰到*時結束。碰到#時,你所輸入的值md5加密後就是flag。

再來分析輸入判斷。由於是驅動檔案,所以輸入比較的是16進位制的鍵盤碼

LABEL_28:
        v6 += 6;
        if ( !--v7 )
          goto LABEL_29;
      }
      aO[v5] = 46;
      v8 = *v6;
      if ( *v6 == 0x17 )                 // I
      {
        if ( v5 & 0xFFFFFFF0 )           // 當V5>16,條件成立,因為是向上。所以不用考慮208這倒數第二層的邊界
        {
          v5 -= 16;                      //上移
          goto LABEL_21;
        }
        v5 += 208;                       // 當V5<16也就是在第一層,強制碰到最後一層牆壁結束
        dword_1400030E4 = v5;
      }
      if ( v8 == 0x25 )                  // K
      {
        if ( (v5 & 0xFFFFFFF0) != 208 )  // 當V5>16且不等於208,條件成立,因為是向下。所以要考慮208這倒數第二層的邊界
        {
          v5 += 16;                      //下移
          goto LABEL_21;
        }
        v5 -= 208;                       // 當v5=208,強制碰到第一層牆壁結束
        dword_1400030E4 = v5;
      }
      if ( v8 == 0x24 )                  // J
      {
        if ( v5 & 15 )                   //當v5不等於16的倍數時,即不在每一層的左邊界,條件成立
        {
          --v5;                          //左移
          goto LABEL_21;
        }
        v5 += 15;                        //當v5等於16的倍數時,即在某一層的左邊界 ,向右移15位,即移動到這一層的右邊界
        dword_1400030E4 = v5;
      }
      if ( v8 != 0x26 )                   // L
        goto LABEL_22;
      if ( (v5 & 15) == 15 )              //當v5等於16的倍數-1時,即在某一層的右邊界,條件成立      
        v5 -= 15;                         //向左移15位,即移動到這一層的左邊界
      else
        ++v5;                             //右移
LABEL_21:
      dword_1400030E4 = v5;

所以,根據上面的迷宮和程式碼的分析:
若為正向迷宮,則行走路徑為 LKKKLLKLKKKLLLKKKLLLLLL;
若為反向迷宮,則行走路徑為 JIIIJJIJIIIJJJIIIJJJJJJ。

然後進行md5 32位小寫加密,進行驗證,可得到只有正向才是對的,即flag{403950a6f64f7fc4b655dea696997851} 。