0. 背景

目前市面上越来越多通过虚拟化多开的应用或者开源项目,包括

  • 平行空间
  • VirtualApp
  • 双开助手
  • DualSpace
  • Go双开
  • 双开精灵

其中VirtualApp是一个个人开源的,直接点击可以跳转到GitHub页面。这些虚拟化方案都已经非常成熟并且许多经过了市场的检验。

但是很多敏感的应用,比如支付,社交,金融并不想让自己运行在虚拟环境中,因为在虚拟环境中很容易进行伪造设备,进行注入,进行调试等操作。因此如何检测出应用自身是否存在于多开环境下就有应用的环境了,在检测出处于自己虚拟环境下时可以提醒用户风险,直接关闭应用或者上报服务器进行风险控制。

1. 多开基本原理

其实除了VirtualApp我粗略了解过他一部分实现以及看过一些分析文章以外,其他虚拟化应用或者框架我都没有仔细了解过,但是根据我尝试测试以及查看他们的表现形式之后,发现他们的实现原理都是类似的,通过在宿主容器上面新建一个进程供插件APK寄宿,然后通过hook一些系统接口欺骗应用—让虚拟化后应用以为自己是正常运行的独立APP,欺骗系统—让系统认为此虚拟化应用是一个已正常安装在系统的应用。

我们要做的是,如何在虚拟化的应用内部判断自己是处于虚拟化环境的。

  • 尝试直接获取已安装应用,判断是否有某些多开应用的包名,发现有几个虚拟化应用居然机智的把自己屏蔽掉,导致在虚拟化环境下无法获取到宿主应用的信息。该方法不可行。

  • 尝试在宿主应用私有目录“/data/data/pkg“下创建和删除文件,一般来说如果应用是没有被虚拟化运行的话,是没有办法访问宿主下的私有目录的,只有在uid一致的情况下才有权限访问,如果能创建和删除成功证明应用被虚拟化并且拥有和宿主一样的uid,而uid和应用是一一对应的,因此可以反推出此应用是被虚拟化出来的。本来以为这个方法是比较靠谱的,虽然要hardcode并查找出市面上大部分的虚拟化应用的包名,但至少可行。但是发现部分虚拟化框架居然连文件访问都做了保护,导致虚拟化出来的应用无法访问宿主的目录。该方法也不可行。

进行当然不止上面的两个尝试,有些已经不太记得了,但是第二个尝试的描述还是有价值的,下面将描述一个可行的方案。

2. 检测的方式

通过上面的描述,可以发现uid是一个虚拟化无法绕过的东西,不同于传统linux上的含义,因为Android是单用户系统,因此传统的uid失去了原来的意义,但是Android巧妙的修改了uid的含义:uid是系统分配的一个应用的标志,每一个APP对应一个uid。因为虚拟化并没有真正的安装应用,因此uid必定是和宿主一致的。

接下来就是在uid上面做文章了,根据上面的第二个尝试的描述,虚拟化将文件访问也做了虚拟化,因此虚拟化后的应用必定是有自己的”/data/data/pkg”私有目录的。那么这样就有一个冲突的地方了,”/data/data”目录下会为已安装的应用创建一个私有目录,并且只创建一个。那么如果一个uid下面有两个进程,进程名对应包名,而包名对应的”/data/data”私有目录有两个可以访问,那是不是就和只为一个应用创建唯一一个私有目录相冲突了
如下图所示,ps,过滤uid之后得到的结果:


可以看到com.lbe.parallel和cn.zarathustra.checkvirtualapk这两个应用的包名,但是他们的uid都为u0_a541。

总结一下,我们的检测方法就是—-如果满足同一uid下的两个进程对应的包名,在”/data/data”下有两个私有目录,则该应用被多开了。

3. 实现

在我的项目里面是用C实现的,主要是为了执行效率和代码安全考虑,但是在写总结的时候发现其实在java层也完全可以实现,为了方便各位使用和接入,不用特地拷贝一个so或者弄一个Native层,因此用Java重写了一遍,下面是一些关键代码,完整项目可查看Github。


public static boolean isRunInVirtual() {String filter = getUidStrFormat();String result = exec("ps");if (result == null || result.isEmpty()) {return false;}String[] lines = result.split("\n");if (lines == null || lines.length <= 0) {return false;}int exitDirCount = 0;for (int i = 0; i < lines.length; i++) {if (lines[i].contains(filter)) {int pkgStartIndex = lines[i].lastIndexOf(" ");String processName = lines[i].substring(pkgStartIndex <= 0? 0 : pkgStartIndex + 1, lines[i].length());File dataFile = new File(String.format("/data/data/%s",processName, Locale.CHINA));if (dataFile.exists()) {exitDirCount++;}}}return exitDirCount > 1;
}

4. 成功率测试以及总结

以下为在Android 6.0 三星Note 5,Android 7.0 一加5,Android 4.4 Sony Lt55上面测试的结果,测试包可在github上面的testcase目录下看到。

多开APP应用 测试结果
Go双开 测试通过
双开精灵 测试通过
VirtualApp 测试通过
平行空间 测试通过
双开助手 测试通过
双开精灵 测试通过

兼容性目前看来还是很有保障的

虽然这里公开的方法如果虚拟化框架作者看到还能能防御,比如hook住获取uid的接口,欺骗/data/data的访问,限制ps命令,但是我觉得虚拟化框架主要是为了某些对安全或者不介意的应用使用,如果在虚拟化框架下会产生损害应用利益的行为下,应用禁止了多开,这也是合理的。虚拟化框架不应该成为作恶的工具,方便用户固然好,但是为黑产提供方便之门就是作恶了。

