Closed yunshouhu closed 7 years ago
Android N下面有比较多的坑,所以还只是试验性质
目前通过对比android6.0和android7.0的源码: http://androidxref.com/7.0.0_r1/xref/art/runtime/class_linker.cc#7380 定位到是runtime->class_linker->ResolveMethod->CheckIncompatibleClassChange引起的。 android7.0之后ClassLinker开启了kForceICCECheck 对调用者进行了强检查。
以下是android7.0 runtime的class_linker.cc源码
template
看了下Android 6.0上的ResolveMethod
方法,也是有检查方法的属性的:
http://androidxref.com/6.0.1_r10/xref/art/runtime/class_linker.cc#5409
那么问题应该就是Android N的混合编译造成的。Android N的应用在安装时使用的是解释模式,运行过程中可能还会有有编译的过程。所以在应用运行一段时间后,也会有调用到ResolveMethod
。但是Android N之前就不存在这个问题,因为应用在安装时就已经编译完成,运行后不会再调用ResolveMethod
了。
hook绕过检查感觉确实不太好做,正如所说,是inline的
不过Android N上在应用运行时加载的dex,是编译而非解释的,所以同样的操作放到VirtualHook中应该就不会出现,可以试验下
hook了ThrowIncompatibleClassChangeError方法强制绕过后,后面还是存在调用匹配检查,
从原方法句柄在jit-code-cache中,可以看出如果应用运行时加载的dex,经过dex2oat编译后,应该可以绕过ThrowIncompatibleClassChangeError异常。
http://androidxref.com/7.0.0_r1/xref/art/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc#2063
06-02 09:38:39.414: W/YAHFA(2674): Hook_Toast_show
06-02 09:38:39.415: E/YAHFA(2674): Hook_Toast_show yahfahook origin
06-02 09:38:39.415: I/YAHFA-Native(2674): ThrowIncompatibleClassChangeError expected_type=0,found_type=2 //这里hook了ThrowIncompatibleClassChangeError方法强制绕过后
06-02 09:38:39.415: A/art(2674): art/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc:2063] Check failed: self->IsExceptionPending()
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] Runtime aborting...
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] Aborting thread:
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] "main" prio=5 tid=1 Runnable
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] | group="" sCount=0 dsCount=0 obj=0x73c3f950 self=0xa3c8b400
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] | sysTid=2674 nice=0 cgrp=default sched=0/0 handle=0xa7fbf534
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] | state=R schedstat=( 0 0 0 ) utm=7 stm=28 core=1 HZ=100
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] | stack=0xbf69d000-0xbf69f000 stackSize=8MB
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] | held mutexes= "abort lock" "mutator lock"(shared held)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #00 pc 003cb8de /system/lib/libart.so (???)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #01 pc 00397f6e /system/lib/libart.so (???)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #02 pc 00394f6b /system/lib/libart.so (???)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #03 pc 00380d43 /system/lib/libart.so (???)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #04 pc 003809fa /system/lib/libart.so (???)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #05 pc 0037127b /system/lib/libart.so (???)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #06 pc 00119572 /system/lib/libart.so (_ZN3art10LogMessageD1Ev+1298)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #07 pc 004cc093 /system/lib/libart.so (???)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #08 pc 0010801d /system/lib/libart.so (art_quick_invoke_static_trampoline_with_access_check+77)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] native: #09 pc 000003ac /dev/ashmem/dalvik-jit-code-cache (deleted)
(Java_com_yunshouhu_hookitem_Hook_1Toast_1show_hook_1dvm__Lcom_yunshouhu_dalvik_XC_1MethodHook_00024MethodHookParam_2Landroid_widget_Toast_2+396)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at com.yunshouhu.hookitem.Hook_Toast_show.hook_dvm(Hook_Toast_show.java:65)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at com.yunshouhu.hookitem.Hook_Toast_show.hook(Hook_Toast_show.java:39)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at com.yunshouhu.MainActivity$4.onClick(MainActivity.java:83)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at android.view.View.performClick(View.java:5610)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at android.view.View$PerformClick.run(View.java:22260)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at android.os.Handler.handleCallback(Handler.java:751)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at android.os.Handler.dispatchMessage(Handler.java:95)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at android.os.Looper.loop(Looper.java:154)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at android.app.ActivityThread.main(ActivityThread.java:6077)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at java.lang.reflect.Method.invoke!(Native method)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] Dumping all threads without appropriate locks held: thread list lock
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] All threads:
06-02 09:38:39.434: A/art(2674): art/runtime/runtime.cc:403] All threads:
1、初步测试了通过DexClassLoader动态加载apk/dex的方式去hook后: dex执行了dex2oat流程,不经过jit-code-cache,就没有出现java.lang.IncompatibleClassChangeError异常。 即像博主说的:Android N上在应用运行时加载的dex,是编译而非解释的, 但是多次点击循环执行后,出现了gc的Tried to mark 0xa4d85060 not contained by any spaces异常。 06-03 01:51:52.563: A/art(3245): art/runtime/gc/collector/mark_sweep.cc:413] Tried to mark 0xa4d85060 not contained by any spaces 06-03 01:51:52.563: A/art(3245): art/runtime/utils.cc:184] 12c00000-12e08000 rw-p 00000000 00:04 5615 /dev/ashmem/dalvik-main space (deleted)
2、目前初步估计使用public static void origin(Toast toast) { }方式来保存原方法的句柄在android7.0以上的系统可能会导致: a、声明的调用类型和运行时的调用类型不匹配异常,即强检查了java.lang.IncompatibleClassChangeError。 b、gc的mark_sweep算法无法标记回收,即Tried to mark 0xa4d85060 not contained by any spaces。 也许在android7.0之后使用legend的方法来保存原来的artMethod方法句柄可能兼容性会更好些。
没有试过用legend的方式在android 7.0上做hook,可以试验一下
测试环境: android7.0 armeabi模拟器/android7.1 x86模拟器。 多次执行Toast.show方法后出现如下java.lang.IncompatibleClassChangeError异常,然后程序退出
05-24 04:13:43.362: W/YAHFA(1439): hook end 05-24 04:13:43.366: W/YAHFA(1439): hook 05-24 04:13:43.367: W/YAHFA(1439): hook end 05-24 04:13:43.367: I/Choreographer(1439): Skipped 42 frames! The application may be doing too much work on its main thread. 05-24 04:13:44.462: W/YAHFA(1439): hook 05-24 04:13:44.467: D/AndroidRuntime(1439): Shutting down VM 05-24 04:13:44.472: E/AndroidRuntime(1439): FATAL EXCEPTION: main 05-24 04:13:44.472: E/AndroidRuntime(1439): Process: lab.galaxy.yahfa.demoApp, PID: 1439 05-24 04:13:44.472: E/AndroidRuntime(1439): java.lang.IncompatibleClassChangeError: The method 'void android.widget.Toast.show()' was expected to be of type static but instead was found to be of type virtual (declaration of 'com.yunshouhu.hookitem.Hook_Toast_show' appears in /data/app/lab.galaxy.yahfa.demoApp-1/base.apk) 05-24 04:13:44.472: E/AndroidRuntime(1439): at com.yunshouhu.hookitem.Hook_Toast_show.hook(Hook_Toast_show.java:19) 05-24 04:13:44.472: E/AndroidRuntime(1439): at com.yunshouhu.MainActivity$4.onClick(MainActivity.java:88) 05-24 04:13:44.472: E/AndroidRuntime(1439): at android.view.View.performClick(View.java:5610) 05-24 04:13:44.472: E/AndroidRuntime(1439): at android.view.View$PerformClick.run(View.java:22260) 05-24 04:13:44.472: E/AndroidRuntime(1439): at android.os.Handler.handleCallback(Handler.java:751) 05-24 04:13:44.472: E/AndroidRuntime(1439): at android.os.Handler.dispatchMessage(Handler.java:95) 05-24 04:13:44.472: E/AndroidRuntime(1439): at android.os.Looper.loop(Looper.java:154) 05-24 04:13:44.472: E/AndroidRuntime(1439): at android.app.ActivityThread.main(ActivityThread.java:6077) 05-24 04:13:44.472: E/AndroidRuntime(1439): at java.lang.reflect.Method.invoke(Native Method) 05-24 04:13:44.472: E/AndroidRuntime(1439): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 05-24 04:13:44.472: E/AndroidRuntime(1439): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 05-24 04:13:44.515: W/ActivityManager(378): Force finishing activity lab.galaxy.yahfa.demoApp/com.yunshouhu.MainActivity