Xposed模块开发指南

1、Xposed框架是什么?


Xposed框架是一款开源框架,其功能是可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运行。


2、Xposed模块是什么?


Xposed模块即按照Xposed模块开发规范开发出来的包含你想在别人Apk里面执行的代码的一个Apk。很多时候我们听到的微信抢红包神器、修改手机定位神器等都有可能是一个Xposed模块。


3、Xposed框架如何安装?

找一款可以root的手机或者模拟器,下载XposedInstaller.apk,安装,打开,框架->安装/更新->根据提示重启手机,安装完成

Xposed模块开发指南_第1张图片

Xposed模块开发指南_第2张图片


4、如何开发Xposed模块?(本文重点)

准备工作(工具、环境):

  1. ROOT手机,安装XposedInstaller,并安装Xposed框架
  2. 刷机,自带Xposed的ROM
  3. VirtualXposed 让你无需Root也能使用Xposed框架!
    https://xposed.appkg.com/2799.html
  4. 模拟器(夜神、Genymotion)

以上4种方式,任选,没有自带Xposed的设备需要安装XposedInstaller.apk ,推荐第四种

开发步骤:

  1. 创建Android 项目
  2. 添加依赖
    // https://mvnrepository.com/artifact/de.robv.android.xposed/api
    compileOnly 'de.robv.android.xposed:api:82' //注意是compileOnly,仅参与编译,不参与打包
  3. Manifest application节点下添加如下信息:
    
             //用于标记该APK是一个Xposed模块
            //支持的最低Xposed版本,类似于Android中的minSdkVersion
            //Xposed模块的简介,可以XposedInstall应用中看到此处设置的内容
    

     

  4. 首先我们来了解一些概念,hook一个类的静态属性和hook一个方法时用到的方法参数含义
    /**
     * hook一个类的静态属性
     * @param clazz 被hook的类Class对象
     * @param fieldName 被hook的静态属性名称
     * @param value对该属性设置的新值
     */
    public static void setStaticObjectField(Class clazz, String fieldName, Object value)
  5. XC_MethodHook hook = new XC_MethodHook() {
    
        /**
         * 在被hook的方法代码块执行前执行,相当于在方法代码块第一行之前插入这部分代码
         * @param param
         * @throws Throwable
         */
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            super.beforeHookedMethod(param);
            //param.args被hook的方法的参数列表 param.args[0]即为该方法输入的第一个参数,
            //通过这个参数我们可以修改方法的输入参数值(重要)
    
            //param.thisObject当前被hook的类的对象
    
        }
    
        /**
         * 在被hook的方法返回结果之前执行,相当于在return执行之前插入这部分代码
         * @param param
         * @throws Throwable
         */
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            //param.args同上
            //param.thisObject同上
            //param.getResult() 获取方法的返回值
            //param.setResult(object);设置方法的返回值,利用这个可以修改方法的返回结果(重要)
        }
    };
  6. 创建一个类SimpleHook实现IXposedHookLoadPackage接口,并实现handleLoadPackage方法
    public class SimpleHook implements IXposedHookLoadPackage {
    
        @Override
        public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
            
        }
    }

     

  7. 在assets目录下创建xposed_init文件,并填入上一步创建类的完整类名(包名+类名)
    com.moon.xposed.hook.SimpleHook

     

  8. 首先我们来一个简单的,先改变一下手机的型号,很简单直接修改Build类的静态变量即可
     @Override
     public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
    
            if (lpparam.appInfo == null) {
                return;
            }
    
            if ((lpparam.appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                //不hook系统APP
                return;
            }
    
            XposedHelpers.setStaticObjectField(Build.class, "MODEL", "Xopsed牌");
        }
  9. 运行安装写好的Hook APP
  10. 写一个简单的APP来获取设备型号
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            findViewById(R.id.toast).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(MainActivity.this, "这是一个Toast", Toast.LENGTH_LONG).show();
                }
            });
    
            StringBuilder sb = new StringBuilder();
            sb.append("型号:").append(" ").append(Build.MODEL).append("\n");
            sb.append("MANUFACTURER:").append(" ").append(Build.MANUFACTURER).append("\n");
            sb.append("DEVICE:").append(" ").append(Build.DEVICE).append("\n");
            sb.append("BOARD:").append(" ").append(Build.BOARD).append("\n");
            sb.append("BRAND:").append(" ").append(Build.BRAND).append("\n");
            TextView modelTv = findViewById(R.id.model_tv);
            modelTv.setText(sb.toString());
            TextView manufacturerTv = findViewById(R.id.manufacturer_tv);
            manufacturerTv.setText(Build.MANUFACTURER);
        }
    }
  11. 运行安装该Demo APP

  12. 在XposedInstall中打开“模块”界面,勾选XposedDemo模块,如图所示,并重启设备Xposed模块开发指南_第3张图片
  13. 打开我们的Demo APP可以看到我们修改的设备型号已经生效
  14. Xposed模块开发指南_第4张图片

