Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

一件非常奇怪的事情,调用原方法异常 #83

Closed
ohroy opened this issue Oct 27, 2018 · 12 comments
Closed

一件非常奇怪的事情,调用原方法异常 #83

ohroy opened this issue Oct 27, 2018 · 12 comments

Comments

@ohroy
Copy link

ohroy commented Oct 27, 2018

10-27 19:15:16.895 7612-7612/lab.galaxy.yahfa.demoApp W/YAHFA: in Log.e(): origin, call Log.e()
      Has mic: 
    in String.startsWith(): foo, f
    CertStatus: 
10-27 19:15:16.896 7612-7612/lab.galaxy.yahfa.demoApp W/origin: foo startsWith f is false

显然,

  • 这里第一个hook没有调用原来的方法去Log.e
  • 第二处竟然返回了false

环境是N,我猜测原因可能是:

  1. 源码中只对hook调用了NewGlobalRef而backup没有,会不会backup被回收了呢?不过按道理来讲,如果他被回收应该崩溃才对,但实际上没有崩溃。
  2. 是不是直接替换掉cache和结构体不太行?

有些晕。。。

@ohroy
Copy link
Author

ohroy commented Oct 27, 2018

update:已验证非NewGlobalRef的原因

@ohroy
Copy link
Author

ohroy commented Oct 27, 2018

奇怪的很,出问题的手机是miui9基于android7.0开发的,我给刷成cm(基于7.1)后能正常工作了.
也不知道是小米miui系统的原因还是巧合.

@ohroy
Copy link
Author

ohroy commented Oct 29, 2018

看来作者实在是忙,我就把解决问题的过程记录在这里吧,要是我能解决,算是造福后人,如果解决不了,权当抛砖引玉

@ohroy
Copy link
Author

ohroy commented Oct 29, 2018

为了能够直观跟踪到代码的具体执行逻辑,我选择使用ida来进行动态调试,结果,令人震惊的事情发生了。我发现编译后,调用原方法的那句指令在最终的汇编指令里是不存在的,也就是说,莫名其妙的消失了?????或是被优化掉了?

@ohroy
Copy link
Author

ohroy commented Oct 29, 2018

经过多放调试,原因终于找到了。
先说结论,是被dex2oat优化掉了。
原因是dex2oat的过程是在加载dex的过程中,先执行dex2oat,而这个时候插件本身的代码非常简单。

    public static boolean hook(String thiz, String prefix) {
        Log.w("YAHFA", "in String.startsWith(): "+thiz+", "+prefix);
        return backup(thiz, prefix);
    }

    public static boolean backup(String thiz, String prefix) {
        return false;
  }

这个时候,dex2oat在转换机器指令的时候,会直接将整个backup函数inline掉,直接返回个false。
这种情况下,就不会去调用artmethod对象,更不可能调用原方法了。

所以,之前的有关

backup只是一个placeholder,实现甚至可以为空

这种说法是不够全面的。

完美的解决方案我还没找到,目前我是在backup里写上大量的无意义代码确保不会被inline掉,虽然不美观,但好歹是能用的。。。

@rk700
Copy link
Member

rk700 commented Oct 29, 2018

内联优化与不同系统编译策略有关,相似问题可见#17

可以尝试在backup中添加try-catch block,这样好像不会被内联优化掉

@ohroy
Copy link
Author

ohroy commented Oct 30, 2018

另外一个思路,hook execv 来强行修改dex2oat的参数,从而实现一致的内联策略,或者干脆就是禁止编译。

@uniking
Copy link

uniking commented Oct 30, 2018

人家是怎么快怎么来,你是怎么慢怎么来,干脆不编译,哈哈哈.
有些系统调用优化了,不通过artmethod而是直接指针执行native代码,局限性大啊.
项目坑比较多.

@ohroy
Copy link
Author

ohroy commented Oct 30, 2018

没有办法,内联是为了性能,但是这也给开发带来了极大的不便,尤其是底层开发。比如c++都有noinlinealways_inline的声明,单java好像没有找到。所以为了开发和调试方便,在debug版修改execv也是无奈之举。

@rk700
Copy link
Member

rk700 commented Oct 31, 2018

hook execv是可以的,但需要再引入native hook的整套框架,坑会比较多

@Carlyle-Lee
Copy link

我使用的是master分支代码,作为lib 依赖,直接hook的。(不是使用的插件方式。)
在8.0 系统上,出现了原方法找不到的问题。
在API 21 上,Hook 【java.net.URL openConnection 】 方法,方法直接被阻塞。 也不执行原来的方法。

@rk700
Copy link
Member

rk700 commented Nov 2, 2018

在hook之前,是先通过反射得到目标方法的,所以如果方法找不到,可能是在反射时出错,可以跟进去看是怎么回事

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants