精华内容
下载资源
问答
  • xposed api-82

    2018-04-17 20:54:25
    xposed 开发必须的api 包含两个文件api-82.jar 和 api-82-source.jar
  • Xposed所需要使用的lib库,解压后,复制到Android Studio的module的libs目录下
  • xposed-api-82-sources

    2018-09-07 15:53:36
    xposed-api-82-sources resources 资源文件 和xposed-api-82放到同一个文件夹下
  • 今天学习android hook,需要使用到api-82.jar,然而论坛上大部分资源都要积分 程序员何必为难程序员 0积分资源奉上 欢迎下载!
  • xposed.apk && XposedBridgeApi-82.jar hook 工具
  • Xposed框架与XposedBridgeApi82.rar版本已对应。本人亲自过 使用Android studio 关联夜神模拟器
  • XposedBridgeApi-82

    2016-11-15 00:22:42
    支持andorid6.0.1以及以下系统,这个高版本jar下载资源太少,本人花了很大精力才弄到 网上较多的都是XposedBridgeApi-54,但是只能在4.0.3-4.4.4系统中使用,5.0以后就不支持了,所以感觉更新吧
  • xposed-54.zip

    2019-08-01 12:15:43
    xposed 54 jar 下载
  • Xposed辅助包

    2018-06-22 16:38:49
    Xposed的2个相关api的jar包..................................................
  • Xposed实例

    2017-12-15 16:39:55
    Xposed实例,含有 XposedBridgeApi-54.jar.使用海马玩模拟器,实测通过
  • xposed-v82-83-85 arm
  • Android 4.0.3 up to Android 4.4: 框架:de.robv.android.xposed.installer_v33_36570c.apk API:XposedBridgeApi-54.jar Android 5.0 or higher: 框架:XposedInstaller_3.0_alpha4....API:XposedBridgeApi-82.jar
  • [Android开发] Xposed 插件开发之一: Xposed入门

    万次阅读 多人点赞 2016-09-18 09:27:00
    它是一款特殊的安卓App,其主要功能是提供一个新的应用平台,玩家们安装Xposed框架后,就能够通过Xposed框架搭建起的平台安装更多系统级的应用,实现诸多神奇的功能。 Xposed框架的原理是修改系统文件,替换了/syst

    一、什么是Xposed

    Xposed Framework 为来自国外XDA论坛(forum.xda-developers.com)的rovo89自行开发的一个开源的安卓系统框架。

    它是一款特殊的安卓App,其主要功能是提供一个新的应用平台,玩家们安装Xposed框架后,就能够通过Xposed框架搭建起的平台安装更多系统级的应用,实现诸多神奇的功能。

    Xposed框架的原理是修改系统文件,替换了/system/bin/app_process可执行文件,在启动Zygote时加载额外的jar文件(/data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar),并执行一些初始化操作(执行XposedBridge的main方法)。然后我们就可以在这个Zygote上下文中进行某些hook操作。

    Github开源地址: https://github.com/rovo89/Xposed

    二、安装Xposed

    手机必须先Root,5.0以上通用安装方法(ps: V80仅支持Android 5.以上)


    1. 安装apk
    2. 在Recovery刷入对应的zip包

    ps: 必须了解自己当前系统的CPU版本和系统版本:
    sdkXX (XX 代表安卓系统版本,sdk21代表5.0系统,sdk22代表5.1系统,sdk23代表6.0系统)
    arm## (## 代表cpu版本,arm代表32位cpu ,arm64代表64位cpu)

    官方下载:
    http://forum.xda-developers.com/showthread.php?t=3034811

    网盘下载:
    http://pan.baidu.com/s/1bpxEMh5 密码:wm7a

    三、编写Xposed插件

    ide利用AndroidStudio

    先编写被劫持的测试app
    测试劫持一个app的方法,先写一个app,这个app很简单,点击按钮,显示天平。
    这里写图片描述

    1. 创建插件项目

    这里创建TestXposed一个

    2. 导入Xposed的api库

    方法1:
    Android Studio的依赖:

    repositories {
        jcenter();
    }
    
    dependencies {
        provided 'de.robv.android.xposed:api:82'
    }

    方法2: 下载jar包
    地址: https://bintray.com/rovo89/de.robv.android.xposed/api

    Download有两个jar包:
    api-82-sources.jar: 包含源码的
    api-82.jar: 不包含源码

    这里写图片描述

    下载api-82.jar,复制到Android Studio的module的libs目录下,右键Add as library
    这里写图片描述

    修改依赖方式compile files修改为providedfiles,原因是Xposed里已有该jar包内容,再次打包进去会冲突。

    dependencies {
        provided fileTree(include: ['*.jar'], dir: 'libs')
        testCompile 'junit:junit:4.12'
        compile 'com.android.support:appcompat-v7:24.2.1'
    }

    这里写图片描述
    ps: 上面那个修改很重要,不修改就会导致handleLoadPackage没有回调。

    3. 修改AndroidManifest.xml文件

    在Application标签里面加三个meta-data

    <!-- 是否是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" />

    这里写图片描述

    4. 编写hook类

    创建一个类,实现IXposedHookLoadPackage接口,重写handleLoadPackage方法,我这里创建了一个Main类。

    这里写图片描述

    这里写图片描述

    5. 创建xposed_init文件

    在main目录下创建assets目录,在assets目录下创建xposed_init文件,不要后缀名。这个就是模块的入口,只有一行代码,就是说明入口类

    这里写图片描述

    6.运行结果

    运作安装刚刚编写的插件,打开Xposed,勾选刚刚安装的插件。重启手机。
    打开测试程序,点击按钮就能发现文字不是天平了

    这里写图片描述

    ok,基本模型搭建成功。

    四、Xposed怎么样工作

    写完demo,梳理一下Xposed的工作过程:

    开机时, ./init.rc 脚本文件会启动 Zygote 进程,Zygote对应的具体程序是 /system/bin/app_process ,然后加载需要的类,调用初始化的方法,之后启动的每个应用都是Zygote的拷贝,所以Zygote进程是十分重要的.

    通过在类路径中添加一个jar包,在 app_process 的特定位置调用jar包中的方法,Xposed框架实现了带扩展功能的 app_process ,然后将原有的 app_process 替换掉.

    在 /data/data/de.robv.android.xposed.installer/bin/ 目录下有一个 XposedBridge.jar 文件,它就是被引用的jar包,源码在 github ,main函数在 /src/de/robv/android/xposed/XposedBridge.java 中,每个进程每次启动时都会被调用.加载模块的功能也是在这里实现.

    Xposed真正强大的是它可以hook调用的方法.当你反编译修改apk时,你可以在里面插入xposed的命令,于是你就可以在方法调用前后注入自己的代码.

    XposedBridge有一个私有的本地方法 hookMethodNative ,代码实现放在 app_process 中.在调用被hook的方法前会先调用此方法, hookMethodNative 有一个 handleHookedMethod 方法,可以修改传递给被hook函数的参数,变量甚至是调用其他方法.

    展开全文
  • Xposed模块开发

    千次阅读 2019-07-15 22:59:35
      最近突然看到了Xposed这一项技术,觉得蛮有意思的,现在的蚂蚁森林自动收能量以及微信自动回复等都是通过这个来实现的,因此记录一下Xposed的基本实现。 Xposed模块介绍   Xposed框架是一款开源框架,其功能是...

      最近突然看到了Xposed这一项技术,觉得蛮有意思的,现在的蚂蚁森林自动收能量以及微信自动回复等都是通过这个来实现的,因此记录一下Xposed的基本实现。

    Xposed框架介绍

    概述

      Xposed框架是一款开源框架,其功能是可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。Xposed 就好比是 Google 模块化手机的主体,只是一个框架的存在,在添加其他功能模块(Modules)之前,发挥不了什么作用,但是没了它也不行。也正因为如此,Xposed 具有比较高的可定制化程度。

    工作原理

      Xposed框架主要通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。与采取传统的Inhook方式相比,Xposed在开机的时候完成对所有的Hook Function的劫持,在原Function执行的前后加上自定义代码。
      为什么需要这么做呢?
      Android基于Linux,第一个启动的进程自然是init进程,该进程会启动所有Android进程的父进程——Zygote(孵化)进程,该进程的启动配置在 /init.rc脚本中,而Zygote进程对应的执行文件是/system/bin/app_process, 该文件完成类库的加载以及一些函数的调用工作。在Zygote进程创建后, 再fork出SystemServer进程和其他进程。Xposed Framework,就是用自己实现的app_process替换掉了系统原本 提供的app_process,加载一个额外的jar包,然后入口从原来的: com.android.internal.osZygoteInit.main()被替换成了: de.robv.android.xposed.XposedBridge.main(),
    然后创建的Zygote进程就变成Hook的Zygote进程了,而后面Fork出来的进程 也是被Hook过的。
      这个Jar包在: /data/data/de.rbov.android.xposed.installer/bin/XposedBridge.jar 目录下。
      通过原理我们可以看出,要使用Xposed框架,那么手机必须要拥有最高权限(就是root权限),当然现在还出现了VirtualXposed,这个框架的话就相当于给你的手机开了一个平行空间,这个空间和你的手机系统一样,就相当于一个副本,所以当你在这个空间使用xposed的话,就不需要root,但是在这个空间你需要重新安装你想修改的程序,因为它刚创建出来的时候是什么都没有的,也因此你在这个空间修改并不会影响到你的手机本来的应用,就相当于双开应用。
      值得注意的是,既然给出了最高权限,那么别人就可以做很多坏事了,比如获取你的账号密码,还有一些私密的文件,因此对于别人写的Xposed模块可以看看他是不是开源的再决定用不用,如果不是开源的,建议不要使用。当然如果不想承担这么大的风险又不嫌麻烦的话,可以使用上面介绍的virtualXposed框架。

    环境要求

    ConfigurationRequireMent
    硬件安卓手机或者模拟器
    软件PC:Android studio  手机:xposed框架app
    Root Access因为Xposed工作原理是在/system/bin目录下替换文件,在install的时候需要root权限,但是运行时不需要root权限。
    版本要求需要在Android 4.0以上版本的机器中

    Xposed资源梳理

    • XposedBridge.jar:XposedBridge.jar是Xposed提供的jar文件,负责在Native层与FrameWork层进行交互。/system/bin/app_process进程启动过程中会加载该jar包,其它的Modules的开发与运行都是基于该jar包的。
      注意:XposedBridge.jar文件本质上是由XposedBridge生成的APK文件更名而来。
    • Xposed:Xposed的C++部分,主要是用来替换/system/bin/app_process,并为XposedBridge提供JNI方法。
    • XposedInstaller:Xposed的安装包,负责配置Xposed工作的环境并且提供对基于Xposed框架的Modules的管理。在安装XposedInstaller之后,app_process与XposedBridge.jar放置在了/data/data/de.robv.android.xposed.installer。
    • XposedMods:使用Xposed开发的一些Modules,其中AppSettings是一个可以进行权限动态管理的应用

    Xposed模块实现例子

      从本质上来讲,Xposed 模块也是一个 Android 程序。但与普通程序不同的是,想要让写出的Android程序成为一个Xposed 模块,要额外多完成以下四个硬性任务:

    1. 让手机上的xposed框架知道我们安装的这个程序是个xposed模块。

    2. 模块里要包含有xposed的API的jar包,以实现下一步的hook操作。

    3. 这个模块里面要有对目标程序进行hook操作的方法。

    4. 要让手机上的xposed框架知道,我们编写的xposed模块中,哪一个方法是实现hook操作的。

    &emsp: 对应上面的四个步骤我们需要做的修改有:

    1. AndroidManifest.xml

    2. XposedBridgeApi-xx.jar 与 build.gradle

    3. 实现hook操作的具体代码

    4. xposed_Init

      按照上述顺序一个一个实现,就能完成我们的第一个Xposed模块编写:

    修改AndroidManifest.xml

      首先我们新建了一个空项目,然后在布局文件中定义了一个按钮,点击效果为Toast出文字“我未被劫持”。将其先安装到手机或者模拟器上。
      基于以上的项目,首先想要我们写的app能够被识别成一个xposed模块的话,我们需要修改AndroidManifest.xml文件,如下:

    在这里插入图片描述
      插入之后,把手机连上AndroidStudio ,点击“编译”或者“运行”的话,手机就会启动刚刚编写的这个程序。而在手机里的Xposed框架中也会显示出这个模块:
    在这里插入图片描述
      这说明Xposed框架已经认出了我们写的程序,但是现在这个模块什么都没有做,因为我们还没有做出修改。

    配置XposedBridgeApi-xx.jar 与 build.gradle

      从上面的工作原理可以看出来,实现一个xposed模块,那必须需要XposedBridgeApi-xx.jar这个jar包来提供修改的文件,因此这一步的关键是下载XposedBridgeApi-xx.jar包并且将其放到libs工程目录中,当然这是一种方法,不过在Android studio不用这么麻烦,因为Android studio可以通过修改build.gradle来将其集成进来,插入以下代码:

    repositories {
    
    jcenter()
    
    }
    
    以及
    
    compileOnly 'de.robv.android.xposed:api:82'
    
    compileOnly 'de.robv.android.xposed:api:82:sources'
    

      如下:
    在这里插入图片描述
      这句代码是告诉AndroidStuido使用jcenter作为代码仓库,从这个仓库里远程寻找 de.robv.android.xposed:api:82 这个API,我们不用自己找XposedBridgeApi.jar了。
      注意!此处要用compileOnly这个修饰符!网上有些写的是provide ,现在已经停用了!)

    实现hook操作修改

      在MainActivity的同级路径下新建一个类“HookTest.java”,代码如下:

    package com.example.root.xposd_hook_new;
    import de.robv.android.xposed.IXposedHookLoadPackage;
    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;
    
    public class HookTest implements IXposedHookLoadPackage {
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
          if (loadPackageParam.packageName.equals("com.example.root.xposd_hook_new")) {
              XposedBridge.log(" has Hooked!");
              Class clazz = loadPackageParam.classLoader.loadClass("com.example.root.xposd_hook_new.MainActivity");
              XposedHelpers.findAndHookMethod(clazz, "toastMessage", new XC_MethodHook() {
                  protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                  super.beforeHookedMethod(param);
               //XposedBridge.log(" has Hooked!");
              }
                  protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                  param.setResult("你已被劫持");
              }
         });
       }
      }
    }
    

      如图:
    在这里插入图片描述
      通过IXposedHookLoadPackage接口中的handleLoadPackage方法来实现Hook并篡改程序的输出结果的:

    • 代码中“com.example.root.xposd_hook_new ”是目标程序的包名;
    • ”com.example.root.xposd_hook_new.MainActivity” 是想要Hook的类;
    • “toastMessage”是想要Hook的方法。

      我们在afterHookedMethod方法(用来定义Hook了目标方法之后的操作)中,修改了toastMessage()方法的返回值为“你已被劫持”。

    xposed_init文件

      右键点击 “main ” 文件夹 , 选择new –> Folder –>Assets Folder,新建assets 文件夹:然后右键点击 assets文件夹, new–> file,文件名为xposed_init(文件类型选text),并在其中写上入口类的完整路径(就是自己编写的那一个Hook类),这样, Xposed框架就能够从这个 xposed_init 读取信息来找到模块的入口,然后进行Hook操作了,如图:
    在这里插入图片描述
      注意:最后选择禁用 Instant Run: 单击 File -> Settings -> Build, Execution, Deployment -> Instant Run,把勾全部去掉。因为如果勾选了Instant Run的话,
    在这里插入图片描述
      最后我们将程序运行到手机上,打开xposed框架,然后勾选我们创建的这个模块,重新打开应用,就会发现:
    在这里插入图片描述
      这说明我们的修改已经生效了,当然这只是最简单的对于Xposed模块的开发,举一反三,既然我们都可以修改一个应用的返回值,那么我们可以修改的东西可不止这么一些简单的东西,基于此,那么实现自动收能量、自动回复就都是可能的,当然还有一些数据的修改只需要将返回值修改不就实现了吗。
      在GitHub上这两个app源码可以向我们展示怎么hook类的变量、静态变量、公有方法、私有方法、静态方法、内部类、多复杂参数的方法、内部类的变量等。
      原始程序:https://github.com/Gordon0918/XposedHookTarget
      hook修改源程序地址:https://github.com/Gordon0918/XposedHook
      通过对比,就能发现上述这些是怎么被hook的。
      更深的了解以及实际应用的话可以看这篇帖子:https://www.jianshu.com/p/51dcc24900ba (技术文哦,当初看到这篇文章我才发现还有这么一个东西)。

    展开全文
  • Xposed

    2021-02-27 18:09:15
    xposed开发环境搭建 创建一个无Activity的项目,切换到Project视图,在app目录下创建一个lib目录 ...provided files('lib/api-82.jar') 修改AndroidManifest.xml <meta-data android:name="xposedmodule

    xposed开发环境搭建

    创建一个无Activity的项目,切换到Project视图,在app目录下创建一个lib目录
    在这里插入图片描述
    将xposed的jar添加到lib目录下,选中这个jar包,然后右击,将这个添加为库(编译的时候,不需要打包这个jar包)
    在build.gradle的dependencies中添加一行

    provided files('lib/api-82.jar')
    

    在这里插入图片描述
    修改AndroidManifest.xml

    <meta-data
        android:name="xposedmodule"
        android:value="true" />
    <meta-data
        android:name="xposeddescription"
        android:value="my name is xiaojianbang" />
    <meta-data
        android:name="xposedminversion"
        android:value="53" />
    

    在这里插入图片描述
    然后创建一个类Hook,输入内容

    public class Hook implements IXposedHookLoadPackage{
    
        // Xposed是一个全局的Hook
        // 如果对一个app进行过滤,需要 参数XC_LoadPackage.LoadPackageParam loadPackageParam进行判断
        @Override
        public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
            Log.d("showme","hook start...");
    
            if(!loadPackageParam.packageName.equals("com.xingin.xls")) return;
            
        }
    }
    

    在main目录下创建一个assets目录,创建一个文本文件 xposed_init
    指定入口类:在其中输入 Hook类的完整路径名(包名.类名)
    在这里插入图片描述
    点击Build
    在这里插入图片描述
    找到生成的apk,进行安装
    在这里插入图片描述
    安装好之后,激活模块,然后重启
    在这里插入图片描述

    hook构造函数

    ClassLoader classLoader = loadPackageParam.classLoader;
    Class StudentClass = classLoader.loadClass("com.showme.xposedhook01.Student");
    XposedHelpers.findAndHookConstructor(StudentClass, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            XposedBridge.log("com.showme.xposedhook01.Student() is called!!beforeHookedMethod");
        }
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            XposedBridge.log("com.showme.xposedhook01.Student() is called!!afterHookedMethod");
        }
    });
    
    
    XposedHelpers.findAndHookConstructor(StudentClass, String.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            java.lang.Object[] argsobjarray = param.args;
            String name = (String) argsobjarray[0];
            XposedBridge.log("com.showme.xposedhook01.Student(String) is called!!beforeHookedMethod--" + name);
        }
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            XposedBridge.log("com.showme.xposedhook01.Student(String) is called!!afterHookedMethod");
        }
    });
    
    
    XposedHelpers.findAndHookConstructor("com.showme.xposedhook01.Student", loadPackageParam.classLoader, String.class, String.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            java.lang.Object[] argsobjarray = param.args;
            String name = (String) argsobjarray[0];
            String id = (String) argsobjarray[1];
            XposedBridge.log("com.showme.xposedhook01.Student(String,String) is called!!beforeHookedMethod--" + name + "---" + id);
    
        }
    });
    
    
    ClassLoader pathClassLoader= loadPackageParam.classLoader;
    final Class stuClass=pathClassLoader.loadClass("com.showme.xposedhook01.Student");
    XposedHelpers.setStaticObjectField(stuClass,"teacher","teacher888");
    String teachername2= (String) XposedHelpers.getStaticObjectField(stuClass,"teacher");
    
    
    
    XposedHelpers.findAndHookConstructor(StudentClass, String.class, String.class, int.class,String.class,String.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            java.lang.Object[] argsobjarray = param.args;
            String name = (String) argsobjarray[0];
            String id = (String) argsobjarray[1];
            int age = (int) (argsobjarray[2]);
            argsobjarray[1] = "2050";
            argsobjarray[2] = 100;
    
            String teacher= (String) argsobjarray[3];
            String nickname= (String) argsobjarray[4];
    
            XposedBridge.log("com.showme.xposedhook01.Student(String,String) is called!!beforeHookedMethod--" + name + "---" + id + "--" + age+"---"+teacher+"---"+nickname);
        }
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
    
            Object thisobj = param.thisObject;
    
        /*       Field nicknameField=stuClass.getDeclaredField("nickname");
            XposedBridge.log(stuClass+"--nicknameField->"+nicknameField);
            nicknameField.setAccessible(true);
            nicknameField.set(thisobj,"bear");*/
    
            XposedHelpers.setObjectField(thisobj,"nickname","chick");
    
            Object returnobj = param.getResult();
            XposedBridge.log(thisobj + "---" + returnobj);
            XposedBridge.log("com.showme.xposedhook01.Student(String,String,int) is called!!afterHookedMethod");
        }
    });
    

    hook系统类,DexClassLoader,应用加载了哪些插件

    XposedHelpers.findAndHookConstructor(DexClassLoader.class, String.class, String.class, String.class, ClassLoader.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            Object array[]=param.args;
            String dexpath= (String) array[0];
            String optimizedDirectory= (String) array[1];
            String librarySearchPath= (String) array[2];
            XposedBridge.log("DexClassLoader beforeHookedMethod:"+dexpath+"---"+optimizedDirectory+"---"+librarySearchPath);
    
        }
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
    
            DexClassLoader dexClassLoader= (DexClassLoader) param.thisObject;
            XposedBridge.log("DexClassLoader afterHookedMethod:"+dexClassLoader);
        }
    });
    

    hook属性:使用java反射和Xposed的API

    ClassLoader classLoader = loadPackageParam.classLoader;
    Class StudentClass = classLoader.loadClass("com.showme.xposedhook.Student");
    
    // java反射
    Field teacherField=stuClass.getDeclaredField("teacher");
    teacherField.setAccessible(true);
    teacherField.set(null,"teacher666");
    String teachername1= (String) teacherField.get(null);
    XposedBridge.log("teacherField->"+teachername1);
    
    // Xposed中的实现和java反射一样,但是默认调用了 setAccessible(true);
    XposedHelpers.setStaticObjectField(stuClass,"teacher","teacher888");
    String teachername2= (String) XposedHelpers.getStaticObjectField(stuClass,"teacher");
    
    
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
    
        Object thisobj = param.thisObject;
        XposedHelpers.setObjectField(thisobj,"nickname","chick");
    
        Object returnobj = param.getResult();
        XposedBridge.log(thisobj + "---" + returnobj);
    }
    

    hook一般方法

    ClassLoader classLoader = loadPackageParam.classLoader;
    Class StuClass = classLoader.loadClass("com.showme.xposedhook01.Student");
    
    // 一般java函数的hook 
    XposedHelpers.findAndHookMethod("com.showme.xposedhook01.Student", loadPackageParam.classLoader, "privatefunc", String.class, int.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            Object[] objectarray = param.args;
            String arg0 = (String) objectarray[0];
            int arg1 = (int) objectarray[1];
            XposedBridge.log("beforeHookedMethod11 privatefunc->arg0:" + arg0 + "---arg1:" + arg1);
    
        }
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
    
            String result = (String) param.getResult();
            XposedBridge.log("afterHookedMethod11 privatefunc->result:" + result);
    
        }
    });
    
    // 内部类中的函数hook
    Class personClass = XposedHelpers.findClass("com.showme.xposedhook01.Student$person", loadPackageParam.classLoader);
    XposedHelpers.findAndHookMethod(personClass, "getpersonname", String.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            XposedBridge.log("beforeHookedMethod getpersonname->" + param.args[0]);
        }
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            XposedBridge.log("afterHookedMethod getpersonname->" + param.getResult());
        }
    });
    
    // 匿名内部类函数的hook - 匿名内部类总会有一个类名的,用那个类名就行了
    
    // 类中JNI函数的hook - 和普通函数一样
    

    主动调用函数

    // java 反射的方式
    ClassLoader classLoader = loadPackageParam.classLoader;
    Class StuClass = classLoader.loadClass("com.showme.xposedhook01.Student");
    Method publicstaticfunc_method = StuClass.getDeclaredMethod("publicstaticfunc", String.class, int.class);
    publicstaticfunc_method.invoke(null, "InvokedByXposed", 100);
    
    // Xposed 中的API
    //            public static java.lang.Object callMethod(java.lang.Object obj, java.lang.String methodName, java.lang.Object... args) { /* compiled code */ }
    //
    //            public static java.lang.Object callMethod(java.lang.Object obj, java.lang.String methodName, java.lang.Class<?>[] parameterTypes, java.lang.Object... args) { /* compiled code */ }
    //
    //            public static java.lang.Object callStaticMethod(java.lang.Class<?> clazz, java.lang.String methodName, java.lang.Object... args)
    //
    //            public static java.lang.Object callStaticMethod(java.lang.Class<?> clazz, java.lang.String methodName, java.lang.Class<?>[] parameterTypes, java.lang.Object... args)
    
    java.lang.Class<?>[] parameterTypes = {String.class, int.class};
    
    XposedHelpers.callStaticMethod(StuClass, "publicstaticfunc", parameterTypes, "publicstaticfunc is called by XposedHelpers.callStaticMethod11", 100);
    XposedHelpers.callStaticMethod(StuClass, "publicstaticfunc", "publicstaticfunc is called by XposedHelpers.callStaticMethod22", 200);
    
    XposedHelpers.callStaticMethod(StuClass, "privatestaticfunc", parameterTypes, "privatestaticfunc is called by XposedHelpers.callStaticMethod11", 400);
    XposedHelpers.callStaticMethod(StuClass, "privatestaticfunc", "privatestaticfunc is called by XposedHelpers.callStaticMethod22", 300);
    
    
    Method privatestaticfunc_method = StuClass.getDeclaredMethod("privatestaticfunc", String.class, int.class);
    privatestaticfunc_method.setAccessible(true);
    String result = (String) privatestaticfunc_method.invoke(null, "privatestaticfuncIsInvokedByXposed", 200);
    
    
    //            public static java.lang.Object callMethod(java.lang.Object obj, java.lang.String methodName, java.lang.Object... args) { /* compiled code */ }
    //
    //            public static java.lang.Object callMethod(java.lang.Object obj, java.lang.String methodName, java.lang.Class<?>[] parameterTypes, java.lang.Object... args) { /* compiled code */ }
    
    //            public static java.lang.Object newInstance(java.lang.Class<?> clazz, java.lang.Object... args) { /* compiled code */ }
    //
    //            public static java.lang.Object newInstance(java.lang.Class<?> clazz, java.lang.Class<?>[] parameterTypes, java.lang.Object... args) { /* compiled code */ }
    
    
    Object StuObjByXposed = XposedHelpers.newInstance(StuClass, "StuObjByXposed.newInstance", "500");
    String result1 = (String) XposedHelpers.callMethod(StuObjByXposed, "publicfunc", "publicfunc is called by XposedHelpers.callMethod", 125);
    XposedBridge.log("publicfunc XposedHelpers.callMethod result->" + result1);
    
    XposedHelpers.callMethod(StuObjByXposed, "privatefunc", "privatefunc is called by XposedHelpers.callMethod", 130);
    
    
    
    
    //Student cstudent = new Student("xiaohua", "2020");
    XposedHelpers.findAndHookConstructor(StuClass, String.class, String.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            XposedBridge.log("Student(String,String) is called beforeHookedMethod");
        }
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            XposedBridge.log("Student(String,String) is called afterHookedMethod");
            Object cstudent=param.thisObject;
            XposedHelpers.callMethod(cstudent,"publicfunc","publicfunc is called XposedHelpers.findAndHookConstructor",666);
            XposedHelpers.callMethod(cstudent,"privatefunc","privatefunc is called XposedHelpers.findAndHookConstructor",888);
        }
    });
    
    
    //            public String getNickname() {
    //                return nickname;
    //            }
    
    XposedHelpers.findAndHookMethod(StuClass, "getNickname", new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            Object obj=param.thisObject;
            XposedHelpers.callMethod(obj,"publicfunc","beforeHookedMethod publicfunc is called XposedHelpers.callMethod",444);
            XposedHelpers.callMethod(obj,"privatefunc","beforeHookedMethod privatefunc is called XposedHelpers.callMethod",333);
    
            XposedBridge.log("getNickname is called beforeHookedMethod->"+obj);
        }
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            Object obj=param.thisObject;
            XposedHelpers.callMethod(obj,"publicfunc","afterHookedMethod publicfunc is called XposedHelpers.callMethod",222);
            XposedHelpers.callMethod(obj,"privatefunc","afterHookedMethod privatefunc is called XposedHelpers.callMethod",111);
    
            XposedBridge.log("getNickname is called afterHookedMethod->"+param.thisObject);
        }
    });
    

    加壳APP处理

    /*
    1、对于有壳的apk,Xposed首先拿到的是壳的classloader
    2、壳一般在,壳代码的OnCreate修成classloader
    */
    public class HookShellApk implements IXposedHookLoadPackage {
    
        public static Field getClassField(ClassLoader classloader, String class_name,
                                          String filedName) {
    
            try {
                Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name);
                Field field = obj_class.getDeclaredField(filedName);
                field.setAccessible(true);
                return field;
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
    
        }
    
        public static Object getClassFieldObject(ClassLoader classloader, String class_name, Object obj,
                                                 String filedName) {
    
            try {
                Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name);
                Field field = obj_class.getDeclaredField(filedName);
                field.setAccessible(true);
                Object result = null;
                result = field.get(obj);
                return result;
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
    
        }
    
        public static Object invokeStaticMethod(String class_name,
                                                String method_name, Class[] pareTyple, Object[] pareVaules) {
    
            try {
                Class obj_class = Class.forName(class_name);
                Method method = obj_class.getMethod(method_name, pareTyple);
                return method.invoke(null, pareVaules);
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return null;
    
        }
    
        public static Object getFieldOjbect(String class_name, Object obj,
                                            String filedName) {
            try {
                Class obj_class = Class.forName(class_name);
                Field field = obj_class.getDeclaredField(filedName);
                field.setAccessible(true);
                return field.get(obj);
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NullPointerException e) {
                e.printStackTrace();
            }
            return null;
    
        }
    
        public static ClassLoader getClassloader() {
            ClassLoader resultClassloader = null;
            Object currentActivityThread = invokeStaticMethod(
                    "android.app.ActivityThread", "currentActivityThread",
                    new Class[]{}, new Object[]{});
            Object mBoundApplication = getFieldOjbect(
                    "android.app.ActivityThread", currentActivityThread,
                    "mBoundApplication");
            Application mInitialApplication = (Application) getFieldOjbect("android.app.ActivityThread",
                    currentActivityThread, "mInitialApplication");
            Object loadedApkInfo = getFieldOjbect(
                    "android.app.ActivityThread$AppBindData",
                    mBoundApplication, "info");
            Application mApplication = (Application) getFieldOjbect("android.app.LoadedApk", loadedApkInfo, "mApplication");
            resultClassloader = mApplication.getClassLoader();
            return resultClassloader;
        }
    
        public void GetClassLoaderClasslist(ClassLoader classLoader) {
            //private final DexPathList pathList;
            //public static java.lang.Object getObjectField(java.lang.Object obj, java.lang.String fieldName)
            XposedBridge.log("start dealwith classloader:" + classLoader);
            Object pathListObj = XposedHelpers.getObjectField(classLoader, "pathList");
            //private final Element[] dexElements;
            Object[] dexElementsObj = (Object[]) XposedHelpers.getObjectField(pathListObj, "dexElements");
            for (Object i : dexElementsObj) {
                //private final DexFile dexFile;
                Object dexFileObj = XposedHelpers.getObjectField(i, "dexFile");
                //private Object mCookie;
                Object mCookieObj = XposedHelpers.getObjectField(dexFileObj, "mCookie");
                //private static native String[] getClassNameList(Object cookie);
                //    public static java.lang.Object callStaticMethod(java.lang.Class<?> clazz, java.lang.String methodName, java.lang.Object... args) { /* compiled code */ }
                Class DexFileClass = XposedHelpers.findClass("dalvik.system.DexFile", classLoader);
    
                String[] classlist = (String[]) XposedHelpers.callStaticMethod(DexFileClass, "getClassNameList", mCookieObj);
                for (String classname : classlist) {
                    XposedBridge.log(dexFileObj + "---" + classname);
                }
            }
            XposedBridge.log("end dealwith classloader:" + classLoader);
    
        }
    
        @Override
        public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
            Log.i("Xposed01", loadPackageParam.packageName);
            XposedBridge.log("HookLebo->app packagename" + loadPackageParam.packageName);
            if (loadPackageParam.packageName.equals("com.test.abc")) {
                XposedBridge.log("showme " + loadPackageParam.packageName);
                Class StubAppClass=XposedHelpers.findClass("com.test.abc.MyWrapperProxyApplication",loadPackageParam.classLoader);
                Method[] methods=StubAppClass.getDeclaredMethods();
                for(Method i:methods){
                    XposedBridge.log("com.test.abc.MyWrapperProxyApplication->"+i);
                }
                XposedHelpers.findAndHookMethod("com.test.abc.MyWrapperProxyApplication", loadPackageParam.classLoader, "onCreate", new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        super.beforeHookedMethod(param);
                        XposedBridge.log("com.test.abc.MyWrapperProxyApplication->onCreate beforeHookedMethod");
                    }
    
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        super.afterHookedMethod(param);
                        XposedBridge.log("com.test.abc.MyWrapperProxyApplication->onCreate afterHookedMethod");
    
                        ClassLoader finalClassLoader=getClassloader();
                        XposedBridge.log("finalClassLoader->" + finalClassLoader);
                        XposedHelpers.findAndHookMethod("com.orginal.apk.MainActivity", finalClassLoader, "onCreate", Bundle.class, new XC_MethodHook() {
                            @Override
                            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                super.beforeHookedMethod(param);
                                XposedBridge.log("beforeHookedMethod com.orginal.apk.MainActivity.onCreate");
    
                            }
    
                            @Override
                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                super.afterHookedMethod(param);
                                XposedBridge.log("afterHookedMethod com.orginal.apk.MainActivity.onCreate");
    
                            }
                        });
                    }
                });
            }
        }
    }
    
    

    so中函数处理

    1、创建android studio native项目,使用inhook框架,编写hook的内容
    2、通过Xposed,在java.lang.Runtime.loadLibrary的时机加载so

    // java.lang.System.loadLibrary,的下一级,会使用当前调用者的ClassLoader,所以会被使用成Xposed的ClassLoader
    // 可以用java.lang.Runtimem,但是在不同版本的源码中,loadLibrary的名字不一样,需要适配
    XposedHelpers.findAndHookMethod("java.lang.Runtime", loadPackageParam.classLoader, "loadLibrary", String.class,ClassLoader.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            String soname= (String) param.args[0];
            XposedBridge.log("beforeHookedMethod Runtime.load("+soname+","+param.args[1]+")");
        }
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            String soname= (String) param.args[0];
            XposedBridge.log("afterHookedMethod Runtime.load("+soname+")");
            if(soname.contains("native-lib")){
                System.load("/data/data/com.showme.xposedhookso/files/hookso.so");
            }
        }
    });
    
    对于armv8,可以使用sandHook框架
    

    指纹检测与简单定制

    
    
    展开全文
  • Xposed常用逆向函数

    2021-10-15 09:18:16
    1. 创建Xposed工程 在Android Studio中新建一个app工程,修改其中的 AndroidManifest.xml 文件,在<application></application>标签中增加如下代码 <meta-data android:name="xposedmodule" ...

    1. 创建Xposed工程

    在Android Studio中新建一个app工程,修改其中的 AndroidManifest.xml 文件,在<application></application>标签中增加如下代码

    <meta-data
    	android:name="xposedmodule"
    	android:value="true" />
    <meta-data
    	android:name="xposeddescription"
    	android:value="hello xposed" />
    <meta-data
    	android:name="xposedminversion"
    	android:value="82" />

    在 app/libs 目录下添加Xposed的依赖库,api-82.jar, api-82-sources.jar(网上自行搜索)

    修改 app 目录下的 build.gradle 文件,将以上的两个依赖库添加到 dependencies{} 中,如下

    dependencies {
        compileOnly 'de.robv.android.xposed:api:82'
        compileOnly 'de.robv.android.xposed:api:82:sources'
        
        // other content
        ......
    }

    在 mian 目录下创建一个assets文件夹,并在assets目录下创建一个 xposed_init 文件,文件中写入实现了 IXposedHookLoadPackage 接口的类名及包名;例如我当前新建了一个类 TestReverse 实现了 IXposedHookLoadPackage 接口,且当前包名为 com.test.xposed,则 xposed_init 中的内容应为

    com.test.xposed.TestReverse

    2. 相关API介绍

    Xposed 模块API用法:XposedHelpers | Xposed Framework API

    a.IXposedHookLoadPackage 接口,实现hook逻辑的类必须实现该接口,APP被加载的时候会调用该接口中的 handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) 方法,所以我们需要重写该函数,并在其中实现我们的hook逻辑

    b.XC_LoadPackage.LoadPackageParam,该类下包含与正在加载的应用程序的有关信息。入下,其中packageName可以用于判断当前hook住的APP名称,processName表示当前APP所在的进程,classLoader表示当前APP使用的ClassLoader。

     c.XposedHelpers类

            1.findClass(String className, ClassLoader classLoader),使用特定的ClassLoader查找指定类,返回值为指定类的class;使用如下

    final Class<?> callContextClass = XposedHelpers.findClass("com.alibaba.ariver.engine.api.bridge.model.NativeCallContext",lpparam.classLoader);

            2.XposedHelpers.findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback),hook指定的方法。

            其中 Object... parameterTypesAndCallback是java中的范式,可以传递多个参数;当使用XposedHelpers.findAndHookMethod()方法时,需要传递被hook的函数所需要的全部参数的字节码,这些字节码可以通过.class获取到,或者findClass反射获取;java自带的类型比如String,就可以用String.class获取到。

            回调对象XC_MethodHook()需重写两个方法 beforeHookedMethod(MethodHookParam param):这个方法中的代码逻辑会在hook住的方法调用前执行 ;afterHookedMethod(MethodHookParam param) 方法中的代码逻辑则会在hook住的方法调用完成后执行。

            使用如下,以下代码逻辑表示,在com.baidu.swan.apps.jsbridge.SwanAppGlobalJsBridge 类下的 dispatchOnUiThread() 函数已经被hook住,在这个函数执行前后,beforeHookedMethod() 和 afterHookedMethod() 中的逻辑会分别执行。

    XposedHelpers.findAndHookMethod("com.baidu.swan.apps.jsbridge.SwanAppGlobalJsBridge", lpparam.classLoader, "dispatchOnUiThread", String.class, new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        super.beforeHookedMethod(param);
                        XposedBridge.log("Baidu: dispatchOnUiThread 的线程:" + Thread.currentThread().getName());
                        XposedBridge.log("Baidu:dispatchOnUiThread 入参:" + java.net.URLDecoder.decode(param.args[0].toString()) + "返回值:" + param.getResult());
                    }
    
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        super.afterHookedMethod(param);
                        Field mCallbackHandler = jsbridge_a.getDeclaredField("mCallbackHandler");
                        Object mmCallbackHandler = (Object) mCallbackHandler.get(param.thisObject);
                        //com.baidu.swan.apps.core.slave.SwanAppWebViewWidget
                        XposedBridge.log("Baidu: mCallbackHandler在webview里调用API时的实现类:" + mmCallbackHandler.getClass().getName());
                });

            3. XposedHelpers.findAndHookConstructor(String className, ClassLoader classLoader, Object... parameterTypesAndCallback),参数含义同上findAndHookMethod()。

            使用如下,以下代码逻辑表示,当 com.baidu.swan.apps.jsbridge.SwanAppNativeSwanJsBridge 类的构造函数被调用时,在构造函数执行前后,beforeHookedMethod() 和 afterHookedMethod() 中的逻辑会分别执行。

    XposedHelpers.findAndHookConstructor("com.baidu.swan.apps.jsbridge.SwanAppNativeSwanJsBridge", lpparam.classLoader, container_a, new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        super.beforeHookedMethod(param);
                        Log.d("Baidu:", "SwanAppNativeSwanJsBridge()构造函数参数: " + param.args[0].getClass().getName());
                    }
    
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        super.afterHookedMethod(param);
                    }
                });

    d. XposedBridge类

    1. XposedBridge.log(String text),将消息写入Xposed错误日志。用于打印想要了解的信息

    2. XposedBridge.hookMethod(Member hookMethod, XC_MethodHook callback),用特定的回调方法hook任意的方法或构造函数;用这种方法不需要像XposedHelpers.findAndHookMethod() 构造那么多参数,使用如下,以下代码逻辑表示先从一个类中获取到对应的method实例,然后将该method对象传递给XposedBridge.hookMethod()方法,即可直接hook住该方法

                for(final Method method: TestClass.getDeclaredMethods()){
                    XposedBridge.hookMethod(method, new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            super.beforeHookedMethod(param);
                            XposedBridge.log("Baidu:share中的" + method.getName() + "被调用了");
                            printStack();
                        }
                    });
                }

    3. 打印函数调用栈

    在逆向APP的框架逻辑时,当hook住一个被成功触发的函数,往往需要查看其调用栈,也就是该函数的上层调用函数,这些信息会对我们逆向APP框架有很大的帮助。

    private void printStack() {
            // 获取线程的StackTraceElement[]
            Throwable ex = new Throwable();
            StackTraceElement[] stackElements = ex.getStackTrace();
            if (stackElements != null) {
                for (int i = 0; i < stackElements.length; i++) {
                    XposedBridge.log("Baidu: Dump Stack" + i + ": " + stackElements[i].getClassName()
                            + "----" + stackElements[i].getFileName()
                            + "----" + stackElements[i].getLineNumber()
                            + "----" + stackElements[i].getMethodName());
                }
            }
            XposedBridge.log("Baidu: Dump Stack: ---------------over----------------");
        }

    4. 修改hook住函数的参数

            1. 修改基础数据类型和String类型的参数

            直接赋值即可,如下

    param.args[0] = 5; // int类型
    param.args[1] = "hello"; //String类型

            2.  修改基础数据类型和String类型的参数

            先获取引用,再修改;例如

    Map<String, String> target = (Map<String, String>) param.args[0]; // Map
    target.put("name", "tnoy"); //向Map中添加数据

            3. 修改类的实例中的成员变量

            先用Field获取到相应的成员变量,再用Field.set(类的实例,修改后的值)进行修改;例如

    final Class<?> model_d = XposedHelpers.findClass("com.alipay.android.phone.globalsearch.model.d", lpparam.classLoader);
    Object dVar = param.args[0];
    Field b = model_d.getDeclaredField("b"); // b是model类中的public的String类型的变量
    b.set(dVar, "search_auto");

            4. 修改Object[]类型的数组

            针对Object数组中的某一个元素,先使用.getClass().getName()获取元素的类型,然后去类里面看要修改的对应的Field,然后进行上述第三点的操作,最后封装成一个新的Object[],再把这个Object[]赋值给param.args[i]。例如

    Object[] obj = (Object[]) param.args[2];
    for(Object o: obj){
    if(o != null){
     // 判断当前Object的类是不是我们需要的那个类
            if(o.getClass().getName().equals("com.alipay.mobile.aompfavorite.base.rpc.request.MiniAppHistoryRequestPB")){
            // 在jadx中源码为:List<MiniAppHistoryReqItemPB> miniAppItems;
            Field miniAppItems = MiniAppHistoryRequestPB.getDeclaredField("miniAppItems");
            // 先用List<Object>反射拿到List<MiniAppHistoryReqItemPB>列表
            List<Object> item = (List<Object>) miniAppItems.get(o);
            // 获取List列表的第一个值
            Object item_1 =  item.get(0);
            Log.d("Mini 修改前", o.toString());
            Log.d("Mini List[0]", item_1.toString());
            // MiniAppHistoryReqItemPB类中的成员变量appId
            Field appId = MiniAppHistoryReqItemPB.getDeclaredField("appId");
            String AppId = (String) appId.get(item_1);
            Log.d("Mini appid", AppId);
            appId.set(item_1, "2018112262208014");
            Log.d("Mini 修改后", o.toString());
            }
            Log.d("Mini handler_1.1", o.getClass().getName() + " " + o.toString());
        }
    }

    5. hook动态加载进来的类

            在APP框架中有些代码是动态加载进来的,比如插件化开发。使用以下代码,可以hook住动态加载进来的函数

    XposedBridge.hookAllMethods(ClassLoader.class, "loadClass", new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable {
    
                        if (param.hasThrowable()) return;
                        if (param.args.length != 1) return;
    
                        Class<?> cls = (Class<?>) param.getResult();
                        String name = cls.getName();
    
                        // 判断是否是我要hook的动态加载的类
                        if ("com.bytedance.webview.chromium.ContentSettingsAdapter".equals(name)) {
                            // 指定要hook的method
                            XposedBridge.hookAllMethods(cls,
                                    "setJavaScriptEnabled",
                                    new XC_MethodHook() {
                                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                            try {
                                                XposedBridge.log("commonRe: setJavaScriptEnabled被调用了: " + param.args[0]);
                                                printStack();
                                            } catch (Exception e) {
                                                XposedBridge.log("commonRe: hook error!");
                                            }
                                        }
                                    });
                        }
                    }
                });

     6. 打印动态加载进来的类的存储位置(获取插件apk)

    final Class<?> DexPathList = XposedHelpers.findClass("dalvik.system.DexPathList", lpparam.classLoader);
    
               for (final Method method: DexPathList.getDeclaredMethods()){
                    XposedBridge.hookMethod(method, new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            super.beforeHookedMethod(param);
                            // splitPaths()方法传入的是动态加载进来的类在手机中的路径
                            if(method.getName().equals("splitPaths")){
                                XposedBridge.log("Baidu: DexPathList中的" + method.getName() + "被调用了,传参为" + param.args[0]+" " + param.args[1]);
                            }
                    }
                    }) ;
                }

     7. 自动化hook方法脚本

    在某些情况下,我们拥有一系列需要hook的方法的signature,而且需要hook住这些方法获取某些信息时,我们可以通过自动化脚来实现将这些方法一一hook住,就不需要手工挨个写hook每一个方法的脚本。

    代码举例实现如下

    StaticInfo.java:用于从json文件中读取要hook方法的signature,并通过反射获取到对应的method对象
    package com.example.ttest;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.lang.reflect.Array;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    
    import de.robv.android.xposed.XposedBridge;
    import de.robv.android.xposed.XposedHelpers;
    import de.robv.android.xposed.callbacks.XC_LoadPackage;
    
    public class StaticInfo {
        public static HashMap<PoolHook.normalHandlerHook, Method> HookMethods = new HashMap<>();
        public XC_LoadPackage.LoadPackageParam lpparam;
    
        public StaticInfo(XC_LoadPackage.LoadPackageParam lpparam) throws NoSuchFieldException {
            this.lpparam = lpparam;
            // read from file
            try{
                InputStream is = new FileInputStream(new File("/sdcard/tmp/static_info.json"));
                init(is);
                is.close();
            }catch (Exception e){
                XposedBridge.log("AMZ: read json error! " + e.toString());
            }
        }
    
        public void init(InputStream in) throws IOException, NoSuchFieldException {
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
            StringBuilder sb = new StringBuilder();
            String line;
            String ls = System.getProperty("line.separator");
            while ((line = bufferedReader.readLine()) != null){
                sb.append(line);
                sb.append(ls);
            }
            String text = sb.toString();
            XposedBridge.log("AMZ: 读取json文件成功!");
            JSONArray jsonArray = JSON.parseArray(text);
            for (int i=0; i<jsonArray.size(); i++){
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String signature = jsonObject.getString("signature");
                String filedName = jsonObject.getString("field");
                String type = jsonObject.getString("type");
                String declaringClass = jsonObject.getString("declaringClass");
                reflectMethod(signature, filedName, type, declaringClass);
            }
        }
    
        public void init(String text) throws NoSuchFieldException {
            JSONArray jsonArray = JSON.parseArray(text);
            for (int i=0; i<jsonArray.size(); i++){
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String signature = jsonObject.getString("signature");
                String filedName = jsonObject.getString("field");
                String type = jsonObject.getString("type");
                String declaringClass = jsonObject.getString("declaringClass");
                reflectMethod(signature, filedName, type, declaringClass);
            }
        }
    
        // init HashMap for Method and Field due to json file
        public void reflectMethod(String signature, String fieldName, String type, String declaringClass) throws NoSuchFieldException {
            XposedBridge.log("AMZ: 正在反射获取Method:"+ signature  + " " + fieldName + " " + type);
            Field field = XposedHelpers.findClass(declaringClass, lpparam.classLoader).getDeclaredField(fieldName);
            PoolHook.normalHandlerHook hook = new PoolHook.normalHandlerHook(fieldName,type, signature, field);
            String className = signature.split(" ")[0].substring(1,signature.split(" ")[0].length()-1);
            XposedBridge.log("AMZ: parse classname: " + className);
            try {
                Class<?> clazz = XposedHelpers.findClass(className, this.lpparam.classLoader);
                String methodName = signature.split(" ")[2].split("\\(")[0];
                ArrayList<String> paramTypes = new ArrayList(Arrays.asList(signature.split(" ")[2].split("\\(")[1].substring(0,signature.split(" ")[2].split("\\(")[1].length()-2).split(",")));
                XposedBridge.log("AMZ: 要找的方法的参数为 " + paramTypes.toString());
                for (Method method: clazz.getDeclaredMethods()){
                    XposedBridge.log("AMZ: 正在匹配方法:" + method.getName() + " ==> " + methodName);
                    XposedBridge.log("AMZ: 当前方法参数个数:" + method.getParameterTypes().length + " 目标方法的参数个数:" + paramTypes.size());
                    if (method.getName().equals(methodName)){
                        if (method.getParameterTypes().length == paramTypes.size()){
                            XposedBridge.log("AMZ: 方法名和参数个数匹配上了");
                            ArrayList<String> paramTypesCopy = (ArrayList<String>) paramTypes.clone();
                            for (Class paramType: method.getParameterTypes()){
                                XposedBridge.log("AMZ: 当前方法的参数类型:" + paramType.getName());
                                if (paramTypes.contains(paramType.getName())){
                                    paramTypesCopy.remove(paramType.getName());
                                }
                            }
                            if (paramTypesCopy.size() == 0 && !HookMethods.containsKey(hook)){
                                XposedBridge.log("AMZ: find target method: " + method.toString() + " target_field: " + field);
                                HookMethods.put(hook, method);
                            }
                        }
                        else if (method.getParameterTypes().length == 0 && paramTypes.size() ==1 && paramTypes.get(0).length() == 0){
                            XposedBridge.log("AMZ: 目标方法没有参数,匹配成功");
                            if (!HookMethods.containsKey(hook)){
                                XposedBridge.log("AMZ: find target method: " + method.toString() + " target_field: " + field);
                                HookMethods.put(hook, method);
                            }
                        }
                    }
                }
            }catch (Exception e){
                XposedBridge.log("AMZ: " + e.toString());
            }
        }
    }
    

    PoolHook.java: 继承 IXposedHookLoadPackage 接口,编写hook逻辑

    package com.example.ttest;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    import de.robv.android.xposed.IXposedHookLoadPackage;
    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;
    
    public class PoolHook implements IXposedHookLoadPackage{
        public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable{
            new StaticInfo(lpparam);
            if (lpparam.packageName.equals("com.eg.android.AlipayGphone")){
                XposedBridge.log("AMZ: hook start!!");
                hookPackage(lpparam);
            }
        }
    
        private void hookPackage(XC_LoadPackage.LoadPackageParam lpparam){
            if (StaticInfo.HookMethods.isEmpty()){
                XposedBridge.log("AMZ: HashMap is empty");
            }else {
                XposedBridge.log("AMZ: HashMap is not empty");
            }
            for (Map.Entry<normalHandlerHook, Method> entry: StaticInfo.HookMethods.entrySet()){
                XposedBridge.hookMethod(entry.getValue(), entry.getKey());
            }
        }
    
        static class normalHandlerHook extends XC_MethodHook{
            private String fieldName;
            private String type;
            private Field field;
            private String signature;
    
            public normalHandlerHook(String fieldName, String type, String signature, Field field){
                this.fieldName = fieldName;
                this.type = type;
                this.signature = signature;
                this.field = field;
            }
    
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable{
                System.out.println("AMZ: current method: " + param.method);
                XposedBridge.log("AMZ: hook field right now:" + field.toString());
                XposedBridge.log("AMZ: pool type:" + this.type);
                this.field.setAccessible(true);
                if (this.type.equals("HashMap")){
                    XposedBridge.log("AMZ: this is HashMap");
                    HashMap<Object, Object> mmap = (HashMap<Object, Object>) this.field.get(param.thisObject);
                    for (Map.Entry<Object, Object> entry: mmap.entrySet()){
                        Object key = entry.getKey();
                        Object value = entry.getValue();
                        XposedBridge.log("AMZ: signature=" + this.signature +" key=" + key + " value=" + value);
                    }
                }else if(this.type.equals("Map") || this.type.equals("ConcurrentHashMap") || this.type.equals("LinkedHashMap")){
                    XposedBridge.log("AMZ: this is Map or ConcurrentHashMap");
                    Map<Object, Object> mmap_1 = (Map<Object, Object>) field.get(param.thisObject);
                    for (Map.Entry<Object, Object> entry: mmap_1.entrySet()){
                        Object key = entry.getKey();
                        Object value = entry.getValue();
                        XposedBridge.log("AMZ: signature=" + this.signature +" key=" + key + " value=" + value);
                    }
                }
            }
        }
    }
    

    8. Xposed hook 原理

    Java虚拟机JVM在加载了dex后,会将整个dex文件的内容mmap(一种内存映射文件的方法)到内存中。JVM在load一个class的时候,根据类的描述符,在内存的dex区域,查询到对应的数据,构建出ClassObject对象,以及这个ClassObject关联的Method。

    Method分为directMethod和nativeMethod,分别是Java里实现的方法和C/C++里面实现的方法。Method里面有两个重要的指针:

    const u2* insns;
    DalvikBridgeFunc nativeFunc;

    对于directMethod,insns存放了该方法在内存中的字节码指针;对于nativeMethod,会根据方法描述符,通过特定的映射关系得到一个native层的函数名(JNI method),然后去查找对应的函数,得到了函数指针后,再将这个指针赋值给insns。在nativeFunc这个桥接函数中,将insns解析为函数指针,然后进行调用。

    Xposed在对java方法进行hook的时候,会先将JVM里面的这个方法的Method属性改为nativeMethod(也就是修改一个表示字段),然后将该方法的nativeFunc指向自己实现的一个native方法。于是当被hook的方法被调用到时,就会实际去调用自己实现的这个native方法。

    在自己实现的native方法中,xposed直接调用了一个java方法,这个java方法里面对原方法进行了调用,并在调用前后插入了钩子,于是就hook住了这个方法。

    Android所有的APP进程都是由Zygote进程启动的,所以Zygote进程中加载的代码,在后续所有fork出来的子进程中都有。Xposed替换了Zygote进程对应的可执行文件/system/bin/app_process,并用于加载xposed相关代码。

    总的来说,Xposed将要hook的JAVA方法变成了native方法,在beforeMethodHook()和afterMethodHook()方法中的逻辑实现在native方法中,并将原被hook函数插在这两个函数之间正常调用,示意图如下。

     

    展开全文
  • repositories { jcenter() } compileOnly ‘de.robv.android.xposed:api:82’ compileOnly ‘de.robv.android.xposed:api:82:sources’ 接着在 AndroidDemo/app/src/main/res/layout/activity_main.xml 中 创建一个...
  • Xposed 实现原理分析

    2020-10-11 22:31:53
    文章目录Xposed 实现原理分析前言Xposed 使用方法Xposed 原理概述Android zygote 进程基于 Dalvik 的方法 Hook基于 ART 的方法 HookXposed 工作流程Xposed 项目结构XposedXposedBridgeXposedInstallerandroid_...
  • 安卓Xposed简单实现

    2021-04-06 10:29:37
    1.手机端Xposed 安装 开发插件之前,我们还需要先安装XposedInstaller,这是一个APP,通过它可以方便的导入xposed框架和管理xposed模块。xposed框架只是为我们提供了一个平台,具体的hook操作就由我们开发的插件来...
  • 装X指南之Xposed安装与配置

    千次阅读 2019-01-12 13:26:56
    Xposed 能干嘛?我可以告诉你 Root + Xposed ,真的可以为所欲为。而 Android 开源,为“搞机”带了更多的乐趣的同时,当然也引入安全性问题,部分流氓软件在 Root 下,会盗取用户私密信息,例如:号码、照片、短信...
  • compileOnly ‘de.robv.android.xposed:api:82:sources’ 这两句仍然照常添加。】  好了,我们现在已经搞好了所有的准备工作。下一步,就要开始“施展刀法”(编写 hook 代码)了。 4、实现 hook 操作的具体代码...
  • 微信Xposed案例实战

    2020-04-06 22:51:35
    一、Xposed环境配置和简单的demo 一、新建项目 二、配置相关文件 a.配置activity_main.xml,这个只需要添加一个测试用的按钮即可 b.配置MainActivity.java,同样只需要实现一个按钮事件即可 重点来了: c.添加api-82...
  • 最新的Xposed模块编写教程

    千次阅读 2019-07-04 08:16:04
    这是一篇最新的Xposed模块编写教程 0×00 前言 在互联网上,关于Xposed模块编写的教程可谓是一抓一大把。但由于时间的推移,很多工具和方法都发生了变化(如Eclipse退出安卓编程舞台,AndroidStudio 不断升级导致其...
  • 在上一篇文章《Xposed插件开发手册(1): Xposed框架的安装》,我们学习到了Xposed的安装,这篇文章我们就来做一个简单的Xposed模块,劫持我们写的App,整篇文章我参考了官网的教程来编写。 环境参数 虽然之前的文章...
  • Android 集成Xposed框架

    千次阅读 2020-12-25 20:58:49
    Xposed框架(Xposed Framework)是一套开源的、在Android高权限模式下运行的系统框架服务,可以在不修改APK文件的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块或插件。 ...
  • 为帮助童鞋们更有节奏感地学习,本文分为Demo篇和实战篇来作叙述。...Xposed是一个很强大的android平台上的hook工具,其可以在不修改APK文件的情况下影响程序运行的框架服务,且在功能不冲突的情况下同时运作。
  • XposedBridgeApi-82.jar

    2018-08-05 19:14:37
    xposed api 82 AndroidManifest.xml <meta-data android:name="xposedmodule" android:value="true" /> <meta-data android:name="xposeddescription" android:value="..." /> <meta-data ...
  • Xposed模块开发不起作用

    千次阅读 2019-03-04 17:24:33
    // implementation 'de.robv.android.xposed:api:82' compileOnly 'de.robv.android.xposed:api:82' implementation 'de.robv.android.xposed:api:82':这个是不行的,要使用: compileOnly 'de.rob...
  • XposedBridgeApi-87&82;.jar

    2017-10-18 08:49:36
    2个积分,用于开发Xposed框架的模块之用。由于积分不能再低了,还请各位见谅。多多支持。
  • 本人结合网络上的种种教程以及自己实践,记录下一个完整的基本Xposed模块项目的创建过程。   开发环境: Mac系统 AndroidStudio 3.2.1 gradle 3.2.1 VirtualXposed(无需Root的使用Xposed模块)   Xposed、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 404
精华内容 161
热门标签
关键字:

82xposed