Android 双开沙箱 VirtualApp 源码分析(六)ContentProvider

VirtualApp源码(完整工程) VirtualApp源码(完整工程),基于android studio (ndk,sdk)开发,实现安卓双开。 立即下载

Android 双开沙箱 VirtualApp 源码分析(六)ContentProvider

Provider 注册

回顾前面,Activity 启动的时候会检查 Application 是否初始化,会调用 bindApplication,里面执行了安装 Provider 的方法:

private void installContentProviders(Context app, List<ProviderInfo> providers) {
        long origId = Binder.clearCallingIdentity();
        Object mainThread = VirtualCore.mainThread();
        try {
            for (ProviderInfo cpi : providers) {
                if (cpi.enabled) {
                    ActivityThread.installProvider(mainThread, app, cpi, null);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

这里很简单,调用 ActivityThread.installProvider() 注册就这么完成了。

但是,仔细一想事情没那么简单,按照这个逻辑 ContentProvider 是在 Application 启动的时候注册的,那么如果 Application 没有启动,那么自然就没有注册了,这样的话其他 App 怎么找到 Provider 呢?

Activity 是因为有在 VA 的 Menifest 里注册的 StubActivity,这样启动 StubActivity 自然就启动了在“:p(n)”进程。那么对应的,VA 用了 StubContentProvider 么?确实是有的。

但是请不要误会了,这个注册在 “p(n)”进程的 StubContentProvider(继承自 StubContentProvider 的 C1,C2,Cn……) 并不是 StubActivity 那样的为了给插件 Provider 占坑的 Stub 组件。

StubContentProvider 的真正目的是为了让 AMS 通过 system_process 带起 “p(n)”进程,然后 VAMS 用过远程调用 StubProvider.call() 回插件 IClient 的 IBinder 句柄给 VAMS 持有。这样 VAMS 就可以远程调用插件进程 “p(n)”中的方法了。

事实上在前面第二张 App 启动时就有说过相关内容,但是为了避免大家误解还是有必要重复一下。

public class StubContentProvider extends ContentProvider {

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public Bundle call(String method, String arg, Bundle extras) {
        if ("_VA_|_init_process_".equals(method)) {
            return initProcess(extras);
        }
        return null;
    }

    private Bundle initProcess(Bundle extras) {
        ConditionVariable lock = VirtualCore.get().getInitLock();
        if (lock != null) {
            lock.block();
        }
        IBinder token = BundleCompat.getBinder(extras,"_VA_|_binder_");
        int vuid = extras.getInt("_VA_|_vuid_");
        VClientImpl client = VClientImpl.get();
        client.initProcess(token, vuid);
        Bundle res = new Bundle();
        BundleCompat.putBinder(res, "_VA_|_client_", client.asBinder());
        res.putInt("_VA_|_pid_", Process.myPid());
        return res;
    }

getContentProvider

这里依然 Hook 了 getContentProvider 方法:

 static class GetContentProvider extends MethodProxy {

        @Override
        public String getMethodName() {
            return "getContentProvider";
        }

        @Override
        public Object call(Object who, Method method, Object... args) throws Throwable {
            int nameIdx = getProviderNameIndex();
            String name = (String) args[nameIdx];
            int userId = VUserHandle.myUserId();
            // 远程调用 VPMS 从 VPackage 拿到 ProviderInfo
            ProviderInfo info = VPackageManager.get().resolveContentProvider(name, 0, userId);
            // 拿不到说明目标 App 未启动
            if (info != null && info.enabled && isAppPkg(info.packageName)) {
                // 远程调用 VAMS,然后 VAMS 再通过 AMS 远程调用注册在插件进程的 StubContentProvider.call 初始化插件进程
                int targetVPid = VActivityManager.get().initProcess(info.packageName, info.processName, userId);
                if (targetVPid == -1) {
                    return null;
                }
                args[nameIdx] = VASettings.getStubAuthority(targetVPid);
                Object holder = method.invoke(who, args);
                if (holder == null) {
                    return null;
                }
                // ContentProviderHolder 有两个成员变量provider、connection,provider 是目标 Provider 的 IBinder 句柄。
                // connection 则是 callback
                if (BuildCompat.isOreo()) {
                    IInterface provider = ContentProviderHolderOreo.provider.get(holder);
                    if (provider != null) {
                        // 这里是重点,远程调用了 VAMS 的 acquireProviderClient
                        provider = VActivityManager.get().acquireProviderClient(userId, info);
                    }
                    ContentProviderHolderOreo.provider.set(holder, provider);
                    ContentProviderHolderOreo.info.set(holder, info);
                } else {
                    IInterface provider = IActivityManager.ContentProviderHolder.provider.get(holder);
                    if (provider != null) {
                        provider = VActivityManager.get().acquireProviderClient(userId, info);
                    }
                    IActivityManager.ContentProviderHolder.provider.set(holder, provider);
                    IActivityManager.ContentProviderHolder.info.set(holder, info);
                }
                return holder;
            }
            Object holder = method.invoke(who, args);
            if (holder != null) {
                if (BuildCompat.isOreo()) {
                    IInterface provider = ContentProviderHolderOreo.provider.get(holder);
                    info = ContentProviderHolderOreo.info.get(holder);
                    if (provider != null) {
                        provider = ProviderHook.createProxy(true, info.authority, provider);
                    }
                    ContentProviderHolderOreo.provider.set(holder, provider);
                } else {
                    IInterface provider = IActivityManager.ContentProviderHolder.provider.get(holder);
                    info = IActivityManager.ContentProviderHolder.info.get(holder);
                    if (provider != null) {
                        provider = ProviderHook.createProxy(true, info.authority, provider);
                    }
                    IActivityManager.ContentProviderHolder.provider.set(holder, provider);
                }
                return holder;
            }
            return null;
        }


        public int getProviderNameIndex() {
            return 1;
        }

        @Override
        public boolean isEnable() {
            return isAppProcess();
        }
    }

这里主要做了几件事情:

通过 VPMS 拿到解析好的目标 ProviderInfo,启动目标 Provider 所在的进程,怎么启动?远程调用 VAMS,然后 VAMS 再通过 AMS 远程调用注册在插件进程的 StubContentProvider.call 初始化插件进程。这时候 VAMS 就会持有目标插件进程的 IClient 句柄,以备后续调用。
准备 ContentProviderHolder 相关的事情,ContentProviderHolder 有两个成员变量provider、connection,provider 是目标 Provider 的 IBinder 句柄。
远程调用了 VAMS 的 acquireProviderClient(), 将任务抛给了远端的 VAMS。
下面就来看一下 VAMS.acquireProviderClient()

@Override
    public IBinder acquireProviderClient(int userId, ProviderInfo info) {
        ProcessRecord callerApp;
        synchronized (mPidsSelfLocked) {
            callerApp = findProcessLocked(VBinder.getCallingPid());
        }
        if (callerApp == null) {
            throw new SecurityException("Who are you?");
        }
        String processName = info.processName;
        ProcessRecord r;
        synchronized (this) {
            r = startProcessIfNeedLocked(processName, userId, info.packageName);
        }
        if (r != null && r.client.asBinder().isBinderAlive()) {
            try {
                return r.client.acquireProviderClient(info);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

可以看到调用了 r.client.acquireProviderClient(info);
r.client 就是前面 initProcess 的时候保存下来的插件进程的 IClient 句柄,那么等于远程调用到了插件的 VClientImpl.acquireProviderClient():

注意现在开始流程是在目标 Provider 的 Client App 进程中

@Override
    public IBinder acquireProviderClient(ProviderInfo info) {
        if (mTempLock != null) {
            mTempLock.block();
        }
        // 这里检查 Application 是否启动,注意注册 Provider 的逻辑也在里面
        if (!isBound()) {
            VClientImpl.get().bindApplication(info.packageName, info.processName);
        }
        // 准备 ContentProviderClient
        IInterface provider = null;
        String[] authorities = info.authority.split(";");
        String authority = authorities.length == 0 ? info.authority : authorities[0];
        ContentResolver resolver = VirtualCore.get().getContext().getContentResolver();
        ContentProviderClient client = null;
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                client = resolver.acquireUnstableContentProviderClient(authority);
            } else {
                client = resolver.acquireContentProviderClient(authority);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        if (client != null) {
            // 反射获取 provider
            provider = mirror.android.content.ContentProviderClient.mContentProvider.get(client);
            client.release();
        }
        return provider != null ? provider.asBinder() : null;
    }

这里终于看到了调用 bindApplication 的地方,如果 provider 尚未注册,那么这里将会注册 provider。

最终通过反射 android.content.ContentProviderClient.mContentProvider 获取到了目标 provider 的句柄,然后 provider 沿着目标 Client App 进程——> VAMS 进程 ———-> 回到了调用 Client App 进程中,整个获取 provider 的过程正式完成。

到此,四大组件的代理全部完成,本次分析也基本结束,下一章会写一些总结和补充内容。

转载:https://blog.youkuaiyun.com/ganyao939543405/article/details/76253562

VirtualApp10:应用分身,虚拟多开,模拟用户操作。欢迎各类朋友交流 VirtualApp Android 10.0适应 本项目纯属个人学习修改,有疑问请TG电报群(Telegram)联系: ://t.me/auto_aid(VX:kook_bug)可以过钉钉,企业微信虚拟检测,也有自动化操作模拟操作,按键等 2020.6.4 1,修改原始系统不能反射导致的诸多问题2,修改android版本兼容问题3,修改nullporint客户端应用程序的问题 2020.6.9 1,修复多版本abi兼容问题2,修复AppOps的问题3,修复各类兼容小问题 2020.7.4 1,修复包含WebView的界面会报错2,android 10更多应用稳定兼容3,可以运行当前主 立即下载

相关推荐

所有应用双开、无限多开分身、隐私保护功能 for Android .rar

所有应用双开、无限多开分身、隐私保护功能 for Android

Android 多用户 —— 从入门到应用分身

https://mp.weixin.qq.com/s/CeoijS42tkNLejkHw0waOw 从Android L(5.0)开始引入多用户API。先不论权限问题,我们可以创建多个用户。Android为什么引入这样的多用户概念? 有至少以下2个意图: 实现"访客模式"这样的通常PC端支持的多用户模式。其特点设备可以支持多个人在不同时段登陆, 独享设备。比如上班时登陆A用户,回家给小孩玩,登陆B用户. A/B用户数据完全独立, 互不影响。 单纯为了"应用多开",原生的...

求变,从思想开始 1万+

基于Android 12的虚拟应用分身与模拟开发设计源码

该项目是一款基于Android 12平台的虚拟应用分身与模拟开发设计源码,共包含1250个文件,涵盖多种编程语言。其中,Java文件占836个,XML文件105个,AIDL文件86个,C/C++文件共68个,PNG图片文件54个,其他文件包括Gradle、Gitignore、C/C++头文件和属性文件等。该源码支持应用分身、设备模拟、WiFi模拟、虚拟多开、钉钉打卡、企微打卡、插件开发、XP插件、模拟用户操作、Java和C++ Hook等功能,适用于需要进行复杂模拟开发或应用分身技术的开发者和团队。

【使用VirtualApp无root对手游进行修改】

使用VirtualApp对手游进行修改

qq_45071266的博客 2929

谷歌账号国家或地区设置修改全攻略:条件、流程与避坑指南

谷歌账号的国家或地区设置与付款资料、账号历史行为及登录环境强绑定,修改时需满足特定条件。其原理在于地区作为索引键,关联内容库、货币结算和风控策略。正确切换可解决内容推荐错乱、付款失败等问题,适用于搬家、订阅区域限定服务等场景。操作前需在目标地区创建付款资料、清空余额并取消订阅,且一年仅能修改一次。本文详解从准备到验证的完整流程,并揭示官方文档未提及的实操陷阱,助你安全完成地区切换。

weixin_42521558的博客 2261

Hi3516CV610硬件设计避坑指南:从电源模块到DDR布线实战解析

本文深入解析了Hi3516CV610硬件设计中的关键难点与实战技巧。重点剖析了电源架构的选型陷阱与PCB布局要点,详细阐述了DDR3/L高速布线的等长匹配、信号完整性及端接策略,并提供了MIPI接口与时钟电路的隔离设计指南。旨在帮助工程师规避常见设计错误,提升系统稳定性与可靠性。

ooo22的博客 255

【Android 插件化】VirtualApp 源码分析 ( 目前的 API 现状 | 安装应用源码分析 | 安装按钮执行的操作 | 返回到 HomeActivity 执行的操作 )

一、目前的 API 现状、 二、安装应用源码分析、 1、安装按钮执行的操作、 2、返回到 HomeActivity 执行的操作、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 1946

BUCK降压电路设计实战:从理论到PCB的完整指南

本文详细介绍了BUCK降压电路的设计实战,从基础原理到PCB布局的完整指南。通过关键部件选型、PCB布局黄金法则和调试技巧,帮助工程师高效设计稳定可靠的开关电源。特别针对电感、MOSFET和电容选型提供实用公式和避坑指南,并分享高温环境下的工程经验与测试方法。

weixin_33744141的博客 450

android studio 修改包名,双开一起安装

1  对着项目目录   main ---&gt;java   下面的包名  如 com.aaa.bbb  ,选中 com 或者aaa  或者bbb, 分别重命名,变成如com.ccc.ddd 2 修改项目build.gradle 里面的    defaultConfig  的    applicationId  改成com.ccc.ddd 3修改AndroidManifest.xml的pack...

jinjiashui的博客 1527

1.3、云计算HCIP融合存储产品及部署

目标:描述Oceanstor V3系列存储产品系统组成及产品定位 描述Oceanstor V3硬件结构及软件架构 掌握存储系统与主机系统之间的连接 一、存储型号 低端型存储:Oceanstor 2200 2600 2800 V3/V5 终端型存储:Oceanstor 5300 5500 5600 5800 6800 V3/V5 高端型存储:Oceanstor 18000 二、Oceanstor V3系列存储系统定位 OceanStor V3系列存储系统是华为根据存储产品应用现状和存储

weixin_43666279的博客 1653

基于知识图谱的农作物病虫害问答系统设计与实现

基于规则的问题分类是自问答系统诞生以来就一直存在的方式,主要代表就是众多的专家系统,构建专家系统采用的是规则分类器,优点是能够对特定领域、特征明显的问题进行高效精准问答,但是。,在问答系统中,问题以语音及文本字符等自然语言形式输入,利用问答系统的内部的逻辑处理模块,通过自然语言处理技术获得输入问句的详细语义信息,再经过知识检索、置信分析等步骤,自然语言处理中,用于文本分类任务的机器学习方式有两种,一种用传统的机器学习,如 NBC、SVM 等,另一种采用深度学习,如 CNN 和 RNN 等。

全网粉丝30W+,优快云、稀土掘金人工智能领域签约作者,人工智能、大模型、Python 爬虫,商务合作,请私信沟通。 2166

Android 双开沙箱 VirtualApp 源码分析(一)

最近发现了一个非常好的开源项目,基本实现了一个 Android 上的沙箱环境,不过应用场景最多的还是应用双开。 VA github: https://github.com/asLody/VirtualApp VA 的源码注释: https://github.com/ganyao114/VA_Doc 第一章主要是分析一下项目的整体结构。包结构android.content主要是 PackageP

ganyao939543405的博客 4万+

AgentScope 2.0 扩展开发完全指南:从中间件到模型适配器的深度实践

本文系统讲解 AgentScope 2.0 框架的五大扩展机制,涵盖中间件系统的洋葱模型与钩子设计、ChatModelBase 基类与多供应商适配器开发、工作空间(本地/Docker/E2B)的抽象接口与生命周期管理、凭据工厂与 MCP 协议集成、以及工具协议与存储后端扩展。文中提供完整的架构图、代码示例与故障排查指南,帮助开发者快速掌握 AgentScope 的插件化扩展体系。

program哲学 295

Android Sandbox(沙箱)开源工具介绍

android sandbox 通过利用开源工具动态分析、静态分析android的相关应用,发现应用的具体行为,从而进行判断android应用的危险程度,本文重点介绍几款常用工具。 1、droidbox是基于TaintDroid系统构建的Sandbox,通过hook系统api对apk程序进行监控,随着android SDK的不断更新,其也要随之适配。 droidbox:http://code.google.com/p/droidbox/ taintbox:http://appanalysis.org/

#7的博客 3939

【WRF教程第3.5期】预处理系统 WPS 详解:以4.5版本为例

预处理系统 WPS 详解:以4.5版本为例

WW、forever的博客 1422

LVGL core group焦点分组管理(lv_group.c)

lv_group_t是用于焦点管理的,将需要获取焦点的对像加入到同一个分组内,再将其通过挂到指定的事件驱动中,就可以控制焦点了。而被加入的对象又可以通过焦点状态事件和事件来控制对象的焦点逻辑了。创建好的分组通过接口挂事件驱动中,这样就可以指定一个自定义的焦点分组了。;) {if(!} }友情提示:无论是接口还是都是单例的,即被设置后前一个被设置的值就失效了;此方案可以保证焦点的唯一 性,但也一定要记住要在适合的位置设置回来,以防丢失焦点。

Bigan(安)的博客 3906

修改Android源码实现原生应用双开,应用多开

1. 准备 把某系统双开的两个app的信息进行对比 1.1 目录的对比 1.1.1 data目录对比 原应用: /data/user/0/com.luoyesiqiu.crackme/files 被复制的应用: /data/user/999/com.luoyesiqiu.crackme/files 1.1.2 apk所在目录对比 原应用: /data/app/com.luoyesiqi...

weixin_30735391的博客 4972

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

【Android 插件化】VirtualApp 接入 ( 在 VirtualApp 工程下创建 Module | 添加依赖 | 启动 VirtualApp 插件引擎 )

一、在 VirtualApp 工程下创建 Module、 二、添加依赖、 三、启动 VirtualApp 插件引擎、 四、博客源码、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 2141

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

android 沙盒 开源,沙盒选项  |  Android 开源项目  |  Android Open Source Project

SandboxOptionspublicfinalclassSandboxOptionsextends Objectjava.lang.Object↳com.android.tradefed.sandbox.SandboxOptionsClass that can receive and provide options to aSummaryFieldspublicstaticfinalStrin...

weixin_32712183的博客 442

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

系统安全的关键安全技术 Android中的沙箱模型

沙箱模型是业界保证系统安全的关键安全技术,已经在浏览器等领域得到了成功应用。作为优秀的开源移动平台操作系统,Android也有相应的沙箱模型,本文将对其进行介绍。   一、沙箱模型原理简介   现实中的沙箱(SandBox),是一种儿童玩具,类如KFC中一个装满小球的容器,儿童可以在其中随意玩耍,起到保护儿童的作用。(也可以理解为一种安全环境。)   近年来,随着网络安全问题的日

Yangchen 的专栏 1061

Android 系统分身及应用多开实战 frida hook

常见的分身/多开 工具修改包名,早的时候可以,现在的应用,换包名功能就残缺不能好好用了… 修改 Framework(Android多用户机制。例:小米分身、访客模式等),国产手机中挺常见。但如果系统不提供该功能,自己很难开分身,本文就是告诉你怎么开了它。 通过虚拟化技术实现(例:360分身大师、LBE平行空间),这个应用索要权限非常高,别轻易使用非官方的该类软件。 以插件机制运行 目前很多人都...

gallonyin的博客 2万+

Android 双开沙箱 VirtualApp 源码分析(四)启动插件 Service

上一章:Android 双开沙箱 VirtualApp 源码分析(三)App 启动原生 Service 创建过程首先有必要了解一下原生 framework 对 Service 的创建,因为在 VA 中启动 Service 和 Activity 有很大的区别。首先入口 ContextWrapper.startService():@Override public ComponentName st

ganyao939543405的博客 7800

Android 双开沙箱 VirtualApp 源码分析(三)App 启动

上一章:Android 双开沙箱 VirtualApp 源码分析(二) 在这之前,我们还是要先了解一下 VA Client Framework 和 VAService 之间的通讯方式VAService 与通讯VAService首先,VAService 是指 VA 仿造 Android 原生 framework 层 Service 实现的一套副本,举例有 VActivityManagerServic

ganyao939543405的博客 1万+

VirtualAPP,va,virtualapp源码

zh739115743的专栏 1169

Android应用分身功能介绍

作者 Steven.zhu 1     背景 从去年下半年360奇酷手机发布后,国内的手机新品发布,都会提到应用分身、微信双开等类似概念,有一些第三方应用也以分身/双开作为亮点抢占市场,一时间分身类应用成为主流手机的一个必备功能。 在了解和比较了国内的分身类产品后,我将介绍目前市面上主流的分身类产品,及其使用场景、实现原理和存在的风险整理出来,分享给大家、也作为知识的总结积累

maetelibom的博客 5万+
上一篇: Android 双开沙箱 VirtualApp 源码分析(五)BroadcastReceiver
下一篇: lxl 大厅协议 -- [libcef部分]
CoderAldrich
博客等级 码龄12年 431粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值