首页
论坛
课程
招聘
[原创]尝试着实现了一个 ART Hook
2019-1-27 21:09 11577

[原创]尝试着实现了一个 ART Hook

2019-1-27 21:09
11577

首先要感谢 epic 和 yahfa 这两个开源项目,看完确实有不少收获。

简介

Github: https://github.com/ganyao114/SandHook
CSDN: https://blog.csdn.net/ganyao939543405/article/details/86661040

 

关于 Hook,一直是比较小众的需求。本人公司有在做 Android Sandbox(类似 VA),算是比较依赖 Hook 的产品,好在 Android Framework 大量使用了代理模式。所以也不用费劲在VM层作文章了,直接用动态代理即可。
然而,VM 层的 Java Hook 还是有些需求的,除了测试时候的性能监控,AOP 等之外。大多还是用在了黑灰产,Android Sandbox + ART Hook = 免越狱的 Xposed。
正好拜读了 epic 和 yahfa 的源码,也是有所收获并且尝试着写了这个框架。

SandHook

特点

  • 主要基于 inline hook,条件不允许时进行 ArtMethod 入口替换
  • 接口为注解式,较为友好
  • 支持直接 Hook,也支持在插件场景中的 Hook
  • 本人极少用 C++,所以 native 代码有些 java style,喜欢 java 的同学还是能一眼看懂的(现在 C++ 是好写多了,基本感受不到和 Java 有多大区别)。汇编代码也很好懂。

支持 OS

5.0 - 9.0

支持架构

  • ARM32
  • Thumb-2
  • ARM64

Hook范围

  • 对象方法
  • Static 方法
  • 构造方法
  • JNI 方法
  • 系统方法
  • 抽象方法(非常不可靠)

基本除了抽象方法都能 Hook,抽象方法实在无能为力:大多数情况不走 ArtMethod,即便替换 vtable,依然会遗漏很多实现。

 

最主要的是 ART 很容易确定了接口的实现类就根本不查 vtable,直接调实现方法去了。。。。所以还是老老实实 hook 实现方法吧

使用方法

  • 依赖:

    implementation 'com.swift.sandhook:hooklib:0.0.2'
    
  • 写 Hook 项:

@HookClass(Activity.class)
//@HookReflectClass("android.app.Activity")
public class ActivityHooker {

    // can invoke to call origin
    @HookMethodBackup("onCreate")
    @MethodParams(Bundle.class)
    static Method onCreateBackup;

    @HookMethodBackup("onPause")
    static Method onPauseBackup;

    @HookMethod("onCreate")
    @MethodParams(Bundle.class)
    //@MethodReflectParams("android.os.Bundle")
    public static void onCreate(Activity thiz, Bundle bundle) {
        Log.e("ActivityHooker", "hooked onCreate success " + thiz);
        onCreateBackup(thiz, bundle);
    }

    @HookMethodBackup("onCreate")
    @MethodParams(Bundle.class)
    public static void onCreateBackup(Activity thiz, Bundle bundle) {
        //invoke self to kill inline
        onCreateBackup(thiz, bundle);
    }

    @HookMethod("onPause")
    public static void onPause(Activity thiz) {
        Log.e("ActivityHooker", "hooked onPause success " + thiz);
        onPauseBackup(thiz);
    }

    @HookMethodBackup("onPause")
    public static void onPauseBackup(Activity thiz) {
        //invoke self to kill inline
        onPauseBackup(thiz);
    }

}
  • 添加 Hook 项:
SandHook.addHookClass(JniHooker.class,
                    CtrHook.class,
                    LogHooker.class,
                    CustmizeHooker.class,
                    ActivityHooker.class,
                    ObjectHooker.class);
  • 如果想在插件里配置 Hook 项:
    在插件里 provider 注解:
provided 'com.swift.sandhook:hookannotation:0.0.2'

Hook 项

Hook 项由 Hook 类, Hook 方法,Backup 方法组成,如果不需要掉用原方法则不需要写 Backup 方法。

  • Hook/Backup 方法必须是 static,并且 Hook/Backup 方法描述相同
  • Hook/Backup 方法返回类型,参数列表类型必须与原方法匹配,类型必须可以 Cast,不要求完全一样。
  • 如果原方法是非静态方法,Hook/Backup 方法第一个参数必须是 this

