某加固软件 odex 方式运行必现闪退

前言

挺长时间未更新掘金了,一方面内部的一些案例不方便进行脱敏,另方面近期处理的事都是三方软件故障居多,都在逆向研究别家的 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.solibnmmvm.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>
相关推荐
aningxiaoxixi3 分钟前
android 之 CALL
android
用户2018792831671 小时前
Android 核心大管家 ActivityManagerService (AMS)
android
春马与夏2 小时前
Android自动化AirScript
android·运维·自动化
键盘歌唱家3 小时前
mysql索引失效
android·数据库·mysql
webbin4 小时前
Compose @Immutable注解
android·android jetpack
无知的前端5 小时前
Flutter开发,GetX框架路由相关详细示例
android·flutter·ios
玲小珑5 小时前
Auto.js 入门指南(十二)网络请求与数据交互
android·前端
webbin5 小时前
Compose 副作用
android·android jetpack
whysqwhw5 小时前
Dokka 插件系统与 Android 文档生成技术全解
android
橙子199110166 小时前
ActionBar 和 Toolbar
android