内容简介:本文先介绍了Xposed原理,再通过逆向支付宝,介绍Xposed在android中的使用。带你在android系统中遨游。
Xposed 框架是一款可以在不修改 APK 的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作,在这个框架下,我们可以加载很多插件 App ,这些插件 App 可以直接或间接劫持、篡改、伪造一些信息。
原理探究Android 平台的动态劫持,通过替换 /system/bin/app_process 程序控制 Zygote 进程,使得app_process在启动过程中会加载 XposedBridge.jar 这个 jar 包,从而完成对 Zygote 进程及其创建的 Dalvik 虚拟机的劫持。理论上我们的插件 APP 可以 hook 到系统任意一个 Java 进程zygote、systemserver、systemui。
原理就不讲那么多了,网上有很多分析的文章,比如:
Xposed框架原理深入研究https://blog.csdn.net/ascii2/article/details/47974217
Dalvik虚拟机原理及Xposed hook原理https://cloud.tencent.com/developer/article/1193511
Android Hook框架Xposed原理与源代码分析https://blog.csdn.net/wxyyxc1992/article/details/17320911
不得不稍微提一下:Method中,有两个非常重要的指针:
54 /*
55 * The remaining items are not used for abstract or native methods.
56 * (JNI is currently hijacking "insns" as a function pointer, set
57 * after the first call. For internal-native this stays null.)
58 */
59
60 /* the actual code */
61 const u2* insns; /* instructions, in memory-mapped .dex */
66 /*
67 * JNI: native method ptr; could be actual function or a JNI bridge. We
68 * don't currently discriminate between DalvikBridgeFunc and
69 * DalvikNativeFunc; the former takes an argument superset (i.e. two
70 * extra args) which will be ignored. If necessary we can use
71 * insns==NULL to detect JNI bridge vs. internal native.
72 */
73 DalvikBridgeFunc nativeFunc;
有兴趣的可以去研究一下,这里不做赘述。
免Root使用VirtualXposed,英文原话 “A simple app to use Xposed without root, unlock the bootloader or modify system image, etc. “ ,翻译:“使用 VirtualXposed 可以免 root 、不用解锁 bootloader 或修改系统镜像”。
官方文档:https://vxposed.com/
GitHub:https://github.com/android-hacker/VirtualXposed
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
XposedTools
XposedTools 就是用来帮助我们编译 Xposed 和 XposedBridge 的
XposedMods
开发者使用 Xposed 开发的一些 Modules
Xposed使用AndroidManifest.xml
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="省略一万字,想写啥就写啥~~~" />
<meta-data
android:name="xposedminversion"
android:value="54" />
assets/xposed_init 此文件内容添加Xposed入口类路径
d.xposedshare.hook.MainHookLoad
app/lib/ 此路径下,集成 XposedBridgeAPI-89.jar ,
build.gradle 中添加
compileOnly files('lib/XposedBridgeAPI-89.jar')
然后,我们就可以在 Xposed Installer 中看到我们自己定义的模块了。
注意:在运行 Xposed 之前,需要把 Install Run 去掉哦。每次修改运行 HOOK 相关之处的代码,都需要重启手机!
演示我是如何分析的?
打开App,比如这个页面,为了不增加收入,就把码给挡住了,;-)
这样我们在用 Accessibility 拿到当前页面的 ClassName ,比如这样:
这样就给我们反编译出来的代码找到了分析入口。对就从这个类下手。 className====类路径+类名。 className 在 Xposed 框架使用时,用来拿到 class 。
接下来我们使用 Apktools 打开需要学习的 App,慢慢读起来,学习到很多优秀之处。
解压反编译包的资源
找到二维码页面的 Activity :
找到相关组件 Field :
在分析的过程中,发现了一个点,对于我们熟悉 App 的个别模块的逻辑由很大帮助,一个日志验证类,客官请看:
所以我们平时在打印 log 时一定要注意咯。另外,在分析 App 时,看到混淆的代码,方法、变量等名称都已经变化了,这就要求当使用 Hook 时需要根据不同版本适配。
如何使用Xposed?下面我们就从三个方面演示一下
Hook Android系统方法
public class MainHookLoad implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
//系统的演示用
XposedHelpers.findAndHookMethod("android.telephony.TelephonyManager", lpparam.classLoader,
"getDeviceId", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("donald beforeHookedMethod");
}
@Override
protected void afterHookedMethod(MethodHookParam methodHookParam) throws Throwable {
methodHookParam.setResult("这是被修改的数据imei");
XposedBridge.log("donald Hook device id is successful!!! ");
}
});
}
}
这样就轻轻松松hook住系统方法,任何App在调用时返回我们修改的内容。手机上很多系统方法修改后,一个物理手机就变成多个虚拟手机了。
Hook第三方App(最最有名的支付工具:支付宝)
public class MainHookLoad implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
// hook设置金额和备注的onCreate方法,自动填写数据并点击
XposedHelpers.findAndHookMethod("com.alipay.mobile.payee.ui.PayeeQRSetMoneyActivity", lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Field jinErField = XposedHelpers.findField(param.thisObject.getClass(), "b");
final Object jinErView = jinErField.get(param.thisObject);
Field beiZhuField = XposedHelpers.findField(param.thisObject.getClass(), "c");
final Object beiZhuView = beiZhuField.get(param.thisObject);
//设置支付宝金额和备注
XposedHelpers.callMethod(jinErView, "setText", "123");
XposedHelpers.callMethod(beiZhuView, "setText", "备注内容");
//点击确认
Field quRenField = XposedHelpers.findField(param.thisObject.getClass(), "e");
final Button quRenButton = (Button) quRenField.get(param.thisObject);
quRenButton.performClick();
}
});
// hook获得二维码url的回调方法
XposedHelpers.findAndHookMethod("com.alipay.mobile.payee.ui.PayeeQRSetMoneyActivity", lpparam.classLoader, "a", XposedHelpers.findClass("com.alipay.transferprod.rpc.result.ConsultSetAmountRes", lpparam.classLoader), new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Field moneyField = XposedHelpers.findField(param.thisObject.getClass(), "g");
String money = (String) moneyField.get(param.thisObject);
Field markField = XposedHelpers.findField(param.thisObject.getClass(), "c");
Object markObject = markField.get(param.thisObject);
String mark = (String) XposedHelpers.callMethod(markObject, "getUbbStr");
Object consultSetAmountRes = param.args[0];
Field consultField = XposedHelpers.findField(consultSetAmountRes.getClass(), "qrCodeUrl");
String payUrl = (String) consultField.get(consultSetAmountRes);
XposedBridge.log(money + " " + mark + " " + payUrl);
}
});
}
}
这样就很容易的拿到我们自己设置支付宝金额与备注的收款码了。比如 qrCodeUrl 就是长这样:"https://qr.alipay.com/sldgjsdlgjio23o8hned9nd?t=1546998123456"
Hook日志类(风险)
//这是重点强调:打印日志的逆向风险
Class<?> clazzLog = lpparam.classLoader.loadClass("com.alipay.mobile.verifyidentity.log.VerifyLogCat");
XposedHelpers.findAndHookMethod(clazzLog, "i", String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("====VerifyLogCat==i==" + param.args[0] + " " + param.args[1]);
}
});
XposedHelpers.findAndHookMethod(clazzLog, "d", String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("====VerifyLogCat==d==" + param.args[0] + " " + param.args[1]);
}
});
XposedHelpers.findAndHookMethod(clazzLog, "e", String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("====VerifyLogCat==e==" + param.args[0] + " " + param.args[1]);
}
});
这是重点强调风险:打印日志的逆向风险。随便打一下 log ,我们的 app 逻辑就很容易被捋出来。
社区文化论坛:https://api.xposed.info
Xposed API:https://xposed.appkg.com/
Github:https://github.com/rovo89/Xposed.git
xda-developers(下载资源最好在这里哦):https://forum.xda-developers.com/showthread.php?t=3034811
总结工程源码Github:https://github.com/donald99/XposedShare
Xposed太酷了。值得我们深入学习研究。
其实 Xposed 并没有想象中那么复杂,原理和相关的 API 都很简单,难的是逆向分析的过程,实现 Hook :反编译后分析乱乱的代码,打日志调试输出堆栈信息,抓包等等,需要我们去分析很多未知的东西,不断猜测,不断尝试,折腾一番可能毫无进展,不过不要灰心,有耐心总会找到灵光一现的那一刻。另外研究之后,在开发我们的APP时,对安全威胁方面就会有意识避让。
真正牛逼的不是使用的人,而是他(rovo89)。
以上仅供学习研究,用于其他后果自负。
--END--
识别二维码,关注我们