如果 OS <= 5.1 ,backup 方法建议调用自己(或加 try catch),否则会被内联进 hook 方法,导致无法调用原方法。当然你也可以使用 invoke 调用原方法。

实现

基本原理

简单的来说就是 inline hook。
将目标方法的前(arm32-2/arm64-4)行代码拷贝出来,换上跳转代码跳到一个汇编写的二级跳板,二级跳板再确定当前方法需要 Hook 之后,跳转到 Hook 方法。
除此之外,考虑到 N 以上方法有可能是解释执行,手动调用 JIT 有可能编译失败(很少见),也保留了 ArtMethod 入口替换的逻辑(类似 YAHFA)。

 

详细步骤如下:

  • 初始化,得出 ArtMethod 大小,以及内部一些元素的偏移
  • 解析 Hooker 项,得到 origin,hook,backup 三个 Method 对象
  • 检查 Hooker/Backup 方法和原方法签名是否匹配
  • 手动 resolve 静态方法
  • resolve cache dex,保证 Hook 方法能找到 backup 方法
  • 抽象方法只能走 ArtMethod 入口替换
  • 检查是否是未编译,未编译 >= 7.0 尝试编译。
  • < 7.0 或者编译失败走 ArtMethod 入口替换
  • 编译成功进行 inline hook
  • 如果需要备份方法,拷贝原方法 ArtMethod 覆盖 Backup 的 ArtMethod
  • 为跳板分配可执行内存
  • 备份代码到二级跳板
  • native code 入口插入跳转代码
  • 填充二级跳板
  • 如果需要备份,准备 CallOrigin 跳板并且塞到 backup 方法的 ArtMethod

初始化

这一步主要是确定 ArtMethod 的内存布局

  • 首先用两个相邻的 ArtMethod 相减得到 ArtMethod 的大小
  • 而后有些属性可以在 Java 层查到具体数值(accessFlags 等),拿着数值到 ArtMethod 里面搜索的到对应项目的偏移。
  • 实在得不到的只能通过系统版本和指针长度区分。

resolve 静态方法

静态方法是懒加载的,在所在类未被调用前,是未被 resolve 的状态,此时该类的 code entry 只是一个公用的 resolve static stub,我们 inline hook 这个公共入口没有意义。
我们只需要手动 invoke 该方法即可解决,invoke(new Object()),强行塞给他一个 receiver,既达到了 resolve 的目的,也防止方法被成功调用。
hook 方法也是 static 方法,所以也需要 resolve

resolve DexCache

<= 9.0 时,每个 Dex 存在一个 DexCache,主要目的是跳到下一个方法执行之前,如果是下一个方法在本 Dex 内部,可以通过 index 搜索到下一个方法的 ArtMethod。
而 Hook 方法需要调用的 Backup 方法已经被原方法的 ArtMethod 覆盖,所以需要我们手动填充 DexCache 的 resolvedMethods。

 

有两条路可走:

  • 在 <= 6.0 时,Java 层还保留着 ArtMethod 以及 DexCache 的 Java 对象,并且和 Native 层有映射关系,我们直接填充 Java 层的 resolvedMethods 数组即可。
  • 当 > 6.0 时,Java 层 resolvedMethods 只是 Native 层的地址,7.0 后完全移除,就需要我们在 native 层操作。

编译方法

这点参考 epic 调用 libart-compiler.so 中的 jitcompile 方法手动编译该类。

关于寄存器的使用

跳板代码至少需要使用一个寄存器
在 ARM64 中:

// Method register on invoke.
// 储存正在调用的方法
static const vixl::aarch64::Register kArtMethodRegister = vixl::aarch64::x0;

//参数传递
static const vixl::aarch64::Register kParameterCoreRegisters[] = {
  vixl::aarch64::x1,
  vixl::aarch64::x2,
  vixl::aarch64::x3,
  vixl::aarch64::x4,
  vixl::aarch64::x5,
  vixl::aarch64::x6,
  vixl::aarch64::x7
};

//
const vixl::aarch64::CPURegList vixl_reserved_core_registers(vixl::aarch64::ip0,
                                                             vixl::aarch64::ip1);

