首页
社区
课程
招聘
[原创]XCTF黑客精神—Frida RPC爆破
发表于: 2021-4-9 21:00 13386

[原创]XCTF黑客精神—Frida RPC爆破

2021-4-9 21:00
13386

此题比较简单,网上也有各种各样的wp。wp可以分为两类,一类分析算法,另一类是爆破。此题采用的是异或算法,所以分析算法求flag是最快的。而爆破的话,可以重写成等价的代码,如C++、python,或者直接采用主动调用的方式进行爆破,如Frida的主动调用。采用主动调用的好处是不用重写,而我采用Frida RPC进行主动调用的目的是想利用python丰富的库,方便爆破,缺点相对于直接用JS代码进行爆破是太慢了,慢了200多倍。

输入注册码,显示如下:

在代码中搜索"您的注册码已保存",相关代码如下:

然后跳转到saveSN函数所在的类MyApp,代码如下:

接着分析libmyjni.so文件,在JNI_OnLoad函数中注册了initSNsaveSNwork函数,代码如下:

首先分析initSN函数,其中setValue函数的作用是设置com/gdufs/xman/MyApp类的静态字段m的值,

initSN函数只做了一件事,即如果/sdcard/reg.dat文件的内容是"EoPAoY62@ElRD",com/gdufs/xman/MyApp类的静态字段m的值则设置为1,否则设置为0

通过对com/gdufs/xman/MyApp类的静态字段m交叉引用发现,如果m的值为1,则显示已注册,所以我们怀疑输入的注册码通过一系列的计算后得到的值会保存到/sdcard/reg.dat文件中,如果得到的值为"EoPAoY62@ElRD",则输入的注册码即为flag

saveSN也只干了一件事,把输入的注册码经过异或运算之后存到了/sdcard/reg.dat文件中

我们可以试试,直接把/sdcard/reg.dat文件的内容替换成"EoPAoY62@ElRD",会是什么效果,如下:

则我们的flag格式为xman{注册码}

通过上面的分析过程可知,我们可以通过Frida主动调用的方式爆破出flag,首先给出直接用JS代码进行爆破的脚本,再给出RPC爆破的脚本。

花了大概两分钟爆破出了flag

JavaScript代码

Python代码

采用RPC爆破的方式花了429分钟才爆破出了flag,花的时间是直接使用JS代码进行爆破的214倍

如果出现各种无法解决的问题,尝试换成跟我一样的设备和系统——pixel 3、android 9.0

错误是全局引用表溢出了,具体意思是Java对象的全局引用表溢出了,你在循环里new Java对象就可能会溢出,因为frida对Java对象的引用就是用的全局引用,不知道什么时候才释放,反正循环的时候没有释放

多次调用Java.choose程序就会卡住,好像跟frida版本无关,不知道为什么,所以我直接new一个对象进行主动调用

排列使用的字典是没有重复字符的,所以3个字符中不可能同时出现两个相同的字符,下面的代码就会出现这种问题

解决办法是把字典自加多次,代码如下

链接:https://pan.baidu.com/s/1NRPGU_j6CK7bgB363FN33w
提取码:09wb

 
 
