Xposed-Hook

news2025/1/31 22:32:02

配置 Xposed 模块的 AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="your.package.name">

    <application
        android:label="Your Xposed Module Name"
        android:icon="@mipmap/ic_launcher">

        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        
        <meta-data
            android:name="xposeddescription"
            android:value="这是一个用于监控字符串操作的 Xposed 模块" />
            
        <meta-data
            android:name="xposedminversion"
            android:value="53" />
            
        <meta-data
            android:name="xposedscope"
            android:resource="@array/xposed_scope" />
            
    </application>
</manifest>

在app/src/main/assets创建一个xposed_init文件 。

xposed_init 文件是 Xposed 模块必需的一个配置文件,它用来指定模块的入口类。这个文件需要包含你的 Xposed 模块的主类的完整类名(包含包名):

your.package.name.MainHook

app/build.gradle配置一下:

dependencies {
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.9.0'
    
    // Xposed Framework API
    compileOnly 'de.robv.android.xposed:api:82'
    compileOnly 'de.robv.android.xposed:api:82:sources'
    
    // 如果需要使用 LSPosed API(可选)
    // compileOnly 'org.lsposed.hiddenapibypass:hiddenapibypass:4.3'
}

LoadPackageParam (简称 lpparam) 是 Xposed 框架中的一个重要参数类,它包含了被加载的应用程序的相关信息。

LoadPackageParam 是 XC_LoadPackage 的一个内部类,以下是它的所有成员变量:

public static final class LoadPackageParam extends XCallback.Param {
    /** 应用的包名 */
    public String packageName;

    /** 进程的名称 */
    public String processName;

    /** 应用的 ClassLoader */
    public ClassLoader classLoader;

    /** 应用的 Application 对象 */
    public ApplicationInfo appInfo;

    /** 是否是第一次加载 */
    public boolean isFirstApplication;

    /** 系统服务的进程名(如果是系统服务) */
    public String[] initiatingPackages;

    /** 系统服务的进程名(如果是系统服务) */
    public String initiatingPackage;
}
   // 获取当前加载的应用包名
   String pkgName = lpparam.packageName;
   // 例如: "com.android.chrome"
   // 获取当前进程名
   String procName = lpparam.processName;
   // 可能是: "com.android.chrome"
   // 或者: "com.android.chrome:sandbox"

类加载器

  • 它负责找到并加载你需要的工具(类)

       // 相当于说"帮我找到这个工具"

       Class<?> targetClass = lpparam.classLoader.loadClass("com.example.Target");

       

       // 找到后就可以使用这个类了

       XposedHelpers.findAndHookMethod(targetClass, "方法名", ...);

   // 获取应用的类加载器
   ClassLoader loader = lpparam.classLoader;
   // 用于加载目标应用中的类
   Class<?> targetClass = loader.loadClass("com.example.Target");
   // 获取应用的信息
   ApplicationInfo info = lpparam.appInfo;
   // 可以获取很多应用相关信息
   String sourceDir = info.sourceDir;        // APK 路径
   String nativeLibDir = info.nativeLibraryDir;  // native库路径
   int targetSdkVersion = info.targetSdkVersion; // 目标SDK版本

XposedHelpers

查找和 Hook 方法

// 1. 基本的方法 Hook
XposedHelpers.findAndHookMethod(
    "com.example.Class",  // 类名
    lpparam.classLoader,  // 类加载器
    "methodName",        // 方法名
    String.class,        // 参数类型1
    int.class,           // 参数类型2
    new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) {
            // 方法执行前的处理
        }
        
        @Override
        protected void afterHookedMethod(MethodHookParam param) {
            // 方法执行后的处理
        }
    }
);

// 2. Hook 构造方法
XposedHelpers.findAndHookConstructor(
    targetClass,         // 类
    String.class,        // 参数类型
    new XC_MethodHook() { ... }
);

获取/设置字段值

// 获取字段值
Object fieldValue = XposedHelpers.getObjectField(object, "fieldName");
int intValue = XposedHelpers.getIntField(object, "fieldName");
String stringValue = XposedHelpers.getStaticObjectField(class, "fieldName");

// 设置字段值
XposedHelpers.setObjectField(object, "fieldName", newValue);
XposedHelpers.setIntField(object, "fieldName", 123);
XposedHelpers.setStaticObjectField(class, "fieldName", newValue);

调用方法

// 调用实例方法
Object result = XposedHelpers.callMethod(object, "methodName", arg1, arg2);

