Xposed框架开发

文章目录

  • xpose插件开发步骤
    • 清单文件
    • 新建一个类(插件入口点)
    • 设置入口点
  • Hook第一个实例zhuceji.apk
  • 一些常用的HOOK
    • HookH5Plugin
    • HookProxyPlugin
    • HookSystem
  • 资料
    • Xposed原理初探

xpose插件开发步骤

magisk安装与配置
Xpose Framework API
LSPosed
magisk 一键集成环境,再也不用每次刷完机繁琐得配置环境了!
Xposed 插件开发之一: Xposed入门
Xposed模块开发

清单文件

Xposed框架开发_第1张图片
Xposed框架开发_第2张图片

新建一个类(插件入口点)

Xposed框架开发_第3张图片## 引入模块
在这里插入图片描述
在这里插入图片描述

设置入口点

Xposed框架开发_第4张图片

Hook第一个实例zhuceji.apk

package com.kika.testxposed;

import android.widget.EditText;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.MessageDigest;

public class HookZhuCeJi implements IHook {
    final String packageName = "com.qianyu.zhuceji";

    @Override
    public boolean isThisPackageName(XC_LoadPackage.LoadPackageParam lpparam) {
        return packageName.equals(lpparam.packageName);
    }

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        XposedBridge.log("编写Xposed插件模板, 开启Hook之路!");
        XposedBridge.log("找到我们要hook的应用程序");
        XposedHelpers.findAndHookMethod(
            "com.qianyu.zhuceji.MainActivity",
            lpparam.classLoader, // 类加载器
            "checkSN", // 方法名
            String.class, String.class, // 参数列表
            new XC_MethodHook() {
                // HOOK之前,打印参数信息,修改参数
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    // 打印参数信息
                    XposedBridge.log("username=" + param.args[0]);
                    XposedBridge.log("sn=" + param.args[1]);

                    // 打印方法调用堆栈信息
                    StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
                    for (StackTraceElement wodelog : wodelogs) {
                        XposedBridge.log("查看堆栈:" + wodelog.toString());
                    }
                }

                /**
                 *     private Button btn;
                 *     private EditText edit_sn;
                 *     private EditText edit_username;
                 * @param param param
                 * @throws Throwable Throwable
                 */
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    // 打印返回值信息
                    XposedBridge.log("返回值:" + param.getResult());
                    // 修改返回值
                    // param.setResult(true);
                    Class<?> clazz = param.thisObject.getClass();
                    XposedBridge.log("参数:" + clazz);
                    // 获取用户名字段
                    Field edit_username = clazz.getDeclaredField("edit_username");
                    // 设置可以访问
                    edit_username.setAccessible(true);
                    // 获取组件
                    EditText et_user = (EditText) edit_username.get(param.thisObject);
                    // 获取内容
                    String name = et_user.getText().toString().trim();

                    // 获取注册码字段
                    Field edit_sn = clazz.getDeclaredField("edit_sn");
                    edit_sn.setAccessible(true);
                    EditText et_sn = (EditText) edit_sn.get(param.thisObject);
                    String sn = et_sn.getText().toString().trim();
                    XposedBridge.log("用户名:" + name);
                    XposedBridge.log("注册码:" + name);

                    // 指定算法MD5
                    MessageDigest digest = MessageDigest.getInstance("MD5");
                    // 初始化
                    digest.reset();
                    // 更新
                    digest.update("[email protected]".getBytes());
                    // 获取方法
                    String methodName = "toHexString";
                    Class<?>[] parameterTypes = new Class[]{byte[].class, String.class};
                    Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
                    // 设置可见
                    method.setAccessible(true);
                    // 主动调用方法
                    String hexstr = (String)method.invoke(param.thisObject, new Object[]{digest.digest(), sn});
                    // 字符串拼接
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < hexstr.length(); i++) {
                        sb.append(hexstr.charAt(i));
                    }
                    // 设置编辑框的值
                    et_user.setText("[email protected]");
                    et_sn.setText(sb.toString());
                }
            });
    }
}

一些常用的HOOK

HookH5Plugin

package com.kika.testxposed;

