OWASP Android Crack-Me逆向分析
UnCrackable-Level1
第一题是一个纯java层逆向,首先程序会进行root和debug检测。
root检测就是通过检测su
等文件和Build.TAGS
是否包含test-keys
。因为我的机子是自己编译的userdebug版本,所以会被检测到root,frida直接hook检测函数并返回false即可绕过。
检测通过后会验证输入的flag是否正确,验证逻辑也比较简单就是调用sg.vantagepoint.a.a.a
进行AES加密,加密的数据就是正确的flag。
通过frida hooksg.vantagepoint.a.a.a
得到的返回值即为flag:I want to believe
UnCrackable-Level2
第二题也会进行root和debug检测,同时还会调用native函数init。
init会通过fork子进程并互相ptrace,所以如果使用frida进行hook时应该以spawn模式启动,如果以attach模式启动会失败。
最后调用native函数bar验证,最后得到flag:Thanks for all the fish
UnCrackable-Level3
第三题首先会加载libfoo.so,此so的init_array
存在一个反调试函数sub_31B0
。
sub_31B0会调用pthread_create
创建一个线程,线程函数sub_30d0会通过/proc/self/maps
检测frida和xposed。绕过的活可以hook pthread_create
函数阻止反调试线程的创建,不过这里我想尝试hook线程函数sub_30d0并直接返回。
因为反调试线程是在init_array中的函数创建的,执行时机比较早,所以要想在init_array函数执行前进行hook的话需要选择合适的执行时机。这里我通过hook linker64的call_array
函数,因为so的init_array中的函数都是由此函数调用的。反编译linker64得到call_array的偏移为0x50AF4
。
绕过init_array中的检测使用的frida脚本如下。
// hook linker64"s call_array
var linker64_module = Module.getBaseAddress("linker64");
Interceptor.attach(linker64_module.add(0x50AF4), {
onEnter:function(args){
if(args[3].readCString().match("libfoo.so")){
// hook libfoo.so + 0x30D0 , pass firda/xposed check
var libfoo_module = Module.findBaseAddress("libfoo.so");
Interceptor.replace(libfoo_module.add(0x30D0), new NativeCallback(function (){
return;
}, "void", []))
}
},onLeave:function(result){}
})
接着会调用native的init函数将key2:pizzapizzapizzapizzapizz
保存,同时调用sub_323C
来fork子进程互相ptrace反调试。
通过hook sub_323C
函数来绕过反调试。因为此函数是在apk启动过程中oncreate中调用,并且只调用一次,所以这里选择的hook时机为再libfoo.so被加载时进行hook。libfoo.so是apk调用System.loadLibrary("foo")
加载的,其底层是通过调用libandroid_runtime.so的android_dlopen_ext
来加载的so,注意这里不是通过调用dlopen
加载的so。通过hook libandroid_runtime.so的android_dlopen_ext
函数,并在libfoo.so加载的时候hook sub_323C
函数来绕过反调试。
// hook android_dlopen_ext
var libfoo_loaded_flag = 0;
var android_dlopen_ext_addr = Module.getExportByName("libandroid_runtime.so", "android_dlopen_ext");
Interceptor.attach(android_dlopen_ext_addr, {
onEnter:function(args){
if(-1 != args[0].readCString().indexOf("libfoo.so")){
libfoo_loaded_flag = 1;
}
},onLeave:function(result){
if(libfoo_loaded_flag == 1){
// hook libfoo.so + 0x323C , pass call ptrace
var libfoo_module = Module.findBaseAddress("libfoo.so");
Interceptor.replace(libfoo_module.add(0x323C), new NativeCallback(function(){
return;
}, "void", []));
libfoo_loaded_flag = 0;
}
}
})
上述检测通过后apk还会调用几个java层函数进行root检测,通过frida hook返回false即可绕过。
最后通过调用native层的bar函数验证flag,此函数会通过调用sub_10e0得到key1,并与key2:pizzapizzapizzapizzapizz
异或得到flag。
通过frida hook sub_10e0得到返回的key1并与key2异或即可得到flag:making owasp great again
r2pay
这是一道R2con CTF的赛题r2pay 1.0的修改版,难度较1.0降低了。
-
屏幕上有一个生成绿色令牌(又名 r2coins)的主 PIN 码。如果您看到一个红色的 r2coin,那么这个令牌将不会被社区验证。您还需要找出 4 位 PIN 码和使用的盐。标志:r2con
-
有一个“r2pay 万能密钥”隐藏在层层混淆和保护中。你能打破白盒吗?标记:r2con
原文地址:https://www.cnblogs.com/revercc/p/17277997.html