//浮点参数
static const vixl::aarch64::FPRegister kParameterFPRegisters[] = {
  vixl::aarch64::d0,
  vixl::aarch64::d1,
  vixl::aarch64::d2,
  vixl::aarch64::d3,
  vixl::aarch64::d4,
  vixl::aarch64::d5,
  vixl::aarch64::d6,
  vixl::aarch64::d7
};

// Thread Register.
// 线程
const vixl::aarch64::Register tr = vixl::aarch64::x19;

// Marking Register.
// GC 标记
const vixl::aarch64::Register mr = vixl::aarch64::x20;

// Callee-save registers AAPCS64, without x19 (Thread Register) (nor
// x20 (Marking Register) when emitting Baker read barriers).
const vixl::aarch64::CPURegList callee_saved_core_registers(
    vixl::aarch64::CPURegister::kRegister,
    vixl::aarch64::kXRegSize,
    ((kEmitCompilerReadBarrier && kUseBakerReadBarrier)
         ? vixl::aarch64::x21.GetCode()
         : vixl::aarch64::x20.GetCode()),
     vixl::aarch64::x30.GetCode());

X22 - X28 被 ART 内部用作 Callee Saved

 

看上去只有被定义为 IP0/IP1 的 X16/X17 可以用,但是 X16 在跳板中被使用。
最后我选择了 X17。

 

至于 ARM32 则没得选,只有一个 IP(R12)。

开始内联

 

结构如上图所属:

  • 首先我们需要一块可以执行的内存,mmap 可以解决。
  • 然后原方法的 code entry 是不能写的,memunportect 可以解决
  • 当 >= 7.0 时,JIT 可能会和我们同时修改原方法,在 accessFlags 中:
/ Set by the verifier for a method we do not want the compiler to compile.
static constexpr uint32_t kAccCompileDontBother =     0x02000000;  // method (runtime)

jit 就会忽略该方法

Thumb-2

Thumb 指令必须所在内存必须满足:

bool isThumbCode(Size codeAddr) {
            return (codeAddr & 0x1) == 0x1;
        }

所以 Code Entry 和跳板跳转的地址都必须加以处理

关于 Code Entry 可能重复的问题

除了一些公共的 Stub 之外,epic 作者的文章中提到如果逻辑类似的两个方法也有可能入口相同。这部分我实验没有发现过。
不过为了防止这种情况的发生,还是和 epic 一样做了判断处理,在 Hook 多个相同入口的时候,跳板形成了“责任链模式”。

最后上一下部分代码

跳板

#if defined(__aarch64__)

#define Reg0 x17
#define Reg1 x16
#define RegMethod x0

FUNCTION_START(REPLACEMENT_HOOK_TRAMPOLINE)
    ldr RegMethod, addr_art_method
    ldr Reg0, addr_code_entry
    ldr Reg0, [Reg0]
    br Reg0
addr_art_method:
    .long 0
    .long 0
addr_code_entry:
    .long 0
    .long 0
FUNCTION_END(REPLACEMENT_HOOK_TRAMPOLINE)

#define SIZE_JUMP #0x10
FUNCTION_START(DIRECT_JUMP_TRAMPOLINE)
    ldr Reg0, addr_target
    br Reg0
addr_target:
    .long 0
    .long 0
FUNCTION_END(DIRECT_JUMP_TRAMPOLINE)

FUNCTION_START(INLINE_HOOK_TRAMPOLINE)
    ldr Reg0, origin_art_method
    cmp RegMethod, Reg0
    bne origin_code
    ldr RegMethod, hook_art_method
    ldr Reg0, addr_hook_code_entry
    ldr Reg0, [Reg0]
    br Reg0
origin_code:
    .long 0
    .long 0
    .long 0
    .long 0
    ldr Reg0, addr_origin_code_entry
    ldr Reg0, [Reg0]
    add Reg0, Reg0, SIZE_JUMP
    br Reg0
origin_art_method:
    .long 0
    .long 0
addr_origin_code_entry:
    .long 0
    .long 0
hook_art_method:
    .long 0
    .long 0
addr_hook_code_entry:
    .long 0
    .long 0
