OWASP Android Crack-Me逆向分析

发布时间 2023-04-01 02:44:29作者: 怎么可以吃突突

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