// 调用静态方法
Object result = XposedHelpers.callStaticMethod(class, "methodName", arg1, arg2);

创建新实例

// 创建对象实例
Object newInstance = XposedHelpers.newInstance(class);
Object newInstance = XposedHelpers.newInstance(class, "构造参数1", "构造参数2");

查找类

// 查找类
Class<?> class = XposedHelpers.findClass("com.example.Class", lpparam.classLoader);

Hook Api


GravityBox

GravityBox 是一个非常著名的 Xposed 模块,它是一个系统级的调整工具箱。

  • 更改赋予 Android 终端硬件按钮的功能

  • 修改状态栏的外观和显示的选项

  • 改变可以在手机或平板电脑屏幕上显示的亮度(这个是积极的,尤其是最小的,以节省电池)

  • 直接应用程序分配给设备的触摸按钮

  • 管理终端 RAM 的使用,了解此应用程序的消耗

Xposed Hook


  • choose: 查找某个类的所有实例对象
  • enumerateClassLoaders: 查找所有的类加载器

Java.choose() 和 Java.enumerateClassLoaders() 是 Frida 中两个不同的 API,它们的用途不同:

// 用于查找指定类的所有实例
Java.choose("com.example.TargetClass", {
    onMatch: function(instance) {
        // 每找到一个实例就会调用一次
        console.log("找到实例:", instance);
        console.log("实例字段值:", instance.fieldName);
    },
    onComplete: function() {
        // 搜索完成时调用
        console.log("搜索完成");
    }
});

// 用于列举所有的类加载器
Java.enumerateClassLoaders({
    onMatch: function(loader) {
        // 每找到一个类加载器就会调用一次
        console.log("类加载器:", loader);
        
        // 可以尝试用这个加载器加载类
        try {
            loader.loadClass("com.example.TargetClass");
            console.log("这个加载器可以加载目标类");
        } catch(e) {
            console.log("这个加载器无法加载目标类");
        }
    },
    onComplete: function() {
        console.log("搜索完成");
    }
});

主要区别:

  • choose: 查找某个类的所有实例对象
  • enumerateClassLoaders: 查找所有的类加载器

简单说:

  • 想找对象用 choose
  • 想找类加载器用 enumerateClassLoaders
// 1. 最简单的使用方式
Java.perform(function() {
    // 获取默认的类加载器
    var targetClass = Java.use("com.example.TargetClass");
});

// 2. 当默认加载器找不到类时,可以遍历所有"图书管理员"
Java.enumerateClassLoaders({
    onMatch: function(loader) {
        try {
            // 让每个"管理员"都尝试找这本"书"
            loader.loadClass("com.example.TargetClass");
            console.log("找到了!这个管理员可以找到这本书");
        } catch(e) {
            console.log("这个管理员找不到这本书");
        }
    }
});

让我用更简单的方式解释 IXposedHookLoadPackage:

想象你是一个保安,站在商场门口:

  • 每当有人(应用)要进商场时,你都会被通知
  • 你可以检查他们的身份(包名),决定要不要对他们做什么
// 你就是这个保安
public class MainHook implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
        // 1. 检查是不是你要找的人
        if (lpparam.packageName.equals("com.taobao.qianniu")) {
            // 是千牛应用
            XposedBridge.log("发现千牛启动了!");
            
            // 2. 对这个应用做一些事
            // 比如:监控它的某个方法
            XposedHelpers.findAndHookMethod(
                "com.taobao.qianniu.MainActivity",  // 类名
                lpparam.classLoader,                // 类加载器
                "onCreate",                         // 方法名
                Bundle.class,                       // 参数类型
                new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) {
                        XposedBridge.log("千牛正在启动...");
                    }
                }
            );
        }
    }
}

handleLoadPackage 是 IXposedHookLoadPackage 接口中唯一需要实现的方法。它的作用是:

public class MainHook implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
        // 这个方法会在每个应用启动时被调用
        
        // 1. 可以获取应用的包名
        String packageName = lpparam.packageName;
        
        // 2. 可以获取应用的类加载器
        ClassLoader classLoader = lpparam.classLoader;
        
        // 3. 实际使用示例
        if (packageName.equals("com.taobao.qianniu")) {
            // 找到目标应用后,就可以开始 Hook 了
            XposedBridge.log("找到千牛了!");
            
            // Hook 示例
            XposedHelpers.findAndHookMethod(
                "目标类名",
                classLoader,
                "方法名",
                new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) {
                        // 方法执行前的处理
                    }
                }
            );
        }
    }
}

