Android有一个权限叫读取已安装应用列表,貌似不是原生权限,禁用后,应用就读不到系统的应用列表,只能读到它自己。
实测发现,这个权限形同虚设,利用该漏洞可以绕过读取应用列表权限获取所有应用,目前发现共有四种方法能读取到全部或部分应用列表,该bug截止目前未修补。
方法一:getPackageManager().queryIntent*
这种方法可以获取部分应用,在某些手机上无效。
方法二:adb shell命令
list packages 列表所有应用包名
package 输出所有包信息
如果禁止了读取应用权限,在大部分手机上能获取全部应用,但在oppo手机上不起作用。
方法三:getPackageManager().GetPackagesForUid()
这种方法几乎是万能的,能获取全部应用列表。该方法称为暴力枚举法,遍历系统所有uid,并返回应用id(包名),拿到应用id,剩下只需要来个getPackageInfo即可,但是速度稍慢(慢了0点秒到1秒,其实已经算快了,正常获取应用列表慢的话也需要几秒),如果不要求完美,可以遍历其中一部分,比如前1000个,毕竟一般人的手机不可能装上千个应用。
以上三种方法,推荐方法三,具体实现时首先调用原始api(getInstalledPackages)获取应用列表,然后遍历列表判断是否包含包名为android(系统必需应用)的应用,或者判断其它也行,比如设置(),系统ui()等,如果不包含,则说明权限被禁,然后再强制读取应用。
第三种方法代码如下:
private static List<PackageInfo> forceGetPackageList(Context context) {
PackageManager pm = ();
List<PackageInfo> mList = new ArrayList<>();
//系统应用uid从1000开始,用户应用uid从10000(FIRST_APPLICATION_UID)开始,直接合并查询
for (int i = Process.SYSTEM_UID; i <= Process.LAST_APPLICATION_UID; i++) {
String[] apps = null;
try {
apps = (i);
} catch (Exception e) {
();
}
if (apps != null) {
for (String app : apps) {
try {
PackageInfo info = (app, 0);
if (info != null) {
(info);
}
} catch (Exception e) {
();
}
}
}
}
return mList;
}