一次Art Hook失败问题的跟进

0x00 缘起

最近在使用一款Art Hook框架对应用进行Hook的时候发现,函数Hook之后却总是没有被触发,于是怀疑是被dex2oat做了Inline处理。

以下环境以Android 5.0 x86 为例。

0x01 迷途

使用oatdump --oat-file=oat_path命令进行dump,却发现几乎所有的函数都无法看到汇编代码:

  1. OatMethodOffsets (offset=0x00000000)
  2. code_offset: 0x00000000
  3. gc_map: (offset=0x00000000)
  4. OatQuickMethodHeader (offset=0x00000000)
  5. mapping_table: (offset=0x00000000)
  6. vmap_table: (offset=0x00000000)
  7. QuickMethodFrameInfo
  8. frame_size_in_bytes: 0
  9. core_spill_mask: 0x00000000
  10. fp_spill_mask: 0x00000000
  11. CODE: (code_offset=0x00000000 size_offset=0x00000000 size=0)
  12. NO CODE!
COPY

看起来像是没有进行oat,但是dump的文件却真真实实是一个oat文件啊。不是说Android 5.0都是进行oat编译的吗,总不会是oatdump有问题吧!

0x02 明心

于是,又重新安装了一次,抓logcat看了以下,发现以下日志很可疑:

  1. I/PackageManager( 1546): Running dexopt on: /data/app/com.autonavi.minimap-1/base.apk pkg=com.autonavi.minimap isa=x86 vmSafeMode=true
  2. I/dex2oat ( 3779): /system/bin/dex2oat --zip-fd=5 --zip-location=/data/app/com.autonavi.minimap-1/base.apk --oat-fd=6 --oat-location=/data/dalvik-cache/x86/data@app@com.autonavi.minimap-1@base.apk@classes.dex --instruction-set=x86 --instruction-set-features=default --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=interpret-only
COPY

看起来是interpret-only导致使用了解释方式编译。虽然不确定是不是因为interpret导致Hook不生效,但是看不到汇编代码,心里总是没有底。

所以,现在就要将编译模式改成非解释方式。

/frameworks/native/cmds/installd/commands.c文件的run_dex2oat函数中找到了如下代码:

  1. if (skip_compilation) {
  2. strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-none");
  3. have_dex2oat_compiler_filter_flag = true;
  4. } else if (vm_safe_mode) {
  5. strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
  6. have_dex2oat_compiler_filter_flag = true;
  7. } else if (have_dex2oat_compiler_filter_flag) {
  8. sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", dex2oat_compiler_filter_flag);
COPY

看来就是这个vm_safe_mode导致使用了interpret-only模式,而上面logcat日志显示:vm_safe_mode的值是true

顺便提一句,当vm_safe_modefalse时,系统会使用dex2oat_compiler_filter_flag的值作为编译类型。

  1. char dex2oat_compiler_filter_flag[PROPERTY_VALUE_MAX];
  2. bool have_dex2oat_compiler_filter_flag = property_get("dalvik.vm.dex2oat-filter", dex2oat_compiler_filter_flag, NULL) > 0;
COPY

从上面的代码可以看出,dex2oat_compiler_filter_flag的值是取自dalvik.vm.dex2oat-filter这个系统属性。

可选的值有:verify-none | interpret-only | space | balanced | speed | everything 。而系统默认是没有设置这个属性的,如果我们想设置默认的编译类型,可以修改/system/build.prop文件,添加dalvik.vm.dex2oat-filter=interpret-only,保存文件并重启手机,但是这步操作需要root权限。

系统默认使用的编译类型设置如下:

  1. UsageError(" --compiler-filter=(verify-none|interpret-only|space|balanced|speed|everything):");
  2. UsageError(" select compiler filter.");
  3. UsageError(" Example: --compiler-filter=everything");
  4. #if ART_SMALL_MODE
  5. UsageError(" Default: interpret-only");
  6. #else
  7. UsageError(" Default: speed");
  8. #endif
COPY

因此, 在应用没有设置vm_safe_mode,并且系统没有设置dalvik.vm.dex2oat-filter属性时,就会使用speed模式。

0x03 见性

下面来看vm_safe_mode是怎么设置的。

/frameworks/native/cmds/installd/commands.c

  1. int dexopt(const char *apk_path, uid_t uid, bool is_public,
  2. const char *pkgname, const char *instruction_set,
  3. bool vm_safe_mode, bool is_patchoat){
  4. // ......
  5. run_dex2oat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set, vm_safe_mode);
  6. // ......
  7. }
