首页
论坛
课程
招聘
[程序开发] [系统相关] 黑产对抗系列之 多开检测
2021-4-5 21:03 6276

[程序开发] [系统相关] 黑产对抗系列之 多开检测

2021-4-5 21:03
6276

好久没更新了,最近事情比较多,更新有点慢,勿急。本系列会继续更新,希望能够给新手入门带来一些帮助。(本文章仅讨论安卓平台的实现,iOS和Windows的不做叙述)


  1. 多开在黑产中的作用和危害

多开/分身原本用于方便有多个微信/QQ解决同时登录的问题,但近来年多被各种黑产所利用,多见于薅羊毛、刷单,部分多开App甚至提供了篡改功能。而普通用户根本不会有多开的需求的App,一旦检测到当前运行在多开环境下,就有理由限制该用户的后续行为。


系统级多开

 


多用户模式主要用到 UserManager 相关类,切换不同的用户,在不同的用户下运行 App,实现多开。 最直观的例子是 Android 手机上的 多用户 功能, 手机分身 功能,以及 am switch-user 命令,这种简单粗暴的用法会将 Android 服务都运行一份,如果只用于应用多开,且不说资源消耗,切换用户确实是麻烦。 在Android 5.0上基于多用户功能 添加了 Android for work 功能,可以在同一个桌面启动器下使用受限用户启动 APP,而不再需要切换界面。同时将权限开发给了非系统应用。 chroot UNIX 的 chroot 系统调用在 Android 上也能用,但是需要 root 权限。 在本地挂载运行精简版系统镜像,使用远程桌面软件如 VNC 等访问本地多开的系统。目前尚未发现发行版 APP,可能在 ARM 服务器云手机中用到。


用户级技术



目前市面上的多开App的原理类似,都是以新进程运行被多开的App,并hook各类系统函数,使被多开的App认为自己是一个正常的App在运行。


从形式上来说多开App有2种形式,一种是从多开App中直接加载被多开的App,如平行空间、VirtualApp等,另一种是让用户新安装一个App,但这个App本质上就是一个壳,用来加载被多开的App,其原理和前一种是一样的,市面上多开分身这款App是用的这种形式,用户每分身一个App需新安装一个包名为dkmodel.xxx.xxx的App。


2.如何对抗?


对抗系统级多开


// --- C++ ---

#include <stdlib.h>

bool isDualApp(){

  return 0 != getuid()/100000;

}

// --- Java ---

static boolean isDualApp()

{

return 0 != Process.myUid() / 100000;

}

对抗用户级多开

public boolean checkByPrivateFilePath(Context context) {

        String path = context.getFilesDir().getPath();

        for (String virtualPkg : virtualPkgs) {

            if (path.contains(virtualPkg)) return true;

        }

        return false;

    }


public boolean checkByHasSameUid() {

        String filter = getUidStrFormat();//拿uid

        String 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;

    }

3.全新方法(全新原创)

第2段中所写的方法是从网上抄的,作用也是一般般,但是可以作为一个基本检测来用。从我最近些天研究来看,我发现了一个全新的检测方法。

bool checkDualApp(){

  char buf[128];

  readlink("/proc/self/exe",(char*)&buf,127);

  return strstr("app_process") ==0;

}

原理:大部分多开APP是通过一个自定义的启动器来启动的,而正常APP都是通过app_process或者app_process64来启动的,这时候只需要判断/proc/self/exe指向的文件是不是指向app_process即可判断是否为真实环境。


经过测试,该方法可以秒杀目前99%的多开APP。


[看雪官方培训] Unicorn Trace还原Ollvm算法!《安卓高级研修班》2021年秋季班火热招生!!