Github地址
csdn资源下载

Android虚拟机多开检测相关推荐

  1. 重学Android基础系列篇(五):Android虚拟机指令

    前言 本系列文章主要是汇总了一下大佬们的技术文章,属于Android基础部分,作为一名合格的安卓开发工程师,咱们肯定要熟练掌握java和android,本期就来说说这些~ [非商业用途,如有侵权,请告 ...

  2. Android 虚拟机进化史

    按时间顺序开始介绍吧 1. Dalvik or ART? 2. Android 诞生之初 --> 单纯的 Dalvik 2.1 Dalvik虚拟机概述 2.2 Dalvik虚拟机与Java虚拟机 ...

  3. QEMU KVM 虚拟机移植之性能提高篇小结(android 虚拟机双系统方案)

    一.提升性能核心要素 1.将OPENGL 接口进行穿透调用,下面对opengl穿透做个小结 2.在arm开发板上打开kvm特性,这个qcom&mtk都是实现了的,只需要打开开关即可 二.AND ...

  4. Android中高级进阶开发面试题冲刺合集(七)

    以下主要针对往期收录的面试题进行一个分类归纳整理,方便大家统一回顾和参考.本篇是第七集~ 强调一下:因篇幅问题:文中只放部分内容,全部面试开发文档需要的可在公众号<Android苦做舟>获 ...

  5. android电池容量查看器,Android AccuBattery(电池损耗检测软件)V1.2.5 安卓专业版

    Android AccuBattery(电池损耗检测软件)是一款功能实用的提供安卓手机电池保持最佳状态而设计的电池管家软件.AccuBattery科学地维护电池健康,显示电池使用情况以及测量电池容量( ...

  6. android虚拟机启动不了,android虚拟机adb不能启动情况汇总

    在开启android虚拟机的时候,可能会遇到adb不能启动的问题. 大概有以下几下情况: 1.报错: BUILD FAILED D:\workspace\ganji\build.xml:144: Th ...

  7. Android中高级进阶开发面试题冲刺合集(四)

    以下主要针对往期收录的面试题进行一个分类归纳整理,方便大家统一回顾和参考.本篇是第四集~ 强调一下:因篇幅问题:文中只放部分内容,全部面试开发文档需要的可在公众号<Android苦做舟>获 ...

  8. android虚拟机加载机制,深入解析Android虚拟机

    深入解析Android虚拟机 编辑 锁定 讨论 上传视频 <深入解析Android虚拟机>是2014年由清华大学出版社出版的图书,作者是张子言. 书    名 深入解析Android虚拟机 ...

  9. 手游多开检测新招式,阻止手游外挂满天飞

    在2019年手机游戏用户达到6亿多人,市场规模高达1500多亿元,手游市场繁荣,同时也伴随着手游外挂的泛滥. 现如今手游行业里普遍存在的一个现象,部分恶意玩家使用多开,外挂等程序,给游戏厂商造成了不小 ...

  10. 《深入解析Android 虚拟机》——第1章,第1.3节编译Android源码

    本节书摘来自异步社区<深入解析Android 虚拟机>一书中的第1章,第1.3节编译Android源码,作者 钟世礼,更多章节内容可以访问云栖社区"异步社区"公众号查看 ...

最新文章

  1. Java并发编程基础与实战
  2. Vue.js插槽slot和作用域插槽slot-scope学习小结
  3. TCP三次握手、糊涂窗口、粘包问题
  4. nginx + mysql + php-fpm 环境
  5. Swagger2介绍
  6. 大学生java考试题库6_《JAVA程序设计》期末考试试题_(六)
  7. ArcGis融合小多边形到相邻多边形
  8. CSS3 动画插件 aos.js
  9. 10亿!北大获最大一笔校友捐赠
  10. Java反射设置list的属性值_利用java反射比较两个实体有哪些属性值不一样
  11. C++奥赛一本通贪心题解
  12. 人工智能-线性规划(单纯形法、大M法)和非线性规划(拉格朗日乘子法)python代码
  13. 5G物联网网络相关等专有名词解析-持续更新中
  14. 华为社招16级待遇2020_2020年3月16日乌鲁木齐沙依巴克区发生3.5级地震简报
  15. 【NABCD需求分析】Time Shaft·时间轴
  16. [杂记]就《10.30日华为HR体验官胡玲在心声论坛爆料内部HR腐败行为》有感
  17. SAPnbsp;BORnbsp;--nbsp;…
  18. uniapp 定位服务_uniapp使用高德地图定位
  19. wxPay微信支付订单提交提示「订单号重复」问题
  20. [RK3399][Android7.1] 移植笔记 --- 9.7寸eDP显示屏添加

热门文章

  1. vue-oss阿里云上传图片
  2. 友达5寸工控液晶屏G050VTN01.1 小尺寸液晶屏
  3. c++filt看函数名
  4. pythonscrapy爬虫ip代理池_Scrapy 框架插件之 IP 代理池
  5. android js回调函数,JavaScript回调函数的几种用法
  6. antd源码解读(6)- Affix
  7. 自动锁定计算机快捷键,电脑自动锁屏的快捷键是什么
  8. JAVA SpringBoot接科大讯飞TTS语音合成保姆式教程附源代码
  9. iOS 判断机型是否为iPhone Xs
  10. hashmap怎么保证线程安全的方式