作者:HAI_i

原文来自:https://bbs.ichunqiu.com/thread-42982-1-1.html

0×00 前言

Virtual App是一个很强大的存在,破坏了Android 系统本身的隔离措施,可以进行免root hook和其他黑科技操作,你可以用这个做很多在原来APP里做不到事情,于此同时Virtual App的安全威胁也不言而喻。可以去看看这篇文章。VirtualApp技术黑产利用研究报告
当然还有其他东西,可以去各大论坛进行深度挖掘。
我们这次的重点是放在Anti_Virtual App上。

1.内容

1.1 第一种思路和实现

1.2  第二种思路和实现

我也不知道用什么来命名,感觉要是把思路直接写在标题里之后不好展开。不啰嗦了正文开始。

0×01 第一种思路和实现

1.思路

1.1 思路是从哪来的?

我们要防止App在VirtualAPP上运行就要通过Virtual启动App时的一些特征来逆向分析,VirtualAPP是开源的我们也可以结合源码来进行分析。

1.2 思路挖掘

Android应用隔离是基于Linux系统的多用户机制实现的,即每个应用在安装时被分配了不同的Linux用户uid/gid。而在VirtualApp中,client应用(通过VirtualApp安装的应用)与host应用(即VirtualApp本身)是具有相同用户uid的。

这个是在Virtual资料里的介绍,这里有一个值得关注的地方就是,client应用和host应用具有相同的uid。

我们来进行一个测试。

这个是我们运行在正常环境下的。

用grep过滤一下。

然后我们运行在虚拟机下用grep过滤一下。

有一个前提就是,Android 系统中的UID是在app安装的时候进行分配的,之后是不会进行更改的。而且为了可以进行沙箱和隔离,每一个APP分配到的UID是不同的,而且不同的UID仅仅拥有一个进程。这是Linux的多用户系统被阉割下成为了现在的状态,当然也提高了APP的安全性。相同的UID具有共享的特性。

就这个不同的点,我们进行测试的实现。

2. 实现

实现的方法直接使用NDK来进行开发,或者使用java也可以。
实现思路就是我在app里调用ps |grep,拿到返回行数,简单粗暴易懂,可能会有bug,针对一般情况。轻踩。

我们需要做的第一步就是,获取到APP的UID对应的UNAME。
我这里使用的是封装方法。

    struct passwd *pwd;
    pwd = getpwuid(getuid());
    char *find=pwd->pw_name;

这样可以直接拿到UNAME

然后我们使用字符串拼接,将命令结合,我是不是太啰嗦了。。。

    char cmd[20]="ps | grep ";
    LOGD("%s",cmd);
    strcat(cmd,find);
    LOGD("%s",cmd);

使用popen进行命令的运行

int getEnd(char * cmd)
{
    FILE *pp = popen(cmd, "r"); //建立管道
    if (!pp) {
        LOGD("error");
    }
    int i=0;
    char tmp[1024]; //设置一个合适的长度,以存储每一行输出
    while (fgets(tmp, sizeof(tmp), pp) != NULL) {
        if (tmp[strlen(tmp) - 1] == '\n') {
            tmp[strlen(tmp) - 1] = '\0'; //去除换行符
            i++;
        }
        LOGD("%s",tmp);
    }
    LOGD("i:%d",i);
    return i;
}

最后进行调用判断。整合一下最后的结果。

    struct passwd *pwd;
    pwd = getpwuid(getuid());
    char *find=pwd->pw_name;
    LOGD("%s",find);
    char cmd[20]="ps | grep ";
    LOGD("%s",cmd);
    strcat(cmd,find);
    LOGD("%s",cmd);
    int i =getEnd(cmd);
    if (i>4)
    {
        LOGD("This is VA!");
        kill(0, SIGKILL);
    }

3.测试

3.1 正常环境

3.2 VirtualApp环境测试

0×02 第二种思路和实现

1.思路

Virtual App有一个特点,就是在运行app的时候,如果存在so文件的话,会将so文件拷贝到自己的目录下,那么是不是可以对so文件路劲进行读取,然后进行判断,就可以区分开Virtual App和正常运行环境呢。
这个实现要对/proc/PID/maps这个文件进行分析。实现起来可能有点复杂。去git上看看有没有开源项目。
最后锁定了一个目标。https://github.com/ysrc/AntiVirtualApp

2.实现

