r2pay-v0.9.apk
安装完后,一打开就闪退。
通过adb logcat查看日志,筛选中下面的日志记录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| 02-28 10:34:38.788 11795 11795 I Magisk : zygisk64: [re.pwnme] is on the denylist 02-28 10:34:38.823 11795 11795 I re.pwnme: Late-enabling -Xcheck:jni 02-28 10:34:38.845 1187 1204 I adbd : jdwp connection from 11795 02-28 10:34:38.867 11795 11795 D ProcessState: Binder ioctl to enable oneway spam detection failed: Invalid argument 02-28 10:34:38.785 0 0 I binder : 11795:11795 ioctl 40046210 7fe5e224b4 returned -22 02-28 10:34:38.881 11795 11795 D CompatibilityChangeReporter: Compat change id reported: 171979766; UID 10137; state: DISABLED 02-28 10:34:38.887 11795 11795 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.test.base.jar 02-28 10:34:38.909 11795 11795 V GraphicsEnvironment: ANGLE Developer option for 're.pwnme' set to: 'default' 02-28 10:34:38.909 11795 11795 V GraphicsEnvironment: ANGLE GameManagerService for re.pwnme: false 02-28 10:34:38.909 11795 11795 V GraphicsEnvironment: Neither updatable production driver nor prerelease driver is supported. 02-28 10:34:38.911 11795 11795 D NetworkSecurityConfig: No Network Security Config specified, using platform default 02-28 10:34:38.912 11795 11795 D NetworkSecurityConfig: No Network Security Config specified, using platform default 02-28 10:34:39.391 2400 3117 W FrameTracker: Missing HWUI jank callback for vsyncId: 84855 02-28 10:34:39.612 11795 11795 W re.pwnme: type=1400 audit(0.0:371): avc: denied { read } for name="cache" dev="sda14" ino=16 scontext=u:r:untrusted_app_29:s0:c137,c256,c512,c768 tcontext=u:object_r:cache_file:s0 tclass=lnk_file permissive=0 app=re.pwnme 02-28 10:34:39.612 11795 11795 W re.pwnme: type=1400 audit(0.0:372): avc: denied { read } for name="cache" dev="sda14" ino=16 scontext=u:r:untrusted_app_29:s0:c137,c256,c512,c768 tcontext=u:object_r:cache_file:s0 tclass=lnk_file permissive=0 app=re.pwnme 02-28 10:34:39.612 11795 11795 W re.pwnme: type=1400 audit(0.0:373): avc: denied { read } for name="cache" dev="sda14" ino=16 scontext=u:r:untrusted_app_29:s0:c137,c256,c512,c768 tcontext=u:object_r:cache_file:s0 tclass=lnk_file permissive=0 app=re.pwnme 02-28 10:34:39.678 11795 11795 W re.pwnme: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (unsupported, reflection, allowed) 02-28 10:34:39.678 11795 11795 W re.pwnme: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (unsupported, reflection, allowed) 02-28 10:34:39.725 11795 11795 E RootBeer: b: a() [249] - com.topjohnwu.magisk ROOT management app detected! 02-28 10:34:39.725 11795 11795 E QLog : b: a() [249] - com.topjohnwu.magisk ROOT management app detected! 02-28 10:34:39.726 11795 11795 D AndroidRuntime: Shutting down VM 02-28 10:34:39.727 11795 11795 E AndroidRuntime: FATAL EXCEPTION: main 02-28 10:34:39.727 11795 11795 E AndroidRuntime: Process: re.pwnme, PID: 11795 02-28 10:34:39.727 11795 11795 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{re.pwnme/re.pwnme.MainActivity}: java.lang.ArithmeticException: divide by zero 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3707) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3864) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2253) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:201) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.os.Looper.loop(Looper.java:288) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7870) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: Caused by: java.lang.ArithmeticException: divide by zero 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at re.pwnme.MainActivity.onCreate(SourceFile:38) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8057) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8037) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1341) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3688) 02-28 10:34:39.727 11795 11795 E AndroidRuntime: ... 12 more 02-28 10:34:39.730 1045 11817 I DropBoxManagerService: add tag=data_app_crash isTagEnabled=true flags=0x2 02-28 10:34:39.730 1045 5059 W ActivityTaskManager: Force finishing activity re.pwnme/.MainActivity 02-28 10:34:39.737 11795 11795 I Process : Sending signal. PID: 11795 SIG: 9
|
我把日志丢给grok进行分析,似乎是调用了RootBeer库进行root检测,发现了magisk,因此退出了。
尝试搜索字符串 ROOT management app detected,这里的try catch就是用来检测root的,如果读包错误,就说明这个包不存在,不做任何处理;如果读到“危险”包,就会继续执行b.a.a.c.a.a,并将result置为true。
追踪b.a.a.c.a.a进去看一下,发现就写了一个Log.e。

