XCTF黑客精神解题报告

题目来源:https://adworld.xctf.org.cn/

解题环境:kali + frida 12.8.0 + Win10 + IDA PRO 7.0

整体思路

静态分析.dex,应用的核心思路为com.gdufs.xman.MyAPP类中最先执行的initSN函数

其次,当我们在com.gdufs.xman.RegisterActivity中输入注册码,点击注册后,执行saveSN函数

只有当MyApp类中定义的静态字段m=1时,才会执行work函数

而上述三个关键函数,皆为JNI函数,具体实现在libmyjni.so中

那么解题的重心就需要转到so层了
使用IDA打开libmyjni.so,搜索Function name并未找到三个关键函数,说明采用了动态注册,通过frida脚本hook RegisterNatives函数可以得到三个函数在.so文件中的偏移为0x13b1,0x11f9,0x14cd。

分析initSN函数可知该函数主要功能为:打开/sdcard/reg.dat,读取其中的数据与"EoPAoY62@ElRD"进行比较,如果相同则m为1,如果不同则m为0。

 

再看saveSN函数,该函数的逻辑为:将用户输入的注册码经过一系列加密运算处理后,写入到/sdcard/reg.dat中

work函数的功能主要是当检测到m=1时打印提示信息
 

至此,题目意图已经非常明显,当我们输入的注册码经过一系列加密处理后为"EoPAoY62@ElRD",那么就是正确的注册码,即此题的flag。
这里暂不考虑加密细节,直接利用frida对加密函数进行重放以爆破得到明文,下面给出完整爆破代码。

//frida -U -f com.gdufs.xman -l demo.js --no-pause

//int fputs(const char *str, FILE *stream);
var fputs_str = null;
function hook_so_libc_fputs(){
    var libc_addr = Module.findBaseAddress("libc.so");
    var fputs_addr = Module.findExportByName("libc.so", "fputs");
    console.log("[libc.so] hooked fputs, fputs_addr="+fputs_addr);

    Interceptor.attach(fputs_addr,{
        onEnter: function(args){
            fputs_str = args[0].readCString();
            //console.log("[fputs] str="+fputs_str);
        },
        onLeave: function(retval){

        }

    });
}


function algorithm_cracking(){
    Java.perform(function(){
        var MyApp = Java.use("com.gdufs.xman.MyApp");
        var MyApp_instance = MyApp.$new();
        var dict = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()";
        
        var ciphertext = "EoPAoY62@ElRD";
        var ciphertext_array = new Array("EoP", "AoY", "62@", "ElR");
       
        var plaintext = "";
        var flag = 0;
        var t,i,j,k,g;
        var input;
        for (t = 0; t < ciphertext_array.length; t++) {
            flag =0;
            for (i = 0; i < dict.length; i++) {
                if (flag == 1) break;
                for (j = 0; j < dict.length; j++) {
                    if (flag == 1) break;
                    for (k = 0; k < dict.length; k++) {
                        input = "" + dict[i] + dict[j] + dict[k];
                        //console.log(temp);
                        MyApp_instance.saveSN(Java.use('java.lang.String').$new(input));
                        if (fputs_str == ciphertext_array[t]) {
                            console.log("input=" + input + "--output=" + fputs_str);
                            plaintext = plaintext + input;
                            console.log("plaintext="+plaintext);
                            flag = 1;
                            break;
                        } 

                    }
                }
            }
        }

        for (g = 0; g < dict.length; g++) {
            input = "" + dict[g];
            MyApp_instance.saveSN(Java.use('java.lang.String').$new(input));
            if (fputs_str == "D"){
                plaintext =plaintext + input;
                break;
            }
        }
        
        console.log("plaintext="+plaintext);
        console.log("algorithm_cracking finished");
    });


}



setImmediate(hook_so_libc_fputs);

setTimeout(algorithm_cracking,3*1000);







这里注意一个细节:算法爆破一定要注意输入明文与输出密文之间的对应关系,此题经过多次测试,可以得到以下规律:1明文长度与密文长度等价;2明文以3字符为一组进行加密,即爆破算法以3字符为单元依次进行破解。

 

运行frida脚本可以得到本题的最终flag为xman{201608Am!2333}
实际运行起来会非常耗时,大概需要20分钟才能爆破完成。

 

 最终小结

本题主要考察了算法逆向方面的知识点,较为简单。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值