t貓xsign unidbg逆向

t貓xsign unidbg逆向

加密流程來源于看雪一位大佬的分享

2591919-18a845cc4f30be83.png

findcrypt & findhash

既然已經知道用到了HMAC-SHA1算法了,那就先用findcryptfindhash找找

findcrypt

2591919-95eb1479b4668873.png

可以看到base64的常量

2591919-6be60f33765685ad.png

查看引用

2591919-2ec0cbbdae2a9193.png
2591919-1b409f8c4e5c5e47.png

sub_99BE0應該就是進行base64編碼的地方了

findhash

不知道出了什么問題,沒有找到hash常量。于是看了下findhash的代碼

2591919-7de05a0fa7ec7d9c.png

發現是在.texttext這兩個segment里進行搜索,但是so里沒有這兩個segment。

2591919-0a580e8c7a53bf64.png

嘗試用frida_dump來dump內存中的so,再看看它的segment

2591919-c99f0afd09a09611.png

多了幾個segment,其中有個是.text&ARM.extab,對比一下base64函數

2591919-56cbfb2546dcaa45.png

可以看到segment信息被修復了。既然如此,修改一下findhash的代碼

if 'text' in (idc.get_segm_name(seg)).lower()

然后重新打開ida調用下findhash

2591919-d88d0c67d16732ae.png

發現sub_9AECEsub_9B1E0都包含了SHA1的常量,分別下斷點測試后發現調用的是sub_9B1E0

2591919-6d205a900f3c065a.png
2591919-e52199a9bd4c5d27.png

sub_9B1E0查看引用

2591919-6cdc423bdc3705fa.png

sub_9A0E0

2591919-f13e439033cddd1f.png

可以看到HMAC的常量。

base64 & hmac-sha1

hook一下base64和hmac函數的參數

public void hook_b64() {
    IHookZz hookZz = HookZz.getInstance(emulator);
    hookZz.enable_arm_arm64_b_branch();
    hookZz.wrap(module.base + 0x99BE0 + 1, new WrapCallback<HookZzArm32RegisterContext>() {
        @Override
        public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
            Pointer input = ctx.getPointerArg(0);
            byte[] inputHex = input.getByteArray(0, ctx.getR1Int());
            System.out.println("b64 input: " + Hex.encodeHexString(inputHex));
            //                System.out.println(Hex.encodeHexString(inputHex));

            Pointer output = ctx.getR2Pointer();
            ctx.push(output);
        }

        @Override
        public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
            Pointer output = ctx.pop();
            byte[] outputHex = output.getByteArray(0, ctx.getR0Int());
            System.out.println("b64 output: " + Hex.encodeHexString(outputHex));
        }
    });
    hookZz.disable_arm_arm64_b_branch();
}

public void hook_hmac() {
    IHookZz hookZz = HookZz.getInstance(emulator);
    hookZz.enable_arm_arm64_b_branch();
    hookZz.wrap(module.base + 0x9a0e0 + 1, new WrapCallback<HookZzArm32RegisterContext>() {
        @Override
        public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
            Pointer input = ctx.getPointerArg(3);
            byte[] inputHex = input.getByteArray(0, ctx.getR1Int());
            Inspector.inspect(inputHex, "hmac input");

            Pointer r2 = ctx.getR2Pointer();
            String key = r2.getString(0);
            System.out.println("hmac key: " + key);

            Pointer output = ctx.getR0Pointer();
            ctx.push(output);
        }

        @Override
        public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
            Pointer output = ctx.pop();
            Pointer pointer = output.getPointer(16);
            byte[] outputHex = pointer.getByteArray(0, ctx.getR0Int());
            Inspector.inspect(outputHex, "hmac output");
        }
    });
    hookZz.disable_arm_arm64_b_branch();
}

第一次hmac

2591919-d6ca74ff126213bf.png

base64

2591919-8666a5cf5407acab.png

第二次hmac

2591919-9206a4e32ff200c1.png

cyberchef測試一下

2591919-d845ade464ea75ab.png

說明沒有經過魔改。

白盒AES

根據base64輸入的長度,猜測它就是AES的輸出,由于其長度為80,再加上填充算法的原因,AES輸入的長度應該在70-79之間。接下來的目標就是從第一次hmac的輸出找到AES的輸入,另外還需要找到AES的key和iv(如果有)。

分析AES輸入

對第一次hmac的輸出進行traceRead,看看誰對它進行了讀取

emulator.traceRead(0xbffff168L, 0xbffff168L+20);
2591919-99b66462cbedfa98.png

可以看到是在libc.so進行了讀操作,打開unidbg-android/src/main/resources/android/sdk23/lib/libc.so看看

2591919-aa537161df11cbbc.png

調用了memcpy函數,那就hook一下

public void hook_memcpy() {
    IHookZz hookZz = HookZz.getInstance(emulator);
    hookZz.enable_arm_arm64_b_branch();
    hookZz.wrap(module.findSymbolByName("memcpy"), new WrapCallback<HookZzArm32RegisterContext>() {
        @Override
        public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
            UnidbgPointer output = ctx.getPointerArg(0);
            UnidbgPointer input = ctx.getR1Pointer();
            int length = ctx.getR2Int();
            String hex = Hex.encodeHexString(input.getByteArray(0, length));
            System.out.println("src: " + input + ", dst: " + output + ", data: " + hex);
        }
    });
    hookZz.disable_arm_arm64_b_branch();
}
2591919-30677e2904901b45.png

繼續對0x402cd4f8進行讀跟蹤

2591919-70e9b7987fa87298.png

跳轉過去看看

2591919-c0a7e4fe67982d87.png
2591919-699423b82dad6023.png

