Xposed 框架 Hook 教程

Xposed 框架 Hook 教程

Xposed 也算是有名的框架了,微信抢红包、qq抢红包等工具都是使用 Xposed 框架实现的

目前一些黑产也可以通过 Xposed hook 程序,修改数据或直接调用某些方法,来达到破解软件的目的

下面是一篇简单的使用教程

来说明如何 hook 一个程序

创建一个普通的主项目

此项目什么操作都不做,仅仅有一个按钮及文字显示控件

包名是: com.zhou.hooktest

注意:在 hook 的过程中,包名很重要,插件是通过包名匹配来决定hook的

xml 和 java 文件内容如下:

xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/testBtn"
        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/clickBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点击改变"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"  />

</android.support.constraint.ConstraintLayout>

java

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setNewText("来自 Activity");
        findViewById(R.id.clickBtn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setNewText("来自点击");
            }
        });
        AlertDialog alertDialog=new AlertDialog(this);
        alertDialog.show();
        alertDialog.setCancelable();
        EditText editText;
        editText.getText("");
    }

    public void setNewText(String text) {
        TextView textView = findViewById(R.id.testBtn);
        textView.setText(text);
    }
}

这个工程仅仅显示一段文字内容

创建一个 Xposed 插件工程

创建插件工程的初始步骤和创建普通工程没有区别

首先使用 AS 创建一个普通项目

假设我目前创建的工程包名为: com.zhou.hook

添加 Xposed 插件工程所必须的步骤

AndroidManifest.xml 修改

在 Application 节点中添加:

        <!-- 是否是xposed模块,xposed根据这个来判断是否是模块 -->
        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        <!-- 模块描述,显示在xposed模块列表那里第二行 -->
        <meta-data
            android:name="xposeddescription"
            android:value="测试Xposed模块" />

        <!-- 最低xposed版本号(lib文件名可知) -->
        <meta-data
            android:name="xposedminversion"
            android:value="30" />

app 的 build.gradle 修改

在 app 的build.gradle 添加依赖

注意使用 provided 而不是 implementation

    provided 'de.robv.android.xposed:api:82'

创建一个 java 入口文件

创建一个 xposed 框架插件入口,这个入口继承自:IXposedHookLoadPackage

下面是我创建的示例:

这个示例的java文件路径是: com.zhou.hook.Main


public class Main implements IXposedHookLoadPackage {
    public static final String TAG = "HookXposed";

    @Override
    public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        try {
            hookTest(lpparam);
        } catch (Exception e) {
            Log.i(TAG, " load exception:" + Log.getStackTraceString(e));
        }
    }


    /**
     * 这是测试 xposed 框架是否能运行的方法
     *
     * @param lpparam
     */
    private void hookTest(final XC_LoadPackage.LoadPackageParam lpparam) {
        if (lpparam.packageName.equals("com.zhou.hooktest")) {
            Log.i(TAG, " load success");
            XposedBridge.log("load test apk");
            Log.i(TAG, " load success findAndHookMethod");
            XposedHelpers.findAndHookMethod("com.zhou.hooktest.MainActivity"
                    , lpparam.classLoader, "setNewText", String.class, new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            Log.i(TAG, " load success beforeHookedMethod:" + param.args[0]);
                            XposedBridge.log("test apk param:" + param.args[0]);
                            param.args[0] = "来自 xposed";
                        }

                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            Log.i(TAG, " load success afterHookedMethod");
                            super.afterHookedMethod(param);
                        }
                    });

            Log.i(TAG, "hook over");
        }
    }
}

assets 添加文件

app/src/main/assets 文件夹(也就是资源文件夹)内添加一个文件:xposed_init

注意文件名必须是 xposed_init

在这个文件中添加一行内容,这行内容告诉 xposed 框架,插件的入口类的路径

com.zhou.hook.Main

运行

分别将两个程序安装在有 Xposed 框架且成功激活框架的模拟器或手机上
在 Xposed 框架中,勾选模块并重启,此插件即可运行

正常情况下,打开主程序,应该显示 来自 Activity
而点击按钮,应该显示 来自点击

在 Xposed 框架启用插件后,此程序无论是打开,还是点击按钮,都只显示: 来自 Xposed

在上面的 Xposed 插件程序中,劫持了 setNewText 方法,使用 log 输出了参数,并将该方法参数修改成了: 来自 Xposed

说明

通过 if (lpparam.packageName.equals("com.zhou.hooktest")) ,此插件只会 hook 用来测试的主程序

XposedHelpers.findAndHookMethod 的最后一个参数即回调,

beforeHookedMethod 是方法执行前的调用, 可以在这里获取 方法入参
afterHookedMethod 是方法执行后的调用, 可以获取方法出参

Xposed 插件具有更强大的功能,不只是 hook method ,对象同样可以被反射获取,并且可以更改对象的值

例如: XposedHelpers.findField() 将会返回一个 Field 对象,通过 Field ,可以修改对象的值

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://zwc365.com/2020/06/09/xposed-hook

Buy me a cup of coffee ☕.