攻防世界-Mobile-easyjni-最詳細分析

攻防世界-Mobile-easyjni

本文首發於博主公衆號LISTONE,歡迎關注哦!

這個題分析起來邏輯比上個easyjava要簡單許多,做題速度快了很多。

首先還是用jeb打開,打開後首先看這個配置文件(對於這道比較簡單的題來說,不看也可,不過爲了培養一下好的習慣,看一下比較好)。

在這裏插入圖片描述

打開配置文件後,就找下面這個標籤中的 name 屬性。
在這裏插入圖片描述

然後我們點擊那個 dex ,可以看到反編譯之後的目錄結構了,根據上面那個 name 屬性,我們就可以找到主文件。

在這裏插入圖片描述

接下來還是分析 onCreate 方法。
在這裏插入圖片描述

看到它調用了 MainActivity.a 方法,我們繼續跟進去看看這個 a 方法幹了什麼。

在這裏插入圖片描述

可以看到它有調用了另外一個 a 方法,去分析它。

在第二個 a 方法中可以看到有一個關鍵語句

v0_1 = this.ncheck(new a().a(arg3.getBytes()));

先實例化了一個 a 類的對象,然後調用了 ncheck ,這個ncheck 是我們的 so 文件裏的一個函數。

我們先來看這個 a 類的java代碼,先對它分析一下,我們再去看 so 文件。
在這裏插入圖片描述

我們主要分析 a 函數,看到有一個 a.a 靜態變量,這時我們猜測,這個是否是變種的base64編碼,我們寫一個java文件來調用一下這個類裏的 a 函數,進行測試一下

public class test{
    public static void main(String[] args){
        String s = "listone";//對listone進行變種base64編碼
        System.out.println(new a().a(s.getBytes()));
    }
}

class a {
    private static final char[] a = {'i', '5', 'j', 'L', 'W', '7', 'S', '0', 'G', 'X', '6', 'u', 'f', '1', 'c', 'v', '3', 'n', 'y', '4', 'q', '8', 'e', 's', '2', 'Q', '+', 'b', 'd', 'k', 'Y', 'g', 'K', 'O', 'I', 'T', '/', 't', 'A', 'x', 'U', 'r', 'F', 'l', 'V', 'P', 'z', 'h', 'm', 'o', 'w', '9', 'B', 'H', 'C', 'M', 'D', 'p', 'E', 'a', 'J', 'R', 'Z', 'N'};

    public a() {
        super();
    }

    public String a(byte[] arg10) {
        int v8 = 3;
        StringBuilder v4 = new StringBuilder();
        int v0;
        for(v0 = 0; v0 <= arg10.length - 1; v0 += 3) {
            byte[] v5 = new byte[4];
            int v3 = 0;
            byte v2 = 0;
            while(v3 <= 2) {
                if(v0 + v3 <= arg10.length - 1) {
                    v5[v3] = ((byte)(v2 | (arg10[v0 + v3] & 255) >>> v3 * 2 + 2));
                    v2 = ((byte)(((arg10[v0 + v3] & 255) << (2 - v3) * 2 + 2 & 255) >>> 2));
                }
                else {
                    v5[v3] = v2;
                    v2 = 64;
                }

                ++v3;
            }

            v5[v8] = v2;
            int v2_1;
            for(v2_1 = 0; v2_1 <= v8; ++v2_1) {
                if(v5[v2_1] <= 63) {
                    v4.append(a[v5[v2_1]]);
                }
                else {
                    v4.append('=');
                }
            }
        }

        return v4.toString();
    }
}

將上面的代碼保存爲 test.java ,然後在終端運行
在這裏插入圖片描述

可以看到對 listone 的加密結果爲 bSt9kSRzQ3==

然後我又找了一個python實現的對變種base64的加密實現。

base64_charset = ['i', '5', 'j', 'L', 'W', '7', 'S', '0', 'G', 'X', '6', 'u', 'f', '1', 'c', 'v', '3', 'n', 'y', '4', 'q', '8', 'e', 's', '2', 'Q', '+', 'b', 'd', 'k', 'Y', 'g', 'K', 'O', 'I', 'T', '/', 't', 'A', 'x', 'U', 'r', 'F', 'l', 'V', 'P', 'z', 'h', 'm', 'o', 'w', '9', 'B', 'H', 'C', 'M', 'D', 'p', 'E', 'a', 'J', 'R', 'Z', 'N']