// Xposed 模块中使用 XposedBridge.log

XposedBridge.log("发现目标应用:" + TARGET_PACKAGE);  // 这是 Java 代码

// Frida 脚本中使用 console.log

console.log("发现目标应用:" + TARGET_PACKAGE);  // 这是 JavaScript 代码

XC_MethodHook 是 Xposed 框架中用来 Hook 方法的核心类。它让你可以在方法执行前后添加自己的代码。

XposedHelpers 最常用的方法


// 1. Hook 相关
XposedHelpers.findAndHookMethod(    // Hook 实例方法
    className,      // 类名
    classLoader,    // 类加载器
    methodName,     // 方法名
    parameterTypes, // 参数类型
    callback        // 回调
);

XposedHelpers.findAndHookConstructor(  // Hook 构造方法
    className,
    classLoader,
    parameterTypes,
    callback
);

// 2. 查找类
Class<?> cls = XposedHelpers.findClass(
    "com.example.TargetClass",
    classLoader
);

// 3. 调用方法
// 调用实例方法
Object result = XposedHelpers.callMethod(
    object,        // 对象
    "methodName",  // 方法名
    params         // 参数
);

// 调用静态方法
Object result = XposedHelpers.callStaticMethod(
    className,     // 类名
    "methodName",  // 方法名
    params         // 参数
);

// 4. 获取/设置字段
// 获取实例字段
Object value = XposedHelpers.getObjectField(
    object,        // 对象
    "fieldName"    // 字段名
);

// 获取静态字段
Object value = XposedHelpers.getStaticObjectField(
    className,     // 类名
    "fieldName"    // 字段名
);

// 设置实例字段
XposedHelpers.setObjectField(
    object,        // 对象
    "fieldName",   // 字段名
    newValue       // 新值
);

// 设置静态字段
XposedHelpers.setStaticObjectField(
    className,     // 类名
    "fieldName",   // 字段名
    newValue       // 新值
);

// 5. 创建新实例
Object newObj = XposedHelpers.newInstance(
    className,     // 类名
    params         // 构造参数
);

setAccessible 是 Java 反射中用来绕过访问限制的方法。它可以让你访问私有成员:

// 1. 基本用法
Field field = targetClass.getDeclaredField("privateField");
field.setAccessible(true);  // 允许访问私有字段
Object value = field.get(object);  // 现在可以访问了

// 2. 实际例子
try {
    // 获取私有方法
    Method method = targetClass.getDeclaredMethod("privateMethod");
    method.setAccessible(true);  // 设置可访问
    method.invoke(object);  // 调用私有方法

    // 获取私有字段
    Field field = targetClass.getDeclaredField("privateField");
    field.setAccessible(true);  // 设置可访问
    field.set(object, newValue);  // 修改私有字段值
} catch (Exception e) {
    XposedBridge.log("访问失败: " + e);
}

  • Java.use().$new(): 创建新的 Java 对象
  • Java.cast(): 转换对象类型
  • Java.choose(): 查找已存在的对象实例

$new() 里面的参数对应 Java 类的构造函数参数。让我用具体例子说明:

Java.perform(function() {
    // 1. 无参数构造函数
    var StringBuilder = Java.use("java.lang.StringBuilder");
    var sb1 = StringBuilder.$new();  // 等同于 new StringBuilder()
    
    // 2. 带参数构造函数
    var sb2 = StringBuilder.$new("Hello");  // 等同于 new StringBuilder("Hello")
    
    // 3. String 类例子
    var String = Java.use("java.lang.String");
    var str1 = String.$new();  // new String()
    var str2 = String.$new("Hello");  // new String("Hello")
    
    // 4. 自定义类例子
    var MyClass = Java.use("com.example.MyClass");
    // 如果 MyClass 构造函数需要两个参数:String 和 int
    var myObj = MyClass.$new("参数1", 123);  // new MyClass("参数1", 123)
});

下面是Java.cast(): 转换对象类型:

  • View 就像是一个"容器"
  • 通过 cast 告诉系统:"这个容器其实是个按钮"
  • 转换后就可以用按钮特有的功能了
Java.perform(function() {
    // 1. 找到一个普通的 View
    Java.choose("com.example.MainActivity", {
        onMatch: function(activity) {
            // findViewById 返回的是 View 类型
            var view = activity.findViewById(123);  // 这时候只能用 View 的方法
            
            // 把 View 转成 Button
            var button = Java.cast(view, Java.use("android.widget.Button"));
            
            // 现在可以用 Button 特有的方法了
            button.setText("点击我");     // 设置按钮文字
            button.setEnabled(true);    // 设置按钮可点击
            button.setOnClickListener(/* ... */);  // 设置点击事件
        }
    });
});
// TextView 转换
var textView = Java.cast(view, Java.use("android.widget.TextView"));
textView.setText("这是文本");