2.1 实现思路总结

(1)拿到PID
(2)拿到/proc/PID/maps
  (3) 拿到包名
(4)拿到SO路径
(5)分析比对

2.2 拿到PID

拿到当前进程的PID的方法很多。这里有一个很简单的方法就是

int pid=getpid();

当然还有另外一种就是通过对java层进行反射拿到pid,两种都是实现了的。
反射三步走,轻松拿到,这里对返回值的掌控还没有到轻车熟路的程度,但是这样子的反射还是可以拿到的。

    //反射拿到pid
    jclass Process=env->FindClass("android/os/Process");
    jmethodID myPid=env->GetStaticMethodID(Process,"myPid","()I");
    LOGD("%d",(int)env->CallStaticIntMethod(Process,myPid));
    return (int)env->CallStaticIntMethod(Process,myPid);

2.3 拿到/proc/PID/maps

这里通过文件拼接读取就可以拿到文件指针了。

char data[256];
    char s[64] = {0};
    int pid=getpid();
    sprintf(s, "/proc/%d/maps", pid);
    FILE *fd = fopen(s, "r");
    if (fd==NULL)
    {
        LOGD("The file is field");
    } else
    {
        LOGD("ok");
    }

2.4 拿到包名。

包名可以通过/proc/PID/cmdline这个文件来拿到

我们还是进行相同的操作。然后对文件进行处理,最后拿到了我们的包名。

char *buffer = (char *) malloc(1024);
    memset(buffer, 0, 1024);
    char path_t[256] = {0};
    int pid = getpid();
    sprintf(path_t, "/proc/%d/cmdline", pid);
    int fd = open(path_t, O_RDONLY);
    if (fd > 0) {
        int read_count = (int) read(fd, buffer, 1024);
        close(fd);
        if (read_count > 0) {
            return buffer;
        }
    }
    free(buffer);
    return NULL;

进行一个测试:

2.5拿到SO路径

对我们拿到的maps进行处理。

char path[128] = {0};
    char uid[10] = {0};
    char * filter="libnative-lib.so";
    while (fgets(data, 256, fd)) {
        int len = (int) strlen(data);
        if (len <= 0) {
            continue;
        }
        data[--len] = '\0';
        if (sscanf(data, "%*llx-%*llx %s %*s %*s %*s %s", uid, path) != 2) {
            continue;
        }
            LOGD("%s",data);
        if (strcmp(uid, "r-xp") == 0 && endsWith(path, filter)) {             LOGD("getSoPath1:%s",path);
            break;      
      }
    }

进行测试
现在so也拿到了。

2.6 分析比对

比对的原理是so加载的地方大多只有三个,通过这三个加上包名进行比对,然后就可以发现VirtualApp下运行的App的so包地址已经更改为VirtualApp的地址,原因很有可能就是因为隔离的特性不能越界访问。

size_t len = strlen(p);
    int i=0;
    if (strstr(path,p) != NULL) {
        if (startsWith(path, SO_APP_LIB)) {
            if (strncmp(path + SO_APP_LIB_LEN, p, len)) {
                i++;
            }
        } else if (startsWith(path, SO_DATA_APP)) {
            if (strncmp(path + SO_DATA_APP_LEN, p, len)) {
                i++;
            }
        } else if (startsWith(path, SO_DATA_DATA)) {
            if (strncmp(path + SO_DATA_DATA_LEN, p, len)) {
                i++;
            }
        }
    }

2.7 最后进行一个结果测试

在正常的环境下运行

在VirtualApp下运行

0×03 总结

如果还想进一步深入的话,可以推荐看一下VirtualApp的源码,这样可能对各个方面理解会有很大的帮助。

以上

有问题大家可以留言哦~也欢迎大家到春秋论坛中来玩耍呢!>>>点击跳转

