Android 禁止安装没有授权的第三方应用


平时也就只会跑程序,也不知道Android安装程序是个什么原理

Android应用安装有如下四种方式

1.系统应用安装――开机时完成,没有安装界面
2.网络下载应用安装――通过market应用完成,没有安装界面
3.ADB工具安装――没有安装界面。
4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面

应用安装的流程及路径 
应用安装涉及到如下几个目录:
system/app 系统自带的应用程序,无法删除
data/app 用户程序安装的目录,有删除权限。安装时把apk文件复制到此目录
data/data 存放应用程序的数据
data/dalvik-cache 将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一);


详细介绍第4 种

apk文件安装,会弹出一个安装界面,其实这是Android调用了另外一个叫PackageInstaller的APP来专门卸载和安装

apk。这个还真没想到

首先讲讲他的主界面 PackageInstallActivity

onCreate() 主要就是解析一大堆的APK信息,来判断有没有错误

initiateInstall() 检查是否安装过,有没有相同的包名

startInstallConfirm() 这里面提取权限的信息,并展示权限列表啥的,源码看的也很是头疼。。。点击确认,又到了另外一个类去进行安装的操作了。


刚开始我的想法就简单了,自己自定义个权限,第三方应用过来了我就检查它的权限列表,没有我定义的权限就不让它走后面安装的步骤,弹出了Dialog警告。

提取权限列表的代码


private List getPermissions(PackageInfo pi){

        String[] ps=pi.requestedPermissions;
        if(ps!=null){
            for (String str:ps) {
                Log.e(“AAAAAAAAAAAA”,str);
            }

            return   Arrays.asList(ps);
        }

        return  null;
    }

    private void showFailDialog(){
        final AlertDialog.Builder builder=new AlertDialog.Builder(this);
        builder.setTitle(“安装提示”)
                .setMessage(“该第三方应用缺少权限:com.example.xiefei.permission,不允许安装”)
                .setCancelable(false)
                .setPositiveButton(“确定”, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        dialogInterface.cancel();
                        PackageInstallerActivity.this.finish();
                    }
                });
        builder.create().show();
    }



=================================================================================

搞完之后发现功能是实现了,突然想到为什么不检验签名的信息呢,这样不是更加安全么

获得签名信息最为关键的就是比较公钥是不是相同的。



1.首先在系统的目录下创建个文件夹,来存放信任的.pem文件,因为.pem里通常就只包含公钥的信息,都不用加密的

  http://blog.csdn.net/mycoolx/article/details/6730435   证书的介绍

2.提取第三方应用的签名信息

//PackageParser对外隐藏,所以在外面做的话可以用反射,还有就是版本不同,API可能也有差异

http://blog.csdn.net/wulianghuan/article/details/18400581  可以看看这个


private Signature showUninstallAPKSignatures(String apkPath) {//apk的路径
        PackageParser pp=new PackageParser();
        PackageParser.Package mPackage=pp.parsePackage(new File(apkPath),PackageManager.GET_SIGNATURES);
        pp.collectCertificates(mPackage,PackageManager.GET_SIGNATURES);
        return pp.mSignatures[0];
    }

    public String parseSignature(byte[] signature) {
        String pubKey=””;
        try {
            CertificateFactory certFactory = CertificateFactory.getInstance(“X.509”);
            X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(signature));
            pubKey = cert.getPublicKey().toString();//公钥
            String signNumber = cert.getSerialNumber().toString();//证书的序列号
        } catch (CertificateException e) {
            e.printStackTrace();
        }
        return pubKey;
    }

这两个方法就可以提取第三方应用的公钥了


3.获取信任证书的公钥信息,来校验


private boolean isSystemSign(Signature sign1){
        boolean isSystemSign=false;
         File root=new File(“/system/etc”);
        File[] files = root.listFiles();
        for (File file:files) {
            if (file.isFile()&&file.getName().endsWith(“.pem”)) {
                if (getPublicKey(file.getAbsolutePath()).toString().equals(parseSignature(sign1.toByteArray()))) {
                    isSystemSign=true;
                    break;
                }
            }
        }
        return isSystemSign;
    }

通过.pem文件获得公钥
    private PublicKey getPublicKey(String filePath){
        try {
            CertificateFactory certificatefactory = CertificateFactory.getInstance(“X.509”);
            FileInputStream bais=new FileInputStream(filePath);
            X509Certificate Cert = (X509Certificate)certificatefactory.generateCertificate(bais);
            PublicKey pk = Cert.getPublicKey();
            System.out.println(“pk:”+pk.toString());
            return pk;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

做的这个东西 感觉很鸡肋,因为只有通过APK安装的方式,才会调PackageInstall这个程序,程序员通常用的adb 方式安装apk的话,完全不管这里,直接照样安装,哈哈,还真没多大的意义,不过还是可以防止比人乱下载东西的