查看方法b.a.a.b.a(List )的调用。
Index为0的方法b.a.a.b.a(String[] )如下,属于重载,可以看到,这里只是将字符串加入到packages里,并调用b.a.a.b.a(List )。

而Index为1的方法b.a.a.b.b(String[] )如下,它调用了b.a.a.b.a(String[] )。

之后又一直查看引用,找到b.a.a.j(),这里做了一堆检查root的内容。
不如直接将函数j给hook了,也省得hook其它这么多函数,我观察了一下众多this.X,发现其中的this.e不仅仅在j()被调用,还在其它地方被调用。
总结了一下,需要hook的函数如下:
b.a.a.a()/b.a.a.j()/b.a.a.e()。
首先hook方法a,一般来说,可以根据参数列表不同hook特定的、存在同名的方法,但这里要hook的方法a属于无参方法,而且存在两个无参方法a。
下面是我找ds-r1生成的,不知道行不行得通,看得挺靠谱的,根据返回值类型来判断。(事后发现下面的脚本用不了,别学,这里作为错误示范)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| Java.perform(function() { var targetClass = Java.use("b.a.a.b"); var methods = targetClass.class.getDeclaredMethods(); methods.forEach(function(method) { if (method.getName() === "a" && method.getParameterTypes().length === 0) { var returnType = method.getReturnType().getName(); if (returnType === "boolean") { method.implementation = function() { console.log("Hooked boolean a() method"); return this.a.apply(this, arguments); }; } else if (returnType === "[Ljava.lang.String;") { method.implementation = function() { console.log("Hooked String[] a() method"); return this.a.apply(this, arguments); }; } } }); });
|
不过既然要hook的方法都在b.a.a类中,不妨直接将hook的方法补充进上面这个脚本里,执行后,又闪退了,不过这回查看日志,并没看到之前的那几条记录了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 02-28 15:10:41.848 4531 4531 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstoneProto 02-28 15:10:41.849 655 655 I tombstoned: received crash request for pid 4528 02-28 15:10:41.850 4531 4531 I crash_dump64: performing dump of process 4498 (target tid = 4528) 02-28 15:10:41.871 4531 4531 E DEBUG : failed to read /proc/uptime: Permission denied 02-28 15:10:42.485 0 0 I logd : logdr: UID=10137 GID=10137 PID=4531 n tail=0 logMask=8 pid=4498 start=0ns deadline=0ns 02-28 15:10:42.486 0 0 I logd : logdr: UID=10137 GID=10137 PID=4531 n tail=0 logMask=1 pid=4498 start=0ns deadline=0ns 02-28 15:10:42.498 4531 4531 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 02-28 15:10:42.498 4531 4531 F DEBUG : Build fingerprint: 'OnePlus/OnePlus6/OnePlus6:8.1.0/OPM1.171019.011/06140300:user/release-keys' 02-28 15:10:42.498 4531 4531 F DEBUG : Revision: '0' 02-28 15:10:42.498 4531 4531 F DEBUG : ABI: 'arm64' 02-28 15:10:42.498 4531 4531 F DEBUG : Timestamp: 2025-02-28 15:10:41.870217324+0800 02-28 15:10:42.498 4531 4531 F DEBUG : Process uptime: 0s 02-28 15:10:42.498 4531 4531 F DEBUG : Cmdline: com.google.android.videos 02-28 15:10:42.498 4531 4531 F DEBUG : pid: 4498, tid: 4528, name: re.pwnme >>> com.google.android.videos <<< 02-28 15:10:42.498 4531 4531 F DEBUG : uid: 10137 02-28 15:10:42.498 4531 4531 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xfaba4975 02-28 15:10:42.498 4531 4531 F DEBUG : x0 0000006fe4986670 x1 000000730a2a77cc x2 00000071ceef6220 x3 0000006fe4986618 02-28 15:10:42.498 4531 4531 F DEBUG : x4 00000000000010b0 x5 0000000000000001 x6 0000000000000000 x7 0000000000000000 02-28 15:10:42.498 4531 4531 F DEBUG : x8 00000000000035b2 x9 00000000faba4975 x10 000000008ef93fe9 x11 000000006df6246c 02-28 15:10:42.498 4531 4531 F DEBUG : x12 0000000000000001 x13 00000000fffffff6 x14 00000000cf86a786 x15 0000000000000001 02-28 15:10:42.499 4531 4531 F DEBUG : x16 000000730a2911f8 x17 000000730a20db40 x18 0000000000000000 x19 0000006fe4986670 02-28 15:10:42.499 4531 4531 F DEBUG : x20 0000000000000000 x21 0000006fe498acb0 x22 0000000000001192 x23 0000000000001192 02-28 15:10:42.499 4531 4531 F DEBUG : x24 0000006fe498acb0 x25 0000006fe498acb0 x26 0000006fe498aff8 x27 00000000000fc000 02-28 15:10:42.499 4531 4531 F DEBUG : x28 0000006fe4892000 x29 0000006fe498ac40 02-28 15:10:42.499 4531 4531 F DEBUG : lr 0000006fdffa2668 sp 0000006fe4986670 pc 0000006fdfe77f7c pst 0000000060000000 02-28 15:10:42.499 4531 4531 F DEBUG : backtrace: 02-28 15:10:42.499 4531 4531 F DEBUG : #00 pc 0000000000038f7c /data/app/~~IG0Dzbwr_V__IsLZxDqnLA==/re.pwnme-5cCb3aQP1IrcfKWzdCWgYQ==/lib/arm64/libnative-lib.so (BuildId: f87b3bd9fcae36e63939958f412d03a42e0ce406) 02-28 15:10:42.499 4531 4531 F DEBUG : #01 pc 00000000000b1810 /apex/com.android.runtime/lib64/bionic/libc.so!libc.so (__pthread_start(void*)+264) (BuildId: 6bfaf10f10e5ff343703efae2f1bdbdb) 02-28 15:10:42.499 4531 4531 F DEBUG : #02 pc 00000000000512f0 /apex/com.android.runtime/lib64/bionic/libc.so!libc.so (__start_thread+64) (BuildId: 6bfaf10f10e5ff343703efae2f1bdbdb)
|
查看调用栈,锁定在libnative-lib.so,偏移量是38f7c,用ida打开后,访问那块地址,结果说函数太大,无法进行f5,没辙了,没啥思绪了,看看博客。
https://blog.csdn.net/qq_61253776/article/details/140026070
看来我的第一步分析是正确的,将函数j a e进行了hook,避免了java层的检测,但so层好难。
接下来找博客一步一步做了。
So层的检测针对了root权限和frida注入,下面主要写分析过程。
在re.pwnme.MainActivity类中,静态初始化块加载了native-lib,
然后声明了其中的一个native函数并用于MainActivity的页面代码中。
通过ida观察libnative-lib.so的export表,导出函数和全局变量都被加密了。

点开.datadiv_decodexxxxxx,大部分这类函数只写了一个RET,对应的字节码是C0 03 5F D6。

根据观察,其中的函数datadiv_decode4432700155380705947,它存在函数体,并且大部分操作似乎在做解密。大部分资料显示,这里是在做全局字符串的解密操作。
除此之外,在.init_array段中,存在两个拥有函数体的函数,它们无法f5,反编译成c。

过了java层后,会在so层的某处断开,地址是38f7c。

在ida中来到38f7c,一路跟踪交叉引用,最后判定,这段代码属于sub_83DC。
由于静态无法分析,只能动态分析了,博客中,这里使用了工具QBDI,QBDI是一个动态二进制插桩的DBI框架,可以追踪函数细节,如果只用frida的话,只能看到函数调用前的参数和调用后的结果。
但QBDI咋用啊,wtf,教程也太少了。
时隔多天,在分析完豆瓣后,再次看看这个apk如何分析。
在分析豆瓣的过程中,学会了找退出点的一些方法。
比如:hook函数pthread_create,线程在跑起来后,如果是检测frida的线程,就会杀死frida,所以可以观察哪个线程跑起来后,导致frida退出了。因为libc.so是系统库,加载先于frida的spawn模式,无需担心过早hook。
对应的检测线程脚本如下,不是直接复制就能用,这里放在这仅供参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| function hook_linker_call_constructors() { let linker64_base_addr = Module.getBaseAddress('linker64'); let offset = 0x51BA8; let call_constructors = linker64_base_addr.add(offset); let listener = Interceptor.attach(call_constructors, { onEnter: function(args) { console.log('hook_linker_call_constructors onEnter'); let libnative_module = Process.findModuleByName("libnative-lib.so");
if (libnative_module) { console.log("Module name: " + libnative_module.name); console.log("Base address: 0x" + libnative_module.base.toString(16)); console.log("Size: " + libnative_module.size); console.log("Path: " + libnative_module.path); check_pthread_create(libnative_module.base); listener.detach(); }
} }); }
function check_pthread_create(baseaddr){ var pthread_create = Module.findExportByName("libc.so", "pthread_create");
if(pthread_create){ console.log("pthread_create is exist"); }else{ console.log("pthread_create is not exist"); }
Interceptor.attach(pthread_create, { onEnter: function(args){ console.log("pthread_create is called"); console.log("arg2: 0x" + (args[2] - baseaddr).toString(16)); } }); }
|
之后应该就会看到几个函数的地址,然后尝试hook它们。
1 2 3 4 5 6 7 8 9 10 11 12 13
| function hook_20954(){ let libnative_module = Process.findModuleByName("libnative-lib.so"); Interceptor.replace(libnative_module.base.add(0x20954), new NativeCallback(function () { console.log(`hook_20954 >>>>>>>>>>>>>>>>> replace`); }, 'void', [])); }
function hook_7a660(){ let libnative_module = Process.findModuleByName("libnative-lib.so"); Interceptor.replace(libnative_module.base.add(0x7a660), new NativeCallback(function () { console.log(`hook_7a660 >>>>>>>>>>>>>>>>> replace`); }, 'void', [])); }
|
然后再次跑frida脚本,发现提示除以0的报错,这个报错不是在之前的java层解决了吗?
下面这个脚本是错的,是我早期通过deepseek生成的,我还以为能用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| function hook_java() { var targetClass = Java.use("b.a.a.b"); var methods = targetClass.class.getDeclaredMethods();
console.log("Methods found in b.a.a.b:"); methods.forEach(function(method) { if (method.getName() === "a" && method.getParameterTypes().length === 0) { var returnType = method.getReturnType().getName(); console.log("Return type: " + typeof returnType + ", value: " + returnType); if (returnType === "boolean") { method.implementation = function() { console.log("b.a.a.b.a() is called, res = ", this.a()); console.log("Hooked boolean a() method"); return false; }; } }
if (method.getName() === "j" && method.getParameterTypes().length === 0) { var returnType = method.getReturnType().getName(); if (returnType === "boolean") { method.implementation = function() { console.log("b.a.a.b.j() is called, res = ", this.j()); console.log("Hooked boolean j() method"); return false; }; } }
if (method.getName() === "e" && method.getParameterTypes().length === 0) { var returnType = method.getReturnType().getName(); if (returnType === "boolean") { method.implementation = function() { console.log("b.a.a.b.e() is called, res = ", this.e()); console.log("Hooked boolean e() method"); return false; }; } } }); }
|
将它修改成正常的、简单的脚本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function hook_java() { Java.perform(function() { var targetClass = Java.use("b.a.a.b");
targetClass.a.overload().implementation = function() { console.log("Hooked b.a.a.b.a()"); return false; };
targetClass.j.overload().implementation = function() { console.log("Hooked b.a.a.b.j()"); return false; };
targetClass.e.overload().implementation = function() { console.log("Hooked b.a.a.b.e()"); return false; }; }); }
|
最后整理出来的脚本如下,执行完后能正常跑apk了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| function hook_java() { Java.perform(function() { var targetClass = Java.use("b.a.a.b");
targetClass.a.overload().implementation = function() { console.log("Hooked b.a.a.b.a()"); return false; };
targetClass.j.overload().implementation = function() { console.log("Hooked b.a.a.b.j()"); return false; };
targetClass.e.overload().implementation = function() { console.log("Hooked b.a.a.b.e()"); return false; }; }); }
function hook_linker_call_constructors() { let linker64_base_addr = Module.getBaseAddress('linker64'); let offset = 0x51BA8; let call_constructors = linker64_base_addr.add(offset); let listener = Interceptor.attach(call_constructors, { onEnter: function(args) { console.log('hook_linker_call_constructors onEnter'); let libnative_module = Process.findModuleByName("libnative-lib.so");
if (libnative_module) { console.log("Module name: " + libnative_module.name); console.log("Base address: 0x" + libnative_module.base.toString(16)); console.log("Size: " + libnative_module.size); console.log("Path: " + libnative_module.path); check_pthread_create(libnative_module.base); hook_20954(); hook_7a660(); listener.detach(); }
} }); }
function check_pthread_create(baseaddr){ var pthread_create = Module.findExportByName("libc.so", "pthread_create");
if(pthread_create){ console.log("pthread_create is exist"); }else{ console.log("pthread_create is not exist"); }
Interceptor.attach(pthread_create, { onEnter: function(args){ console.log("pthread_create is called"); console.log("arg2: 0x" + (args[2] - baseaddr).toString(16)); } }); }
function hook_20954(){ let libnative_module = Process.findModuleByName("libnative-lib.so"); Interceptor.replace(libnative_module.base.add(0x20954), new NativeCallback(function () { console.log(`hook_20954 >>>>>>>>>>>>>>>>> replace`); }, 'void', [])); }
function hook_7a660(){ let libnative_module = Process.findModuleByName("libnative-lib.so"); Interceptor.replace(libnative_module.base.add(0x7a660), new NativeCallback(function () { console.log(`hook_7a660 >>>>>>>>>>>>>>>>> replace`); }, 'void', [])); }
function Avoid_divide_by_zero(){ let b = Java.use("b.a.a.b"); b["j"].implementation = function () { return false }; }
hook_linker_call_constructors();
setImmediate(hook_java);
|
成功在豆瓣进修,hhhhhh。