LZ-Says:静心,静心,就是静不下来才叫静心~!好想整个鸡排大大照片挂在床头,桌头~嘿嘿嘿~
完蛋 图传不上来
前言
这几天,各种逆向,各种反编译,有点懵,今天整理下Xposed首战使用心得~
同时也希望可以和各位老铁一块学习,望不慎赐教~!!!
一、Xposed 简介(此处纯粹拷贝官方)
理解程度还不够,阅读几次也只是有个印象而已,这次再次拷贝一份,以供阅读此文的小伙伴简单阅读一下:
Xposed 是什么鬼
Xposed框架是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。
Xposed 工作简述
有一个过程称为“Zygote”。这是Android运行时的核心。每个应用程序都以它的副本(“分支”)开始。/init.rc当手机启动时,此过程由脚本启动。进程的开始是通过/system/bin/app_process加载所需的类并调用初始化方法来完成的。
这就是Xposed进场的地方。当安装框架时,将扩展的app_process可执行文件复制到/system/bin。这个扩展的启动过程向类路径添加了一个额外的jar,并在某些地方从那里调用方法(而这个过程,对应我们实际操作中,只是我们安装Xposed激活后挂载即可)。例如,在创建虚拟机之后,甚至在mainZygote 的方法被调用之前。在这个方法里面,我们是Zygote的一部分,可以在其上下文中行事。
该jar位于/data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar和它的源代码可以在这里找到。查看XposedBridge类,可以看到该main方法。这就是在上面写到的,这在过程的最初阶段就被调用了。一些初始化在那里完成,并且模块也被加载(稍后将回到模块加载)。
方法挂钩/替换
真正产生Xposed威力的是可以“挂钩”方法调用。当通过反编译APK进行修改时,可以直接在需要的位置插入/更改命令。但是,之后需要重新编译/签名APK,并且只能分发整个包。使用Xposed可以放置钩子,不能修改方法内的代码(不可能清楚地定义想要在哪个位置进行哪种更改)。相反,可以在方法之前和之后注入自己的代码,这是Java中可以清晰解决的最小单元。
XposedBridge具有私有的本地方法hookMethodNative。该方法也在扩展中实现app_process。它会将方法类型更改为“native”,并将方法实现链接到它自己的本地通用方法。这意味着每次调用挂钩方法时,通用方法都会被调用,而调用者不知道它。在这种方法中,handleHookedMethod调用XposedBridge中的方法,将参数传递给方法调用,this引用等。然后,此方法负责调用已为此方法调用注册的回调。这些可以改变调用的参数,更改实例/静态变量,调用其他方法,对结果做些什么...或者跳过任何内容。它非常灵活。
二、前期准备
一部Root成功的手机,模拟器也是Okay;
安装 Xposed Installer 3.1.5 并激活;
编写个小demo,很简单,可输入用户名、密码、提交按钮以及最后点击按钮提示;
准备编写我们挂载的‘插件’,准备劫持玩我们想玩的东西~
三、安装,激活
本文基于Xposed Installer 3.1.5,下面附上下载地址:
吐槽一下:CSDN忒恶心,上传下载必须设置积分,难道是我姿势不对?算了,换百度云~
安装之后启动,如下:
完蛋 图传不上来
操作流程:
启动Xposed Installer 3.1.5,首先会提示例如什么会变砖什么鬼的,直接点击左侧《不再提示》,之后点击《确定》即可;
之后进入软件首页,发现提示Xposed框架未激活,之后点击《安装/更新》,俩种方式安装,随便选择一个;
接着,由于未授予此软件Root权限,所以在此需要给予Root权限,完成后,再次点击上一步骤;
最后,安装完成后,选择重启设备。
Okay,完成之后如下效果:
到此,完成安装、激活骚操作第一步~
四、编写准备劫持的Apk Demo
回顾下需求:
用户可以输入用户名以及密码;
提供提交按钮,提示用户登录成功~
五、分析并开始劫持
使用ApkTool进行解包,命令如下:
apktool d xxx.apk
示例图如下:
之后查看解包出来的文件,尤其smali文件以及布局文件:
查看smali文件,如下:
我们猜测如下:
主界面路径可能为:com.hlq.userlogindemo.MainActivity
编写者定义了三个参数,分别为:mSubmitID、mUserNameID以及mUserPwdID,鉴名其意,很容易理解这三个参数对应的含义。
继续往下瞅瞅:
从上图,我们可以得到以下信息:
有个checkInfo方法,猜测用于检测数据,估计也是模拟用户登录检验;
其次,此方法需要俩个参数,分别为:userName以及userPwd。
而下面则是将用户输入的用户名与test、密码与123进行比对,一致认为登录成功,反之登录失败~
别问我为啥知道,我才不告诉你这就是我写的呢~
那么,接下来,去查看xml布局文件,看看我们能get到什么东西:
有木有很兴奋,ID拿到了哦~~~可以浪了~
接下来,编写我们劫持的模块~
编写劫持模块
Step 1:创建一个名为《GetUserInfoXposed》工程作为我们劫持模块。
Step 2:在app下build.gradle中添加引用:
compileOnly 'de.robv.android.xposed:api:82'
LZ这里使用的是Xposed 框架 89,其对应的api版本为:82。
Step 3:编写Xposed实例
这里简单输出日志即可,之后我们将主要在这里进行Hook操作。
package com.hlq.getuserinfoxposed.xposed;import android.util.Log;import de.robv.android.xposed.IXposedHookLoadPackage;import de.robv.android.xposed.XposedBridge;import de.robv.android.xposed.callbacks.XC_LoadPackage;/** * author : HLQ * e-mail : 925954424@qq.com * time : 2018/05/21 * desc : Xposed 劫持 * version: 1.0 */public class Tutorial implements IXposedHookLoadPackage { private static final String TAG = "HLQ_Struggle"; @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { XposedBridge.log("Xposed模块已初始化,准备劫持"); Log.e(TAG, "Xposed模块已初始化,准备劫持"); } }
Step 4: 创建assets目录以及xposed_init文件并将编写Xposed模块地址拷贝进去即可。
这里需要注意点:
创建一个无后缀格式得xposed_init文件,将包名+Xposed模块类名写入即可。
这里需要注意:关于创建无后缀格式文件,可以先创建txt文件,将编写好的Xposed劫持类包得地址复制进去,之后将后缀名移除,LZ这里踩坑了,也纠结好久,特此记录。
例如,这里LZ编写得Xposed模块包名+类名如下:
com.hlq.getuserinfoxposed.xposed.Tutorial
这个文件得作用,声明Xposed主入口。
拷贝进去,关闭Instant Run。
Step 5: 关闭Instant Run,否则这些将不会被打包进apk
Step 6: Xposed装载模块,这里会提示设备重启,重启即可。
勾选右侧复选框,重启设备,会发现有我们之前设置的Log日志:
E/HLQ_Struggle: Xposed模块已初始化,准备劫持
以及Xposed日志中输出:
最后,当然是开启Hook路~
public class Tutorial implements IXposedHookLoadPackage { private static final String TAG = "HLQ_Struggle"; @Override public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { // 1.过滤,Hook指定包名下内容 if (!lpparam.packageName.equals("com.hlq.userlogindemo")) { return; // 不是我们想要的,直接让其滚犊子 } // 2.日志输出,表明当前模块已被装载,可进行下面Hook操作 XposedBridge.log("Xposed模块已初始化,准备劫持"); Log.e(TAG, "Xposed模块已初始化,准备劫持"); // 3. 准备Hook用户名以及密码 XposedHelpers.findAndHookMethod( "com.hlq.userlogindemo.MainActivity", lpparam.classLoader, "checkInfo", String.class, String.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { // hook 到方法,准备截取用户名以及密码 // 加载需要hook实例类 Class c = lpparam.classLoader.loadClass("com.hlq.userlogindemo.MainActivity"); // 获取类字段 也可以理解为获取引用实例 Field userNameField = c.getDeclaredField("mUserNameID"); Field userPwdField = c.getDeclaredField("mUserPwdID"); // 简单可以理解为即使你是私有的,我照挖不误 userNameField.setAccessible(true); userPwdField.setAccessible(true); // 获取到输入框实例 EditText tvUserName = (EditText) userNameField.get(param.thisObject); EditText tvUserPwd = (EditText) userPwdField.get(param.thisObject); // 获取用户输入用户名以及密码 String userName = tvUserName.getText().toString(); String userPwd = tvUserPwd.getText().toString(); // 日志输出 XposedBridge.log("Xposed模块已劫持,用户名:" + userName + " 密码:" + userPwd); Log.e(TAG, "Xposed模块已劫持,用户名:" + userName + " 密码:" + userPwd); } } ); } }
编写完成后运行到设备,记得重启下,不然模块不会更新的。
重启之后,打开我们编写的Demo,输入用户名密码点击提示,查看Log如下:
E/HLQ_Struggle: Xposed模块已劫持,用户名:test 密码:123
这块还是了解太少,太少,太少咯~
GitHub查看地址
参考资料
共同学习,写下你的评论
评论加载中...
作者其他优质文章