一道XCTF安卓逆向之easyapk的變種題分析

0x00

下載下來是一個apk,拖進模擬器運行一下,是一個輸入框,輸入flag然後檢查flag是否正確。

改後綴爲zip後使用dex2jar反編譯得到一個classes-dex2jar.jar。

0x01

將這個jar拖進jd-gui查看一波反編譯出來的java代碼,得到如下核心代碼:

protected static boolean checkflag(String paramString) {
	    String[] arrayOfString = paramString.split("_");
	    System.out.println("xxx1"+":"+String.format("%d", new Object[] { Integer.valueOf(arrayOfString.length) }));
	    if (arrayOfString.length == 4 && paramString.length() == 27) {
	      StringBuilder stringBuilder = new StringBuilder();
	      for (int i = 0; i < arrayOfString.length; i++) {
	        String str2 = reChange(arrayOfString[i]);
	        System.out.println(str2);
	        String str1 = str2.substring(0, i + 1);
	        str2 = str2.substring(i + 1);
	        str1 = reChange(str1);
	        str2 = reChange(str2);
	        stringBuilder.append(str1);
	        stringBuilder.append(str2);
	      } 
	      BigInteger bigInteger1 = new BigInteger(stringBuilder.toString(), 16);
	      BigInteger bigInteger2 = new BigInteger("A3332C65844CC6F5E5DABE8DD42FDE39", 16);
	      if (bigInteger1.pow(65537).mod(bigInteger2).toString(16).compareTo("6d14c92d4ae244b583227f1e870f57bc") == 0)
	        return true; 
	    } 
	    return false;
	  }
public static String reChange(String paramString) {
	    char[] arrayOfChar = paramString.toCharArray();
	    int j = arrayOfChar.length;
	    for (int i = 0; i < j / 2; i++) {
	      char c = arrayOfChar[i];
	      int k = j - 1 - i;
	      arrayOfChar[i] = arrayOfChar[k];
	      arrayOfChar[k] = c;
	    } 
	    return String.valueOf(arrayOfChar);
	  }

0x02邏輯分析:

首先是一系列的字符變換,這個先不管,看最後一句

bigInteger1.pow(65537).mod(bigInteger2).toString(16).compareTo("6d14c92d4ae244b583227f1e870f57bc"

RSA實錘了。大體就是將所給的字符串經過字符變換之後轉換爲16進制大整數通過RSA加密。

所以需要先將RSA密文還原爲明文,再根據字符變換逆回flag。

0x03攻擊RSA

在這裏,我開始的思路是猜測私鑰不會太大,使用已知明文攻擊找私鑰,但跑了一個小時還是沒出來,所以我估計私鑰不會太小。

此處RSA的n:"A3332C65844CC6F5E5DABE8DD42FDE39"和e:"65537"已經給出,故嘗試分解n得到p,q,再根據p,q和e得到私鑰d。

0x04暴力分解N

此處可以使用在線站點,也可以使用RSAtools:

此處使用RSA-tool2:在N處輸入模數N,如果是16進制,右上角base選擇16,然後FactorN,得到p:12004517743563056963

q:18070686016358995667

0x05根據p,q,e計算私鑰d

此處給出已知p,q,e求d的python3代碼:

#已知p,q,e,求解密密鑰d
def egcd(a, b):
    if a == 0:
      return (b, 0, 1)
    else:
      g, y, x = egcd(b % a, a)
      return (g, x - (b // a) * y, y)
def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
      raise Exception('模數分解失敗')
    else:
      return x % m
def main():
    e=65537
    p=12004517743563056963
    q=18070686016358995667
    d = modinv(e,(p-1)*(q-1))
    print(d) 
if __name__ == '__main__':
    main()

運行之後得到:d=72585793360129405920426096641020292037

0x06根據d與密文c計算明文m

RSA的解密數學公式爲:

明文m=c^d (mod N)

這裏^指求冪。

其他博客用的是大整數計算工具big Integer Calculator,這個工具我沒找到,直接使用python3的pow函數:

pow(c,d,N):

計算得到明文m=62823249404463802755091465448,轉爲16進制:cafe2c86588df9d0798304e8

0x07回到java,根據字符變換逆回flag。

在checkflag處打斷點,輸入"abcd_ef_ghijk",使用F5步進查看變量變化情況以觀察其邏輯,得到如下邏輯:

1.根據下劃線將字符串分爲3組

2.分別對每個分組根據組號作爲長度做字符串反轉

3.分別對每個分組根據組號作爲長度做字符串切割

4.拼接操作得到結果:

d abc ef ijk gh

0x08根據字符變換邏輯寫出逆向算法:

根據上述邏輯,該字符串分爲4組,且第 i 組長度至少爲 i  , 否則會發生數組下標越界。

且明文長度爲24,推測每組6個字符。如果每一組的長度不等,或許還有其他flag也能通過驗證。

根據上述邏輯,將cafe2c86588df9d0798304e8分爲4組,第一組取第一個字符拼接到第一組末尾,第二組取前兩個字符拼接到第二組末尾,3,4同理。最終得到flag:afe2cc_588d86_079f9d_e88304

發佈了109 篇原創文章 · 獲贊 35 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章