一次有關算法的安卓CTF

某年的CTF大賽題目
總結:遇到算法別頭大,耐心、細心,讓自己靜下來。

點開之後長這樣子,隨便輸入幾個字符,提示錯誤。
在這裏插入圖片描述
查殼發現沒有殼。
直接使用Jeb進行反編譯。

在這裏插入圖片描述

看出來了,突破口是this.b.check()這個函數。

package ctf.bobbydylan;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

public class M extends T {
    public M() {
        super();
    }

    public void check(String arg10) {
        String v0_1;
        int v7 = 15;
        int v6 = 7;
        int v1 = 0;
        int v5 = 5;
        if(arg10.length() != 16) {
            throw new RuntimeException();
        }

        try {
            v0_1 = this.getKey();
        }
        catch(Exception v0) {
            v0_1 = this.getKey();
            System.arraycopy(v0_1, 0, arg10, v5, v5);
        }

        int[] v2 = new int[16];
        v2[0] = 0;
        v2[12] = 14;
        v2[10] = v6;
        v2[14] = v7;
        v2[v7] = 42;
        int v4 = 3;
        try {
            v2[1] = v4;
            v2[5] = 5;
            System.out.println();
        }
        catch(Exception v3) {
            v2[v5] = 37;
            v2[1] = 85;
        }

        v2[6] = v7;
        v2[2] = 13;
        v2[3] = 19;
        v2[11] = 68;
        v2[4] = 85;
        v2[13] = v5;
        v2[9] = v6;
        v2[v6] = 78;
        v2[8] = 22;
        while(v1 < arg10.length()) {
            if((v2[v1] & 0xFF) != ((arg10.charAt(v1) ^ v0_1.charAt(v1 % v0_1.length())) & 0xFF)) {
                throw new RuntimeException();
            }

            ++v1;
        }
    }

    public String getKey() {
        return "bobbydylan";
    }

    public void onCreate(Bundle arg4) {
        super.onCreate(arg4);
        this.setContentView(0x7F030000);
        this.startService(new Intent(((Context)this), P.class));
        this.findViewById(0x7F060001).setOnClickListener(new a(this, this.findViewById(0x7F060000)));
    }

    protected void onPause() {
        this.stopService(new Intent(((Context)this), P.class));
        super.onPause();
    }
}

看到這個check,很長說實話。

裏面嵌套了好幾層的try catch語句,我不確定這個程序大體流程執行下去會是怎樣的,也許在try看起來怎麼都不會有異常拋出的地方就有異常了呢,我不想繼續審代碼了,還是動態調試更舒服。

Jeb動態調試

在這裏插入圖片描述
找到對應進程,不解釋。
Jeb沒有調試僞代碼的功能,所以就對着smali代碼和僞代碼一起看吧。

這裏的邏輯經過調通,只要輸入的字符串長度等於16,代碼邏輯就不會跳進catch裏。
在這裏插入圖片描述
經過閱讀,其實只要字符串長度滿足16,和下面的算法即可。

在這裏插入圖片描述
其實也就是

v2[v1] = arg10.charAt(v1) ^ v0_1.charAt(v1 % v0_1.length())

這個等式成立就行。
其中v2是死的,v0_1是getKey()接口返回的"bobbydylan"也是死的。

這裏我們可以通過Jeb動態調試的時候看到v2和v0_1的值。
求出來的args10就是我們要的flag。
如果v2和v0_1類型不對,顯示的值不太好觀察時,直接修改它們的類型就可以。
在這裏插入圖片描述
直接修改類型。
在這裏插入圖片描述
在這裏插入圖片描述

我們知道對一個數異或兩次,其實就等於沒有做任何運算。
所以這個算法可以這樣去做。

v2[v1] ^ v0_1.charAt(v1 % 8) = args.charAt(v1)

貼上C語言代碼

#include <stdio.h>
#include <stdlib.h>
int main(){
	int v2[16] = {0,3,13,19,85,5,15,78,0,7,7,68,14,5,15,42};
	char v0_1[] = "bobdylan";
	for(int i = 0; i < 16; i++){
		int nIndex = i % 8;
		int nTmp = v0_1[nIndex];
		printf("%c", v2[i] ^ nTmp);
	}
}

我使用go,結果給我的是這個玩意,而且還費了我不少時間。
在這裏插入圖片描述
在這裏插入圖片描述
很明顯不對。

有可能是自己太久沒寫代碼或者當時使用go很少做異或或者ascii之類的計算吧,果然底層運算還是選C靠譜。
在這裏插入圖片描述

在這裏插入圖片描述

結束。

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