探究Android权限动态检察机制
一 Android权限
一般来说,Android的APK包在安装时会向Android系统申请权限,用户在安装APK时会看到此APK索要的权限,用户要么全都批准,要么拒绝本次安装。Android的权限与Android的API对应,一个APK如果获得了某项权限,这就意味着它在运行时可以调用Android的Java
API,从而实现对Android受限资源进行访问的目的。Android的权限主要包括三部分信息:权限名称,属于的组和保护级别。属于的组是指这个权限在一个权限组里。如何理解?切换到android源码framework\base\data\etc\platform.xml,如下图所示:
比如第一个权限android.permission,BLUETOOTH_ADMIN,它所在的组是net_bt_admin。保护级别分为四种,Norma,Dangerous,Signature,SignatureOrSystem,不同的保护级别代表此权限的认证级别高低,后面两种要求申请权限的APK包具有和拥有此权限的APK包相同的数字签名。如果开发者在编制Android应用程序时想要使用某种权限,比如访问网络,那么必须在应用程序的AndroidManifest.xml文件中申请,形如<use-permissions>,同样Android应用程序的某个组件也可以设置访问权限,也就是说,如果另一个组件要想执行对设有访问权限组件的操作时,必须先获取此权限。
二
Android静态权限检查
Android静态权限检查发生在安装包被解析后。Android的框架层代码frameworks\base\core\java\...\PackageParser.java负责解析APK包,并把解析到的信息保存起来,而对APK中AndroidManifest.xml文件所涉及的权限申请在框架层代码frameworks\base\services\java\com\android\server\pm\PackageManagerService.java中的grantPermissionsLPw方法中得以检查和批准:
if (bp.protectionLevel == PermissionInfo.PROTECTION_NORMAL || bp.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) { allowed = true; } else if (bp.packageSetting == null) { // This permission is invalid; skip it. allowed = false; } else if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE || bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { allowed = (compareSignatures( bp.packageSetting.signatures.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH) || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH);
从以上的代码
三
Android动态权限检查
Android会有动态权限检查吗?答案是有!这里的动态权限检查是指Android系统在APP运行时对App发起的某些操作或某些数据访问才进行的权限检查,其中就有一个方法checkUidPermission(String
permName, int uid),它也在PackageMangerService.java中被定义。此方法是根据APP的UID和此时所提出的权限名permName进行检查,方法很简单,首先根据uid找到APP在安装时所被批准的权限集,然后看看permName是不是在其中。
synchronized (mPackages) { Object obj = mSettings.getUserIdLPr(uid); if (obj != null) { GrantedPermissions gp = (GrantedPermissions)obj; if (gp.grantedPermissions.contains(permName)) {
四 实验验证动态权限检查
实验目的:试验checkUidPermission是否真的会在APP运行时进行权限检查?
实验方法:在以上代码第5行处在写一行代码:
if(uid >= 10000 && permName == "android.permission.CAMERA") {return PackageManager.PERMISSION_DENIED;}
以上代码是说只要有非系统用户申请了访问camera的权限,那么系统就拒绝。如果Android系统有权限动态检查,那么摄像功能是不能用了。
编译Android源码:
1. 模块编译
首先进行模块编译
切换到shell,切换到android的源码目录,输入:
source build/envsetup.sh lunch full-eng mmm frameworks\baser\service\java
这样只是编译java\这个模块,注意:java\必须有Android.mk文件,这相当与Linux的makefile
2. Android源码整体编译
在上述编译成功后,直接输入make
3. 运行模拟器
输入emulator,等模拟器跑起来,点击Camera程序,我们发现如下:
摄像头没有被启动。而编译之前的Camera是能够开启摄像头的,如下:
原因分析:当Camera被安装到Android系统后,Camera的APP就会被分配一个唯一的UID和GID,一般来说UID等于GID,每个APP运行在独立的沙箱(Dalvik虚拟机)里,因此,当此Camera的进程提出访问摄像设备时,到了Android框架层,checkUidPermission会被调用,从而拒绝本次访问,那么内核的进程也就无从访问此类设备了。