over 4 years ago

這是一題 ARM 架構 reverse 題,用來包裝的 apk 中有個 libbctfjni.so,其中有 JNI1 ~ JNI6 六個函數。而主程式的 java 部份很簡單: 傳入 24 byte 的字串給 JNI1,然後有個 callback 中會檢查回傳值 (3 byte) 正不正確。

我們分頭研究 JNI1 ~ JNI6,試圖理解它們在做什麼,幾個重點如下:

  1. JNI1 會根據字串第 [0], [4], [8], [12], [16], [20] 位的值,決定 JNI 1~6 之後要接著呼叫誰,只能指定一個。
  2. JNI2 ~ JNI6 包含一些對字符本身的限制,例如 [7]>[5], [1]=[7], [2]是數字, [6]是大寫字母 ...
  3. JNI5 把字串前半段和後半段對調
  4. JNI2 將字串後半段移到前半段,並且之後長度/2
  5. JNI6 將字串折半 xor ,再折半 xor,所以總長度/4

我們一開始是假設所有函式恰被用過一次,也就是一個 1 ~ 6 的排列。JNI1 一定是第一個沒有問題,再來 JNI6 一定是最後一個,否則它回傳的字串長度已經太短了。而 JNI2 是倒數第二個,因為其中只有 JNI6 是只需要看 12 byte 的。剩下的 JNI 3,4,5,我們則發現不論順序怎麼排列,一定會有無法成立的條件 ... 為此我們再三檢查有沒有看錯 (ARM 沒有很熟練),然後一無所獲。

直到第一個提示出現,我們立刻果斷丟掉 JNI4,結果一切都說得通了。我們得到函式的呼叫順序是 1,5,3,2,6,7(end),這裡得到的字串是:

I...i...s... ... ...e...

接下來套上 JNI5 的限制,會得到

[0]=[6]+2=[9]+8, [1]=[7]=[12]=[16], [4]=[5]-5=[13]+3=[20]+4=[2]+7=[17]-4, [8]=[11]-1=[19]
I b.inG sA.t f.. m.se...
   R      l   or  Y  lf   (猜測得來的,其中 R-Y 符合了 [3]+7=[18],是很強力的條件)

這裡已經有點看得出樣子了,接下來加上 JNI3, JNI2 檢查和確定大小寫或數字等。最後 JNI6 加上後,我們發現最後一位沒辦法確定

I bRinG sA1t f0r mYse1f.

不過由大小的限制我們知道它是一個小於 48 的符號,可能的組合不多。我們嘗試了 .?! 後,發現正確的 key 如下:

I bRinG sA1t f0r mYse1f!
← BCTF 新型架构 Writeup BCTF 初来乍到 Writeup →