def encode(origin_bytes):
    # 將每一位bytes轉換爲二進制字符串
    base64_bytes = ['{:0>8}'.format(str(bin(b)).replace('0b', '')) for b in origin_bytes]

    resp = ''
    nums = len(base64_bytes) // 3
    remain = len(base64_bytes) % 3

    integral_part = base64_bytes[0:3 * nums]
    while integral_part:
        # 取三個字節,以每6比特,轉換爲4個整數
        tmp_unit = ''.join(integral_part[0:3])
        tmp_unit = [int(tmp_unit[x: x + 6], 2) for x in [0, 6, 12, 18]]
        # 取對應base64字符
        resp += ''.join([base64_charset[i] for i in tmp_unit])
        integral_part = integral_part[3:]

    if remain:
        # 補齊三個字節,每個字節補充 0000 0000
        remain_part = ''.join(base64_bytes[3 * nums:]) + (3 - remain) * '0' * 8
        # 取三個字節,以每6比特,轉換爲4個整數
        # 剩餘1字節可構造2個base64字符,補充==;剩餘2字節可構造3個base64字符,補充=
        tmp_unit = [int(remain_part[x: x + 6], 2) for x in [0, 6, 12, 18]][:remain + 1]
        resp += ''.join([base64_charset[i] for i in tmp_unit]) + (3 - remain) * '='

    return resp

if __name__ == '__main__':
    s = 'listone'.encode()
    local_base64 = encode(s)
    print('使用本地base64加密:', local_base64)

然後我們對 listone 進行加密

在這裏插入圖片描述

可以看到結果與java運行的一致,也因此證明了我們的猜想。

通過解壓軟件解壓apk文件,然後可以在lib目錄裏找到這個so文件。

接下來就是看 so 文件裏的 ncheck 函數是幹什麼的了。

在這裏插入圖片描述

這個v6我們可以大膽地猜測它爲我們傳入的字符串

在這裏插入圖片描述

然後我們看那個循環幹了什麼

v7 = 0;
do
{
    //將s1[v7]的地址賦值給v8
    v8 = &s1[v7];
    //第一輪就是 s1[0] = v6[16]
    s1[v7] = v6[v7 + 16];
    //第一輪就是先 v9 = v6[0],然後v7 = v7+1 = 1
    v9 = v6[v7++];
    //第一輪是v8[16]=s1[16]=v9
    v8[16] = v9;
}
while ( v7 != 16 );

分析之後就可以知道,這個循環就是將我們傳入的字符串的前16位與後16位字符對調。

然後繼續分析下一個循環

v10 = 0;
do
{
    v12 = __OFSUB__(v10, 30);
    v11 = v10 - 30 < 0;
    
    //第一輪v16=s1[0]
    v16 = s1[v10];
    //第一輪s1[0] = s1[1]
    s1[v10] = s1[v10 + 1];
    //第一輪s1[1] = v16 = s1[0]
    s1[v10 + 1] = v16;
    v10 += 2;
}
while ( v11 ^ v12 );

可以發現這個循環是將字符串兩兩對調位置。

現在再來分析循環的結束條件,這個結束條件一開始直接把我整懵逼了,查了些資料,__OFSUB__ 表示x-y是否溢出,溢出返回1,沒有溢出返回0。在此情況下,應該不存在溢出,則返回均爲0,即v12=0,當v10>30時,v11=0。此時異或得0,循環結束。

這裏返回值是與一個字符串比較的結果,那我們就將該字符串逆推回去,寫出逆向腳本。

在這裏插入圖片描述

寫出腳本爲:

def decode(base64_str):
    base64_charset = "i5jLW7S0GX6uf1cv3ny4q8es2Q+bdkYgKOIT/tAxUrFlVPzhmow9BHCMDpEaJRZN"
    base64_bytes = ['{:0>6}'.format(str(bin(base64_charset.index(s))).replace('0b', '')) for s in base64_str if
                    s != '=']
    resp = bytearray()
    nums = len(base64_bytes) // 4
    remain = len(base64_bytes) % 4
    integral_part = base64_bytes[0:4 * nums]

    while integral_part:
        tmp_unit = ''.join(integral_part[0:4])
        tmp_unit = [int(tmp_unit[x: x + 8], 2) for x in [0, 8, 16]]
        for i in tmp_unit:
            resp.append(i)
        integral_part = integral_part[4:]

    if remain:
        remain_part = ''.join(base64_bytes[nums * 4:])
        tmp_unit = [int(remain_part[i * 8:(i + 1) * 8], 2) for i in range(remain - 1)]
        for i in tmp_unit:
            resp.append(i)

    return resp

if __name__ == '__main__':
    flag_1 = 'MbT3sQgX039i3g==AQOoMQFPskB1Bsc7'
    print('加密後的字符串:',flag_1)
    # 前後16位調換位置
    flag_2 = flag_1[len(flag_1)//2:] + flag_1[0:len(flag_1)//2]
    print('前後16位調換位置:',flag_2)
    flag_3 = ''
    for i in range(len(flag_2)//2):
        flag_3 += flag_2[i*2+1] + flag_2[i*2]
    print('前後兩位調換位置:',flag_3)
    print('解密後:',decode(flag_3))

最後運行腳本:

在這裏插入圖片描述

就解出flag的值了。

這個題總體來說邏輯比上一個easyjava要簡單一些,不過這個涉及到了對so文件的簡單分析,也算是學到了一個小知識吧。

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