好友
阅读权限10
听众
最后登录1970-1-1
|
陈司机
发表于 2021-2-2 21:13
本帖最后由 陈司机 于 2021-2-2 21:23 编辑
系列文章:
上篇 [玩转WX之一]一行命令打印安卓WX数据库密码并取出数据库文件到电脑查看
有兴趣的请关注,系列文章保持高实用性,不说废话,点明过程中的重点,最后直接给出结果。
基础须知:
1.热加载是可以让安卓App不重新安装但是又能改机运行逻辑的技术,腾讯系软件使用自家的热加载系统Tinker。
2.应用程序会从清单的appliction name开始进行运行, 一把程序加壳,多dex,热加载,都在这里做工作,这是应用程序自己的代码能被最早执行的地方。
3.热加载分成总体分资源,so, dex热加载,业务逻辑代码绝大部分在dex, 所以一般关注dex热加载比较多。
4.系统会先执行Application里面的生命周期函数attachBaseContext,比我们熟悉的onCreate更早。
如果代码是热加载的,很有可能会导致插件运行出错。如下所示:
wx热加载前的classloader
dalvik.system.PathClassLoader[DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/system/framework/com.google.android.maps.jar", zip file "/data/app/com.tencent.mm-cm3A_pxRWC2RjCfVnM6X4A==/base.apk"],nativeLibraryDirectories=[/data/app/com.tencent.mm-cm3A_pxRWC2RjCfVnM6X4A==/lib/arm64, /data/app/com.tencent.mm-cm3A_pxRWC2RjCfVnM6X4A==/base.apk!/lib/arm64-v8a, /system/lib64]]]
wx热加载后classloader
dalvik.system.DelegateLastClassLoader[DexPathList[[zip file "/data/user/0/com.tencent.mm/tinker/patch-d93c1e4d/dex/tinker_classN.apk"],nativeLibraryDirectories=[/data/user/0/com.tencent.mm/tinker/patch-d93c1e4d/lib/lib/arm64-v8a, /data/app/com.tencent.mm-cm3A_pxRWC2RjCfVnM6X4A==/lib/arm64, /data/app/com.tencent.mm-cm3A_pxRWC2RjCfVnM6X4A==/base.apk!/lib/arm64-v8a, /system/lib64]]]
为了兼容热加载,我们也要对类加载器进行修正。如何修正热加载器,我们要先对热加载流程做个分析,做到心中有数。
以下代码基于WX7.0.19
我们开始从0开始跟进分析,先查看应用程序入口
1
来看类 com.tencent.mm.app.Application
2
来看 com.tencent.mm.app.Application 父类 TinkerApplication
3
类初始化之后,就会由系统调用生命周期函数 attachBaseContext
4
loadTinker
5
反射调用真正的tryLoad
6
使用 tryLoadPatchFilesInternal 进行热加载
7
快速看下这个函数,发现比较重要的是loadTinkerJars
这个函数也对dex热加载文件进行验证以及读入
8
由loadTinkerJars进入installDexes
9
进入installDexes,根据不同的系统环境, 安装热更新
10
安卓热更新的关键是创建新的TinkerClassLoader,合并原有的classLoader
11
完成新的类加载器创建,并替换Application的类加载器
12
替换线程上下文和LoadedApk的classloader
13
替换classloader完毕,校验是否加载成功,如果成功了,就用tinker_xxx.dex等的类
14
经过上面分析,我们这样玩:
wx没替换classloader,我们就不替换xp的classloader;
wx替换了classloader,我们跟着替换xp的classloader。
class Hook : IXposedHookLoadPackage {
override fun handleLoadPackage(LoadPackageParam: XC_LoadPackage.LoadPackageParam) {
if (LoadPackageParam.packageName == "com.tencent.mm") {
Log.i("ACCESS", "%%% app_cl 1: ${AndroidAppHelper.currentApplication()?.classLoader}")
// 这个时候,wx未修改classloader,保持xp的不变,
XposedBridge.hookAllMethods("com.tencent.tinker.loader.app.TinkerApplication".getClass(LoadPackageParam.classLoader), "onBaseContextAttached", object :XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
LoadPackageParam.classLoader = XposedHelpers.callMethod(param.thisObject, "getClassLoader") as ClassLoader
LoggerUtil.i("ACCESS", "%%% app_cl 2: ${LoadPackageParam.classLoader}")
XposedBridge.hookAllMethods("com.tencent.mm.app.MMApplicationWrapper".getClass(LoadPackageParam.classLoader), "onCreate", object :XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
// 这个时候tinker有可能已经发生热加载了
val app = XposedHelpers.getObjectField(param.thisObject, "app")
val context = XposedHelpers.callMethod(app, "getApplicationContext") as Context
Log.i("ACCESS", "%% context:${context} cl:${context.classLoader}")
// 使用全局static对这两个关键变量进行保存。
Global.context = context
Global.classLoader = context.classLoader // 后面所有查找类加载类使用这个类加载器。不要再使用xp回调传过来的。或者使用TinkerClassLoader.findClass。
// 下面开始调用注入逻辑
}
})
}
})
}
}
}
|
免费评分
-
查看全部评分
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|