Xposed——hook方法学习

Xposed是基于java层的hook框架,在不修改apk源码的情况下,编写自己的模块来改变apk的行为。以下总结了常见的Xposed的hook方法:

hook普通方法

创建一个类继承IXposedHookLoadPackage,修改 handleLoadPackage方法,首先要判断是否为特定的包。

public void handleLoadPackage(XC_LoadPackage.LoadPackageParam Param) throws Throwable {
    if(Param.packageName.equals("com.example.xposed_new3")){......}
}

hook普通方法调用的函数都是XposedHelpers.findAndHookMethod

XposedHelpers.findAndHookMethod(
className(包名+类名),
Param.classLoader(固定参数),
methodName(被hook的函数名)
**.class(函数的参数),
new XC_MethodHook(){}
)

XC_MethodHook方法详解

QQ截图20210901190645.png

hook普通方法的主要作用是打印各种参数信息,或者修改某些参数使其直接通过程序。

hook匿名内部类

匿名内部类一般为普通方法,所以仍然用findAndHookMethod的hook方法。

注:匿名内部类辨别方法:在smali代码中一个类为一个文件,且匿名内部类后缀会加上”$”符号,在工程管理器中直接找出相关类。

Lcom/example/xposed_new4/MainActivity$1

@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
    if(loadPackageParam.packageName.equals("com.example.xposed_new4")){
        XposedHelpers.findAndHookMethod(
        "com.example.xposed_new4.MainActivity$1",
        loadPackageParam.classLoader,
        "onClick",
        View.class,
        new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                super.beforeHookedMethod(param);
                View v=(View)param.args[0];
                XposedBridge.log("view:"+v.getId());
            }
         });
     }
}

在findAndHookMethod方法中的包名类名参数使用smali代码中的包名加类名,其余操作与普通方法hook相同。

Xposed—java 反射

java反射主要作用为突破修饰符的限制,如获取私有方法和私有字段。

以hook某一私有控件为例

//获取类
Class<?> clazz=param.thisObject.getClass();
//获取字段
Field field=clazz.getDeclaredField("Text");
//设置可见
field.setAccessible(true);

EditText ed_sn= (EditText) field.get(param.thisObject);//把类中的控件参数传给ed_sn
XposedBridge.log("输入结果为:"+ed_sn.getText().toString().trim());
//修改编辑框
ed_sn.setText("L61q4_cheng");

hook某一私有方法

//获取方法
Method method=clazz.getDeclaredMethod("MethodName",new Class[]{.class,.class...});
//显示可见
method.setAccessible(true);
//调用方法
返回值=method.invoke(param.thisObject,new Object(){...});//调用函数的参数

hook主动调用

主动调用,直接调用apk中的函数来实现hook操作,方便对数据进行直接操作。主动调用函数为XposedHelpers。该方法一般用于获取某一数据来通过某一入口,而不是直接修改方法的返回值。Xposed通过主动调用可以直接使用Android项目中某些方法,使其可以有更强大的功能。

XposedHelpers方法详解

XposedHelpers.callMethod();//调用普通方法
XposedHelpers.callStaticMethod();//调用静态方法
XposedHelpers.callMethod(
    param.getClass(),//固定句式
    "methodName"//需要主动调用的方法名
    new Object[]{...,...},//大括号中为调用函数中的参数,
)

在调用方法之前,可将程序中对参数的操作直接复制过来,例如加密操作,格式操作。

如果该方法有返回值且需要获取,可将该方法直接用在某一变量上,例如:

String str=(String)XposedHelpers.callMethod(
    param.getClass(),
    "methodName"
    new Object[]{...,...},
)
param.args[1]=str.toString();

Xposed—hook静态变量

实例变量在每一份实例出来的类中都有不同的值,先有对象才有实例变量,因此在没有对象之前是不能hook修改实例变量。在内存中静态变量不会改变。因此可以在对象之前hook。

故hook静态变量不需要获取类对象,直接修改类中私有静态变量。hook的方法有XposedHelpers,以变量类型Int为例。

final Class<?> clazz= XposedHelpers.findClass(
            "com.example.xposed_new5.MainActivity",
            loadPackageParam.classLoader);//方便起见提前赋给clazz
XposedHelper.setStaticIntField(clazz,"变量名",value(修改的值));
XposedHelpers.setStaticObjectField();//修改字符串

注:不同变量类型使用不同方法。

final Class<?>clazz=XposedHelpers.findClass(
        "com.example.xposed_new5.MainActivity",
        loadPackageParam.classLoader);        
XposedHelpers.setStaticIntField(clazz,"staticInt",99);

Xposed—hook构造方法

Java构造方法

与类同名,通过关键字new调用,每个类至少有一个或一个以上的构造方法(如果没有定义构造方法,系统会自动定义一个无参数的构造方法)。构造方法可以无参、一个或多个参数,且构造方法没有返回值。例如:

MainActivity(){
}
MainActivity(int a,int b){
}
MainActivity(String str){
}

hook构造方法

hook构造方法不需要添加方法名,采用的hook方法为XposedHelpers.findAndHookConstructor。

此时不能hook实例变量,因为对象还没有产生。

findAndHookConstructor详解

final Class<?> clazz=XposedHelpers.findClass(
"com.example.xposed_new6.MainActivity",//包名加类名
loadPackageParam.classLoader);//固定格式
XposedHelpers.findAndHookConstructor(
clazz,//可以提前定义,也可以直接在这里写出来
int.class,//构造方法的参数
String.class,//无参数也可以不写
new XC_MethodHook(){
//和普通方法写法一样
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        XposedBridge.log("Haha, HookDemo constructed was hooked" );
        }
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
        }        
});

Xposed—hook所有函数遍历所有类

对于动态dex文件可以采用这种方法来hook。

 XposedHelpers.findAndHookMethod(
        ClassLoader.class,
        "isok",
        String.class,
        new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                     super.afterHookedMethod(param);
                     Class<?> clazz=(Class<?>) loadPackageParam.getResult();
                     XposedBridge.log("Clazz:"+clazz.getName());
                     }
         }
});

通过hook主动调用获取相关数据

获取类

Class<?> clazz=param.thisObject.getClass();

对类进行操作(获取字段)

Field[] fields=clazz.getDeclaredFields();
for(Field field:fields){
     XposedBridge.log("字段名称:"+field.getName());
}

获取类中的所有方法

Method[] methods=clazz.getDeclaredMethods();
for(Method method:methods)
{
      XposedBridge.log("方法名称:"+method.getName());
}

通过主动调用获取普通方法

XposedHelpers.callMethod(loadPackageParam.getClass(),"methodName",new Object(){...});

通过主动调用获取静态方法

Class<?> clazz1=XposedHelpers.findClass(
    "com.example.xposed_new7.MainActivity",
    loadPackageParam.classLoader);
XposedHelpers.callStaticMethod(clazz1,"methodName",new Object(){...});

通过主动调用获取普通字段(不是方法中的特定字段)

XposedHelpers.getBooleanField(loadPackageParam.getClass(),"fieldName");

获取静态字段

Class<?> clazz2=XposedHelpers.findClass(
    "com.example.xposed_new7.MainActivity",
    loadPackageParam.classLoader);
XposedHelpers.getStaticBooleanField(clazz2,"fieldName");

Xposed—hook替换函数

if(loadPackageParam.packageName.equals("com.example.xposed_new8")){
            Class<?>clazz=XposedHelpers.findClass(
                "com.example.xposed_new8.MainActivity",
                loadPackageParam.classLoader);
            XposedHelpers.findAndHookMethod(
                    "com.example.xposed_new8.MainActivity",
                    loadPackageParam.classLoader,
                    "ButtonTest1",
                    new XC_MethodReplacement() {
                    @Override
                    protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
                            XposedBridge.log("方法替换成功");
                            XposedHelpers.callMethod(clazz,"ButtonTest2");//主动调用ButtonTest2
                            return null;
                        }
                    }
            );
}

*Xposed—hook多DEX

在一个apk中有多个dex文件时,在apk打包的时候优先加载主dex文件,会优先有些类hook不到,采用attach方法来解决。

XposedHelpers.findAndHookMethod(
        Application.class,
        "attach",
        Context.class,
        new XC_MethodHook() {
                 @Override
                 protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                 super.beforeHookedMethod(param);
                 Context context= (Context) param.args[0];
                 ClassLoader loader=context.getClassLoader();
                 XposedHelpers.findAndHookMethod(
                         "com.example.xposed_new8.MainActivity",
                         loader,
                         "ButtonTest1",
                         new XC_MethodHook() {
                                 @Override
                                 protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                            super.beforeHookedMethod(param);
                              }
                         }
                );
           }
       }
);