import android.util.Log;
import android.webkit.WebView;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class HookH5Plugin implements IHook{
    @Override
    public boolean isThisPackageName(XC_LoadPackage.LoadPackageParam lpparam) {
        return true;
    }

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        // 强制H5调试插件开发
        XposedBridge.hookAllConstructors(
            WebView.class,
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    // 主动调用静态方法call 第一参数传的是类
                    final Object[] params = {true};
                    XposedHelpers.callStaticMethod(WebView.class, "setWebContentsDebuggingEnabled", params);
                    Log.d(HookH5Plugin.class.getSimpleName(), "package:" + lpparam.packageName);
                }
            }
        );
        // 方法重载
        XposedBridge.hookAllMethods(
            WebView.class,
            "setWebContentsDebuggingEnabled",
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    param.args[0] = true;
                    Log.d(HookH5Plugin.class.getSimpleName(), "package:" + lpparam.packageName);
                }
            }
        );
        // 拦截替换直接方法逻辑
        XposedHelpers.findAndHookMethod(
            "io.dcloud.common.adapter.ui.WebViewImpl",
            lpparam.classLoader,
            "setWebViewData",
            new XC_MethodReplacement() {
                @Override
                protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
                    Log.d(HookH5Plugin.class.getSimpleName(), "setWebViewData is replace");
                    return null;
                }
            });
    }
}

HookProxyPlugin

package com.kika.testxposed;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;

public class HookProxyPlugin implements IHook{
    @Override
    public boolean isThisPackageName(XC_LoadPackage.LoadPackageParam lpparam) {
        return true;
    }

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        XposedHelpers.findAndHookMethod(
            System.class,
            "getProperty",
            String.class,
            new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    XposedBridge.log("绕过代理检测");
                    String str = (String) param.args[0];
                    if (str.equals("https.proxyHost") || str.equals("http.proxyHost")
                        || str.equals("https.proxyPort") || str.equals("http.proxyPort")) {
                        param.setResult(null);
                    }
                }
            }
        );

        XposedHelpers.findAndHookMethod(
            URL.class,
            "openConnection",
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    XposedBridge.log("强制代理");
                    param.args[0] = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("192.168.99.13", 8888));
                }
            });
    }
}

HookSystem

package com.kika.testxposed;

import android.net.wifi.WifiInfo;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import java.net.InetAddress;

/**
 * Hook 系统的一些方法
 */
public class HookSystem implements IHook {
    public static long isToLong(String strIp) {
        long[] ip = new long[4];
        int position1 = strIp.indexOf(".");
        int position2 = strIp.indexOf(".", position1 + 1);
        int position3 = strIp.indexOf(".", position2 + 1);
        // 将每个.之间的字符串转换成整形
        ip[0] = Long.parseLong(strIp.substring(0, position1));
        ip[1] = Long.parseLong(strIp.substring(position1 + 1, position2));
        ip[2] = Long.parseLong(strIp.substring(position2 + 1, position3));
        ip[3] = Long.parseLong(strIp.substring(position3 + 1));
        return (ip[0] << 24) + (ip[1] << 16) + (ip[2] >> 8) + ip[3];
    }

    @Override
    public boolean isThisPackageName(XC_LoadPackage.LoadPackageParam lpparam) {
        return true;
    }

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        // 拦截系统方法,篡改IMEI设备号
        XposedHelpers.findAndHookMethod(
            "android.telephony.TelephonyManager",
            lpparam.classLoader,
            "getDeviceId",
            new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    //param.setResult(HookSystem.isToLong(param.getResult().toString()));
                    XposedBridge.log("imei:" + param.getResult());
                }
            });
        // HOOK构造方法,拦截IP地址
        XposedHelpers.findAndHookConstructor(
            "java.net.InetSocketAddress",
            lpparam.classLoader,
            String.class,
            int.class,
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    XposedBridge.log("IP地址:" + param.args[0]);
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                }
            }
        );
        // 拦截流量上网IP地址
        XposedHelpers.findAndHookMethod(InetAddress.class,
            "getHostAddress",
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    XposedBridge.log("IP地址:" + param.getResult());
                }
            });
        // 拦截WIFI上网IP地址
        XposedHelpers.findAndHookMethod(
            WifiInfo.class,
            "getIpAddress",
            new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    XposedBridge.log("IP地址:" + param.getResult());
                    // 分割字符串
                    String[] str = "192.168.1.99".split("\\.");
                    // 定义一个字符串,用来存储反转后的IP地址
                    String ipAddress = "";
                    // for循环控制IP地址反转
                    for (int i = 3; i >= 0; i--) {
                        ipAddress = ipAddress + str[i] + ".";
                    }
                    // 去除最后一位的"."
                    ipAddress = ipAddress.substring(0, ipAddress.length() - 1);
                    // 返回新的整形IP地址
                    param.setResult((int) isToLong(ipAddress));
                }
            }
        );
    }
}

