参考地址:https://www.jianshu.com/p/c37b1bdb4757

多开软件检测

多开软件的检测方案这里提供5种,首先4种来自
《Android多开/分身检测》
https://blog.darkness463.top/2018/05/04/Android-Virtual-Check/

《Android虚拟机多开检测》
https://www.jianshu.com/p/216d65d9971e

这里提供代码整理,一键调用,

        VirtualApkCheckUtil.getSingleInstance().checkByPrivateFilePath(this);VirtualApkCheckUtil.getSingleInstance().checkByOriginApkPackageName(this);VirtualApkCheckUtil.getSingleInstance().checkByHasSameUid();VirtualApkCheckUtil.getSingleInstance().checkByMultiApkPackageName();VirtualApkCheckUtil.getSingleInstance().checkByPortListening(getPackageName(),CallBack);

第5种方案来自我同事的启发,我起名叫端口检测法,具体思路已经单独成文见
《一行代码帮你检测Android多开软件》
https://www.jianshu.com/p/65c841749dd6

测试情况

测试机器/多开软件* 多开分身6.9 平行空间4.0.8389 双开助手3.8.4 分身大师2.5.1 VirtualXP0.11.2 Virtual App *
红米3S/Android6.0/原生eng XXXOO OXOOO OXOOO XOOOO XXXOO XXXOO
华为P9/Android7.0/EUI 5.0 root XXXXO OXOXO OXOXO XOOXO XXXXO XXXOO
小米MIX2/Android8.0/MIUI稳定版9.5 XXXXO OXOXO OXOXO XOOXO XXXXO XXXOO
一加5T/Android8.1/氢OS 5.1 稳定版 XXXXO OXOXO OXOXO XOOXO XXXXO XXXOO

*测试方案顺序如下12345,测试结果X代表未能检测O成功检测多开
*virtual app测试版本是git开源版,商用版已经修复uid的问题
*现在方案1234检测狭义多开已经失效,建议使用方案5做广义多开检测

1.文件路径检测

public boolean checkByPrivateFilePath(Context context) {String path = context.getFilesDir().getPath();for (String virtualPkg : virtualPkgs) {if (path.contains(virtualPkg)) return true;}return false;}

2.应用列表检测

简单来说,多开app把原始app克隆了,并让自己的包名跟原始app一样,当使用克隆app时,会检测到原始app的包名会和多开app包名一样(就是有两个一样的包名)

    public boolean checkByOriginApkPackageName(Context context) {try {if (context == null)  return false;int count = 0;String packageName = context.getPackageName();PackageManager pm = context.getPackageManager();List<PackageInfo> pkgs = pm.getInstalledPackages(0);for (PackageInfo info : pkgs) {if (packageName.equals(info.packageName)) {count++;}}return count > 1;} catch (Exception ignore) {}return false;}

3.maps检测

需要维护多款分身包名

    public boolean checkByMultiApkPackageName() {BufferedReader bufr = null;try {bufr = new BufferedReader(new FileReader("/proc/self/maps"));String line;while ((line = bufr.readLine()) != null) {for (String pkg : virtualPkgs) {if (line.contains(pkg)) {return true;}}}} catch (Exception ignore) {} finally {if (bufr != null) {try {bufr.close();} catch (IOException e) {}}}return false;}

4.ps检测

