文档章节

Xposed从入门到弃坑:0x02、IXposedHook相关接口解析

WrBug
 WrBug
发布于 2017/04/27 11:51
字数 1547
阅读 738
收藏 8
点赞 0
评论 3

在上一篇文章中我们通过一个简单的例子开发了一款Xposed框架,感受到了Xposed的强大功能,在demo中我们新建了一个XposedInit的类实现了IXposedHookLoadPackage 接口,在handleLoadPackage中进行hook,最终达到了我们的目的,那IXposedHookLoadPackage是干什么的呢?还有handleLoadPackage什么时候会调用呢?还有IXposedHookInitPackageResources和IXposedHookZygoteInit的左右是什么?这期会做一个讲解。对上一篇文章有遗忘的可以回过头在看一遍:Xposed从入门到弃坑:一、Xposed初探

IXposedHookLoadPackage

从字面上翻译就是在加载包时开始hook。接口需要实现handleLoadPackage方法,该方法会在执行Application.onCreate()方法前调用,并且携带一个XC_LoadPackage.LoadPackageParam lpparam返回过来,lpparam包含了hook到的应用的一些信息,具体通过表格来说明 (表格的description均为hook到的应用相关信息,不是Xposed项目的信息)

fieldstypedescription
packageNameString应用包名
processNameString应用加载后的进程名
classLoaderClassLoader应用的classloader
appInfoApplicationInfo应用的信息,包括verisonCode,uid等

表格只是简单的介绍,具体需要再今后的开发中再讲解,在上篇文章中,在hook到方法后,使用反射获取textview,再来回顾下代码:

//不能通过Class.forName()来获取Class ,在跨应用时会失效
Class c=lpparam.classLoader.loadClass("com.wrbug.xposeddemo.MainActivity");
Field field=c.getDeclaredField("textView");
field.setAccessible(true);
//param.thisObject 为执行该方法的对象,在这里指MainActivity
TextView textView= (TextView) field.get(param.thisObject);
textView.setText("Hello Xposed");

在第一行中 class没有用Class.forName()来获取,是什么原因呢?我们先来看看Class.forName()的源码:

    @CallerSensitive
    public static Class<?> forName(String className) throws ClassNotFoundException {
        return forName(className, true, VMStack.getCallingClassLoader());
    }
	
	@CallerSensitive
    public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException {
        if (loader == null) {
            loader = BootClassLoader.getInstance();
        }
        Class<?> result;
        try {
            result = classForName(name, initialize, loader);
        } catch (ClassNotFoundException e) {
            Throwable cause = e.getCause();
            if (cause instanceof LinkageError) {
                throw (LinkageError) cause;
            }
            throw e;
        }
        return result;
    }

    /** Called after security checks have been made. */
    static native Class<?> classForName(String className, boolean shouldInitialize, ClassLoader classLoader) throws ClassNotFoundException;

在三个参数的方法中,有一个需要传一个ClassLoader进去,在一个参数的方法中,ClassLoader是通过VMStack.getCallingClassLoader()获取的。VMStack是一个虚拟机栈,在Android系统中,每个应用都有一个独立的虚拟机,所以VMStack.getCallingClassLoader()是获取当前应用的ClassLoader,即xposed项目的ClassLoader,所以,如果使用Class.forName("xxx.xxx.xxxActivity")获取不同应用的类会提示找不到,这就是需要通过lpparam.classLoader.loadClass()获取的原因。

IXposedHookInitPackageResources

这个是在资源布局初始化时进行hook,需要实现handleInitPackageResources(XC_InitPackageResources.InitPackageResourcesParam resparam) 方法,在初始化时调用,resparam有以下两个字段:

fieldtypedescription
packageNameString应用包名
resXResources资源相关

resparam.res是一个非常重要的字段,里面包含了很多资源的信息,并且继承Resources。下面通过一个例子做个简要的说明。还是使用上期的demo,项目地址:https://github.com/WrBug/XposedDemo , 命令切换到提交:

git checkout 0be008e

demo为在R.layout.activity_main布局初始化时进行hook,打印出hook到的view。布局做些修改,多加几个控件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.wrbug.xposeddemo.MainActivity">

    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button"/>

    <RatingBar
        android:id="@+id/ratingBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Switch
            android:id="@+id/switch1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Switch"/>

        <ListView
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </LinearLayout>