资料

Xposed原理初探

一、Xposed 框架实现 Hook 的原理介绍
Zygote是Android的核心,每运行一个app,Zygote就会fork一个虚拟机实例来运行app,
Xposed Framework深入到了Android核心机制中,通过改造Zygote来实现一些很牛逼的
功能。Zygote的启动配置在init.rc 脚本中,由系统启动的时候开启此进程,对应的
执行文件是/system/bin/app_process,这个文件完成类库加载及一些函数调用的工作。
当系统中安装了Xposed Framework之后,会对app_process进行扩展,也就是说,Xposed
Framework 会拿自己实现的app_process覆盖掉Android原生提供的app_process文件,
当系统启动的时候,就会加载由 Xposed Framework 替换过的进程文件,并且,Xposed
Framework 还定义了一个 jar 包,系统启动的时候,也会加载这个包:
/data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar

二、Xposed框架运行的条件
1.Rooted Device / Emulator (已root的手机或者模拟器)
2.Xposed Installer (Xposed安装程序下载)
3.Hooking Android App (要被Hook的目标 App)

Xposed Framework就是一个apk包也就是上面下载的Xposed安装程序,下载后用下面
的命令安装到手机上或者模拟器:
adb install de.robv.android.xposed.installer_v32_de4f0d.apk

app
framework
C++
linux内核

linux内核 --> init --> app_process --> Zygote

Zygote进程在启动过程中,除了创建一个Dalvik虚拟机实例之外,还会将Java运行时库
加载到进程中来,同时还会注册一些Android核心类的JNI方法到前面创建的Dalvik虚拟
机实例中去。

一个应用程序被孵化出来的时候,其不仅会获得Zygote进程中的Dalvik虚拟机实例,还
会与Zygote一起共享Java运行时库,这也是可以将XposedBridge.jar这个jar包加载到
每一个Android应用中的原因。

Xposed_zygote进程启动后会初始化一些so文件(/system/lib、/system/lib64),然后
进入XposedBridge.jar中的XposedBridge.main中加载模块,初始化jar包完成对一些关键
Android系统函数的hook。

Hook则是利用修改过的虚拟机将函数注册为native函数。
然后再返回zygote中完成原本zygote需要做的工作。

META-INF/ 里面有文件配置脚本 flash-script.sh 配置各个文件安装位置。
system/bin/ 替换zygote进程等文件
system/framework/XposedBridge.jar jar包位置
system/lib system/lib64 一些so文件所在位置
xposed.prop xposed版本说明文件

Android
https://developer.android.google.cn/

SDK刷机包下载
x86:https://dl-xda.xposed.info/framework/
x86_64:https://github.com/youling257/XposedTools/files/1931996/xposed-x86_64.zip

VirtualApp
https://github.com/asLody/VirtualApp

Android Hook技术防范漫谈
https://tech.meituan.com/android_anti_hooking.html

XPOSED魔改一
https://bbs.pediy.com/thread-258639.htm

企业壳反调试及hook检测分析
https://mp.weixin.qq.com/s/StnqWtZMFCu09snIEGi1RQ

破解某支付软件防Xposed等框架Hook功能检测机制
https://mp.weixin.qq.com/s/Je1kRksxHTTYb4l9x3bTmQ

阿里系产品Xposed Hook检测机制原理分析
https://bbs.pediy.com/thread-218848.htm

抖音短视频检测 Xposed 分析(一)
https://www.52pojie.cn/thread-684757-1-1.html

抖音短视频检测 Xposed 分析(二)
https://www.52pojie.cn/thread-691584-1-1.html

你可能感兴趣的:(Xposed)