前言
挺长时间未更新掘金了,一方面内部的一些案例不方便进行脱敏,另方面近期处理的事都是三方软件故障居多,都在逆向研究别家的 TOP 软件问题,这个公开也不太好,正好有个比较特殊的问题可以展开说说。一个与 dex-vmp 加固有关的问题。
问题描述
国内某款软件,在程序安装后,首次打开能够正常使用,之后反复冷启动测试过程中,当首次出现应用冻屏闪退后,该应用就再也无法打开,由于该程序的一些信号处理逻辑问题造成死循环,错误日志也被应用本身给拦截了。
错误堆栈
对应这种情况,我们可以先用 strace 跟踪看看具体什么原因程序闪退。
css
16:23:11 faccessat(AT_FDCWD, "/data/user/0/me.abc.xianfeng/app_bugly/../files/native_record_lock", F_OK) = 0 <0.000027>
16:23:11 unlinkat(AT_FDCWD, "/data/user/0/me.abc.xianfeng/app_bugly/../files/native_record_lock", 0) = 0 <0.000086>
16:23:11 rt_sigaction(SIGFPE, {sa_handler=0x6f15452614, sa_mask=[INT ILL TRAP ABRT BUS FPE SEGV USR2 PIPE TERM STKFLT SYS], sa_flags=SA_ONSTACK|SA_SIGINFO}, NULL, 8) = 0 <0.000012>
16:23:11 rt_sigaction(SIGILL, {sa_handler=0x6f15452614, sa_mask=[INT ILL TRAP ABRT BUS FPE SEGV USR2 PIPE TERM STKFLT SYS], sa_flags=SA_ONSTACK|SA_SIGINFO}, NULL, 8) = 0 <0.000012>
16:23:11 rt_sigaction(SIGBUS, {sa_handler=0x6f15452614, sa_mask=[INT ILL TRAP ABRT BUS FPE SEGV USR2 PIPE TERM STKFLT SYS], sa_flags=SA_ONSTACK|SA_SIGINFO}, NULL, 8) = 0 <0.000015>
16:23:11 rt_sigaction(SIGABRT, {sa_handler=0x6f15452614, sa_mask=[INT ILL TRAP ABRT BUS FPE SEGV USR2 PIPE TERM STKFLT SYS], sa_flags=SA_ONSTACK|SA_SIGINFO}, NULL, 8) = 0 <0.000011>
16:23:11 rt_sigaction(SIGTRAP, {sa_handler=0x6f15452614, sa_mask=[INT ILL TRAP ABRT BUS FPE SEGV USR2 PIPE TERM STKFLT SYS], sa_flags=SA_ONSTACK|SA_SIGINFO}, NULL, 8) = 0 <0.000011>
16:23:11 rt_sigaction(SIGQUIT, {sa_handler=0x6f1545d280, sa_mask=[QUIT], sa_flags=SA_SIGINFO}, NULL, 8) = 0 <0.000011>
16:23:11 rt_sigaction(SIGSTKFLT, {sa_handler=0x6f15452614, sa_mask=[INT ILL TRAP ABRT BUS FPE SEGV USR2 PIPE TERM STKFLT SYS], sa_flags=SA_ONSTACK|SA_SIGINFO}, NULL, 8) = 0 <0.000013>
16:23:11 kill(15956, SIGSEGV) = 0 <0.008951>
16:23:11 rt_sigreturn({mask=[USR1 PIPE RTMIN]}) = 71703364 <0.000333>
16:23:11 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xbdbf504004461b44} ---
程序一直在 SIGSEGV 中死循环,因此出现冻屏,我们可以直接抓 core 文件即可。
shell
# ./data/core-parser -p `pidof me.abc.xianfeng`
yaml
core-parser> bt
Switch oat version(259) env.
"main" sysTid=19023 Runnable
| group="main" daemon=0 prio=5 target=0x0 uncaught_exception=0x0
| tid=1 sCount=1 flags=11 obj=0x72a00b18 self=0xb400007028a4d380 env=0xb400007158a54c70
| stack=0x7fe892a000-0x7fe892c000 stackSize=0x7ff000 handle=0x7282841098
| mutexes=0xb400007028a4db20 held="mutator lock"(shared held)
x0 0xb400007068a91d28 x1 0x0000000000000000 x2 0x0000006f1ba654df x3 0x000fffffffffffff
x4 0x0000000000000000 x5 0x0000000000000000 x6 0x632e1f1f1f1f6261 x7 0x7f7f7f7f7f7f7f7f
x8 0x0000000000000065 x9 0x0000000000989680 x10 0x00000000000003e8 x11 0x9c3eb4d6bc62c83f
x12 0x000003d9fc6968b0 x13 0x000000004cec4ec5 x14 0x0000000000000018 x15 0x000003d9fc68c768
x16 0x000000724939a870 x17 0x0000007249382200 x18 0x00000072825e4000 x19 0x00000072814c9880
x20 0xb400007198a7f750 x21 0x00000000000000b3 x22 0x0000000000000000 x23 0x0000000000000114
x24 0x0000006f1bab6f18 x25 0x00000072814c9880 x26 0x0000006f1bab7030 x27 0x0000007248f773f8
x28 0x0000000000000400 fp 0xb400007068a91d40
lr 0x0000007249333400 sp 0xb400007068a91d20 pc 0x0000007249382204 pst 0x0000000080001000
Native: #0 0000007249382204 nanosleep+0x4
Native: #1 00000072493333fc usleep+0x4c
Native: #2 0000006f1ba49354 /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/lib/arm64/libBugly_Native.so+0x9354
Native: #3 0000007248f6dd74 art::SignalChain::Handler(int, siginfo*, void*)+0x484
Native: #4 00000072826e3860 /system/bin/linker64+0x4b860
<<maybe handle signal ucontext: 0x7068a91f40>>
x0 0x0000000004462efc x1 0x0000000000000002 x2 0x00000000af5d1568 x3 0x0000000000000002
x4 0x0000007fe9122b10 x5 0x0000006f39c1b286 x6 0x3b6c69696c696949 x7 0x0000006f39c54013
x8 0x9c3eb4d6bc62c83f x9 0x9c3eb4d6bc62c83f x10 0x0000000000000000 x11 0x000000005c000000
x12 0x0000007fe9122dd8 x13 0x000000000000009d x14 0x0000000000000000 x15 0x0000000000000001
x16 0x0000000000000000 x17 0x000000005c000000 x18 0x00000072825e4000 x19 0xb400007028a4d380
x20 0x0000000000000000 x21 0xb400007028a4d440 x22 0x0000000004462ec8 x23 0x000000006f8455e0
x24 0xaf6fd45000000002 x25 0xaf6fd41000000000 x26 0xaf6fd4f000000000 x27 0x000000006f8455e0
x28 0x000000000000300b fp 0x0000007fe9122fc0
lr 0x0000006f37516dc0 sp 0x0000007fe9122ec0 pc 0x0000006f37516dbc pst 0x0000000080001000
Native: #5 0000006f37516dbc /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/oat/arm64/base.odex+0x482dbc
Native: #6 0000006f37516dbc /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/oat/arm64/base.odex+0x482dbc
Native: #7 0000006f39c1b5ae
JavaKt: #00 0000000000000000 liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.lIlLLIiIIiiILlliILIILlLIlilIiIlllLLillL.LiLiLIiliILIlLLlilLLlLILLLlIiiiliLIili
JavaKt: #01 0000006f39e29454 okhttp3.MediaType.parameter
JavaKt: #02 0000006f39e2d58a okhttp3.RequestBody$Companion.create
JavaKt: #03 0000000000000000 br.bewilder.deduce.base.network.NetworkApi.llIiliIIIlLllLlIllILIiiILiilILLlIIiLiiL
JavaKt: #04 0000006f39fa60da wr.exquisite.foster.CommonRequestModel$attribution$1.invokeSuspend
JavaKt: #05 0000006f39fa5b10 wr.exquisite.foster.CommonRequestModel$attribution$1.invoke
JavaKt: #06 0000006f39fa56cc wr.exquisite.foster.CommonRequestModel$attribution$1.invoke
JavaKt: #07 0000000000000000 br.bewilder.deduce.base.ext.BaseViewModelExtKt$request$3.invokeSuspend
...
由于错误在 odex 代码中,并且此时的未保存 java frame 到,因此需要进行假数据调整。
yaml
core-parser> bt
"main" sysTid=19023 Runnable
| group="main" daemon=0 prio=5 target=0x0 uncaught_exception=0x0
| tid=1 sCount=1 flags=11 obj=0x72a00b18 self=0xb400007028a4d380 env=0xb400007158a54c70
| stack=0x7fe892a000-0x7fe892c000 stackSize=0x7ff000 handle=0x7282841098
| mutexes=0xb400007028a4db20 held="mutator lock"(shared held)
x0 0xb400007068a91d28 x1 0x0000000000000000 x2 0x0000006f1ba654df x3 0x000fffffffffffff
x4 0x0000000000000000 x5 0x0000000000000000 x6 0x632e1f1f1f1f6261 x7 0x7f7f7f7f7f7f7f7f
x8 0x0000000000000065 x9 0x0000000000989680 x10 0x00000000000003e8 x11 0x9c3eb4d6bc62c83f
x12 0x000003d9fc6968b0 x13 0x000000004cec4ec5 x14 0x0000000000000018 x15 0x000003d9fc68c768
x16 0x000000724939a870 x17 0x0000007249382200 x18 0x00000072825e4000 x19 0x00000072814c9880
x20 0xb400007198a7f750 x21 0x00000000000000b3 x22 0x0000000000000000 x23 0x0000000000000114
x24 0x0000006f1bab6f18 x25 0x00000072814c9880 x26 0x0000006f1bab7030 x27 0x0000007248f773f8
x28 0x0000000000000400 fp 0xb400007068a91d40
lr 0x0000007249333400 sp 0xb400007068a91d20 pc 0x0000007249382204 pst 0x0000000080001000
Native: #0 0000007249382204 nanosleep+0x4
Native: #1 00000072493333fc usleep+0x4c
Native: #2 0000006f1ba49354 /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/lib/arm64/libBugly_Native.so+0x9354
Native: #3 0000007248f6dd74 art::SignalChain::Handler(int, siginfo*, void*)+0x484
Native: #4 00000072826e3860 /system/bin/linker64+0x4b860
<<maybe handle signal ucontext: 0x7068a91f40>>
x0 0x0000000004462efc x1 0x0000000000000002 x2 0x00000000af5d1568 x3 0x0000000000000002
x4 0x0000007fe9122b10 x5 0x0000006f39c1b286 x6 0x3b6c69696c696949 x7 0x0000006f39c54013
x8 0x9c3eb4d6bc62c83f x9 0x9c3eb4d6bc62c83f x10 0x0000000000000000 x11 0x000000005c000000
x12 0x0000007fe9122dd8 x13 0x000000000000009d x14 0x0000000000000000 x15 0x0000000000000001
x16 0x0000000000000000 x17 0x000000005c000000 x18 0x00000072825e4000 x19 0xb400007028a4d380
x20 0x0000000000000000 x21 0xb400007028a4d440 x22 0x0000000004462ec8 x23 0x000000006f8455e0
x24 0xaf6fd45000000002 x25 0xaf6fd41000000000 x26 0xaf6fd4f000000000 x27 0x000000006f8455e0
x28 0x000000000000300b fp 0x0000007fe9122fc0
lr 0x0000006f37516dc0 sp 0x0000007fe9122ec0 pc 0x0000006f37516dbc pst 0x0000000080001000
Native: #5 0000006f37516dbc /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/oat/arm64/base.odex+0x482dbc
Native: #6 0000006f37516dbc /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/oat/arm64/base.odex+0x482dbc
Native: #7 0000006f39c1b5ae
JavaKt: #00 0000006f39e29474 okhttp3.MediaType.parameter
JavaKt: #01 0000006f39e2d58a okhttp3.RequestBody$Companion.create
JavaKt: #02 0000000000000000 br.bewilder.deduce.base.network.NetworkApi.llIiliIIIlLllLlIllILIiiILiilILLlIIiLiiL
JavaKt: #03 0000006f39fa60da wr.exquisite.foster.CommonRequestModel$attribution$1.invokeSuspend
JavaKt: #04 0000006f39fa5b10 wr.exquisite.foster.CommonRequestModel$attribution$1.invoke
JavaKt: #05 0000006f39fa56cc wr.exquisite.foster.CommonRequestModel$attribution$1.invoke
JavaKt: #06 0000000000000000 br.bewilder.deduce.base.ext.BaseViewModelExtKt$request$3.invokeSuspend
JavaKt: #07 0000006f3994b062 kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith
JavaKt: #08 0000006f39a07f44 kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith
JavaKt: #09 0000006f39a0d4d8 kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable
JavaKt: #10 0000006f399cabfe kotlinx.coroutines.CoroutineStart.invoke
JavaKt: #11 0000006f399c6ff4 kotlinx.coroutines.BuildersKt.launch$default
JavaKt: #12 0000000000000000 br.bewilder.deduce.base.ext.BaseViewModelExtKt.request
JavaKt: #13 0000006f39fb459c wr.exquisite.foster.CommonRequestModel.attribution
...
Core 分析
yaml
core-parser> f 0
JavaKt: #00 0000006f39e29474 okhttp3.MediaType.parameter(java.lang.String)
{
Location: /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/oat/arm64/base.vdex
art::ArtMethod: 0xaf706b98
dex_pc_ptr: 0x6f39e29474
quick_frame: 0x7fe9122ec0
frame_pc: 0x6f37516dbc
method_header: 0x6f37516c2c
DEX CODE:
0x6f39e2946a: 5354 6123 | iget-object v3, v5, Lokhttp3/MediaType;.parameterNamesAndValues:[Ljava/lang/String; // field@24867
0x6f39e2946e: 0346 0103 | aget-object v3, v3, v1
0x6f39e29472: 1412 | const/4 v4, #+1
0x6f39e29474: 3071 122e 0463 | invoke-static {v3, v6, v4}, boolean liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.iIIiliiiillLliLIlLiLLlLIllLLLLLLlliiiLL.equals(java.lang.String, java.lang.String, boolean) // method@4654
OAT CODE:
0x6f37516d98: 1000007e | adr x30, 0x6f37516da4
0x6f37516d9c: b5ed5a34 | cbnz x20, 0x6f374f18e0
0x6f37516da0: b9400ec0 | ldr w0, [x22, #0xc]
0x6f37516da4: b9400801 | ldr w1, [x0, #8]
0x6f37516da8: 6b01033f | cmp w25, w1
0x6f37516dac: 54000662 | b.hs 0x6f37516e78
0x6f37516db0: 11003000 | add w0, w0, #0xc
0x6f37516db4: 1000007e | adr x30, 0x6f37516dc0
0x6f37516db8: b5f04fd4 | cbnz x20, 0x6f374f77b0
0x6f37516dbc: b8797801 | ldr w1, [x0, x25, lsl #2]
0x6f37516dc0: aa1703e2 | mov x2, x23
0x6f37516dc4: aa0103fb | mov x27, x1
}
core-parser>
由于 x25 寄存器 0xaf6fd41000000000 因此造成数组越界。事实上此处的指令是为函数调用的参数准备,也就是真正对应的字节码过程是 "aget-object v3, v3, v1",即 x25 << 2 则是 vAA <- vBB[vCC] 的 vCC 参数。而此处指令的参数类型应为 int 类型,如今却是 x25 寄存器表达成 long 类型。
yaml
core-parser> method 0xaf706b98 --dex --oat
public final java.lang.String okhttp3.MediaType.parameter(java.lang.String) [dex_method_idx=13268]
DEX CODE:
0x6f39e29424: 001a 76b5 | const-string v0, "name" // string@30389
0x6f39e29428: 2071 06af 0006 | invoke-static {v6, v0}, void kotlin.jvm.internal.Intrinsics.checkNotNullParameter(java.lang.Object, java.lang.String) // method@1711
0x6f39e2942e: 5054 6123 | iget-object v0, v5, Lokhttp3/MediaType;.parameterNamesAndValues:[Ljava/lang/String; // field@24867
0x6f39e29432: 1071 0681 0000 | invoke-static {v0}, liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.IIiIiLliIlLilLLILilILILlIIiillLIliL kotlin.collections.ArraysKt___ArraysKt.IlIIliLilIiiilLlIilLiIIlILLIlIIllIILlilI(java.lang.Object[]) // method@1665
0x6f39e29438: 000c | move-result-object v0
0x6f39e2943a: 2112 | const/4 v1, #+2
0x6f39e2943c: 2071 0c33 0010 | invoke-static {v0, v1}, liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.lIlLLIiIIiiILlliILIILlLIlilIiIlllLLillL liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.LLIilIIIIIiiIIiIIIIilllLlLlIiliILLiL.IlIlLiilIiLlIILlLILILlLlilIlLlIiIII(liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.lIlLLIiIIiiILlliILIILlLIlilIiIlllLLillL, int) // method@3123
0x6f39e29442: 000c | move-result-object v0
0x6f39e29444: 106e 1cda 0000 | invoke-virtual {v0}, int liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.lIlLLIiIIiiILlliILIILlLIlilIiIlllLLillL.IlIiLillILlILlIlilLIlIiIIlLlLIILLIl() // method@7386
0x6f39e2944a: 010a | move-result v1
0x6f39e2944c: 106e 1cdc 0000 | invoke-virtual {v0}, int liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.lIlLLIiIIiiILlliILIILlLIlilIiIlllLLillL.lLLlLlLiIILLilLIiiILLlliiILlIlIililIIlIlI() // method@7388
0x6f39e29452: 020a | move-result v2
0x6f39e29454: 106e 1cdb 0000 | invoke-virtual {v0}, int liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.lIlLLIiIIiiILlliILIILlLIlilIiIlllLLillL.LiLiLIiliILIlLLlilLLlLILLLlIiiiliLIili() // method@7387
0x6f39e2945a: 000a | move-result v0
0x6f39e2945c: 003a 0005 | if-ltz v0, 0x6f39e29466 //+5
0x6f39e29460: 2136 001a | if-gt v1, v2, 0x6f39e29494 //+26
0x6f39e29464: 0328 | goto 0x6f39e2946a //+3
0x6f39e29466: 2134 0017 | if-lt v1, v2, 0x6f39e29494 //+23
0x6f39e2946a: 5354 6123 | iget-object v3, v5, Lokhttp3/MediaType;.parameterNamesAndValues:[Ljava/lang/String; // field@24867
0x6f39e2946e: 0346 0103 | aget-object v3, v3, v1
0x6f39e29472: 1412 | const/4 v4, #+1
0x6f39e29474: 3071 122e 0463 | invoke-static {v3, v6, v4}, boolean liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.iIIiliiiillLliLIlLiLLlLIllLLLLLLlliiiLL.equals(java.lang.String, java.lang.String, boolean) // method@4654
0x6f39e2947a: 030a | move-result v3
0x6f39e2947c: 0338 0008 | if-eqz v3, 0x6f39e2948c //+8
0x6f39e29480: 5654 6123 | iget-object v6, v5, Lokhttp3/MediaType;.parameterNamesAndValues:[Ljava/lang/String; // field@24867
0x6f39e29484: 41b0 | add-int/2addr v1, v4
0x6f39e29486: 0646 0106 | aget-object v6, v6, v1
0x6f39e2948a: 0611 | return-object v6
0x6f39e2948c: 2132 0004 | if-eq v1, v2, 0x6f39e29494 //+4
0x6f39e29490: 01b0 | add-int/2addr v1, v0
0x6f39e29492: ec28 | goto 0x6f39e2946a //-20
0x6f39e29494: 0612 | const/4 v6, #+0
0x6f39e29496: 0611 | return-object v6
OAT CODE:
[0x6f37516c30, 0x6f37516e8c]
0x6f37516c30: d1400bf0 | sub x16, sp, #2, lsl #12
0x6f37516c34: b940021f | ldr wzr, [x16]
GeneralStackMap[0] (NativePc=0x6f37516c38 DexPc=0x6f39e29424)
0x6f37516c38: f81a0fe0 | str x0, [sp, #-0x60]!
0x6f37516c3c: f90017f6 | str x22, [sp, #0x28]
0x6f37516c40: a90363f7 | stp x23, x24, [sp, #0x30]
0x6f37516c44: a9046bf9 | stp x25, x26, [sp, #0x40]
0x6f37516c48: a9057bfb | stp x27, x30, [sp, #0x50]
0x6f37516c4c: f94002b5 | ldr x21, [x21]
GeneralStackMap[1] (NativePc=0x6f37516c50 DexPc=0x6f39e29424)
0x6f37516c50: 35000142 | cbnz w2, 0x6f37516c78
0x6f37516c54: aa0103f6 | mov x22, x1
0x6f37516c58: aa0203f7 | mov x23, x2
0x6f37516c5c: d0000421 | adrp x1, 0x6f3759c000
0x6f37516c60: b947b421 | ldr w1, [x1, #0x7b4]
0x6f37516c64: aa0103f8 | mov x24, x1
0x6f37516c68: d0000440 | adrp x0, 0x6f375a0000
0x6f37516c6c: b94c1c00 | ldr w0, [x0, #0xc1c]
0x6f37516c70: f9400c1e | ldr x30, [x0, #0x18]
0x6f37516c74: d63f03c0 | blr x30
GeneralStackMap[2] (NativePc=0x6f37516c78 DexPc=0x6f39e29428)
0x6f37516c78: aa0103f6 | mov x22, x1
0x6f37516c7c: aa0203f7 | mov x23, x2
0x6f37516c80: 1000007e | adr x30, 0x6f37516c8c
0x6f37516c84: b5ed62f4 | cbnz x20, 0x6f374f18e0
0x6f37516c88: b9400ed8 | ldr w24, [x22, #0xc]
0x6f37516c8c: 90000460 | adrp x0, 0x6f375a2000
0x6f37516c90: b94f9400 | ldr w0, [x0, #0xf94]
0x6f37516c94: 3941ac10 | ldrb w16, [x0, #0x6b]
0x6f37516c98: 7103c21f | cmp w16, #0xf0
0x6f37516c9c: 54000d23 | b.lo 0x6f37516e40
0x6f37516ca0: 35000178 | cbnz w24, 0x6f37516ccc
0x6f37516ca4: f0000461 | adrp x1, 0x6f375a5000
0x6f37516ca8: 1000007e | adr x30, 0x6f37516cb4
0x6f37516cac: b9448c21 | ldr w1, [x1, #0x48c]
0x6f37516cb0: b5f65314 | cbnz x20, 0x6f37503710
0x6f37516cb4: b4000ce1 | cbz x1, 0x6f37516e50
0x6f37516cb8: aa0103f9 | mov x25, x1
0x6f37516cbc: d0000440 | adrp x0, 0x6f375a0000
0x6f37516cc0: b94c1c00 | ldr w0, [x0, #0xc1c]
0x6f37516cc4: f9400c1e | ldr x30, [x0, #0x18]
0x6f37516cc8: d63f03c0 | blr x30
GeneralStackMap[3] (NativePc=0x6f37516ccc DexPc=0x6f39e29432)
0x6f37516ccc: b0000460 | adrp x0, 0x6f375a3000
0x6f37516cd0: b940ec00 | ldr w0, [x0, #0xec]
0x6f37516cd4: f940e67e | ldr x30, [x19, #0x1c8]
0x6f37516cd8: d63f03c0 | blr x30
GeneralStackMap[4] (NativePc=0x6f37516cdc DexPc=0x6f39e29432)
0x6f37516cdc: f0000461 | adrp x1, 0x6f375a5000
0x6f37516ce0: 1000007e | adr x30, 0x6f37516cec
0x6f37516ce4: b9449421 | ldr w1, [x1, #0x494]
0x6f37516ce8: b5f65154 | cbnz x20, 0x6f37503710
0x6f37516cec: b4000ba1 | cbz x1, 0x6f37516e60
0x6f37516cf0: b9400b01 | ldr w1, [x24, #8]
0x6f37516cf4: 51000423 | sub w3, w1, #1
0x6f37516cf8: aa0003e1 | mov x1, x0
0x6f37516cfc: aa0103f9 | mov x25, x1
0x6f37516d00: 52800002 | mov w2, #0
0x6f37516d04: 52800024 | mov w4, #1
0x6f37516d08: f0000440 | adrp x0, 0x6f375a1000
0x6f37516d0c: b9401400 | ldr w0, [x0, #0x14]
0x6f37516d10: f9400c1e | ldr x30, [x0, #0x18]
0x6f37516d14: d63f03c0 | blr x30
GeneralStackMap[5] (NativePc=0x6f37516d18 DexPc=0x6f39e29432)
0x6f37516d18: aa1903e1 | mov x1, x25
0x6f37516d1c: 52800042 | mov w2, #2
0x6f37516d20: d0000440 | adrp x0, 0x6f375a0000
0x6f37516d24: b94ea800 | ldr w0, [x0, #0xea8]
0x6f37516d28: f9400c1e | ldr x30, [x0, #0x18]
0x6f37516d2c: d63f03c0 | blr x30
GeneralStackMap[6] (NativePc=0x6f37516d30 DexPc=0x6f39e2943c)
0x6f37516d30: b940001f | ldr wzr, [x0]
GeneralStackMap[7] (NativePc=0x6f37516d34 DexPc=0x6f39e29444)
0x6f37516d34: aa0003e1 | mov x1, x0
0x6f37516d38: aa0103f8 | mov x24, x1
0x6f37516d3c: f0000440 | adrp x0, 0x6f375a1000
0x6f37516d40: b9401800 | ldr w0, [x0, #0x18]
0x6f37516d44: f9400c1e | ldr x30, [x0, #0x18]
0x6f37516d48: d63f03c0 | blr x30
GeneralStackMap[8] (NativePc=0x6f37516d4c DexPc=0x6f39e29444)
0x6f37516d4c: aa1803e1 | mov x1, x24
0x6f37516d50: aa0003f9 | mov x25, x0
0x6f37516d54: f0000440 | adrp x0, 0x6f375a1000
0x6f37516d58: b9402000 | ldr w0, [x0, #0x20]
0x6f37516d5c: f9400c1e | ldr x30, [x0, #0x18]
0x6f37516d60: d63f03c0 | blr x30
GeneralStackMap[9] (NativePc=0x6f37516d64 DexPc=0x6f39e2944c)
0x6f37516d64: aa1803e1 | mov x1, x24
0x6f37516d68: aa0003fa | mov x26, x0
0x6f37516d6c: f0000440 | adrp x0, 0x6f375a1000
0x6f37516d70: b9401c00 | ldr w0, [x0, #0x1c]
0x6f37516d74: f9400c1e | ldr x30, [x0, #0x18]
0x6f37516d78: d63f03c0 | blr x30
GeneralStackMap[10] (NativePc=0x6f37516d7c DexPc=0x6f39e29454)
0x6f37516d7c: 37f80080 | tbnz w0, #0x1f, 0x6f37516d8c
0x6f37516d80: 6b1a033f | cmp w25, w26
0x6f37516d84: 5400050c | b.gt 0x6f37516e24
0x6f37516d88: 14000003 | b 0x6f37516d94
0x6f37516d8c: 6b1a033f | cmp w25, w26
0x6f37516d90: 540004ab | b.lt 0x6f37516e24
0x6f37516d94: aa0003f8 | mov x24, x0
0x6f37516d98: 1000007e | adr x30, 0x6f37516da4
0x6f37516d9c: b5ed5a34 | cbnz x20, 0x6f374f18e0
0x6f37516da0: b9400ec0 | ldr w0, [x22, #0xc]
0x6f37516da4: b9400801 | ldr w1, [x0, #8]
GeneralStackMap[11] (NativePc=0x6f37516da8 DexPc=0x6f39e2946e)
0x6f37516da8: 6b01033f | cmp w25, w1
0x6f37516dac: 54000662 | b.hs 0x6f37516e78
0x6f37516db0: 11003000 | add w0, w0, #0xc
0x6f37516db4: 1000007e | adr x30, 0x6f37516dc0
0x6f37516db8: b5f04fd4 | cbnz x20, 0x6f374f77b0
0x6f37516dbc: b8797801 | ldr w1, [x0, x25, lsl #2]
0x6f37516dc0: aa1703e2 | mov x2, x23
0x6f37516dc4: aa0103fb | mov x27, x1
0x6f37516dc8: 52800023 | mov w3, #1
0x6f37516dcc: d0000440 | adrp x0, 0x6f375a0000
0x6f37516dd0: b94f4800 | ldr w0, [x0, #0xf48]
0x6f37516dd4: f9400c1e | ldr x30, [x0, #0x18]
0x6f37516dd8: d63f03c0 | blr x30
GeneralStackMap[12] (NativePc=0x6f37516ddc DexPc=0x6f39e29474)
0x6f37516ddc: 350000c0 | cbnz w0, 0x6f37516df4
0x6f37516de0: 6b1a033f | cmp w25, w26
0x6f37516de4: 54000200 | b.eq 0x6f37516e24
0x6f37516de8: 0b180339 | add w25, w25, w24
0x6f37516dec: f94002b5 | ldr x21, [x21]
GeneralStackMap[13] (NativePc=0x6f37516df0 DexPc=0x6f39e2946a)
0x6f37516df0: 17ffffea | b 0x6f37516d98
0x6f37516df4: 1000007e | adr x30, 0x6f37516e00
0x6f37516df8: b5ed5754 | cbnz x20, 0x6f374f18e0
0x6f37516dfc: b9400ec0 | ldr w0, [x22, #0xc]
0x6f37516e00: 11000721 | add w1, w25, #1
0x6f37516e04: b9400802 | ldr w2, [x0, #8]
GeneralStackMap[14] (NativePc=0x6f37516e08 DexPc=0x6f39e29486)
0x6f37516e08: 6b02003f | cmp w1, w2
0x6f37516e0c: 540003a2 | b.hs 0x6f37516e80
0x6f37516e10: 11003000 | add w0, w0, #0xc
0x6f37516e14: 1000007e | adr x30, 0x6f37516e20
0x6f37516e18: b5f04cd4 | cbnz x20, 0x6f374f77b0
0x6f37516e1c: b8617800 | ldr w0, [x0, x1, lsl #2]
0x6f37516e20: 14000002 | b 0x6f37516e28
0x6f37516e24: 52800000 | mov w0, #0
0x6f37516e28: f94017f6 | ldr x22, [sp, #0x28]
0x6f37516e2c: a94363f7 | ldp x23, x24, [sp, #0x30]
0x6f37516e30: a9446bf9 | ldp x25, x26, [sp, #0x40]
0x6f37516e34: a9457bfb | ldp x27, x30, [sp, #0x50]
0x6f37516e38: 910183ff | add sp, sp, #0x60
0x6f37516e3c: d65f03c0 | ret
0x6f37516e40: f9000fe0 | str x0, [sp, #0x18]
0x6f37516e44: 94020473 | bl 0x6f37598010
GeneralStackMap[15] (NativePc=0x6f37516e48 DexPc=0x6f39e29432)
0x6f37516e48: f9400fe0 | ldr x0, [sp, #0x18]
0x6f37516e4c: 17ffff95 | b 0x6f37516ca0
0x6f37516e50: 5280cbc0 | mov w0, #0x65e
0x6f37516e54: 9402048b | bl 0x6f37598080
GeneralStackMap[16] (NativePc=0x6f37516e58 DexPc=0x6f39e29432)
0x6f37516e58: 2a0003e1 | mov w1, w0
0x6f37516e5c: 17ffff97 | b 0x6f37516cb8
0x6f37516e60: f9000fe0 | str x0, [sp, #0x18]
0x6f37516e64: 5280cd00 | mov w0, #0x668
0x6f37516e68: 94020486 | bl 0x6f37598080
GeneralStackMap[17] (NativePc=0x6f37516e6c DexPc=0x6f39e29432)
0x6f37516e6c: 2a0003e1 | mov w1, w0
0x6f37516e70: f9400fe0 | ldr x0, [sp, #0x18]
0x6f37516e74: 17ffff9f | b 0x6f37516cf0
0x6f37516e78: aa1903e0 | mov x0, x25
0x6f37516e7c: 9402046d | bl 0x6f37598030
GeneralStackMap[18] (NativePc=0x6f37516e80 DexPc=0x6f39e2946e)
0x6f37516e80: aa0103e0 | mov x0, x1
0x6f37516e84: aa0203e1 | mov x1, x2
0x6f37516e88: 9402046a | bl 0x6f37598030
GeneralStackMap[19] (NativePc=0x6f37516e8c DexPc=0x6f39e29486)
core-parser>
kotlin
public final String parameter(String name) {
Intrinsics.checkNotNullParameter(name, "name");
lIlLLIiIIiiILlliILIILlLIlilIiIlllLLillL IlIlLiilIiLlIILlLILILlLlilIlLlIiIII = LLIilIIIIIiiIIiIIIIilllLlLlIiliILLiL.IlIlLiilIiLlIILlLILILlLlilIlLlIiIII(ArraysKt___ArraysKt.IlIIliLilIiiilLlIilLiIIlILLIlIIllIILlilI(this.parameterNamesAndValues), 2);
int IlIiLillILlILlIlilLIlIiIIlLlLIILLIl = IlIlLiilIiLlIILlLILILlLlilIlLlIiIII.IlIiLillILlILlIlilLIlIiIIlLlLIILLIl();
int lLLlLlLiIILLilLIiiILLlliiILlIlIililIIlIlI = IlIlLiilIiLlIILlLILILlLlilIlLlIiIII.lLLlLlLiIILLilLIiiILLlliiILlIlIililIIlIlI();
int LiLiLIiliILIlLLlilLLlLILLLlIiiiliLIili = IlIlLiilIiLlIILlLILILlLlilIlLlIiIII.LiLiLIiliILIlLLlilLLlLILLLlIiiiliLIili();
if (LiLiLIiliILIlLLlilLLlLILLLlIiiiliLIili >= 0) {
if (IlIiLillILlILlIlilLIlIiIIlLlLIILLIl > lLLlLlLiIILLilLIiiILLlliiILlIlIililIIlIlI) {
return null;
}
} else if (IlIiLillILlILlIlilLIlIiIIlLlLIILLIl < lLLlLlLiIILLilLIiiILLlliiILlIlIililIIlIlI) {
return null;
}
while (!iIIiliiiillLliLIlLiLLlLIllLLLLLLlliiiLL.equals(this.parameterNamesAndValues[IlIiLillILlILlIlilLIlIiIIlLlLIILLIl], name, true)) {
if (IlIiLillILlILlIlilLIlIiIIlLlLIILLIl == lLLlLlLiIILLilLIiiILLlliiILlIlIililIIlIlI) {
return null;
}
IlIiLillILlILlIlilLIlIiIIlLlLIILLIl += LiLiLIiliILIlLLlilLLlLILLLlIiiiliLIili;
}
return this.parameterNamesAndValues[IlIiLillILlILlIlilLIlIiIIlLlLIILLIl + 1];
}
java
core-parser> rd 0x6f375a1018
6f375a1018: af6fd450af6fd410 ..o.P.o.
core-parser> method af6fd410
public final native int liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.lIlLLIiIIiiILlliILIILlLIlilIiIlllLLillL.IlIiLillILlILlIlilLIlIiIIlLlLIILLIl() [dex_method_idx=57892]
Binary:
af6fd410: 10200111af4a0810 ffff000b0000e224 ..J.....$.......
af6fd420: 0000006f32e9cbd4 0000000071217040 ...2o...@p!q....
bash
core-parser> vtor 0000006f32e9cbd4
* OR: 0x7572a60bd4
* MMAP: 0x0
* OVERLAY: 0x0
[6f320c1000, 6f32fdf000) r-x 0000f1e000 0000f1e000 /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/lib/arm64/libnmmp.so [*]
core-parser>
原因是该 native 函数(来自 libnmmp.so 与 libnmmvm.so)返回的结果是个 long 类型而非 int 类型导致数组越界。
为什么初次安装运行正常?
由于此时仍生成对应的 oat 代码段,因此该函数运行的方式为解释运行,若以 nterp 方式运行。

可以看到此处处理成 32-bit 寄存器传入,因此不会有该问题,那为什么 oat 就不行?
less
在解释运行中,该过程处理比较繁杂,需多条指令复合完成,而 oat 代码运行优化成单条指令,那是不是能够替换成32-bit 寄存器呢?我们可以本地编辑一个段汇编代码。
ldr w1, [x0, w25, lsl #2]
aarch64-linux-gnu-as -o code code.s
code.s: Assembler messages: code.s:1:
Error: invalid use of 32-bit register offset at operand 2 -- `ldr w1,[x0,w25,lsl#2]'
因此当后台 dex2opt 将 apk 翻译成 oat 代码后,再次冷启动打开加载了 oat code 运行,就会出现该问题。 同样的若以 switch 方式运行也是被显式转 32-bit。

okhttp3 项目
该项目已经相当成熟的,咋会犯这种错误?脱壳该程序可看到该 nmmp.so 库的加载代码。
ini
0x0000000000000001 (NEEDED) Shared library: [libnmmvm.so]
0x0000000000000001 (NEEDED) Shared library: [liblog.so]
0x0000000000000001 (NEEDED) Shared library: [libm.so]
0x0000000000000001 (NEEDED) Shared library: [libdl.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so]
0x000000000000000e (SONAME) Library soname: [libnmmp.so]
java
package com.nmmedit.protect;
public class NativeUtil {
static {
System.loadLibrary("nmmp");
}
public static native void classes2Init0(int i);
public static native void classes3Init0(int i);
public static native void classes4Init0(int i);
public static native void classes5Init0(int i);
public static native void classes6Init0(int i);
public static native void classesInit0(int i);
}
这个一个 dex-vmp 的加固工具,将 okhttp3 parameter 原数组的 begin, size 等函数藏匿在 c++ 处实现,因此问题本身不在该项目而是开发者与加固软件上,事实上 okhttp3 的代码没有加固的必要。
com.squareup.okhttp3:okhttp:4.11.0 版本的原代码:
yaml
core-parser> method 0x725d703bb8 --dex --oat
public final java.lang.String okhttp3.MediaType.parameter(java.lang.String) [dex_method_idx=62202]
DEX CODE:
0x6f3b0972e0: 001a d4a8 | const-string v0, "name" // string@54440
0x6f3b0972e4: 2071 d055 0006 | invoke-static {v6, v0}, void kotlin.jvm.internal.Intrinsics.checkNotNullParameter(java.lang.Object, java.lang.String) // method@53333
0x6f3b0972ea: 5054 814d | iget-object v0, v5, Lokhttp3/MediaType;.parameterNamesAndValues:[Ljava/lang/String; // field@33101
0x6f3b0972ee: 0021 | array-length v0, v0
0x6f3b0972f0: 00d8 ff00 | add-int/lit8 v0, v0, #-1
0x6f3b0972f4: 2112 | const/4 v1, #+2
0x6f3b0972f6: 0212 | const/4 v2, #+0
0x6f3b0972f8: 3071 cc4c 0102 | invoke-static {v2, v0, v1}, int kotlin.internal.ProgressionUtilKt.getProgressionLastElement(int, int, int) // method@52300
0x6f3b0972fe: 000a | move-result v0
0x6f3b097300: 003a 001a | if-ltz v0, 0x6f3b097334 //+26
0x6f3b097304: 01d8 0202 | add-int/lit8 v1, v2, #+2
0x6f3b097308: 5354 814d | iget-object v3, v5, Lokhttp3/MediaType;.parameterNamesAndValues:[Ljava/lang/String; // field@33101
0x6f3b09730c: 0346 0203 | aget-object v3, v3, v2
0x6f3b097310: 1412 | const/4 v4, #+1
0x6f3b097312: 3071 d973 0463 | invoke-static {v3, v6, v4}, boolean kotlin.text.StringsKt.equals(java.lang.String, java.lang.String, boolean) // method@55667
0x6f3b097318: 030a | move-result v3
0x6f3b09731a: 0338 0008 | if-eqz v3, 0x6f3b09732a //+8
0x6f3b09731e: 5554 814d | iget-object v5, v5, Lokhttp3/MediaType;.parameterNamesAndValues:[Ljava/lang/String; // field@33101
0x6f3b097322: 42b0 | add-int/2addr v2, v4
0x6f3b097324: 0546 0205 | aget-object v5, v5, v2
0x6f3b097328: 0511 | return-object v5
0x6f3b09732a: 0233 0003 | if-ne v2, v0, 0x6f3b097330 //+3
0x6f3b09732e: 0328 | goto 0x6f3b097334 //+3
0x6f3b097330: 1201 | move v2, v1
0x6f3b097332: e928 | goto 0x6f3b097304 //-23
0x6f3b097334: 0512 | const/4 v5, #+0
0x6f3b097336: 0511 | return-object v5
core-parser>
dex-vmp 加固
该加固软件是个国人大佬的开源项目,相关链接 github.com/maoabc/nmmp 项目。
java
core-parser> method af6fd410
public final native int liilliiililililijilIIllLiiiLLiiiiLjjiL.liiLLiiIIiLLiiLiiiiLLiiiiLllllIliliji.llijilliilijilijiiijllLLiiiLjilllII.lIlLLIiIIiiILlliILIILlLIlilIiIlllLLillL.IlIiLillILlILlIlilLIlIiIIlLlLIILLIl() [dex_method_idx=57892]
Binary:
af6fd410: 10200111af4a0810 ffff000b0000e224 ..J.....$.......
af6fd420: 0000006f32e9cbd4 0000000071217040 ...2o...@p!q....
取前面加固函数地址,可以看到该异常结果的返回值来自函数 vmInterpret ,也就是该加固模块的核心处理函数。

ini
typedef union jvalue {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
} jvalue;
jvalue vmInterpret(
JNIEnv *env,
const vmCode *code,
const vmResolver *dvmResolver
);
由于 jvalue 是个 union 类型,因此此处编译后会定义成最大的类型,也就是 jlong ,如果返回其它类型时没有对返回值做处理,很有可能会存在高位地址为脏数据的情况。在函数调用完成后断点跟踪可以看到 x0 寄存器存在 Object 对象的地址。
shell
[3121|3121] event_addr:0x6f350cac30 hit_count:4, Regs:
[x0=0xaf6fea6000000000,x1=0x5c,x2=0xaf5d1a50,x3=0x2,x4=0x7fe9122b10,x5=0x6f3a4db286,x6=0x3b6c69696c696949,x7=0x6f3a514013,x8=0xc4da19fef24ac95a,x9=0xc4da19fef24ac95a,x10=0x0,x11=0x5c000000,x12=0x7fe9122dd8,x13=0x9d,x14=0x0,x15=0x1,x16=0x6f3526d9d8,x17=0x6fb1b9a5c4,x18=0x72825e4000,x19=0x72814c9880,x20=0x1,x21=0xb400007028a4d440,x22=0xb400007158a54c70,x23=0x22,x24=0x27,x25=0xaf6fea60,x26=0x464d048,x27=0x6f8455e0,x28=0x300b,x29=0x7fe9122df0,lr=0x6f350cac30,sp=0x7fe9122da0,pc=0x6f350cac30]
Backtrace:
#00 pc 0000000000ddbc30 /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/lib/arm64/libnmmp.so
#01 pc 00000000002fb0b0 /system/framework/arm64/boot.oat (art_jni_trampoline+112)
#02 pc 00000000004afcb8 /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/oat/arm64/base.odex (okhttp3.MediaType.parameter+280)
#03 pc 00000000004b3840 /data/app/~~Vy2krCpa4Uf0ET6Q9CQwPg==/me.abc.xianfeng-D1YwFx9b523JT25yRF3qmw==/oat/arm64/base.odex (okhttp3.RequestBody$Companion.create+208)
#04 pc 000000000036fb94 /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612)
#05 pc 00000000002b6938 /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+216)
#06 pc 00000000002b5834 /apex/com.android.art/lib64/libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+564)
vmInterpret 函数的具体实现暂时没有去看,先搁置。
原理模拟
核心代码
arduino
package penguin.odex_tester;
public class OatTester {
static {
System.loadLibrary("odex_tester");
}
static String[] sTabel = {"penguin", "pikachu"};
public String getName() {
int idx = indexFromJNI();
return sTabel[idx];
}
/**
* A native method that is implemented by the 'odex_tester' native library,
* which is packaged with this application.
*/
public native int indexFromJNI();
}
arduino
#include <jni.h>
#include <string>
static long getIndex() {
return 0xdeaddead00000001UL;
}
extern "C" JNIEXPORT int JNICALL
Java_penguin_odex_1tester_OatTester_indexFromJNI(
JNIEnv* env,
jobject /* this */) {
return getIndex();
}
yaml
core-parser> disas Java_penguin_odex_1tester_OatTester_indexFromJNI
LIB: /data/app/~~mv-OWuc0iigEHQFDpDy-hA==/penguin.odex_tester-GFlURmvc7VSmoYLhLM4oSA==/base.apk!/lib/arm64-v8a/libodex_tester.so
Java_penguin_odex_1tester_OatTester_indexFromJNI: [6f2e66b678, 6f2e66b69c]
0x6f2e66b678: d10083ff | sub sp, sp, #0x20
0x6f2e66b67c: a9017bfd | stp x29, x30, [sp, #0x10]
0x6f2e66b680: 910043fd | add x29, sp, #0x10
0x6f2e66b684: f90007e0 | str x0, [sp, #8]
0x6f2e66b688: f90003e1 | str x1, [sp]
0x6f2e66b68c: 94000004 | bl 0x6f2e66b69c
0x6f2e66b690: a9417bfd | ldp x29, x30, [sp, #0x10]
0x6f2e66b694: 910083ff | add sp, sp, #0x20
0x6f2e66b698: d65f03c0 | ret
对于编译而言,此处是不会将 bl 的返回结果处理成 w0 的,除非有显示 (int) getIndex();,或 int idx = getIndex(); 然后返回 idx 的方式。编译只有在使用到该函数才会被显式处理成 32-bit 寄存器。而 .odex 的编译以及 apk 的 .so 编译都是相互独立的。因此对调用函数者,只会关注返回结果在 x0 寄存器。
测试方法
安装测试程序后,主动让程序生成对应的 oat 代码。
bash
# cmd package compile -f -m speed penguin.odex_tester
less
06-09 16:12:21.333 2451 2451 I opencore: Init opencore-1.4.15 environment..
06-09 16:12:21.340 2451 2451 I opencore: Wait (2518) coredump
06-09 16:12:21.341 2518 2518 I opencore: Coredump /storage/emulated/0/Android/data/penguin.odex_tester/files/core.uin.odex_tester_2451_1749456741 ...
06-09 16:12:22.737 2518 2518 I opencore: Finish done.
yaml
Timestamp: 2025-06-09 16:12:22.786364829+0800
Process uptime: 3s
Cmdline: penguin.odex_tester
pid: 2451, tid: 2451, name: uin.odex_tester >>> penguin.odex_tester <<<
uid: 10298
tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
signal 11 (SIGSEGV), code -6 (SI_TKILL), fault addr --------
x0 deaddead00000001 x1 000000000250261c x2 0000000000000002 x3 0000000000000008
x4 0000007fe9124d28 x5 0000006fb6f0ba37 x6 00000000616b6970 x7 0000006f37bdb0cd
x8 b4b2a9de8d239bba x9 b4b2a9de8d239bba x10 000000005c000000 x11 0000000000000000
x12 0000000000060006 x13 0000000000996250 x14 0000000000796250 x15 000000728118f200
x16 0000000000000000 x17 000000005c000000 x18 00000072825e4000 x19 b400007028a4d380
x20 0000000000000000 x21 b400007028a4d440 x22 0000000002502658 x23 0000000002485918
x24 00000000024e84a8 x25 00000000025019d8 x26 0000000002389e48 x27 0000000000000000
x28 00000000134a64e2 x29 0000000000000000
lr 0000006f38ce2864 sp 0000007fe9124fb0 pc 0000006f38ce2860 pst 0000000080001000
28 total frames
backtrace:
#00 pc 0000000000fba860 /data/app/~~mv-OWuc0iigEHQFDpDy-hA==/penguin.odex_tester-GFlURmvc7VSmoYLhLM4oSA==/oat/arm64/base.odex (penguin.odex_tester.MainActivity.onCreate+1392)
#01 pc 000000000022b1f4 /system/framework/arm64/boot-framework.oat (android.app.Activity.performCreate+1332) (BuildId: de277112a520afe7745652e3098976104c01e2da)
#02 pc 0000000000305c40 /system/framework/arm64/boot-framework.oat (android.app.Instrumentation.callActivityOnCreate+80) (BuildId: de277112a520afe7745652e3098976104c01e2da)
#03 pc 000000000028824c /system/framework/arm64/boot-framework.oat (android.app.ActivityThread.performLaunchActivity+4252) (BuildId: de277112a520afe7745652e3098976104c01e2da)
#04 pc 0000000000290da8 /system/framework/arm64/boot-framework.oat (android.app.ActivityThread.handleLaunchActivity+1672) (BuildId: de277112a520afe7745652e3098976104c01e2da)
#05 pc 00000000006a4920 /apex/com.android.art/lib64/libart.so (nterp_helper+4016) (BuildId: 28bde5aedef57686a890da10d56d9347)
...
css
core-parser> fake stack --pc 0x0000006f38ce2860 --sp 0x0000007fe9124fb0
yaml
core-parser> bt
"main" sysTid=2451 Runnable
| group="main" daemon=0 prio=5 target=0x0 uncaught_exception=0x0
| tid=1 sCount=0 flags=0 obj=0x72a00b18 self=0xb400007028a4d380 env=0xb400007158a54c70
| stack=0x7fe892a000-0x7fe892c000 stackSize=0x7ff000 handle=0x7282841098
| mutexes=0xb400007028a4db20 held="mutator lock"(shared held)
x0 0xdeaddead00000001 x1 0x000000000250261c x2 0x0000000000000002 x3 0x0000000000000008
x4 0x0000007fe9124d28 x5 0x0000006fb6f0ba37 x6 0x00000000616b6970 x7 0x0000006f37bdb0cd
x8 0xb4b2a9de8d239bba x9 0xb4b2a9de8d239bba x10 0x000000005c000000 x11 0x0000000000000000
x12 0x0000000000060006 x13 0x0000000000996250 x14 0x0000000000796250 x15 0x000000728118f200
x16 0x0000000000000000 x17 0x000000005c000000 x18 0x00000072825e4000 x19 0xb400007028a4d380
x20 0x0000000000000000 x21 0xb400007028a4d440 x22 0x0000000002502658 x23 0x0000000002485918
x24 0x00000000024e84a8 x25 0x00000000025019d8 x26 0x0000000002389e48 x27 0x0000000000000000
x28 0x00000000134a64e2 fp 0x0000000000000000
lr 0x0000006f38ce2864 sp 0x0000007fe9124fb0 pc 0x0000006f38ce2860 pst 0x0000000080001000
Native: #0 0000006f38ce2860 /data/app/~~mv-OWuc0iigEHQFDpDy-hA==/penguin.odex_tester-GFlURmvc7VSmoYLhLM4oSA==/oat/arm64/base.odex+0xfba860
Native: #1 0000006f38ce2860 /data/app/~~mv-OWuc0iigEHQFDpDy-hA==/penguin.odex_tester-GFlURmvc7VSmoYLhLM4oSA==/oat/arm64/base.odex+0xfba860
JavaKt: #00 0000006f37943ac4 penguin.odex_tester.MainActivity.onCreate
JavaKt: #01 0000006fb5eaf4ee android.app.Activity.performCreate
JavaKt: #02 0000006fb5f3a49a android.app.Instrumentation.callActivityOnCreate
JavaKt: #03 0000006fb5e9a74a android.app.ActivityThread.performLaunchActivity
JavaKt: #04 0000006fb5e9a144 android.app.ActivityThread.handleLaunchActivity
JavaKt: #05 0000006fb5fea57a android.app.servertransaction.LaunchActivityItem.execute
JavaKt: #06 0000006fb5fec9ae android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem
JavaKt: #07 0000006fb5feca3a android.app.servertransaction.TransactionExecutor.executeTransactionItems
JavaKt: #08 0000006fb5fec802 android.app.servertransaction.TransactionExecutor.execute
JavaKt: #09 0000006fb5e989c6 android.app.ActivityThread$H.handleMessage
JavaKt: #10 0000006fb4d79b22 android.os.Handler.dispatchMessage
JavaKt: #11 0000006fb4da2cca android.os.Looper.loopOnce
JavaKt: #12 0000006fb4da35e8 android.os.Looper.loop
JavaKt: #13 0000006fb5ea68b4 android.app.ActivityThread.main
JavaKt: #14 0000000000000000 java.lang.reflect.Method.invoke
JavaKt: #15 0000006fb3b5064a com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run
JavaKt: #16 0000006fb3b553d8 com.android.internal.os.ZygoteInit.main
yaml
core-parser> f 0
JavaKt: #00 0000006f37943ac4 penguin.odex_tester.MainActivity.onCreate(android.os.Bundle)
{
Location: /data/app/~~mv-OWuc0iigEHQFDpDy-hA==/penguin.odex_tester-GFlURmvc7VSmoYLhLM4oSA==/base.apk
art::ArtMethod: 0x72667cf1b0
dex_pc_ptr: 0x6f37943ac4
quick_frame: 0x7fe9124fb0
frame_pc: 0x6f38ce2860
method_header: 0x6f38ce22ec
DEX CODE:
0x6f37943abc: 106e efbf 0002 | invoke-virtual {v2}, java.lang.String penguin.odex_tester.OatTester.getName() // method@61375
0x6f37943ac2: 020c | move-result-object v2
0x6f37943ac4: 206e 12a9 0021 | invoke-virtual {v1, v2}, void android.widget.TextView.setText(java.lang.CharSequence) // method@4777
OAT CODE:
0x6f38ce283c: 1000007e | adr x30, 0x6f38ce2848
0x6f38ce2840: b502af14 | cbnz x20, 0x6f38ce7e20
0x6f38ce2844: b940eb21 | ldr w1, [x25, #0xe8]
0x6f38ce2848: b9400822 | ldr w2, [x1, #8]
0x6f38ce284c: 6b02001f | cmp w0, w2
0x6f38ce2850: 540008e2 | b.hs 0x6f38ce296c
0x6f38ce2854: 11003021 | add w1, w1, #0xc
0x6f38ce2858: 1000007e | adr x30, 0x6f38ce2864
0x6f38ce285c: b537cc34 | cbnz x20, 0x6f38d521e0
0x6f38ce2860: b8607822 | ldr w2, [x1, x0, lsl #2]
0x6f38ce2864: 1000007e | adr x30, 0x6f38ce2870
0x6f38ce2868: b5fe59d4 | cbnz x20, 0x6f38cdf3a0
}
core-parser>