FUNCTION_END(INLINE_HOOK_TRAMPOLINE)

FUNCTION_START(CALL_ORIGIN_TRAMPOLINE)
    ldr RegMethod, call_origin_art_method
    ldr Reg0, addr_call_origin_code
    br Reg0
call_origin_art_method:
    .long 0
    .long 0
addr_call_origin_code:
    .long 0
    .long 0
FUNCTION_END(CALL_ORIGIN_TRAMPOLINE)

#endif

跳板安装

HookTrampoline* TrampolineManager::installReplacementTrampoline(mirror::ArtMethod *originMethod,
                                                                    mirror::ArtMethod *hookMethod,
                                                                    mirror::ArtMethod *backupMethod) {
        AutoLock autoLock(installLock);

        if (trampolines.count(originMethod) != 0)
            return getHookTrampoline(originMethod);
        HookTrampoline* hookTrampoline = new HookTrampoline();
        ReplacementHookTrampoline* replacementHookTrampoline = nullptr;
        Code replacementHookTrampolineSpace;

        replacementHookTrampoline = new ReplacementHookTrampoline();
        replacementHookTrampoline->init();
        replacementHookTrampolineSpace = allocExecuteSpace(replacementHookTrampoline->getCodeLen());
        if (replacementHookTrampolineSpace == 0)
            goto label_error;
        replacementHookTrampoline->setExecuteSpace(replacementHookTrampolineSpace);
        replacementHookTrampoline->setEntryCodeOffset(quickCompileOffset);
        replacementHookTrampoline->setHookMethod(reinterpret_cast<Code>(hookMethod));
        hookTrampoline->replacement = replacementHookTrampoline;

        trampolines[originMethod] = hookTrampoline;
        return hookTrampoline;

    label_error:
        delete hookTrampoline;
        delete replacementHookTrampoline;
        return nullptr;
    }

    HookTrampoline* TrampolineManager::installInlineTrampoline(mirror::ArtMethod *originMethod,
                                                               mirror::ArtMethod *hookMethod,
                                                               mirror::ArtMethod *backupMethod) {

        AutoLock autoLock(installLock);

        if (trampolines.count(originMethod) != 0)
            return getHookTrampoline(originMethod);
        HookTrampoline* hookTrampoline = new HookTrampoline();
        InlineHookTrampoline* inlineHookTrampoline = nullptr;
        DirectJumpTrampoline* directJumpTrampoline = nullptr;
        CallOriginTrampoline* callOriginTrampoline = nullptr;
        Code inlineHookTrampolineSpace;
        Code callOriginTrampolineSpace;
        Code originEntry;

        //生成二段跳板
        inlineHookTrampoline = new InlineHookTrampoline();
        checkThumbCode(inlineHookTrampoline, getEntryCode(originMethod));
        inlineHookTrampoline->init();
        inlineHookTrampolineSpace = allocExecuteSpace(inlineHookTrampoline->getCodeLen());
        if (inlineHookTrampolineSpace == 0)
            goto label_error;
        inlineHookTrampoline->setExecuteSpace(inlineHookTrampolineSpace);
        inlineHookTrampoline->setEntryCodeOffset(quickCompileOffset);
        inlineHookTrampoline->setOriginMethod(reinterpret_cast<Code>(originMethod));
        inlineHookTrampoline->setHookMethod(reinterpret_cast<Code>(hookMethod));
        if (inlineHookTrampoline->isThumbCode()) {
            inlineHookTrampoline->setOriginCode(inlineHookTrampoline->getThumbCodeAddress(getEntryCode(originMethod)));
        } else {
            inlineHookTrampoline->setOriginCode(getEntryCode(originMethod));
        }
        hookTrampoline->inlineSecondory = inlineHookTrampoline;

        //注入 EntryCode
        directJumpTrampoline = new DirectJumpTrampoline();
        checkThumbCode(directJumpTrampoline, getEntryCode(originMethod));
        directJumpTrampoline->init();
        originEntry = getEntryCode(originMethod);
        if (!memUnprotect(reinterpret_cast<Size>(originEntry), directJumpTrampoline->getCodeLen())) {
            goto label_error;
        }

        if (directJumpTrampoline->isThumbCode()) {
            originEntry = directJumpTrampoline->getThumbCodeAddress(originEntry);
        }

        directJumpTrampoline->setExecuteSpace(originEntry);
        directJumpTrampoline->setJumpTarget(inlineHookTrampoline->getCode());
        hookTrampoline->inlineJump = directJumpTrampoline;

        //备份原始方法
        if (backupMethod != nullptr) {
            callOriginTrampoline = new CallOriginTrampoline();
            checkThumbCode(callOriginTrampoline, getEntryCode(originMethod));
            callOriginTrampoline->init();
            callOriginTrampolineSpace = allocExecuteSpace(callOriginTrampoline->getCodeLen());
            if (callOriginTrampolineSpace == 0)
                goto label_error;
            callOriginTrampoline->setExecuteSpace(callOriginTrampolineSpace);
            callOriginTrampoline->setOriginMethod(reinterpret_cast<Code>(originMethod));
            Code originCode = nullptr;
            if (callOriginTrampoline->isThumbCode()) {
                originCode = callOriginTrampoline->getThumbCodePcAddress(inlineHookTrampoline->getCallOriginCode());
                #if defined(__arm__)
                Code originRemCode = callOriginTrampoline->getThumbCodePcAddress(originEntry + directJumpTrampoline->getCodeLen());
                Size offset = originRemCode - getEntryCode(originMethod);
                if (offset != directJumpTrampoline->getCodeLen()) {
                    Code32Bit offset32;
                    offset32.code = offset;
                    unsigned char offsetOP = callOriginTrampoline->isBigEnd() ? offset32.op.op2 : offset32.op.op1;
                    callOriginTrampoline->tweakOpImm(OFFSET_INLINE_OP_ORIGIN_OFFSET_CODE, offsetOP);
                }
                #endif
            } else {
                originCode = inlineHookTrampoline->getCallOriginCode();
            }
            callOriginTrampoline->setOriginCode(originCode);
            hookTrampoline->callOrigin = callOriginTrampoline;
        }

        trampolines[originMethod] = hookTrampoline;
        return hookTrampoline;

    label_error:
        delete hookTrampoline;
        if (inlineHookTrampoline != nullptr) {
            delete inlineHookTrampoline;
        }
        if (directJumpTrampoline != nullptr) {
            delete directJumpTrampoline;
        }
        if (callOriginTrampoline != nullptr) {
            delete callOriginTrampoline;
        }
        return nullptr;
    }