到此一个最简单的Xposed模块已经制作完毕。

 

示例一:是谁偷偷的弹了Toast?

学以致用,大家是不是有时候会遇到Android手机不知什么原因的弹Toast,且不知道是哪个APP偷偷的在干,有了Xposed我们就可以找出这个元凶。代码很简单,直接hook这个方法即可:

public static Toast makeText(Context context, CharSequence text, int duration)

hook代码如下:

XC_MethodHook toastHook = new XC_MethodHook() {
     @Override
     protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
          super.beforeHookedMethod(param);
          String text = (String) param.args[1];
          text = "被Hook " + getAppName((Context) param.args[0]) + ":" + text;
          param.args[1] = text;
     }

     @Override
     protected void afterHookedMethod(MethodHookParam param) throws Throwable {
          super.afterHookedMethod(param);
       }
     };

XposedHelpers.findAndHookMethod(Toast.class.getName(), lpparam.classLoader,
                "makeText", Context.class, CharSequence.class, int.class, toastHook);

然后看我们的Demo APP弹Toast的相关代码:

findViewById(R.id.toast).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "这是一个Toast", Toast.LENGTH_LONG).show();
            }
 });

看效果:这样我们就可以知道这个Toast是一个叫test的APP弹出来的了。

Xposed模块开发指南_第5张图片

 

示例二:实现一个小目标

曾经王首富的一句话“最好先定一个能达到的小目标,比方说我先挣它一个亿”,瞬间在网络走红,网友纷纷开始留言,有的笑谈、有的吐槽、有的自嘲……“。今天我们就来帮大家实现一个“小目标”,利用Xposed将微信钱包的余额修改为这个小目标。

  1. 首先我们定位到钱包余额展示页面Activity为com.tencent.mm.plugin.mall.ui.MallIndexUI,并定位到余额是在protected final void bNi()方法中,通过一个变量名为omy的TextView进行设置展示的。具体怎么定位到的属于逆向破解方法的内容,本文暂不讨论。
  2. 由此我们便可以通过在bNi()结束时重新设置一下omy的内容来实现我们的小目标了
    XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
    
            //此处为什么要在Application的attach方法结束时来hook MallIndexUI类的bNi方法呢?
            //因为微信APK有分包,里面有多个dex,直接在handleLoadPackage方法里面进行hook有可能MallIndexUI类所在的dex尚未加载,就会出现找不到类的异常
    
            ClassLoader cl = ((Context) param.args[0]).getClassLoader();
            Class hookclass = null;
            try {
                hookclass = cl.loadClass("com.tencent.mm.plugin.mall.ui.MallIndexUI");
            } catch (Exception e) {
                Log.e("Xposed", "查找com.tencent.mm.plugin.mall.ui.MallIndexUI报错", e);
                return;
            }
    
            Log.i("Xposed", "查找com.tencent.mm.plugin.mall.ui.MallIndexUI成功 " + lpparam.processName + " " + lpparam.packageName);
            XposedHelpers.findAndHookMethod(hookclass, "bNi", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    //此处通过反编译得到omy属性在MallIndexUI的父类MallIndexBaseUI中声明,因此反射获取该Field需要通过父类的class
                    final Class base = Class.forName("com.tencent.mm.plugin.mall.ui.MallIndexBaseUI", false, lpparam.classLoader);
                    Field omyField = base.getDeclaredField("omy");
                    omyField.setAccessible(true);
                    //得到omy对象,直接强转为TextView进行使用
                    TextView omyTextView = (TextView) omyField.get(param.thisObject);
                    omyTextView.setText("一个亿");
                }
            });
    
        }
    });

     

  3. 运行Hook APP,重启设备,查看结果,一个小目标实现了

Xposed模块开发指南_第6张图片

 

绝逼不是P图,有动画为证

 

其实Xposed可以做的事情很多,除了修改设备信息绕过风控做黑灰产、装逼炫酷外,还可以做一些监控,比如hook一些获取用户隐私数据的方法,用来检测是否有APP在后台恶意窃取用户隐私等。Xposed真的可以为所欲为,用在优秀的人手中就可以造福万民。


源码传送

推荐网站:

Xposed相关源码:https://github.com/rovo89

Xposed中文网站https://xposed.appkg.com/

 


作者简介:就职于甜橙金融信息技术部,负责翼支付android客户端开发工作,喜欢研究新的技术,不断学习,不断提升。

你可能感兴趣的:(Android,逆向)