public class RegActivity extends Activity {
    private Button btn_reg;
    private EditText edit_sn;
 
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reg);
        this.btn_reg = (Button) findViewById(R.id.button1);
        this.edit_sn = (EditText) findViewById(R.id.editText1);
        this.btn_reg.setOnClickListener(new View.OnClickListener() {
            /* class com.gdufs.xman.RegActivity.AnonymousClass1 */
 
            public void onClick(View v) {
                String sn = RegActivity.this.edit_sn.getText().toString().trim();
                if (sn == null || sn.length() == 0) {
                    Toast.makeText(RegActivity.this, "您的输入为空", 0).show();
                    return;
                }
                ((MyApp) RegActivity.this.getApplication()).saveSN(sn);
                new AlertDialog.Builder(RegActivity.this).setTitle("回复").setMessage("您的注册码已保存").setPositiveButton("好吧", new DialogInterface.OnClickListener() {
                    /* class com.gdufs.xman.RegActivity.AnonymousClass1.AnonymousClass1 */
 
                    public void onClick(DialogInterface dialog, int which) {
                        Process.killProcess(Process.myPid());
                    }
                }).show();
            }
        });
    }
}
public class RegActivity extends Activity {
    private Button btn_reg;
    private EditText edit_sn;
 
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reg);
        this.btn_reg = (Button) findViewById(R.id.button1);
        this.edit_sn = (EditText) findViewById(R.id.editText1);
        this.btn_reg.setOnClickListener(new View.OnClickListener() {
            /* class com.gdufs.xman.RegActivity.AnonymousClass1 */
 
            public void onClick(View v) {
                String sn = RegActivity.this.edit_sn.getText().toString().trim();
                if (sn == null || sn.length() == 0) {
                    Toast.makeText(RegActivity.this, "您的输入为空", 0).show();
                    return;
                }
                ((MyApp) RegActivity.this.getApplication()).saveSN(sn);
                new AlertDialog.Builder(RegActivity.this).setTitle("回复").setMessage("您的注册码已保存").setPositiveButton("好吧", new DialogInterface.OnClickListener() {
                    /* class com.gdufs.xman.RegActivity.AnonymousClass1.AnonymousClass1 */
 
                    public void onClick(DialogInterface dialog, int which) {
                        Process.killProcess(Process.myPid());
                    }
                }).show();
            }
        });
    }
}
public class MyApp extends Application {
    public static int m = 0;
 
    public native void initSN();
 
    public native void saveSN(String str);
 
    public native void work();
 
    static {
        System.loadLibrary("myjni");
    }
 
    public void onCreate() {
        initSN();
        Log.d("com.gdufs.xman m=", String.valueOf(m));
        super.onCreate();
    }
}
public class MyApp extends Application {
    public static int m = 0;
 
    public native void initSN();
 
    public native void saveSN(String str);
 
    public native void work();
 
    static {
        System.loadLibrary("myjni");
    }
 
    public void onCreate() {
        initSN();
        Log.d("com.gdufs.xman m=", String.valueOf(m));
        super.onCreate();
    }
}
 
 
 
 
 
 
 
 
 
 
 
 
var fputs_str = null;
 
function Hook() {
    Java.perform(function () {
        const imports = Module.enumerateImportsSync("libmyjni.so");
        const imports_len = imports.length;
        var fputs_addr = null;
        for (var i = 0; i < imports_len; i++) {
            if (imports[i].name == "fputs") {
                fputs_addr = imports[i].address;
                break;
            }
        }
        if (fputs_addr != null) {
            Interceptor.attach(fputs_addr, {
                onEnter: function (args) {
                    fputs_str = args[0].readCString();
                },
                onLeave: function (retval) {
                }
            })
        }
    })
}
 
function Invoke(try_str) {
    Java.perform(function () {
        Java.choose("com.gdufs.xman.MyApp", {
            onMatch: function (instance) {
                instance.saveSN(try_str);
            },
            onComplete: function () {
            }
        })
    })
}
 
function Main() {
    Hook();
    Java.perform(function () {
        const three_character_array = new Array("EoP", "AoY", "62@", "ElR");
        const last_character = "D";
        const my_dict = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()?_"
        const myapp_class_obj = Java.use("com.gdufs.xman.MyApp");
        const three_character_array_len = three_character_array.length;
        const my_dict_len = my_dict.length
        const myapp = Java.use("com.gdufs.xman.MyApp").$new();
        var flag = "";
        for (var i = 0; i < three_character_array_len; i++) {
            var found = false;
            for (var j = 0; j < my_dict_len; j++) {
                if (found == true) {
                    break;
                }
                for (var k = 0; k < my_dict_len; k++) {
                    if (found == true) {
                        break;
                    }
                    for (var m = 0; m < my_dict_len; m++) {
                        const try_str = my_dict[j] + my_dict[k] + my_dict[m];
                        console.log(`try_str: ${try_str}`);
                        myapp.saveSN(try_str);
                        if (three_character_array[i] == fputs_str) {
                            flag += try_str;
                            console.log(`found: ${try_str}`);
                            found = true;
                            break;
                        }
                    }
                }
            }
        }
 
        for (var i = 0; i < my_dict_len; i++) {
            const try_str = my_dict[i];
            console.log(`try_str: ${try_str}`);
            Invoke(try_str);
            if (last_character == fputs_str) {
                flag += try_str;
                console.log(`found: ${try_str}`);
                break;
            }
        }
        console.log(`flag: xman{${flag}}`);
    })
}
 