// ImageView 转换
var imageView = Java.cast(view, Java.use("android.widget.ImageView"));
imageView.setImageResource(R.drawable.icon);

// EditText 转换
var editText = Java.cast(view, Java.use("android.widget.EditText"));
editText.setHint("请输入...");

主要区别:

  • $new() 是 Frida (JavaScript) 的方法
  • newInstance 是 Xposed (Java) 的方法
  • 功能是一样的,都是创建新对象

简单说:

  • 在 Frida 脚本中用 $new()
  • 在 Xposed 模块中用 newInstance

Frida 的 $new()

Java.perform(function() {
    // Frida 方式创建对象
    var String = Java.use("java.lang.String");
    var str = String.$new("Hello");  // 创建字符串
    
    var ArrayList = Java.use("java.util.ArrayList");
    var list = ArrayList.$new();  // 创建列表
});

Xposed 的 newInstance

// Xposed 方式创建对象
String str = (String) XposedHelpers.newInstance(
    String.class,  // 类
    "Hello"       // 参数
);

ArrayList list = (ArrayList) XposedHelpers.newInstance(
    ArrayList.class  // 类
);

简单说就是三步:

  • 找到类 (findClass)
  • 创建实例 (newInstance)
  • 调用方法 (callMethod)
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
    // 1. 首先查找类
    Class<?> targetClass = XposedHelpers.findClass(
        "com.example.TargetClass",  // 类名
        lpparam.classLoader         // 类加载器
    );
    
    // 2. 创建类的实例
    Object instance = XposedHelpers.newInstance(targetClass);
    // 如果构造函数有参数
    // Object instance = XposedHelpers.newInstance(targetClass, "参数1", 123);
    
    // 3. 调用实例的方法
    XposedHelpers.callMethod(
        instance,       // 实例对象
        "methodName",   // 方法名
        "参数1",        // 方法参数
        123            // 更多参数
    );
}

NanoHTTPD


NanoHTTPD 是一个轻量级的 HTTP 服务器库。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2288076.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【PyTorch】6.张量形状操作:在深度学习的 “魔方” 里,玩转张量形状

目录 1. reshape 函数的用法 2. transpose 和 permute 函数的使用 4. squeeze 和 unsqueeze 函数的用法 5. 小节 个人主页&#xff1a;Icomi 专栏地址&#xff1a;PyTorch入门 在深度学习蓬勃发展的当下&#xff0c;PyTorch 是不可或缺的工具。它作为强大的深度学习框架&am…

实现基础的shell程序

1. 实现一个基础的 shell 程序&#xff0c;主要完成两个命令的功能 cp 和 ls 1.1.1. cp 命令主要实现&#xff1a; ⽂件复制⽬录复制 1.1.2. ls 命令主要实现&#xff1a; ls -l 命令的功能 1.1. 在框架设计上&#xff0c;采⽤模块化设计思想&#xff0c;并具备⼀定的可扩…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.18 逻辑运算引擎:数组条件判断的智能法则

1.18 逻辑运算引擎&#xff1a;数组条件判断的智能法则 1.18.1 目录 #mermaid-svg-QAFjJvNdJ5P4IVbV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QAFjJvNdJ5P4IVbV .error-icon{fill:#552222;}#mermaid-svg-QAF…

知识库管理系统助力企业实现知识共享与创新价值的转型之道

内容概要 知识库管理系统&#xff08;KMS&#xff09;作为现代企业知识管理的重要组成部分&#xff0c;其定义涵盖了系统化捕捉、存储、共享和应用知识的过程。这类系统通过集成各种信息来源&#xff0c;不仅为员工提供了一个集中式的知识平台&#xff0c;还以其结构化的方式提…

SpringBoot 日志与配置文件

SpringBoot 配置文件格式 Properties 格式 Component ConfigurationProperties(prefix "person") //和配置文件person前缀的所有配置进行绑定 Data public class Person {private String name;private Integer age;private Date birthDay;private Boolean like;pr…

Qt中Widget及其子类的相对位置移动

Qt中Widget及其子类的相对位置移动 最后更新日期&#xff1a;2025.01.25 下面让我们开始今天的主题… 一、开启篇 提出问题&#xff1a;请看上图&#xff0c;我们想要实现的效果是控件黄色的Widge&#xff08;m_infobarWidget&#xff09;t随着可视化窗口&#xff08;m_glWidge…