</LinearLayout>

在Activity的onCreate里面加入两个log:

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("Xposed", "before setcontent");
        setContentView(R.layout.activity_main);
        Log.i("Xposed", "after setcontent");
        textView = (TextView) findViewById(R.id.textview);
        textView.setText("WrBug");

        Log.i("Xposed", "before inflate");
        getLayoutInflater().inflate(R.layout.view_demo, null);
        Log.i("Xposed", "after inflate");
    }

也就是在setContentView两边加了before setcontent和after setcontent两个log,添加一个inflate布局的方法,接下来在XposenInit里面实现IXposedHookInitPackageResources接口,并且实现handleInitPackageResources(XC_InitPackageResources.InitPackageResourcesParam resparam) 方法,代码如下:

public class XposedInit implements IXposedHookLoadPackage, IXposedHookInitPackageResources {
    @Override
    public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) {
        if (lpparam.packageName.equals("com.wrbug.xposeddemo")) {
            XposedHelpers.findAndHookMethod("com.wrbug.xposeddemo.MainActivity", lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    //不能通过Class.forName()来获取Class ,在跨应用时会失效
                    Class c = lpparam.classLoader.loadClass("com.wrbug.xposeddemo.MainActivity");
                    Field field = c.getDeclaredField("textView");
                    field.setAccessible(true);
                    //param.thisObject 为执行该方法的对象,在这里指MainActivity
                    TextView textView = (TextView) field.get(param.thisObject);
                    textView.setText("Hello Xposed");
                }
            });
        }
    }

    @Override
    public void handleInitPackageResources(XC_InitPackageResources.InitPackageResourcesParam resparam) throws Throwable {
        if (resparam.packageName.equals("com.wrbug.xposeddemo")) {
            resparam.res.hookLayout(resparam.packageName, "layout", "activity_main", new XC_LayoutInflated() {
                @Override
                public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
                    printView((ViewGroup) liparam.view, 1);
                }
            });
            resparam.res.hookLayout(resparam.packageName, "layout", "view_demo", new XC_LayoutInflated() {
                @Override
                public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
                    XposedBridge.log("hook view_demo");
                }
            });
        }
    }
    //遍历资源布局树,并打印出来
    private void printView(ViewGroup view, int deep) {
        String viewgroupDeepFormat = "";
        String viewDeepFormat = "";
        for (int i = 0; i < deep - 1; i++) {
            viewgroupDeepFormat += "\t";
        }
        viewDeepFormat = viewgroupDeepFormat + "\t";
        XposedBridge.log(viewgroupDeepFormat + view.toString());
        int count = view.getChildCount();
        for (int i = 0; i < count; i++) {
            if (view.getChildAt(i) instanceof ViewGroup) {
                printView((ViewGroup) view.getChildAt(i), deep + 1);
            } else {
                XposedBridge.log(viewDeepFormat + view.getChildAt(i).toString());
            }
        }
    }
}

安装重启后,打开demo,查看打印的日志:

04-26 23:24:52.123 1818-1818/com.wrbug.xposeddemo I/Xposed: before setcontent
04-26 23:24:52.183 1818-1818/com.wrbug.xposeddemo I/Xposed: android.support.v7.widget.ContentFrameLayout{2fb5cbd7 V.E..... ......I. 0,0-0,0 #1020002 android:id/content}
04-26 23:24:52.183 1818-1818/com.wrbug.xposeddemo I/Xposed: 	android.widget.LinearLayout{33cd7cc4 V.E..... ......I. 0,0-0,0}
04-26 23:24:52.183 1818-1818/com.wrbug.xposeddemo I/Xposed: 		android.support.v7.widget.AppCompatTextView{2e1a07ad V.ED.... ......ID 0,0-0,0 #7f0b005e app:id/textview}
04-26 23:24:52.183 1818-1818/com.wrbug.xposeddemo I/Xposed: 		android.support.v7.widget.AppCompatButton{2c3a2ae2 VFED..C. ......I. 0,0-0,0 #7f0b005f app:id/button}
04-26 23:24:52.183 1818-1818/com.wrbug.xposeddemo I/Xposed: 		android.support.v7.widget.AppCompatRatingBar{1aa14e73 VFED.... ......ID 0,0-0,0 #7f0b0060 app:id/ratingBar}
04-26 23:24:52.183 1818-1818/com.wrbug.xposeddemo I/Xposed: 		android.widget.LinearLayout{1c87a130 V.E..... ......I. 0,0-0,0}
04-26 23:24:52.184 1818-1818/com.wrbug.xposeddemo I/Xposed: 			android.widget.Switch{13fc71a9 VFED..C. ......I. 0,0-0,0 #7f0b0061 app:id/switch1}
04-26 23:24:52.184 1818-1818/com.wrbug.xposeddemo I/Xposed: 			android.widget.ListView{3ed4132e V.ED.VC. ......I. 0,0-0,0}
04-26 23:24:52.184 1818-1818/com.wrbug.xposeddemo I/Xposed: after setcontent
04-26 23:24:52.184 1818-1818/com.wrbug.xposeddemo I/Xposed: before inflate
04-26 23:24:52.184 1818-1818/com.wrbug.xposeddemo I/Xposed: hook view_demo
04-26 23:24:52.184 1818-1818/com.wrbug.xposeddemo I/Xposed: after inflate

日志可以看出handleInitPackageResources会在setContentView(R.layout.activity_main);getLayoutInflater().inflate(R.layout.view_demo, null);时调用。对setContentView有了解的都明白setContentView也会调用inflate方法。所以,也可以看成是hook了inflate方法。在返回的数据XC_InitPackageResources.InitPackageResourcesParam resparam中,有一个 liparam.view的字段,通过日志可以看出setContentView方法的是一个ContentFrameLayout,下面包含了LinearLayout,这个LinearLayout也就是我们activity_main布局最外层的view,获取到这个view以后就可以进行一系列的操作了。 更多精彩内容可以关注我的博客:www.mandroid.cn

© 著作权归作者所有

共有 人打赏支持
WrBug

WrBug

粉丝 10
博文 8
码字总数 8149
作品 4
杭州
Android工程师
加载中

评论(3)

OSC_pZcjyW
OSC_pZcjyW
q
吴佩在
吴佩在

引用来自“吴佩”的评论

啦啦

@吴佩厉害了
吴佩在
吴佩在
啦啦
Xposed (一) Android hook框架入门

原理 Xposed替换了/system/bin/app_process可执行文件,在启动Zygote时加载额外的jar文件(/data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar),并执行一些初始化操作(执行...

pseudo ⋅ 2015/06/26 ⋅ 3

1109 - PDF 标注导出,从入门到弃坑

这两天,研究了如果导出 PDF 标注。没搞定,大致列一些关键的点,供大家参考: PDF 标准是 Adobe 牵头搞了,标准又老又长,一般还是别看了 Apple 提供了 PDFKit;不过,十几年没更新了,功能...

atJason ⋅ 2017/11/09 ⋅ 0

Android.Hook框架Cydia篇

Cydia Substrate是一个代码修改平台.它可以修改任何主进程的代码,不管是用Java还是C/C++(native代码)编写的.而Xposed只支持HOOK app_process中的java函数,因此Cydia Substrate是一款强大而...

henry-zhang ⋅ 2015/11/11 ⋅ 2

XSharedPreferences在Xposed里面的作用

Xposed的开发文档 https://github.com/rovo89/XposedBridge/wiki/Development-tutorial 比如我们要做一个App(类似于http://git.oschina.net/sulliy/MinMinLock),它可以限制系统系统中其他...

开源中国驻成都办事处 ⋅ 2016/09/29 ⋅ 0

Xposed模块的开发

Xposed模块的开发 snowdream - Impossible is nothing!2017-06-0631 阅读 android 作者:snowdream Email:yanghui1986527#gmail.com Github: https://github.com/snowdream QQ 群: 5293276......

snowdream - Impossible is nothing! ⋅ 2017/06/06 ⋅ 0

Xposed开发初体验

盗个图 本篇文章具体是Xposed开发,如何安装Xposed需自行上网查找,本文同步更新于旺仔的个人博客,访问可能有点慢,多刷新几次。 Xposed 什么是Xposed呢? “Xposed是一个适用于Android的框架...

叫我旺仔 ⋅ 2017/10/08 ⋅ 0

virjar/xposedhooktool

hook base工具 Android 破解的hook工具,集成一些帮助破解的常用功能,如自动网络抓包、网络堆栈爆破、文件日志、webview调试环境 入口在 com.virjar.xposedhooktool.hotload.XposedInit,但是...

virjar ⋅ 04/22 ⋅ 0

想改变?先练习“弃坑占坑”心法

大部分人都有改变的意愿,比如想多读点书、想早睡早起、想学习英语等等,但是大部分时候改变并未如愿发生或者发生了不久又变回原样了,这是为什么? 每个人在一段时间内都会形成自己的日常,...

葛亮 ⋅ 04/26 ⋅ 0

你了解你的数据吗(练气篇)

0x00 前言 数据一道,可深可浅,可大可小。同为数据人,新手和老鸟亦有很大差别。本篇是了解数据的入门篇,包含两部门内容: 数据接入,你的掌控力如何?主要聊一聊数据接入人员对自己接入数...

木东居士 ⋅ 01/13 ⋅ 0

Android逆向之旅---破解某支付软件防Xposed的hook功能检测机制过程分析

一、情景介绍 最近想写几个某支付软件的插件,大家现在都知道现在插件大部分都是基于Xposed的hook功能,包括之前写了很多的某社交软件的插件,所以不多说就直接用Jadx打开支付软件之后然后找...

jiangwei0910410003 ⋅ 05/15 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java集合类总结笔记

一、集合类的层次关系 主要容器集合类的特点: ArrayList 一种可以动态增长和缩减的索引序列 LinkedList 一种可以在任何位置进行高效地插入和删除的有序序列 ArrayDeque 一种用循环数组实现的...

edwardGe ⋅ 10分钟前 ⋅ 0

spring RMI远程调用

RMI https://www.cnblogs.com/wdh1995/p/6792407.html

BobwithB ⋅ 15分钟前 ⋅ 0

Jenkins实践2 之基本配置

1 插件管理 系统管理->插件管理 在可选插件中可以自主安装插件 2 管理用户 系统管理->管理用户->新建用户 3 安全配置 系统管理->全局安全配置 授权策略 选择安全矩阵 然后添加现有的用户,赋...

晨猫 ⋅ 15分钟前 ⋅ 0

c++智能指针

1、是一种泛型类,针对指针类型的泛型类,会保存指针 2、重载了符号 *和-> 对智能指针使用这两个符号,相当于对保存的泛型使用这两个符号 3、当智能指针引用计数为0时,会去释放指针指向的资...

国仔饼 ⋅ 16分钟前 ⋅ 0

Spring Boot错误处理机制

1)、SpringBoot默认的错误处理机制 默认效果: 1)、浏览器,返回一个默认的错误页面 浏览器发送请求的请求头: 2)、如果是其他客户端,默认响应一个json数据 原理: 可以参照ErrorMvcAut...

小致dad ⋅ 18分钟前 ⋅ 0

ftp连接不上的终极办法 SFTP

假如FTP由于各种原因就是连不上,那么用SFTP协议吧,使用登录服务器的账号密码。

sskill ⋅ 22分钟前 ⋅ 0

Unity 围绕旋转角度限制(Transform.RotateAround)

在 Unity 中可以利用 Transform.RotateAround 围绕指定物体进行旋转,但某些情况下可能需要对旋转角度进行控制。我是先计算出预设角度大小,然后判断是否在限定角度范围内是则进行旋转。 相关...

大轩 ⋅ 23分钟前 ⋅ 0

阿里沙箱环境支付宝测试demo

阿里支付宝支付和微信支付,包括:阿里沙箱环境支付宝测试demo,支付宝支付整合到spring+springmvc+mybatis环境和微信整合到如上环境,功能非常齐全,只需要修改对应的配置文件即可,帮助文档...

码代码的小司机 ⋅ 26分钟前 ⋅ 0

JDK1.6和JDK1.7中,Collections.sort的区别,

背景 最近,项目正在集成测试阶段,项目在服务器上运行了一段时间,点击表格的列进行排序的时候,有的列排序正常,有的列在排序的时候,在后台会抛出如下异常,查询到不到数据,而且在另外一...

tsmyk0715 ⋅ 43分钟前 ⋅ 0

C++ 中命名空间的 5 个常见用法

相信小伙伴们对C++已经非常熟悉,但是对命名空间经常使用到的地方还不是很明白,这篇文章就针对命名空间这一块做了一个叙述。 命名空间在1995年被引入到 c++ 标准中,通常是这样定义的: 命名...

柳猫 ⋅ 47分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部