内存分配

Code TrampolineManager::allocExecuteSpace(Size size) {
        if (size > MMAP_PAGE_SIZE)
            return 0;
        AutoLock autoLock(allocSpaceLock);
        void* mmapRes;
        Code exeSpace = 0;
        if (executeSpaceList.size() == 0) {
            goto label_alloc_new_space;
        } else if (executePageOffset + size > MMAP_PAGE_SIZE) {
            goto label_alloc_new_space;
        } else {
            exeSpace = executeSpaceList.back();
            Code retSpace = exeSpace + executePageOffset;
            executePageOffset += size;
            return retSpace;
        }
    label_alloc_new_space:
        mmapRes = mmap(NULL, MMAP_PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
                             MAP_ANON | MAP_PRIVATE, -1, 0);
        if (mmapRes == MAP_FAILED) {
            return 0;
        }
        exeSpace = static_cast<Code>(mmapRes);
        executeSpaceList.push_back(exeSpace);
        executePageOffset = size;
        return exeSpace;
    }

[注意] 欢迎加入看雪团队!base上海,招聘安全工程师、逆向工程师多个坑位等你投递!

收藏
点赞5
打赏
分享
打赏 + 28.00
打赏次数 4 金额 + 28.00
 
赞赏  menglinxi   +20.00 2019/02/12 希望能多适配机型,能多开,能hook,感谢
赞赏  kanxue   +1.00 2019/02/01 精品文章~
赞赏  CCkicker   +2.00 2019/01/30
赞赏  junkboy   +5.00 2019/01/27
最新回复 (21)
雪    币: 10943
活跃值: 活跃值 (83)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
junkboy 活跃值 2019-1-27 21:25
2
0
支持
雪    币: 1380
活跃值: 活跃值 (243)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
坑大 活跃值 2 2019-1-27 22:00
3
1
补充.... 如果目标方法被 inline 到了某个方法中,那也没办法 hook。
雪    币: 15496
活跃值: 活跃值 (20926)
能力值: (RANK:75 )
在线值:
发帖
回帖
粉丝
Editor 活跃值 2019-1-28 09:14
4
0
感谢分享!
雪    币: 2048
活跃值: 活跃值 (940)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Vn小帆 活跃值 2019-1-28 14:53
5
0
这个  能hook   其他进程么   还是只能hook 本进程
雪    币: 1380
活跃值: 活跃值 (243)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
坑大 活跃值 2 2019-1-28 15:05
6
0
Vn小帆 这个 能hook 其他进程么 还是只能hook 本进程
理论上是 Hook 本进程,其他进程你需要自己将 hooklib 注进去,或者可以结合 VA 这种 Sandbox 框架实现。
雪    币: 36
活跃值: 活跃值 (313)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
芃杉 活跃值 2019-1-28 15:17
7
0
mark,支持
雪    币: 402
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
DWwinter 活跃值 2019-1-29 11:27
8
0
mark,
雪    币: 1342
活跃值: 活跃值 (330)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
开花的水管 活跃值 2019-1-29 17:26
9
0
mark
雪    币: 1589
活跃值: 活跃值 (699)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
pxhb 活跃值 2 2019-1-29 19:34
10
0
感谢分享
雪    币: 223
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
泪落晨曦 活跃值 2019-1-30 17:25
11
0
mark一个
雪    币: 2248
活跃值: 活跃值 (25)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
图灵技师 活跃值 1 2019-1-31 15:54
12
0
这个调用原方法稳定吗,我在yahfa尝试使用jit编译原方法,但是通过backup跳转原方法不稳定,写的demo没问题,但是用到项目上就不行,有些莫名其妙的问题,不是不执行原方法就是执行原方法crash
雪    币: 1380
活跃值: 活跃值 (243)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
坑大 活跃值 2 2019-1-31 19:29
13
1
图灵技师 这个调用原方法稳定吗,我在yahfa尝试使用jit编译原方法,但是通过backup跳转原方法不稳定,写的demo没问题,但是用到项目上就不行,有些莫名其妙的问题,不是不执行原方法就是执行原方法cras ...
yahfa 执行原方法之前没有把 x0 设置程原 artmethod。是可能出问题的,这个我处理了
雪    币: 15496
活跃值: 活跃值 (20926)
能力值: (RANK:75 )
在线值:
发帖
回帖
粉丝
Editor 活跃值 2019-2-1 10:24
14
0
赞!诚邀楼主来创建您的看雪专栏(https://zhuanlan.kanxue.com/
雪    币: 2248
活跃值: 活跃值 (25)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
图灵技师 活跃值 1 2019-2-1 11:09
15
0
ro寄存器这个我也处理了,自己写的demo里验证都是没有问题的,但是实际用在项目上就不稳定,代码执行到jit-code-cache里就出问题,或者根本不执行。然而AOT编译的就没问题,不hook,原方法执行也没问题。想请教一下楼主这种问题怎么分析处理,我对编译的东西不怎么了解,jit-code-cache里的东西也看不到
雪    币: 1380
活跃值: 活跃值 (243)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
坑大 活跃值 2 2019-2-1 12:32
16
0
图灵技师 ro寄存器这个我也处理了,自己写的demo里验证都是没有问题的,但是实际用在项目上就不稳定,代码执行到jit-code-cache里就出问题,或者根本不执行。然而AOT编译的就没问题,不hook,原方 ...
这个我还没遇到过,可能是我测的 case 比较少,你可以试试我的方案能不能复现。原方法没执行可能是 backup 方法被内联了
雪    币: 417
活跃值: 活跃值 (6509)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2019-2-1 17:49
17
0
雪    币: 28
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
魏晋之风 活跃值 2019-2-18 14:40
18
0
大大,请问下,你是否出现过当应用运行在后台一小段时间后,返回应用,再次调用含有反射调用原方法的hook方法时导致崩溃的现象。
    --------- beginning of crash
2019-02-18 14:22:56.663 2937-2937/   A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10 in tid 2937 , pid 2937 (curity.demohook)
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG: Build fingerprint: 
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG: Revision: 'MP1.0'
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG: ABI: 'arm64'
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG: Cause: null pointer dereference
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG:     x0  0000000000000000  x1  0000007fe5025000  x2  0000000000000010  x3  656d003c7373616c
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG:     x4  000000782844fcbd  x5  0000007fe5025071  x6  6e616c2e6176616a  x7  3c7373616c432e67
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG:     x8  0000000000000000  x9  0000000000000000  x10 0000000000000000  x11 0000000000000010
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG:     x12 6c616974696e496e  x13 203a7373616c4320  x14 0000007fe5024794  x15 0000007fe502432c
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG:     x16 00000078a93ba838  x17 00000078a9161b30  x18 0000007fe502432a  x19 0000007fe5025000
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG:     x20 000000001492aaa8  x21 00000078ae0545e0  x22 0000000000000001  x23 0000000000000001
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG:     x24 00000078ae0545f0  x25 00000078287fdc00  x26 00000078ae0545e0  x27 0000007fe5025060
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG:     x28 0000007fe5025080  x29 0000007fe5024fd0
2019-02-18 14:22:56.700 2980-2980/? A/DEBUG:     sp  0000007fe5024f90  lr  0000007828267d0c  pc  0000007828268308
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG: backtrace:
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #00 pc 000000000038f308  /system/lib64/libart.so (art::mirror::Class::GetDescriptor(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)+160)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #01 pc 000000000038ed08  /system/lib64/libart.so (art::mirror::Class::PrettyClass()+80)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #02 pc 0000000000111348  /system/lib64/libart.so (art::ClassLinker::EnsureInitialized(art::Thread*, art::Handle<art::mirror::Class>, bool, bool)+724)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #03 pc 0000000000451608  /system/lib64/libart.so (art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned long)+2544)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #04 pc 00000000003e278c  /system/lib64/libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+52)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #05 pc 000000000011d6d4  /system/framework/arm64/boot.oat (offset 0x113000) (java.lang.Class.getDeclaredMethodInternal [DEDUPED]+180)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #06 pc 0000000000545d88  /system/lib64/libart.so (art_quick_invoke_stub+584)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #07 pc 00000000000cf698  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #08 pc 000000000027aba8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #09 pc 0000000000274be8  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+948)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #10 pc 0000000000515a20  /system/lib64/libart.so (MterpInvokeVirtual+588)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #11 pc 0000000000538314  /system/lib64/libart.so (ExecuteMterpImpl+14228)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #12 pc 0000000000010440  /data/app/akira.me.security.demohook-qd0Lxs7ej66x3B5_ZIPOew==/oat/arm64/base.vdex (akira.me.security.demohook.hook.InstanceAddHook.addHook+52)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #13 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #14 pc 00000000005066dc  /system/lib64/libart.so (artQuickToInterpreterBridge+1032)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #15 pc 000000000054eefc  /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #16 pc 0000000000545d88  /system/lib64/libart.so (art_quick_invoke_stub+584)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #17 pc 00000000000cf698  /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #18 pc 000000000027aba8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #19 pc 0000000000274be8  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+948)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #20 pc 0000000000515a20  /system/lib64/libart.so (MterpInvokeVirtual+588)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #21 pc 0000000000538314  /system/lib64/libart.so (ExecuteMterpImpl+14228)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #22 pc 000000000000f30a  /data/app/akira.me.security.demohook-qd0Lxs7ej66x3B5_ZIPOew==/oat/arm64/base.vdex (akira.me.security.demohook.MainActivity$2.onClick+18)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #23 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #24 pc 00000000002542c8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #25 pc 0000000000274bcc  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #26 pc 0000000000516990  /system/lib64/libart.so (MterpInvokeInterface+1392)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #27 pc 0000000000538514  /system/lib64/libart.so (ExecuteMterpImpl+14740)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #28 pc 0000000000b83b2a  /system/framework/boot-framework.vdex (android.view.View.performClick+34)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #29 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #30 pc 00000000002542c8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #31 pc 0000000000274bcc  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #32 pc 0000000000518a4c  /system/lib64/libart.so (MterpInvokeVirtualQuick+584)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #33 pc 000000000053c094  /system/lib64/libart.so (ExecuteMterpImpl+29972)
2019-02-18 14:22:56.787 2980-2980/? A/DEBUG:     #34 pc 0000000000d27fd6  /system/framework/boot-framework.vdex (android.view.View.performClickInternal+6)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #35 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #36 pc 00000000002542c8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #37 pc 0000000000274bcc  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #38 pc 0000000000516d54  /system/lib64/libart.so (MterpInvokeDirect+296)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #39 pc 0000000000538414  /system/lib64/libart.so (ExecuteMterpImpl+14484)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #40 pc 0000000000d26f96  /system/framework/boot-framework.vdex (android.view.View.access$3100)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #41 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #42 pc 00000000002542c8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #43 pc 0000000000274bcc  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #44 pc 0000000000516f18  /system/lib64/libart.so (MterpInvokeStatic+204)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #45 pc 0000000000538494  /system/lib64/libart.so (ExecuteMterpImpl+14612)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #46 pc 0000000000b72922  /system/framework/boot-framework.vdex (android.view.View$PerformClick.run+4)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #47 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #48 pc 00000000002542c8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #49 pc 0000000000274bcc  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #50 pc 0000000000516990  /system/lib64/libart.so (MterpInvokeInterface+1392)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #51 pc 0000000000538514  /system/lib64/libart.so (ExecuteMterpImpl+14740)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #52 pc 0000000000c47cf2  /system/framework/boot-framework.vdex (android.os.Handler.handleCallback+4)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #53 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #54 pc 00000000002542c8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #55 pc 0000000000274bcc  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #56 pc 0000000000516f18  /system/lib64/libart.so (MterpInvokeStatic+204)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #57 pc 0000000000538494  /system/lib64/libart.so (ExecuteMterpImpl+14612)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #58 pc 0000000000ae5500  /system/framework/boot-framework.vdex (android.os.Handler.dispatchMessage+8)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #59 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #60 pc 00000000002542c8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #61 pc 0000000000274bcc  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #62 pc 0000000000515a20  /system/lib64/libart.so (MterpInvokeVirtual+588)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #63 pc 0000000000538314  /system/lib64/libart.so (ExecuteMterpImpl+14228)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #64 pc 0000000000aec610  /system/framework/boot-framework.vdex (android.os.Looper.loop+404)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #65 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #66 pc 00000000002542c8  /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #67 pc 0000000000274bcc  /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+920)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #68 pc 0000000000516f18  /system/lib64/libart.so (MterpInvokeStatic+204)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #69 pc 0000000000538494  /system/lib64/libart.so (ExecuteMterpImpl+14612)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #70 pc 00000000003856a2  /system/framework/boot-framework.vdex (android.app.ActivityThread.main+214)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #71 pc 000000000024eb68  /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3830762457+488)
2019-02-18 14:22:56.788 2980-2980/? A/DEBUG:     #72 pc 00000000005066dc  /system/lib64/libart.so (artQuickToInterpreterBridge+1032)
雪    币: 1380
活跃值: 活跃值 (243)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
坑大 活跃值 2 2019-2-18 18:51
19
0
你看一下我的新代码,反射用 SandHook.callOriginMethod,应该是因为 moving gc 移动了 declaringClass
雪    币: 1380
活跃值: 活跃值 (243)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
坑大 活跃值 2 2019-2-18 19:05
20
0
看楼下
雪    币: 1380
活跃值: 活跃值 (243)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
坑大 活跃值 2 2019-2-19 16:03
21
0
魏晋之风 大大,请问下,你是否出现过当应用运行在后台一小段时间后,返回应用,再次调用含有反射调用原方法的hook方法时导致崩溃的现象。 --------- beginning of crash 20 ...
用反射调原方法现在还有点问题,暂时不要用吧
雪    币: 28
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
魏晋之风 活跃值 2019-2-19 20:20
22
0
坑大 用反射调原方法现在还有点问题,暂时不要用吧
感谢坑大,我现在也是自己构造一个静态空方法来调用原方法,不走反射那条路,目前测试一段时间好像没出现这种问题了。
游客
登录 | 注册 方可回帖
返回