探索Android的HOOK之旅

来源:互联网 发布:mysql中的level 编辑:程序博客网 时间:2024/06/05 09:06

探索AndroidHOOK之旅


因为项目需求,最近在研究Androidhook方法,总结一下研究的结果,做一个笔记。

 

因为我只研究了AndroidJava层的代码hookNative层的hook还未实际研究与应用。

 

一、Hook是什么

 

Hook的中文翻译是“钩子”,简单的说就是,钩住你的代码,对你的方法执行前后做一些操作,例如:改变方法返回值,改变传入方法的参数,替换现有的方法。

 

当然,这些改变都是不可以在原有代码上进行更改,因为改变原有方法,有时成本很大,并且很繁琐,而且hook不光是hook自己写的代码,还可以hook系统原有的代码。例如你要更改你代码所有的文字样式,在Android中也就是TextView,如果在应用已经完成,再去自定义一个TextView更改起来就很麻烦,此时你只需要hookTextView中相应的方法,就可以更改所有文字的样式了。

 

二、Hook的应用

 

Hook 的应用场景有很多,前边提到的hook其实并不常用,常用的hook应该就是热更新技术了。所谓的热更新,就是在应用不重新安装新版本,而修复和升级一些bug和功能。

因为热更新技术就是hook应用的完美展现,所以围绕热更新技术去研究hook技术,是一个不错的方向。

 

三、热更新技术

 

热更新技术阿里和腾讯都有自己的实现方案,阿里的Sophix,微信用的Tinker

这是三种热更新技术的对比图。网上有很多详细的,这里就不讲了。

 

四、我走过的路

 

因为公司需求并不是热更新,一开始我一直在寻找Android的Hook方法,准确来说是无侵入的Hook方法,就是不改变原有代码的基础上去hook。

 

最先看的到是Xposed框架,这个框架实现hook更改手机所有应用的代码,框架很好,但是需要手机进行了root权限,这就直接pass了。

 

后来又找到的Legend的框架,这个的确是实现了我的需求,它只需要很少的代码,就可以hook到你自己应用中的方法,对方法进行更改,但是很可惜,他并不可以在Android 7.0以上的系统上运行。这个作者好像是在高二时候写的(给跪),现在也不更新了,所以只好放弃了。

 

后来我采用的是YAHFA去做的,这个框架总体还是很好的,支持7.0,虽然7.0是在测试阶段,但是并没有发现什么错误。只不过他不是在本应用中添加代码,而是以插件的形式,把你的代码打包成一个debug.apk,存储到sd卡中,进行加载,从而更改代码。这更像是热更新的操作,只是如果sd卡中删除了这个debug.apk,就失效了。不过热更新用这个应该很不错,我的需求,我更喜欢在本应用中添加hook方法,而不是插件式添加。

 

五、YAHFA的应用

 

GitHub地址:https://github.com/rk700/YAHFA

 

很感谢作者提供的这个框架。

 

GitHub中,作者对框架的介绍已经很详细了,我就简单的再说一下。

 

下载demo后导入Android studio,其中有一个demoApp和demoPlugin,还有一个library,library中就是hook的逻辑,其实hook就是代码的反射调用,AOP编程的一些逻辑,不知道AOP的朋友可以百度一下。

 

demoApp安装到你的手机,把demoPlugin打包成一个debug.apk,存入你的手机内存,只要在demoApp中的lication的类中指定这个dubug的路径就好。

 

demoPlugin中编写你要hook的方法。

 


className是指定的hoook的类名

methodName是指定要hook 的方法

methodSig是指定的类型签名

(Ljava/lang/String;)Ljava/net/URI;

(Ljava/lang/String;)Ljava/net/URI;

括号中是参数的签名,括号外是返回值的签名

签名是jni中经常用法哦的,如归不是基本数据类型,就要L开头,后边跟类的全路径名用“/”分割

基本数据类型有自己的类型签名


hook方法是你重写的代码逻辑

origin方法是你的原放啊

如果返回值不是基本数据类型,就写成Object

oringin方法中写什么都可以,不影响运行


1.静态方法

 

public class Hook_url {    public static String className = "java.net.URI";    public static String methodName = "create";    public static String methodSig = "(Ljava/lang/String;)Ljava/net/URI;";    public static Object hook(String url)    {        Log.w("YAHFA", "in hook_url: "+url);        Log.w("YAHFA", "网址");        url = "http://suggest.taobao.com/sug?code=utf-8&q=袜子&callback=cb";        return origin(url);    }    public static Object origin(String url)    {        Log.w("YAHFA", "String.startsWith() should not be here");        return url;    }}

这是静态方法的hook,静态方法和静态差不多,区别就是,非静态的方法在hook和origin的参数中,多加一个Object 的参数


url是传入的参数,把url更改,在调用origin,这样就是更改了访问网址

 

2. 非静态方法

 

 

public class hookbean {    public static String className = "lab.galaxy.yahfa.demoApp.DemoBean";    public static String methodName = "getbean";    public static String methodSig =            "(Ljava/lang/String;Ljava/lang/String;)Llab/galaxy/yahfa/demoApp/Bean;";    public static Object hook(Object obj,String a, String b) {        Log.w("YAHFA", "in getBean: "+a+b);        a = "ni";        b = "咱们";        return origin(obj,a, b);    }    public static Object origin(Object obj,String a, String b) {        Log.w("YAHFA", "ClassWithStaticMethod.tac() should not be here");        return "";    }}

 这是非静态方法的hook,返回值是我自定义的类,所以签名是我的全路径,返回值类型是Object


3. 返回值为非基本数据类型


可以参考2,静态和非静态都是如此


4. 参数是非基本数据类型

 

public class Hook_WebViewClient_onReceivedSslError {    public static String className = "android.webkit.WebViewClient";    public static String methodName = "onReceivedSslError";    public static String methodSig =            "(Landroid/webkit/WebView;Landroid/webkit/SslErrorHandler;Landroid/net/http/SslError;)V";    public static void hook(Object thiz, WebView webView, SslErrorHandler handler, SslError error) {        Log.w("YAHFA", "WebViewClient.onReceivedSslError()");        handler.proceed();    }}


参数是非基本数据类型,返回值是void

任何情况下都可以不写origin方法,这样只是不调用原方法了


5. Jni方法

以后补充

6. jar中的方法

如果需要hook第三方依赖,jar包的方法,需要把debug.apk中也添加依赖和jar

 

7.内部类的hook

内部类只是编译时的概念,一旦编译成功,就会出现两个不同的类,例如,类outClass中有个intClass,那么编译后就出现一个名为outClass.class和一个outClass$intClass.class的类。所以className中就要指定类路径为a.b.c.outClass$intClass。

 

六、总结

 

Hook主要就是通过反射,有很多例子,都是直接反射调用类,然后更改,只是用了框架,就不用一个个代码去反射调用更该了,省了很多的时间去做一些你更该后的代码优化等操作。

原创粉丝点击