2018xman冬令營選拔賽第2題wp-Android結合js的逆向實踐

第2題wp 繞着繞着就出來了

1.      使用jd-gui反編譯apk源代碼。

2.      查看主進程中的OnCreate()函數:

點擊按鈕a的時候,會創建b對象,b對象會執行url中的js。



3.      查看b類的源代碼:

點擊的響應函數是調用a對象的a方法對輸入的字符串進行處理,之後主進程中的b對象加載url中的“javascript:o0O0oo0o0o0o0oO()”js代碼。


4.      查看a對象的a方法是如何對輸入字符串處理的。

主要有以下幾個關鍵點:

(1)      輸入由‘-’分成了四組;

(2)      輸入除了’-‘可以包含數字、大小寫字母;

(3)      最後交由b方法處理輸入字符串。

這大概是一個註冊碼,我們應該是做一個逆向,推出其中正確的註冊碼。

public static void a(String paramString)

  {

    a = 0;

    b = 0;

    MainActivity.b.getSettings().setUserAgentString(MainActivity.b.getSettings().getUserAgentString() + ";" + a + ";" + b);

    String[] arrayOfString = paramString.split("-");

    if (arrayOfString.length != 4) {

      return;

    }

    for (int i = 0;; i++)

    {

      if (i >= arrayOfString.length) {

        break label192;

      }

      if (arrayOfString[i].length() != 4) {

        break;

      }

      int j = 0;

      label95:

      if (j < arrayOfString[i].length())

      {

        if ((arrayOfString[i].charAt(j) > '/') && (arrayOfString[i].charAt(j) < ':')) {}

        for (;;)

        {

          j++;

          break label95;

          if ((arrayOfString[i].charAt(j) <= '@') || (arrayOfString[i].charAt(j) >= '[')) {

            if ((arrayOfString[i].charAt(j) <= '`') || (arrayOfString[i].charAt(j) >= '{')) {

              break;

            }

          }

        }

      }

    }

    label192:

    b(paramString);

  }

 

5.      查看a對象的b方法是如何對輸入字符串處理的。

主要有以下幾個關鍵點:

(1)      原來輸入的順序被重新排列,變成了1 3 4 2;

(2)      包含了一系列的判斷條件,只要滿足其中一個,就不會執行最下面的語句,所以應該讓所有的判斷條件不滿足;

(3)      出現了很多奇怪的字符,是反編譯的時候錯誤將負數當成了字符處理,具體的數值要查看smali代碼獲得(可以參考下面的逆向腳本);

(4)      a和b是其中關鍵了兩個數字,他們由字符串的某一位異或而來。根據判斷條件可知,這一位和其他位有着聯繫;

(5)      最後,主進程的b對象(WebView)的UserAgent後面加上了";" + a + ";" + b,其中的a大於b,並且a小於100。

public static void b(String paramString)

  {

    String[] arrayOfString = paramString.split("-");

    char[] arrayOfChar1 = arrayOfString[0].toCharArray();

    char[] arrayOfChar2 = arrayOfString[3].toCharArray();

    if (arrayOfChar1[0] != '�' + arrayOfChar2[1]) {}

    label33:

    char[] arrayOfChar3;

    char[] arrayOfChar4;

    do

    {

      do

      {

        do

        {

          break label33;

          do

          {

            return;

          } while ((arrayOfChar1[3] != (char)(0x1 | arrayOfChar2[2])) || (arrayOfChar2[2] % '\002' == 1));

          a = 0x37 ^ arrayOfChar2[3];

        } while ((arrayOfChar2[2] != arrayOfChar1[2] + 2 * arrayOfChar1.length) || (arrayOfChar2[0] != arrayOfChar1[0] - arrayOfChar1.length / 2) || (arrayOfChar2[1] != (char)(0x12 ^ arrayOfChar1[3])) || ('\002' * arrayOfChar1[1] != '' + arrayOfChar1[2]) || (arrayOfChar2[3] != arrayOfChar1[2]));

        arrayOfChar3 = arrayOfString[1].toCharArray();

        arrayOfChar4 = arrayOfString[2].toCharArray();

      } while ((arrayOfChar3[1] + 3 * arrayOfString.length != arrayOfChar3[3]) || ('\002' * arrayOfChar4[1] != '' + arrayOfChar3[3]));

      b = 0x71 ^ arrayOfChar3[2] - arrayOfChar4.length;

    } while ((arrayOfChar3[0] + arrayOfChar4[0] != 187) || (arrayOfChar3[0] + arrayOfChar4[3] != 210) || ((arrayOfChar3[3] ^ arrayOfChar3[2]) != '/') || ((arrayOfChar3[0] ^ arrayOfChar3[1]) != '\017') || ((arrayOfChar4[2] ^ arrayOfChar3[1]) != '\005') || (a <= b) || (a >= 100));

    MainActivity.b.getSettings().setUserAgentString(MainActivity.b.getSettings().getUserAgentString() + ";" + a + ";" + b);

  }

 

6.      查看完a對象的a方法後,查看./android_asset/check_flag.html這個文件的 “javascript:o0O0oo0o0o0o0oO()”js代碼。

可以看到有相當大的混淆代碼,進行優化。


7.      只貼上優化後的關鍵代碼。

主要有以下幾個關鍵點:

(1)      Js 首先取出了userAgent中的數字,保存在bbb中;

(2)      Js中 包含了較多的匿名函數;

(3)      Js中通過navigator函數使用數組中的字符串,進行函數的調用;

(4)      Js最後的語句是將result變量設置爲"flagis XCTF{your input}" 或者 "try again",當然我們希望是前者,所以要ggg(bbb[bbb["length"] - 2])(bbb[bbb["length"] -1])是true;

(5)      ggg是一個匿名函數,首先通過傳入一個參數,返回了再次使用一個參數的函數,這個函數也是匿名函數,包含一個遞歸函數返回了一系列的表達式的與 值;

(6)      因此ggg爲true,就要求調用的匿名函數中的一系列表達式都成立;

(7)      第一個表達式是一個二元二次方程,用平方差公式化簡就是c-e==56,第二、三個表達式限定了一定的範圍,第四個表達式表達的意義和輾轉相除餘7相似;

(8)      貌似這樣的c和e是有很多種的。

var aaa = ["map", ";", "split", "userAgent", "innerHTML", "result", "getElementById", "length", "flag is XCTF{your input}", "try again"];

        var arr = [aaa[0], aaa[1], aaa[2], aaa[3], aaa[4], aaa[5], aaa[6], aaa[7], aaa[8], aaa[9]];

function F2() {

            const bbb = navigator["userAgent"]["split"](";")["map"]((fff) = > Number(fff));

            var ggg = function(c)

            {

                return

                function(e)

                {               

                    var ddd = function(c, e)

                    {

                        return 0 === e ? c : ddd(e, c % e)

                    };

 

                    return c * c - e * e == 56 * (c + e) && 1e4 < c * c + c * e + e * e && 1e4 > c * c - c * e - e * e && 7 == ddd(c, e)

                }

            };

            document["getElementById"]("result")["innerHTML"] = ggg(bbb[bbb["length"] - 2])(bbb[bbb["length"] - 1]) ? "flag is XCTF{your input}" : "try again"

        }

 

8.      理一下思路,Apk內是對輸入字符串合法性的檢驗,並將字符串轉換爲兩個數字,通過加在userAgent後面傳遞到js中,如果這兩個數字正確那麼就會有相應的提示。那麼應該根據js推出這兩個數字,再根據字符串之間的制約關係,還原其中的一個可行註冊碼。

9.      第一步的腳本,還原兩個數字。

結果只有一組,是91 和 35。那麼對應到apk中,就是a=91,b=35。

def d(c,e):

         if e==0:

                   return c

         else:

                   return d(e, c % e)

 

for e in range(45):

         c=56+e

         if(1e4 < c * c + c * e + e * e):

                   if(1e4 > c * c - c * e - e * e):

                            if(7 == d(c, e)):

                                     print(str(c)+"   "+str(e))

 

 

10.  第二步的腳本,還原註冊碼。

Apk源代碼中的錯誤字符,參考smali代碼。結果就是flag。

d2lu-bmVy-Y7hp-bgtl

a=91

b=35

a1=[0,0,0,0]

a2=[0,0,0,0]

a3=[0,0,0,0]

a4=[0,0,0,0]

a2[3]=a^0x37

a1[2]=a2[3]

a2[2]=a1[2]+2*4

a1[1]=(int) ((a1[2]-8)/2)

a1[3]=0x1 | a2[2]

a2[1]=0x12^a1[3]

a1[0]=a2[1]-3

a2[0]=(int)(a1[0]-1/2*4)

 

a3[2]=(b+4)^0x71

a3[3]=47^a3[2]

a3[1]=a3[3]-3*4

a3[0]=a3[1]^15

a4[2]=a3[1]^5

a4[3]=210-a3[0]

a4[0]=187-a3[0]

a4[1]=(int)((a3[3]-0xb)/2)

 

for i in range(4):

         a1[i]=chr(a1[i])

for i in range(4):

         a2[i]=chr(a2[i])

for i in range(4):

         a3[i]=chr(a3[i])

for i in range(4):

         a4[i]=chr(a4[i])         

print(''.join(a1)+'-'+''.join(a3)+'-'+''.join(a4)+'-'+''.join(a2))

11.  這道題目思路比較簡單,但是很繞,需要耐心細緻的分析和琢磨。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章