下斷點看看函數的輸入輸出

2591919-9f39b335b463c661.png
2591919-348751eaf7584b08.png

r2應該是buffer,存儲返回值的,blr下斷點,c執行到返回處,看看原r2的數據

2591919-ebad8c3209be8a56.png

就做了個byte轉hex的操作。

對0x402db090進行讀跟蹤

2591919-9c08ec9eb2029447.png

還是在libc.somemcpy進行讀取,看看之前hook的記錄

2591919-0f745efeebee962b.png

此次memcpy之后還有幾次memcpy,并且后面連接了一些字符

2591919-11254b1504370440.png

可以發現是hmac的key,此時字符串的長度是73,符合之前提到的AES輸入的長度要求,我們可以合理推斷它就是AES的輸入。

對最后一次寫入的地址0x4043a000進行讀跟蹤

2591919-001ffbbc5c5cd3e3.png

跳轉過去

2591919-d9247292f124737f.png

下個斷點看看

2591919-a766a97303fd084f.png
2591919-32e5c1a402b19db6.png

可以看到后面進行了填充。

設置AES輸入和iv

已經知道是白盒AES,那我們接下來要做些準備工作,把輸入設置到一個分組,把iv設置為0。

在此處bt看看調用棧

2591919-932be504391da127.png
2591919-3a291a0212f8b694.png

hook看看函數入參

2591919-ccd2d9ea8bc01344.png
2591919-bc1017358282a2d0.png

0x49=73正是字符串的長度。

那就hook函數改一下入參

public void set_input() {
    IHookZz hookZz = HookZz.getInstance(emulator);
    hookZz.enable_arm_arm64_b_branch();
    hookZz.wrap(module.base + 0x6A864 + 1, new WrapCallback<HookZzArm32RegisterContext>() {
        @Override
        public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
            UnidbgPointer r2 = ctx.getR2Pointer();
            UnidbgPointer input = r2.getPointer(0);
            String str = "everhu";
            input.write(str.getBytes());
            r2.setInt(4, str.length());
            System.out.println("set aes input: " + str);
        }
    });
    hookZz.disable_arm_arm64_b_branch();
}
2591919-50fa78495ad835ec.png

地址已經改變了

2591919-5bf7fc0071c764a9.png

可以看到AES的輸入已經變成一個分組

接下來找找iv,分析一下匯編指令

2591919-7c1ad382c55f186c.png

0x6AE72處r1加載了輸入的地址,0x6AE82處加載輸入的數據,0x6AE84處r1和r2進行了異或,由此猜測r2是iv,r2是在0xAE7A從lr加載的。

下斷點看看

2591919-08abfddf904bf941.png
2591919-5ab0790d3d9180c7.png

方便后續的dfa,把iv設為0,選擇了偷懶的方式,直接patch 0x6AE84的語句,改為nop,相當于沒有進行異或。

public void set_iv() {
    emulator.getMemory().pointer(module.base + 0x6AE84).write(new byte[] {0x00, (byte) 0xbf});
}

重新hook看看base64的輸入,也就是AES的結果看看

2591919-9380edcc68bf14fd.png
查找state

繼續分析異或之后的操作,0x6AE8A將異或后的結果存到了r2處的地址,下斷點看看

2591919-2cad04c54b953454.png

數據存入了0x402dabc0,對其進行讀跟蹤

2591919-3db3f4ece899f3e9.png
2591919-bac61eacacf47848.png

0x6AFD0讀取數據到r5之后,0x6AFE2又將其存到了r3。

下斷點看看地址

2591919-6a2357cf49662c63.png

對0xbffff028進行讀跟蹤

2591919-145ab5f33c69c45d.png

發現了9輪讀取,看來這就是AES的state,看看匯編

2591919-78336188786175fa.png

下斷點看看

2591919-f3ddb5ec765208f4.png

發現地址對不上

同時進行讀跟蹤和下斷點

2591919-61f897ece6371f04.png

重新在0x6bb12下斷點

2591919-bc8234bd82d2844d.png

確實是在這進行讀取。

DFA

接下來進行DFA攻擊,函數在0x6bb12進行了16*9次數據讀取,由于DFA需要在第8輪列混淆和第9輪列混淆之間進行操作,因此在第16*8次讀取時隨機修改一個字節。

public void dfa() {
    emulator.attach().addBreakPoint(module.base + 0x6bb12, new BreakPointCallback() {
        @Override
        public boolean onHit(Emulator<?> emulator, long address) {
            Arm32RegisterContext ctx = emulator.getContext();
            if (count == 16 * 8) {
                UnidbgPointer r3 = ctx.getR3Pointer();
                r3.setByte(randInt(0, 16), (byte) randInt(0, 0xff));
                System.out.println("dfa");
            }
            count += 1;
            return true;
        }
    });
}
2591919-e72276a85e7d67e1.png

和正確結果對比,發現有4個字節不同,說明操作是對的。

接下來就是去掉多余的輸出,調整打印的格式,多次調用。

public static void main(String[] args) {
    Logger.getLogger("com.github.unidbg.linux.ARM32SyscallHandler").setLevel(Level.ERROR);
    TMall test = new TMall();
    test.call_init();
    //        test.hook_memcpy();
    test.hook_b64();
    //        test.hook_hmac();
    test.set_input();
    test.set_iv();
    
    test.callXSign();
    
    test.dfa();

    for (int i=0; i<16; i++) {
        test.count = 0;
        test.callXSign();
    }
}
2591919-b5b841ab4b48720d.png

之后就比較簡單了,調用JeanGrey/phoenixAESSideChannelMarvels/Stark即可還原出key。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,268評論 2 375

推薦閱讀更多精彩內容