【Android 安全】DEX 加密 ( Application 替换 | 分析 ContentProvider 组件中调用 getApplication() 获取的 Application 二 )(二)

简介: 【Android 安全】DEX 加密 ( Application 替换 | 分析 ContentProvider 组件中调用 getApplication() 获取的 Application 二 )(二)

二、 installProvider 方法的第三分支分析


下面代码中的三个分支就是给 ContentProvider 组件设置 Application 上下文的代码 ;


public final class ActivityThread {
    private ContentProviderHolder installProvider(Context context,
            ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
    // 该上下文对象很重要 
            Context c = null;
            ApplicationInfo ai = info.applicationInfo;
    // 该 context 是 ProxyApplication , 代理 Application 
            if (context.getPackageName().equals(ai.packageName)) {
    // 在应用中配置的代理 Application 包名与真实 Application 包名都是相等的
    // 该分支是命中的 
                c = context;
            } else if (mInitialApplication != null &&
                    mInitialApplication.getPackageName().equals(ai.packageName)) {
    // 该分支中 mInitialApplication 就是 Context context 参数 , 肯定不为空 
    // 该分支无法命中 
                c = mInitialApplication;
            } else {
    // 上述两个分支都无法命中 , 才进入该分支 
    // 需要将代理 Application 的包名 与 真实应用的包名设置成不同的
    // 此时上面两个分支都无法命中 
                try {
                    c = context.createPackageContext(ai.packageName,
                            Context.CONTEXT_INCLUDE_CODE);
                } catch (PackageManager.NameNotFoundException e) {
                    // Ignore
                }
            }
        return retHolder;
  }
}


参考路径 : frameworks/base/core/java/android/app/ActivityThread.java



在上面的分析中 , 如果要使得分支一 context.getPackageName().equals(ai.packageName) 与分支二 mInitialApplication.getPackageName().equals(ai.packageName) , 都无法命中 , 就需要 Application 的 getPackageName 方法获取的包名不等于在 AndroidManifest.xml 中的包名 ai.packageName , 这里重写 ProxyApplication 的 getPackageName 方法 , 使该方法返回值为 “” 字符串 , 这样就无法命中前两个分支 , 只能进入 else 分支 ;






三、 ContextImpl 中 createPackageContext 方法分析


继续分析 分支三 中的内容 , 如果 Application 的 getPackageName 方法返回 “” , 将导致分支一二都没有命中 , 进入分支三 ;


public final class ActivityThread {
    private ContentProviderHolder installProvider(Context context,
            ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
    // 该上下文对象很重要 
            Context c = null;
            ApplicationInfo ai = info.applicationInfo;
    // 该 context 是 ProxyApplication , 代理 Application 
            if (context.getPackageName().equals(ai.packageName)) {
            } else if (mInitialApplication != null &&
                    mInitialApplication.getPackageName().equals(ai.packageName)) {
            } else {
    // 上述两个分支都无法命中 , 才进入该分支 
    // 需要将代理 Application 的包名 与 真实应用的包名设置成不同的
    // 此时上面两个分支都无法命中 
                try {
                    c = context.createPackageContext(ai.packageName,
                            Context.CONTEXT_INCLUDE_CODE);
                } catch (PackageManager.NameNotFoundException e) {
                    // Ignore
                }
            }
        return retHolder;
  }
}


参考路径 : frameworks/base/core/java/android/app/ActivityThread.java



分支三中调用了 , context 的 createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE) 方法 , 该方法在 ContextImpl 中定义 ;


在 ContextImpl 中的 createPackageContext 方法 , 调用了 createPackageContextAsUser 方法 , 调用了如下代码 , 创建 Context 上下文 ,


ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, user,
                    flags, null);


上述代码中创建 ContextImpl 时 , 使用的 mMainThread , pi , 都没有替换过 Application , 因此分支三创建的 ContentProvider 对应的 Application 也是代理 Application , 替换前的 Application 对象 ;



class ContextImpl extends Context {
  // 在该方法中调用了 createPackageContextAsUser 方法创建上下文
    @Override
    public Context createPackageContext(String packageName, int flags)
            throws NameNotFoundException {
        return createPackageContextAsUser(packageName, flags,
                mUser != null ? mUser : Process.myUserHandle());
    }
    @Override
    public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
            throws NameNotFoundException {
        if (packageName.equals("system") || packageName.equals("android")) {
            // The system resources are loaded in every application, so we can safely copy
            // the context without reloading Resources.
            return new ContextImpl(this, mMainThread, mPackageInfo, null, mActivityToken, user,
                    flags, null);
        }
  // 注意该 LoadedApk 对象
        LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
        if (pi != null) {
    // 创建新的 ContextImpl 
    // 此时还没有替换 Application 
            ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, user,
                    flags, null);
            final int displayId = mDisplay != null
                    ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
            c.setResources(createResources(mActivityToken, pi, null, displayId, null,
                    getDisplayAdjustments(displayId).getCompatibilityInfo()));
            if (c.mResources != null) {
                return c;
            }
        }
        // Should be a better exception.
        throw new PackageManager.NameNotFoundException(
                "Application package " + packageName + " not found");
    }
}