//不能用setImmediate(Main),会出现Process crashed: SIGSYS SYS_SECCOMP
//需要延迟一下再爆破
setTimeout(Main, 500);
var fputs_str = null;
 
function Hook() {
    Java.perform(function () {
        const imports = Module.enumerateImportsSync("libmyjni.so");
        const imports_len = imports.length;
        var fputs_addr = null;
        for (var i = 0; i < imports_len; i++) {
            if (imports[i].name == "fputs") {
                fputs_addr = imports[i].address;
                break;
            }
        }
        if (fputs_addr != null) {
            Interceptor.attach(fputs_addr, {
                onEnter: function (args) {
                    fputs_str = args[0].readCString();
                },
                onLeave: function (retval) {
                }
            })
        }
    })
}
 
function Invoke(try_str) {
    Java.perform(function () {
        Java.choose("com.gdufs.xman.MyApp", {
            onMatch: function (instance) {
                instance.saveSN(try_str);
            },
            onComplete: function () {
            }
        })
    })
}
 
function Main() {
    Hook();
    Java.perform(function () {
        const three_character_array = new Array("EoP", "AoY", "62@", "ElR");
        const last_character = "D";
        const my_dict = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()?_"
        const myapp_class_obj = Java.use("com.gdufs.xman.MyApp");
        const three_character_array_len = three_character_array.length;
        const my_dict_len = my_dict.length
        const myapp = Java.use("com.gdufs.xman.MyApp").$new();
        var flag = "";
        for (var i = 0; i < three_character_array_len; i++) {
            var found = false;
            for (var j = 0; j < my_dict_len; j++) {
                if (found == true) {
                    break;
                }
                for (var k = 0; k < my_dict_len; k++) {
                    if (found == true) {
                        break;
                    }
                    for (var m = 0; m < my_dict_len; m++) {
                        const try_str = my_dict[j] + my_dict[k] + my_dict[m];
                        console.log(`try_str: ${try_str}`);
                        myapp.saveSN(try_str);
                        if (three_character_array[i] == fputs_str) {
                            flag += try_str;
                            console.log(`found: ${try_str}`);
                            found = true;
                            break;
                        }
                    }
                }
            }
        }
 
        for (var i = 0; i < my_dict_len; i++) {
            const try_str = my_dict[i];
            console.log(`try_str: ${try_str}`);
            Invoke(try_str);
            if (last_character == fputs_str) {
                flag += try_str;
                console.log(`found: ${try_str}`);

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-4-21 11:17 被genliese编辑 ,原因:
收藏
免费 5
支持
分享
最新回复 (6)
雪    币: 420
活跃值: (2638)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
good job
2021-4-14 08:46
0
雪    币: 1461
活跃值: (1452)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
好奇,我用这个Frida调试的时候,为什么找不到这个进程呢?直接ps能看到,frida-ps -U就找不到这个com.gdufs.xman进程了?
2021-4-24 10:43
0
雪    币: 1461
活跃值: (1452)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
4
hackdaliu 好奇,我用这个Frida调试的时候,为什么找不到这个进程呢?直接ps能看到,frida-ps -U就找不到这个com.gdufs.xman进程了?
找到原因了,之前装的frida,这次升级只升级了frida,没有连frida-tools一起升级导致的。。
2021-4-24 11:44
0
雪    币: 2484
活跃值: (2968)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
hackdaliu 找到原因了,之前装的frida,这次升级只升级了frida,没有连frida-tools一起升级导致的。。
好的
2021-4-24 11:49
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
这不是非虫大佬提供的crackMe吗
2021-4-25 08:44
0
雪    币: 208
活跃值: (770)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
今天我终于能看懂这脚本了,还是积累不够
2022-4-27 09:30
0
游客
登录 | 注册 方可回帖
返回
//