COPY

一路向上,找到/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java中的performDexOptLI函数,里面包含如下代码:

  1. final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
  2. Log.i(TAG, "Running dexopt on: " + path + " pkg="
  3. + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
  4. + " vmSafeMode=" + vmSafeMode);
  5. final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
  6. pkg.packageName, dexCodeInstructionSet, vmSafeMode);
COPY

可以看出,vmSafeMode是从应用信息里读出来的,最终在反编译出来的AndroidManifest.xml里,我们找到了以下配置:

  1. <application android:allowBackup="false" android:hardwareAccelerated="true" android:icon="@0x7f0213b0" android:label="@0x7f090000" android:largeHeap="true" android:name="com.autonavi.minimap.MapApplication" android:resizeableActivity="false" android:roundIcon="@0x7f0213b0" android:supportsRtl="true" android:theme="@0x7f0b0065" android:vmSafeMode="true">
COPY

0x04 缘灭

解决方法就是,将android:vmSafeMode字段设为false,重打包应用,然后安装。

  1. I/PackageManager( 1546): Running dexopt on: /data/app/com.autonavi.minimap-1/base.apk pkg=com.autonavi.minimap isa=x86 vmSafeMode=false
COPY

vmSafeMode已经被成功修改成false了。

使用oatduump命令查看oat信息:

  1. OatMethodOffsets (offset=0x0282dfa0)
  2. code_offset: 0x0520ff08
  3. gc_map: (offset=0x02c554ba)
  4. OatQuickMethodHeader (offset=0x0520fef0)
  5. mapping_table: (offset=0x03202b8b)
  6. vmap_table: (offset=0x034095d5)
  7. v65534/r5, v2/r6, v0/r7, v65535/r16
  8. QuickMethodFrameInfo
  9. frame_size_in_bytes: 48
  10. core_spill_mask: 0x000100e0 (r5, r6, r7, r16)
  11. fp_spill_mask: 0x00000000
  12. CODE: (code_offset=0x0520ff08 size_offset=0x0520ff04 size=192)...
  13. 0x0520ff08: 85842400E0FFFF test eax, [esp + -8192]
  14. suspend point dex PC: 0x0000
  15. GC map objects: v2 (r6)
  16. 0x0520ff0f: 83EC2C sub esp, 44
  17. 0x0520ff12: 896C2420 mov [esp + 32], ebp
  18. 0x0520ff16: 89742424 mov [esp + 36], esi
  19. 0x0520ff1a: 897C2428 mov [esp + 40], edi
  20. 0x0520ff1e: 8BE8 mov ebp, eax
  21. 0x0520ff20: 890424 mov [esp], eax
  22. 0x0520ff23: 8BF1 mov esi, ecx
  23. 0x0520ff25: 8B4514 mov eax, [ebp + 20]
  24. 0x0520ff28: 8B80D4AC0100 mov eax, [eax + 109780]
  25. 0x0520ff2e: 85C0 test eax, eax
  26. 0x0520ff30: 746A jz/eq +106 (0x0520ff9c)
  27. 0x0520ff32: 8BF8 mov edi, eax
  28. 0x0520ff34: 8B4514 mov eax, [ebp + 20]
  29. 0x0520ff37: 8B805C7C0000 mov eax, [eax + 31836]
COPY

汇编指令也可以正常显示了。

经过测试,Hook也被正常调用了。所以,应该是该Hook框架还不支持解释模式编译的应用。

分享

Related Issues not found

Please contact @drunkdream to initialize the comment