【Node.js】Koa2 整合接口文档

部分学习来源&#xff1a;https://blog.csdn.net/qq_38734862/article/details/107715579 依赖 // koa2-swagger-ui UI视图组件 swagger-jsdoc 识别写的 /***/ 转 json npm install koa2-swagger-ui swagger-jsdoc --save配置 config\swaggerConfig.js const Router requir…

Docker/K8S

文章目录 项目地址一、Docker1.1 创建一个Node服务image1.2 volume1.3 网络1.4 docker compose 二、K8S2.1 集群组成2.2 Pod1. 如何使用Pod(1) 运行一个pod(2) 运行多个pod 2.3 pod的生命周期2.4 pod中的容器1. 容器的生命周期2. 生命周期的回调3. 容器重启策略4. 自定义容器启…

leetcode——排序链表(java)

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示例 3&#xff1a; …

基于springboot的校园部门资料管理系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业多年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…

数据结构初阶之堆的介绍与堆的实现

一、堆的概念与结构 如果有一个关键码的集合&#xff0c;把它的所有元素按完全二叉树的顺序存储在一个一维数组中&#xff0c;并满足&#xff1a;&#xff0c;则称为小堆&#xff08;或大堆&#xff09;。 将根结点最大的堆叫做最大堆或大根堆&#xff0c;根结点最小的堆叫做…

Day29(补)-【AI思考】-精准突围策略——从“时间贫困“到“效率自由“的逆袭方案

文章目录 精准突围策略——从"时间贫困"到"效率自由"的逆袭方案**第一步&#xff1a;目标熵减工程&#xff08;建立四维坐标&#xff09;** 与其他学习方法的结合**第二步&#xff1a;清华方法本土化移植** 与其他工具对比**~~第三步&#xff1a;游戏化改造…

docker中运行的MySQL怎么修改密码

1&#xff0c;进入MySQL容器 docker exec -it 容器名 bash 我运行了 docker ps命令查看。正在运行的容器名称。可以看到MySQL的我起名为db docker exec -it db bash 这样就成功的进入到容器中了。 2&#xff0c;登录MySQL中 mysql -u 用户名 -p 回车 密码 mysql -u root -p roo…

leetcode——二叉树的中序遍历(java)

给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[] 示例 3&#xff1a; 输入&#xff1a;root [1] 输出…

信息安全专业优秀毕业设计选题汇总:热点选题

目录 前言 毕设选题 开题指导建议 更多精选选题 选题帮助 最后 前言 大家好,这里是海浪学长毕设专题! 大四是整个大学期间最忙碌的时光&#xff0c;一边要忙着准备考研、考公、考教资或者实习为毕业后面临的升学就业做准备,一边要为毕业设计耗费大量精力。学长给大家整理…

Java---猜数字游戏

本篇文章所实现的是Java经典的猜数字游戏 , 运用简单代码来实现基本功能 目录 一.题目要求 二.游戏准备 三.代码实现 一.题目要求 随机生成一个1-100之间的整数(可以自己设置区间&#xff09;&#xff0c;提示用户猜测&#xff0c;猜大提示"猜大了"&#xff0c;…

SAP系统中的主要采购类型/采购模式总结

在 SAP 系统中,采购类型主要有以下几种: 一、标准采购订单(Standard Purchase Order) 描述:这是最常用的采购类型,用于一次性采购货物或服务。采购部门根据需求部门提出的采购申请,向供应商发出采购订单,明确规定了采购的物料、数量、价格、交货日期等详细信息。 应…

论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(五)

Understanding Diffusion Models: A Unified Perspective&#xff08;五&#xff09; 文章概括基于得分的生成模型&#xff08;Score-based Generative Models&#xff09; 文章概括 引用&#xff1a; article{luo2022understanding,title{Understanding diffusion models: A…

ThinkPHP 8模型与数据的插入、更新、删除

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用VS Code开发ThinkPHP项目-CSDN博客 编程与应用开…

项目升级Sass版本或升级Element Plus版本遇到的问题

项目升级Sass版本或升级Element Plus版本遇到的问题 如果项目有需求需要用到高版本的Element Plus组件&#xff0c;则需要升级相对应的sass版本&#xff0c;Element 文档中有提示&#xff0c;2.8.5及以后得版本&#xff0c;sass最低支持的版本为1.79.0&#xff0c;所升级sass、…