APK防护——Anti_Virtual App的思路和实现的更多相关文章

  1. 我的Android进阶之旅------>解决如下错误failed to copy 'Settings2.apk' to '/system/app//Settings2.apk': Read-only

    push apk的时候报错 ouyangpeng@oyp-ubuntu:~/apk升级$ adb push Settings2.apk /system/app/ failed to copy 'Set ...

  2. Flutter - You need to use a different version code for your APK or Android App Bundle because you already have one with version code 1.

    前两天提交了一个版本Google Play,结果今天收到拒绝的邮件,说App内购有问题. 于是把设置里面的支付宝和微信打赏功能关闭,又打了一个aab. 然后上传到Google Play,结果提示 Yo ...

  3. Android Apk加固的初步实现思路(dex整体加固)

    一.前 言 Android Apk加固的发展已经有一段时间了,相对来说本篇博客要记录的Android加壳的实现思路是4年的东西了,已经被老鸟玩烂了,Android加固的安全厂商也不会采用这么粗犷的方式 ...

  4. 手机APP测试思路及测试要点

    一  手机APP测试基本思路: 测试计划--测试方案--测试用例--执行: 很多小公司都没有具体的需求,项目时间也比较紧,而且流程也不是很严谨,在这样的情况之下,作为测试的我们,该怎样去对项目进行用例 ...

  5. 浏览器唤起APP的思路(本文转载)

    在做 h5 页面中,会遇到这样一个需求,有一个立即打开的按钮,如果本地安装了我们的 app,那么点击就直接唤起本地 app,如果没有安装,则跳转到下载. 首先想到的是两个问题:一是如何唤起本地 app ...

  6. 学习app开发思路

    1.首先在学习之前进行一次或者是整体或者是部分的检测,当第一次检测就通过,则可以认为是熟练掌握的东西(可以在后期对其进行验证是否是熟练)2.后面的学习过程,对回答的正确与否以及从第一次开始学习到目前为 ...

  7. 解决 genymotion 安装apk报错 app contains ARM native code and your Genymotion device cannot run ARM instructions

    1.某些APP安装在模拟器时提示“ this probably means that the app contains ARM native code and your Genymotion devi ...

  8. Windows下adb push 总是提示Failed to copy "XX.apk" to 'system/app':Read-only file system

    一般情况看到这种提示我们会想到需要root权限,然后敲上adb remount,但是当我们执行过adb remount后,提示成功,但执行push命令依旧无法完成push. 那么此时我们的做法应该是重 ...

  9. 批量执行app自动化测试思路设计图

随机推荐

  1. 阿里云视频直播PHP-SDK

    阿里云 视频直播 配置 及 PHP-SDK 接入教程准备工作域名管理配置鉴权地址生成器及DEMO演示-熟悉鉴权接入SDK推流回调的配置阿里云 视频直播 配置 及 PHP-SDK 接入教程 个人感觉,阿 ...

  2. 部署一个基于python语言的web发布环境

    ---恢复内容开始--- 1) 一门面向对象的语言 2)拥有丰富的库 3)可移植性 4)免费.开源 5)简单易易学 可做软件开发.人工智能.web开发等等 部署流程: Cnetos7.5+Nginx+ ...

  3. BUILDING WITH BOOTSTRAP

    BUILDING WITH BOOTSTRAP Bootstrap Generalizations You just built an impressive webpage using the Boo ...

  4. python入门学习2

    变量 变量名就像我们现实社会的名字,把一个值赋值给一个名字时,它会存储在存储中,称之为变量(Variable),在大多数语言中,都把这种行为称为“给变量赋值”或“把值存储在变量中”. 而Python与 ...

  5. jQuery 新添加元素事件绑定无效

    jQuery中事件绑定,大多使用on就足够了. 但是对于新添加的元素 on 的绑定事件 会不起作用. 因为 append 中的 节点是在整个文档加载之后才添加的,页面并不会为未来的元素初始化添加点击事 ...

  6. Windows驱动开发VS2012 DDK/WDK的环境配置

    [开发Windows驱动的配置是很必要的,下文将详细介绍VS2012如何配置驱动开发环境] [转载] 以下部分内容是转载博客:http://blog.csdn.net/huangxy10/articl ...

  7. IO高级应用关于字符码表

    ASCII码表: 计算机里只有数字,我在计算机软件里的一切都是用数字来表示,屏幕上显示的一个个字符也不例外.计算机诞生在美国,最开始所用到字符就是我们现在键盘上的一些符号和少数几个特殊的符号,每一个字 ...

  8. Java 基础之--注解Annotation详解

    自定义注解入门: public @interface Annotation01 { //set default value ""; String value() default & ...

  9. js原生的节点操作API

    // yi获取元素节点 //一 :过id的方式( 通过id查找元素,大小写敏感,如果有多个id只找到第一个) document.getElementById('div1'); // 通过类名查找元素, ...

  10. 点击导出table表格

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...