简单来说,检测自身进程,如果该进程下的包名有不同多个私有文件目录,则认为被多开

    public boolean checkByHasSameUid() {String filter = getUidStrFormat();//拿uidString result = CommandUtil.getSingleInstance().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;}

5.端口检测

前4种方案,有一种直接对抗的意思,不希望我们的app运行在多开软件中,第5种方案,我们不直接对抗,只要不是在同一机器上同时运行同一app,我们都认为该app没有被多开。
假如同时运行着两个app(无论先开始运行),两个app进行一个通信,如果通信成功,我们则认为其中有一个是克隆体。

        //遍历查找已开启的端口String tcp6 = CommandUtil.getSingleInstance().exec("cat /proc/net/tcp6");if (TextUtils.isEmpty(tcp6)) return;String[] lines = tcp6.split("\n");ArrayList<Integer> portList = new ArrayList<>();for (int i = 0, len = lines.length; i < len; i++) {int localHost = lines[i].indexOf("0100007F:");//127.0.0.1:if (localHost < 0) continue;String singlePort = lines[i].substring(localHost + 9, localHost + 13);Integer port = Integer.parseInt(singlePort, 16);portList.add(port);}

对每个端口开启线程尝试连接,并且发送一段自定义的消息,作为钥匙,这里一般发送包名就行(刚好多开软件会把包名处理)

            Socket socket = new Socket("127.0.0.1", port);socket.setSoTimeout(2000);OutputStream outputStream = socket.getOutputStream();outputStream.write((secret + "\n").getBytes("utf-8"));outputStream.flush();socket.shutdownOutput();

之后自己再开启端口监听作为服务器,等待连接,如果被连接上之后且消息匹配,则认为有一个克隆体在同时运行。

private void startServer(String secret) {Random random = new Random();ServerSocket serverSocket = null;try {serverSocket = new ServerSocket();serverSocket.bind(new InetSocketAddress("127.0.0.1",random.nextInt(55534) + 10000));while (true) {Socket socket = serverSocket.accept();ReadThread readThread = new ReadThread(secret, socket);readThread.start();
//                serverSocket.close();}} catch (BindException e) {startServer(secret);//may be loop forever} catch (IOException e) {e.printStackTrace();}}

*因为端口通信需要Internet权限,本库不会通过网络上传任何隐私

作者:普通的程序员
链接:https://www.jianshu.com/p/c37b1bdb4757
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Android安全防护/检查root/检查Xposed/反调试/应用多开/模拟器检测(持续更新1.0.5)相关推荐

  1. Android安全防护/检查root/检查Xposed/反调试/应用多开/模拟器检测(持续更新)

    转载请注明出处,转载时请不要抹去原始链接.代码已上传git,欢迎star/fork/issue https://github.com/lamster2018/EasyProtector 复制代码 文章 ...

  2. android 修改编译内核源码 对抗反调试

    0×00  写在前面 攻防对立.程序调试与反调试之间的对抗是一个永恒的主题.在安卓逆向工程实践中,通过修改和编译安卓内核源码来对抗反调试是一种常见的方法.但网上关于此类的资料比较少,且都是基于AOSP ...

  3. android的反调试方法,Android平台融合多特征的APP反调试方法与流程

    本发明涉及Android平台融合多特征的APP反调试方法,属于计算机与信息科学技术领域. 背景技术: 应用程序本身并不具备反调试的功能,但是动态调试是动态分析应用逻辑.动态脱壳等攻击方式所采取的必要手 ...

  4. Android安全防护之旅---Android应用反调试操作的几种方案解析

    一.前言 在之前介绍了很多破解相关的文章,在这个过程中我们难免会遇到一些反调试策略,当时只是简单的介绍了如何去解决反调试,其实在去年我已经介绍了一篇关于Android中的安全逆向防护之战的文章:And ...

  5. Android安全防护之旅—只需要这几行代码让Android程序项目变得更加安全

    一.混淆永远都不可或缺 这里说的混淆不是说的传统大家都知道的简单混淆策略,而是高级一点的混淆策略,首先是代码混淆,大家可以参考小黄车app的代码: 看到了吧人家把代码混淆成中国人可以看懂的信息,可惜这 ...

  6. Android安全防护之旅---几行代码让Android应用变得更加安全

    我们在编码美丽微信公众号已经弄过了很多app了,不管是协议还是外挂,我们都是那么一路走过来了,在操作的过程中也发现了很多问题就是应用不在乎安全问题带来的后果,因为安全始终都是不可忽视的问题,辛辛苦苦写 ...

  7. Android逆向之旅---应用的反调试方案解析(附加修改IDA调试端口和修改内核信息)

    一.前言 在前一篇文章中详细介绍了 Android现阶段可以采用的几种反调试方案策略,我们在破解逆向应用的时候,一般现在第一步都回去解决反调试,不然后续步骤无法进行,当然如果你是静态分析的话获取就没必 ...

  8. 反调试技巧总结-原理和实现(1)(2)(3)(4)(5)(6)......

    反调试技巧总结-原理和实现 -------------------------------------------------------------------------------------- ...

  9. php反调试,反调试原理

    一. 前言 前段学习反调试和vc,写了antidebug-tester,经常会收到message希望交流或索要实现代码,我都没有回复.其实代码已经在编程版提供了1个版本,另其多是vc内嵌asm写的,对 ...

最新文章

  1. vue 怎么在字符串中指定位置插入字符_Vue数组变更方法
  2. Yann LeCun主讲!纽约大学《深度学习》2021课程全部放出,附slides与视频
  3. hibernate加载持久化对象的两种方式---------------load方式和get方式
  4. java实现word邮件合并,Aspose.Words控件操作实例—邮件合并功能概述
  5. STM32开发 -- Git的详细使用
  6. 第一阶段:Java基础之控制结构
  7. 一文完整MySQL连接查询,笛卡尔乘积,内连接外连接交叉连接
  8. 这 5 条 IntelliJ IDEA 调试技巧太强了!
  9. 《Redis入门指南》第2版 读书笔记
  10. [过年菜谱之]红烧甲鱼
  11. undefined reference to '__android_log_print'解决方案
  12. Python ConfigParser
  13. 从0开始构建自己的前端知识体系-JS-事件-键盘事件总结
  14. centos 7 8安装quaartus 遇到的问题及解决方法
  15. np合并 python_Python办公自动化自动更新不对称表格
  16. icem密度盒怎么设置_哪种外卖盒最健康?常吃外卖的必知!
  17. 堪萨斯州立大学 计算机科学,美国堪萨斯州立大学排名怎么样?热门专业有哪些...
  18. 一文搞懂如何兼容苹果HomeKit?智汀助你轻松打造智慧家庭
  19. 21届本科大数据菜鸡:我是怎么在互联网寒冬拿到腾讯、华为、京东、美团、快手等大厂offer的?
  20. mysql查询统计不及格人数_MySQL,查询及格人数,不及格人数

热门文章

  1. GAN —— Generative Adversarial Network
  2. idea启动项目报错 java:程序包xxx不存在解决方案
  3. 华为机试真题 Python 实现【报文解压缩】
  4. linux 打印date,打印当前时间
  5. 爆料微商如何自导自演!!!大揭秘...
  6. Unity异形(不规则)按钮
  7. 困境:何时使用片段与活动:
  8. 【Visual C++】游戏开发五十五 浅墨DirectX教程二十二 水乳交融的美学:alpha混合技术
  9. Java日期时间(LocalDate、LocalTime、LocalDateTime)
  10. 全球准点排名第二,谢列梅捷沃机场7月份客运量同比增长149.1%