源码路径 : frameworks/base/core/java/android/app/ContextImpl.java


ContextImpl 中的 public Context createPackageContext(String packageName, int flags) 方法是公开方法 , 重写该方法 , 在重写的 createPackageContext 方法中 , 先进行一次 Application 替换 , 然后继续执行 super.createPackageContext 方法的后续操作 , 这样创建的 ContentProvider 中的上下文就是用户自定义的 MyApplication , 不再是 ProxyApplication ;


只有在创建 ContentProvider 时才调用到该 createPackageContext 方法 , 如果没有调用到该方法 , 说明该应用中没有配置 ContentProvider ;






四、ContentProvider 中替换 Application 的总结


ContentProvider 中替换 Application 的总结 :


① 分支选择 : 首先要命中 ActivityThread 中 installProvider 方法的分支三 ;

② Application 替换 : 然后要在 ContextImpl 的 createPackageContext 方法执行前进行一次 Application 替换 ;


目录
相关文章
|
数据安全/隐私保护 Android开发
2023安卓逆向 -- 某合伙apk登录加密分析
2023安卓逆向 -- 某合伙apk登录加密分析
362 0
|
存储 监控 算法
taosd 写入与查询场景下压缩解压及加密解密的 CPU 占用分析
在当今大数据时代,时序数据库的应用越来越广泛,尤其是在物联网、工业监控、金融分析等领域。TDengine 作为一款高性能的时序数据库,凭借独特的存储架构和高效的压缩算法,在存储和查询效率上表现出色。然而,随着数据规模的不断增长,在保证数据安全性和存储效率的同时,如何优化 CPU 的资源占用,成为了一个值得深入讨论的问题。
332 1
|
JavaScript 数据安全/隐私保护 Python
JS逆向 -- 某视频vurl值的加密分析
JS逆向 -- 某视频vurl值的加密分析
681 0
|
安全 网络协议 网络安全
【Azure 环境】从网络包中分析出TLS加密套件信息
An TLS 1.2 connection request was received from a remote client application, but non of the cipher suites supported by the client application are supported by the server. The connection request has failed. 从远程客户端应用程序收到 TLS 1.2 连接请求,但服务器不支持客户端应用程序支持的任何密码套件。连接请求失败。
628 2
|
数据采集 数据可视化 数据挖掘
基于python django的scrapy去哪儿网数据采集与分析,包括登录注册和可视化大屏,有md5加密
本文介绍了一个基于Python和Django框架,使用Scrapy进行去哪儿网数据采集与分析的项目,包括实现登录注册功能、MD5加密以及通过可视化大屏展示分析结果的综合系统。
347 1
基于python django的scrapy去哪儿网数据采集与分析,包括登录注册和可视化大屏,有md5加密
|
JavaScript 前端开发 安全
安全开发-JS应用&原生开发&JQuery库&Ajax技术&加密编码库&断点调试&逆向分析&元素属性操作
安全开发-JS应用&原生开发&JQuery库&Ajax技术&加密编码库&断点调试&逆向分析&元素属性操作
309 5
|
存储 SQL 安全
网络安全与信息安全:漏洞分析与加密技术探讨
在当今数字化时代,网络安全与信息安全日益成为全球关注的焦点。本文深入探讨了网络安全中的常见漏洞类型及其影响,并介绍了当前流行的加密技术和提升安全意识的方法,旨在为读者提供系统的知识分享与技术探讨。
213 3
|
人工智能 监控 安全
未来金融将如何借助加密货币发展,可以从以下几个方面进行清晰的分析和归纳
**区块链与加密货币推动金融革命:降低交易成本,提高安全,扩大服务范围,赋能智能合约与DeFi,及改变监管方式。加密经济助力金融效率与普惠性,但也伴随风险,需平衡发展与监管。**
|
存储 前端开发 算法
加密算法在网络通信中的应用及优势分析
本文将探讨加密算法在网络通信中的重要性,以及不同加密算法的应用和优势。通过对前端、后端、Java、Python、C、PHP、Go等多种技术的分析,我们将了解在日益增长的网络威胁下,加密算法对于确保数据安全和隐私保护的必要性。
|
Android开发 数据安全/隐私保护
安卓逆向 -- FridaHook分析3DES加密值
安卓逆向 -- FridaHook分析3DES加密值
197 0
安卓逆向 -- FridaHook分析3DES加密值