收藏
点赞2
打赏
分享
最新回复 (17)
雪    币: 94
活跃值: 活跃值 (1405)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
乌云科技团队 活跃值 2021-4-5 21:26
2
0
我特么直接内核级
雪    币: 1868
活跃值: 活跃值 (1581)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
virjar 活跃值 1 2021-4-6 09:22
3
0
3不太理解
雪    币: 3303
活跃值: 活跃值 (923)
能力值: ( LV6,RANK:85 )
在线值:
发帖
回帖
粉丝
fjqisba 活跃值 2021-4-6 09:35
4
0
顶个啊
雪    币: 1072
活跃值: 活跃值 (727)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
TUGOhost 活跃值 2021-4-6 10:53
5
0
果然是会检测文件创建的
雪    币: 551
活跃值: 活跃值 (365)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
莫灰灰 活跃值 9 2021-4-6 11:26
6
0
chroot的话,很多手机版虚拟机用的类似的技术实现的。
雪    币: 259
活跃值: 活跃值 (833)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
StriveMario 活跃值 2021-4-6 11:52
7
0
第三种我刚试了下很旧版本的virtualxposed, 路径指向就是app_process
雪    币: 26
活跃值: 活跃值 (870)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
不吃早饭 活跃值 2021-4-6 17:36
8
0
你这检测手段也太简陋了
雪    币: 1868
活跃值: 活跃值 (1581)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
virjar 活跃值 1 2021-4-6 23:37
9
0
StriveMario 第三种我刚试了下很旧版本的virtualxposed, 路径指向就是app_process[em_40]
所以解释下,3到底啥意思呢
雪    币: 26
活跃值: 活跃值 (870)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
不吃早饭 活跃值 2021-4-7 01:47
10
0

所有的android非native进程都是由zygote fork出来的,不管是不是va拉起来的。va本质上只是用了一招欺上瞒下,实际启动的还是普通的android进程,因此同样是zygote fork出来的,所以方法三是没用的,什么都检测不出来。实际上检测va的手段由很多,例如利用va在io重定向方面的遗漏,通过应该处理(但未处理)的io类syscall来进行检测;扫描VMHook时替换的jni指针;扫描libc或linker等opcode,看一下是否被inline hook了等,随便想想都能想到六七种。

最后于 2021-4-7 01:49 被不吃早饭编辑 ,原因:
雪    币: 26
活跃值: 活跃值 (870)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
不吃早饭 活跃值 2021-4-7 01:53
11
0
除了native层的检测手段外,还有很多java层的检测手段,例如看一下ClassLoader加载了的Class的类名,看看是否包含“lody”之类的特征字段;看一下ServiceManager的cache是否被进行了非法替换;看一下函数的调用堆栈等
雪    币: 26
活跃值: 活跃值 (870)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
不吃早饭 活跃值 2021-4-7 01:54
12
0

更高级一些的手段,可以手动解析一下linker内的SoInfo Map,遍历一下加载了的模块等

最后于 2021-4-7 01:55 被不吃早饭编辑 ,原因:
雪    币: 2782
活跃值: 活跃值 (195)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_evaqjarh 活跃值 2021-4-7 09:02
13
0
而普通用户根本不会有多开的需求的App
雪    币: 628
活跃值: 活跃值 (2218)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
珍惜Any 活跃值 2021-4-7 14:40
14
0
svc去读文件目录就行了
雪    币: 409
活跃值: 活跃值 (973)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
恋空 活跃值 2021-4-8 08:43
15
0
不吃早饭 所有的android非native进程都是由zygote&nbsp;fork出来的,不管是不是va拉起来的。va本质上只是用了一招欺上瞒下,实际启动的还是普通的android进程,因此同样是z ...
va我没试过这个方法,我写这个的时候是因为第一第二个方法在国内某多开里检测不了,所以写了这个
雪    币: 1358
活跃值: 活跃值 (523)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
Amun 活跃值 2021-4-8 10:34
16
0
https://bbs.pediy.com/thread-255212.htm
`从网上抄的` 没毛病。
雪    币: 3519
活跃值: 活跃值 (67)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
梨树生果 活跃值 2021-4-8 18:43
17
0
Amun https://bbs.pediy.com/thread-255212.htm `从网上抄的` 没毛病。[em_1]
我看着也眼熟
雪    币: 5917
活跃值: 活跃值 (2747)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
GitRoy 活跃值 3 2021-4-8 21:08
18
0
哥, 能不能多来点黑灰产对抗相关的东西
游客
登录 | 注册 方可回帖
返回