Android应用安全防护的基本策略
混淆机制
代码混淆
在反编译apk后,看到的代码类名、方法名已经代码格式看起来不像正常的Android项目代码,这就是经过混淆的代码。
资源混淆
资源混淆的功能具体可看微信团队的开源项目:https://github.com/shwenzhang/AndResGuard。
对于资源混淆,在获取到资源对于的int类型值后,可在/res/values/public.xml找到对应的一个name项的值,然后通过这个name的值可以在相应的xml中查找到对应的资源。
签名保护
Android中每个应用都有一个唯一的签名。
为了防止应用被二次打包,可以在程序入口处添加签名验证,从而防止运行被修改的程序。
手动注册native方法
在Android中,当程序Java层运行System.loadLibrary(“jnitest”);这行代码后,程序会去载入jnitest.so文件。与此同时,产生一个Load事件,这个事件触发后,程序默认会在载入的.so文件的函数列表中查找JNI_OnLoad函数并执行(卸载时触发UnLoad事件,并查找JNI_OnUnload函数执行。JNI_OnLoad和JNI_OnUnload函数并不强制要求用户去实现)。一般情况下,在C组件中的JNI_OnLoad函数用来实现给VM注册接口,以方便VM可以快速地找到Java代码需要调用的C函数。
应用层的Java类通过VM而调用native函数,这个搜索的过程可能较为漫长。C组件开发者可以将本地函数向VM进行注册,从而加快后续调用native函数的效率。
一般而言,对应native层的函数名是:Java_类名_方法名
显示注册需要在native层的代码中调用如下三个函数:
(*env)->RegisterNatives(env, clazz, methods, methodsLenght)
:这个函数用于手动手动注册native方法。clazz就是需要注册native方法的那个类,methods是一个结构体包含name(Java中函数的名字)、signature(用字符串描述了函数的参数和返回值)、fnPtr(函数指针,指向C函数)。
jint JNI_OnLoad(JavaVM* vm, void* reserved)
:在这个函数里面执行上面的注册函数。
void JNI_OnUnload(JavaVM* vm, void* reserved)
反调试检测
ptrace机制有一个特点:如果一个进程被调试了,在它进程的status文件中有一个字段TracerPid会记录调试者的进程id值。通过判断这个TracerPid的值是否为0,就可以判断是否被调试中,从而实现反调试。
Android中常用权限分析
辅助功能权限
Android提供了辅助(Accessibility)功能和服务帮助用户更加简单地操作设备,包括文字转语音、触觉反馈、手势操作、轨迹球和手柄操作。辅助功能实质上就是监听应用窗口变化和事件。
使用辅助功能的时候必须声明以下权限:
1 | <application> |
在代码中直接打开相应的Intent跳转到授权界面:
1 | Intent accIntent = new Intent(Setting.ACTION_ACCESSIBILITY_SERVICE); |
存在的风险:可以监听设备当前的窗口变化,分析当前应用的View结构之后模拟点击:
- 模拟一些社交App的登录窗口页面,这样用户是无感知的。
- 当监听到当前应用是社交App,而且是聊天记录页面时,就可以得知当前聊天记录。
- 分析设备中的应用情况,在用户不知情的情况下,模拟点击任何一个应用进行操作,从而获取信息。
设备管理权限
作用类似于iPhone中的“查找我的手机”功能,可以快速定位以及擦除设备数据等。另外还可以防止被卸载。
存在的风险:申请这个权限后,设备相当于是给申请者管理了,他们可以修改设备的锁屏密码、擦除数据等。
通知栏管理权限
这个功能专门用于监听设备的通知栏消息。
存在的风险:与辅助功能一样,申请这个权限后用户设备的通知栏消息就会被它接管。
VPN开发权限
存在的风险:如果申请了这个权限,就代表这个设备的网络访问消息会被申请者接管。
Android中的run-as命令
run-as命令的作用是可以用root身份运行命令,但是必须携带指定应用包名参数,而且这个应用是debug模式的。即开发中如果想看自己应用的沙盒数据(/data/data/xxx/),在设备没有root的情况下,可以使用这个命令进行查看。
命令分析和使用
使用run-as [packagename]后即可进入相应的目录:/data/data/packagename/。
Android中命令一般都在/system/bin和/system/xbin目录下,对应的源码都在Android源码目录下的/system/core下。
run-as命令运行是有诸多限制的:
运行命令的用户id只能是shell和root用户
应用的安装必须合法
应用的uid必须合法
应用是否为debug模式
Linux中的setuid和setgid概念
Linux/Unix下的可执行文件一旦被设置了setuid标记,使用该可执行程序的进程就将拥有该执行文件的所有者权限。
Android中setuid和setgid的使用场景
zygote降级处理
zygote启动后,会进入一个轮询使用socket来监听ActivityManagerService发来的消息,比如应用的启动,zygote就fork出一个进程,开始运转。因为zygote是root用户的,所以zygote通过setuid、setgid进行降级处理,避免所有fork出来的程序都是root权限。
su工具原理
Android手机的root原理是:一个普通进程通过执行su,从而获得一个具有root权限的进程。通过配合superuser这款app,可以在需要时对应用进行授权,从而避免了root权限的滥用。
run-as命令
run-as命令本身的uid是root,gid是shell。
run-as命令的作用
在Android中要调试一个程序,首先这个程序必须是debug模式的,也就是在AndroidManifest.xml中设置的属性,所以一般是修改XML中的debug属性,然后才进行代码关联调试。
Android中的allowBackup属性
allowBackup属性介绍
Android API Level 8及以上Android系统提供了位应用程序数据的备份和恢复功能,此功能的开关由应用程序中AndroidManifest.xml文件中的allowBackup属性值决定,其默认为true,可通过adb backup
或adb restore
命令对应用数据进行备份和恢复。
这个属性的安全风险源于adb backup命令容许任何一个能够打开USB调试开关的人从Android手机中复制应用数据到外设,一旦应用数据被备份后,所有应用数据都可被用户读取;adb restore容许用户指定一个回复的数据,来源来恢复应用程序数据的创建。
Android中的签名机制
基本概念
数据摘要
数据摘要其实是一种算法,就是对一个数据源进行一个算法操作之后得到一个摘要,也叫作数据指纹。
消息摘要算法是一种能产生特殊输出格式的算法,其原理是根据一定的运算规则对原始数据进行某种形式的消息提取,提取出的信息就称为原始数据的数据摘要。
签名文件和证书文件
签名文件和证书文件是成对出现的,二者不可分离。
jarsign和signapk工具
这两个是Android中的签名工具。jarsign是用于jar签名,signapk是用于apk签名。
Android中的签名流程
signapk的源码位于:Android源码中的 com/android/signapk/sign.java。
Android签名apk后,会有一个META-INF目录,这里有三个文件:MANIFEST.MF、CERT.SF、CERT.RSA。
MANIFEST.MF
这个文件主要包括apk中所有文件的数据摘要内容。
CERT.SF
这个文件先对之前的MANIFEST.MF整个内容做一个SHA1方法哦SHA1-Digest-Manifest字段中。
然后逐条计算MANIFEST.MF文件中每一个块的SHA1,并进过BASE64编码后,记录在CERT.SF同名块中,属性名是SHA1-Digest。
CERT.RSA
这个文件就是对前面CERT.SF文件做签名操作后的结果,也就是前面提到的签名文件。