APK防护——Anti_Virtual App的思路和实现
作者: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的思路和实现的更多相关文章
- 我的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 ...
- 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 ...
- Android Apk加固的初步实现思路(dex整体加固)
一.前 言 Android Apk加固的发展已经有一段时间了,相对来说本篇博客要记录的Android加壳的实现思路是4年的东西了,已经被老鸟玩烂了,Android加固的安全厂商也不会采用这么粗犷的方式 ...
- 手机APP测试思路及测试要点
一 手机APP测试基本思路: 测试计划--测试方案--测试用例--执行: 很多小公司都没有具体的需求,项目时间也比较紧,而且流程也不是很严谨,在这样的情况之下,作为测试的我们,该怎样去对项目进行用例 ...
- 浏览器唤起APP的思路(本文转载)
在做 h5 页面中,会遇到这样一个需求,有一个立即打开的按钮,如果本地安装了我们的 app,那么点击就直接唤起本地 app,如果没有安装,则跳转到下载. 首先想到的是两个问题:一是如何唤起本地 app ...
- 学习app开发思路
1.首先在学习之前进行一次或者是整体或者是部分的检测,当第一次检测就通过,则可以认为是熟练掌握的东西(可以在后期对其进行验证是否是熟练)2.后面的学习过程,对回答的正确与否以及从第一次开始学习到目前为 ...
- 解决 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 ...
- Windows下adb push 总是提示Failed to copy "XX.apk" to 'system/app':Read-only file system
一般情况看到这种提示我们会想到需要root权限,然后敲上adb remount,但是当我们执行过adb remount后,提示成功,但执行push命令依旧无法完成push. 那么此时我们的做法应该是重 ...
- 批量执行app自动化测试思路设计图
随机推荐
- 【浅说】堆(heap)和栈(stack)区别
在了解堆与栈之前,我们想来了解下程序的内存分配 一个编译的程序占用的内存分为以下几个部分 : 1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式 ...
- html转换pdf
项目需求:移动端APP项目需要在手机上签订合同,将html转换成pdf格式的文件 解决方案:是用插件wkhtmltopdf; 记录用法:1.网址https://wkhtmltopdf.org/ 下载压 ...
- .Net 中读写Oracle数据库常用两种方式
.net中连接Oracle 的两种方式:OracleClient,OleDb转载 2015年04月24日 00:00:24 10820.Net 中读写Oracle数据库常用两种方式:OracleCli ...
- spark streaming之三 rdd,job的动态生成以及动态调度
前面一篇讲到了,DAG静态模板的生成.那么spark streaming会在每一个batch时间一到,就会根据DAG所形成的逻辑以及物理依赖链(dependencies)动态生成RDD以及由这些RDD ...
- 关于C语言头文件写法的探讨
我不是软件工程出身,对于这方面一直处于探索阶段. 目前按照这样的习惯吧. 除主函数所在的文件以外,为每一个源文件配置一个头文件. 头文件里面不能写变量的申明和定义.头文件里面只写 #define,st ...
- python下划线的5种含义
本文介绍了Python中单下划线和双下划线("dunder")的各种含义和命名约定,名称修饰(name mangling)的工作原理,以及它如何影响你自己的Python类. 单下划 ...
- linux增加,删除用户组,解压缩命令,VIM使用命令
ln -s 建立软连接 ln -s /usr/bin/fdfs_trackerd /usr/local/bin ln -s /usr/bin/stop.sh /usr/ ...
- 【c++】内存检查工具Valgrind介绍,安装及使用以及内存泄漏的常见原因
转自:https://www.cnblogs.com/LyndonYoung/articles/5320277.html Valgrind是运行在Linux上一套基于仿真技术的程序调试和分析工具,它包 ...
- Failed to decode downloaded font
碰到如下错误,该错误是开启layui的打印.导出.筛选列时出现的,不能正常显示图标及文字 原因: @参考文章 因为经过maven的filter,会破坏font文件的二进制文件格式,到时前台解析出错 解 ...
- 网络传输 buf 封装 示例代码
网络传输 buf 封装 示例代码 使用boost库 asio // BufferWrapTest.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h&quo ...