跳至主要內容

加载已安装应用、未安装 apk 中的资源

JI,XIAOYONG...大约 2 分钟

加载已安装应用、未安装 apk 中的资源,其思路主要是获取到对应的 ClassLoader/Context,通过 ClassLoader 加载 R.java 等类,再通过反射获取对应的资源 id 及资源。

加载已安装应用资源

sharedUserId

在当前应用中加载已安装的其他应用资源,需要二者有相同的sharedUserId,这样 Android 系统为二者分配同一个 Linux 用户 ID,两个 App 可以相互访问代码、资源等。

通过 Shared User id,拥有同一个 User id 的多个 APK 可以配置成运行在同一个进程中。所以默认就是可以互相访问任意数据。也可以配置成运行成不同的进程,同时可以访问其他 APK 的数据目录下的数据库和文件。就像访问本程序的数据一样。

Android 逆向之旅---Android 中的 sharedUserId 属性详解 - CSDN 博客open in new window

具体设置方法如下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cf.android666.dynamicloadapk"
    android:sharedUserId="cf.android666.dynamic">
</manifest>

筛选所有已安装应用信息

private var packageBeanList: ArrayList<PackageInfoBean> = arrayListOf()
private var packageInfoList: ArrayList<PackageInfo> = arrayListOf()

var packageInfoList = packageManager.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES) as ArrayList<PackageInfo>

if (packageInfoList.isNotEmpty()) {
    for (x in packageInfoList) {
        if (x.sharedUserId != null
            && x.sharedUserId.equals(sharedUid)
            && !x.packageName.equals(packageName)) {
            //sharedUserId 与当前 App 相同,且 packageName 和当前 App 不同的 App 信息,即插件 App
            packageBeanList.add(PackageInfoBean(packageManager
                                                .getApplicationLabel(x.applicationInfo).toString(), x.packageName))
                }
            }
        }

生成插件 App 的 Context

activity.createPackageContext("cf.android666.pluginapp",
        Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY)

通过 Context 反射获取插件 App 中的资源

//获取 ClassLoader
var pClassLoader = PathClassLoader(pluginContext.packageResourcePath
                , ClassLoader.getSystemClassLoader())
//反射获取该类及其资源
var clazz = pluginContext.classLoader
        .loadClass(pluginContext.packageName + ".R\$mipmap")
var abc = clazz.getField(s)
var id = abc.getInt(R.mipmap::class.java)
//调用插件 App 的 Context 获取其资源
var bg = pluginContext.resources.getDrawable(id)

加载未安装 Apk 内资源

获取 apk 信息

val sdPath = Environment.getExternalStorageDirectory().absolutePath
val apkPath = "$sdPath/plugin/plugin.apk"
var info = packageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES)//获取未安装 apk 的 packageInfo

获取 ClassLoader

var file = getDir("dex", Context.MODE_PRIVATE)
var dexClassLoader = DexClassLoader(apkPath, file.absolutePath, null, ClassLoader.getSystemClassLoader())

getDir() 调用了 Context 的 getDir()

Retrieve, creating if needed, a new directory in which the application can place its own custom data files. You can use the returned File object to create and access files in this directory. Note that files created through a File object will only be accessible by your own application; you can only set the mode of the entire directory, not of individual files.

通过反射加载类,获取资源

var drawableClazz = dexClassLoader.loadClass("cf.android666.pluginapp.R\$drawable")
var onePng = drawableClazz.getDeclaredField("abc")
var onId = onePng.getInt(R.id::class.java)//反射获取资源 id

var resources = getUninstallApkResource()//resource 也是通过反射获取到
var drawable = resources.getDrawable(onId)

AssetManager.addAssetPath()方法是用来将 apk 等中的资源添加到AssetManager中,再通过其获取到Resources对象,这样就获取到未安装 apk 中的资源了。

fun getUninstallApkResource(): Resources {
    var assetManager = AssetManager::class.java.newInstance()
    var addAssetPath = assetManager.javaClass.getMethod("addAssetPath",String::class.java)
    addAssetPath.invoke(assetManager, apkPath)//设置了 apkPath
    return Resources(assetManager, resources.displayMetrics, resources.configuration)
}

参考资源

Android 之 Android apk 动态加载机制的研究(二):资源加载和 activity 生命周期管理 - lee0oo0 - 博客园 open in new window

Android 逆向之旅---Android 中的 sharedUserId 属性详解 - CSDN 博客open in new window

文章标题:《加载已安装应用、未安装 apk 中的资源》
本文作者: JI,XIAOYONG
发布时间: 2018/04/15 21:40:32 UTC+8
更新时间: 2023/12/30 16:17:02 UTC+8
written by human, not by AI
本文地址: https://jixiaoyong.github.io/blog/posts/8d60b485.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 许可协议。转载请注明出处!
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8