1. 程式人生 > >android指定簽名的apk才能安裝

android指定簽名的apk才能安裝

最近專案有需求: 只有使用特定簽名籤的apk才可以安裝,其他任何apk都不能安裝(root版,使用adb push進去的除外),以供以後參考。

我們已經知道的是:Android對每一個Apk檔案都會進行簽名,在Apk檔案安裝時,系統會對其簽名信息進行比對,判斷程式的完整性,從而決定該Apk檔案是否可以安裝,在一定程度上達到安全的目的。

給定一個Apk檔案,解壓,可以看到一個META-INFO資料夾,在該資料夾下有三個檔案:分別為MANIFEST.MF、CERT.SF和CERT.RSA。這三個檔案分別表徵以下含義:

(1)MANIFEST.MF:這是摘要檔案。程式遍歷Apk包中的所有檔案(entry),對非資料夾非簽名檔案的檔案,逐個用SHA1生成摘要資訊,再用Base64進行編碼。如果你改變了apk包中的檔案,那麼在apk安裝校驗時,改變後的檔案摘要資訊與MANIFEST.MF的檢驗資訊不同,於是程式就不能成功安裝。

說明:如果攻擊者修改了程式的內容,有重新生成了新的摘要,那麼就可以通過驗證,所以這是一個非常簡單的驗證。

(2)CERT.SF:這是對摘要的簽名檔案。對前一步生成的MANIFEST.MF,使用SHA1-RSA演算法,用開發者的私鑰進行簽名。在安裝時只能使用公鑰才能解密它。解密之後,將它與未加密的摘要資訊(即,MANIFEST.MF檔案)進行對比,如果相符,則表明內容沒有被異常修改。

說明:在這一步,即使開發者修改了程式內容,並生成了新的摘要檔案,但是攻擊者沒有開發者的私鑰,所以不能生成正確的簽名檔案(CERT.SF)。系統在對程式進行驗證的時候,用開發者公鑰對不正確的簽名檔案進行解密,得到的結果和摘要檔案(MANIFEST.MF)對應不起來,所以不能通過檢驗,不能成功安裝檔案。

(3)CERT.RSA檔案中儲存了公鑰、所採用的加密演算法等資訊。

說明:系統對簽名檔案進行解密,所需要的公鑰就是從這個檔案裡取出來的。

結論:從上面的總結可以看出,META-INFO裡面的說那個檔案環環相扣,從而保證Android程式的安全性。(只是防止開發者的程式不被攻擊者修改,如果開發者的公私鑰對對攻擊者得到或者開發者開發出攻擊程式,Android系統都無法檢測出來。)

我們將apk包解包,然後使用命令 keytool -printcert -file CERT.RSA 檢視CERT.RSA,如圖所示:

答案很明顯,CERT.RSA檔案中存放了關於簽名的資訊。


不多說,上修改程式碼:

frameworks/base/services/java/com/android/server/pm/PackageManagerService.java

import java.security.cert.Certificate;
import java.security.MessageDigest;
import java.util.Locale;

    // longroey++ start
    /**
     * Returns the {@link Certificate} fingerprint as returned by <code>keytool</code>.
     *
     * @param certificate
     * @param hashAlgorithm
     */
    public static String getFingerprint(Signature signature, String hashAlgorithm) {
        if (signature == null) {
            return null;
        }
        try {
            MessageDigest digest = MessageDigest.getInstance(hashAlgorithm);
            return toHexadecimalString(digest.digest(signature.toByteArray()));
        } catch(NoSuchAlgorithmException e) {
            // ignore
        }
        return null;
    }


    private static String toHexadecimalString(byte[] value) {
        StringBuffer sb = new StringBuffer();
        int len = value.length;
        for (int i = 0; i < len; i++) {
            int num = ((int) value[i]) & 0xff;
            if (num < 0x10) {
                sb.append('0');
            }
            sb.append(Integer.toHexString(num));
            if (i < len - 1) {
                sb.append(':');
            }
        }
        return sb.toString().toUpperCase(Locale.US);
    }
    // longroey++ end




    private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {

        ......

        try {
            pp.collectCertificates(pkg, parseFlags);
            pp.collectManifestDigest(pkg);
        } catch (PackageParserException e) {
            res.setError("Failed collect during installPackageLI", e);
            return;
        }

        // longroey++ start
        final String CUSTOMIZED_SIGNATURE = "CF:23:86:90:CB:82:73:F1:B1:F8:F0:44:9E:7A:11:47:67:C3:D5:A2";
        final Signature[] mSignatures = pkg.mSignatures;
        Slog.d(TAG, "signature fingerprint"
                + getFingerprint(mSignatures[0], "SHA-1"));
        if (!getFingerprint(mSignatures[0], "SHA-1").equals(CUSTOMIZED_SIGNATURE)) {
            res.setError(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
                    "Signature verification failed");
            return;
        }
        // longroey++ end


        /* If the installer passed in a manifest digest, compare it now. */
        if (args.manifestDigest != null) {
            if (DEBUG_INSTALL) {
                final String parsedManifest = pkg.manifestDigest == null ? "null"
                        : pkg.manifestDigest.toString();
                Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
                        + parsedManifest);
            }


            if (!args.manifestDigest.equals(pkg.manifestDigest)) {
                res.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest changed");
                return;
            }
        } else if (DEBUG_INSTALL) {
            final String parsedManifest = pkg.manifestDigest == null
                    ? "null" : pkg.manifestDigest.toString();
            Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);
        }

        ......

    }

android簽名的應用-- 禁止未經授權簽名的apk安裝

最近專案有需求: 只有使用特定簽名籤的apk才可以安裝,其他任何apk都不能安裝(root版,使用adb push進去的除外)。n多度娘、google之後最終實現,把實現程式碼羅列一下,以供以後參考.

1、使用工具自己製作簽名檔案,這個簽名就是需要提供給apk製作者簽名使用的。 

可以參考原始碼路徑 build/target/product/security/README 檔案

development/tools/make_key testkey  ‘/C=CN/ST=ShangHai/L=ShangHai/O=xxx/OU=MTK/CN=China/[email protected]'

2、使用製作好的簽名檔案簽名一個內建的apk,本例採用使用 com.mediatek.factorymode  作為以後簽名的對比物件

mediatek/packages/apps/FactoryMode/Android.mk

增加 

  1. ifeq ($(XHW_SIGNATURE_CONFIG),yes)  
  2. LOCAL_CERTIFICATE := testkey  
  3. endif  

3、在安裝過程中對比簽名,如果簽名相同的話就繼續安裝,否則給出一個錯誤號,彈一個訊息框

frameworks/base/services/java/com/android/server/pm/PackageManagerService.java

  1. private PackageParser.Package scanPackageLI(PackageParser.Package pkg,  
  2.             int parseFlags, int scanMode, long currentTime, UserHandle user) {  
  3.             ...  
  4.         if (!verifySignaturesLP(pkgSetting, pkg)) {  
  5.         ...  
  6.         }  
  7. //add start
  8.         if(com.mediatek.common.featureoption.FeatureOption.XHW_SIGNATURE_CONFIG) {  
  9.            // is xhw signatures
  10.             Signature[] xhwSignatures = getXWHSignatures();  
  11.                    if (xhwSignatures != null) {  
  12.                        if (compareSignatures(xhwSignatures, pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {  
  13.                             mLastScanError = PackageManager.INSTALL_FAILED_INVALID_SIGNATURES;  
  14.                             returnnull;  
  15.                         }  
  16.                    }  
  17.         }  
  18. //add end
  19.             // Verify that this new package doesn't have any content providers
  20.             // that conflict with existing packages.  Only do this if the
  21.             // package isn't already installed, since we don't want to break
  22.             // things that are installed.
  23.             if ((scanMode&SCAN_NEW_INSTALL) != 0) {  
  24.            ...  
  25. }         

因為在啟動是也要走 scanPackageLI 函式,故增加一個變數 mIsInstallApkFlag 判斷是否是安裝過程

  1. privatevoid installPackageLI(InstallArgs args,  
  2.             boolean newInstall, PackageInstalledInfo res) {  
  3.             ...  
  4.         Log.i(TAG, "Start installation for package: " + pkg.packageName);  
  5.  //add start
  6.     if(com.mediatek.common.featureoption.FeatureOption.XHW_SIGNATURE_CONFIG) {  
  7.         Log.i(TAG, "installPackageLI-111- mIsInstallApkFlag="+mIsInstallApkFlag);  
  8.         mIsInstallApkFlag = true;  
  9.         Log.i(TAG, "installPackageLI-222- mIsInstallApkFlag="+mIsInstallApkFlag);  
  10.     }  
  11. //add end
  12.         if (replace) {  
  13.             replacePackageLI(pkg, parseFlags, scanMode, args.user,  
  14.                     installerPackageName, res);  
  15.         } else {  
  16.             installNewPackageLI(pkg, parseFlags, scanMode, args.user,  
  17.                     installerPackageName, res);  
  18.         }  
  19.         Log.i(TAG, "Installation done for package: " + pkg.packageName);  
  20.         ...  
  21.     }              

增加的函式為:
  1. //add start
  2.     privateboolean mIsInstallApkFlag = false;  
  3.     private Signature[] getXWHSignatures(){  
  4.         if(!mIsInstallApkFlag) returnnull;  
  5.         // 取得xhw簽名    
  6.         Signature[] xhwSigns = null;  
  7.         String packageName = "com.mediatek.factorymode";  
  8. /*      try {            
  9.             //PackageInfo xhwPackageInfo = mContext.getPackageManager().getPackageInfo("com.mediatek.factorymode", PackageManager.GET_SIGNATURES);    //-- 只能取得已安裝的apk 簽名    
  10.             PackageInfo xhwPackageInfo = getPackageInfo("com.mediatek.factorymode", PackageManager.GET_SIGNATURES, Process.SYSTEM_UID);    
  11.             if(xhwPackageInfo != null){ 
  12.                 xhwSigns = xhwPackageInfo.signatures;  
  13.             } 
  14.         } catch (Exception e) {             
  15.             e.printStackTrace();    
  16.         } 
  17. if(xhwSigns != null) Log.e(TAG, "....----getXWHSignatures--xhw_Signs[0]="+xhwSigns[0].toCharsString()); 
  18. */
  19.         //another method
  20.             PackageSetting ps = mSettings.mPackages.get(packageName);  
  21.             if (ps != null) {  
  22.                 PackageParser.Package pkg = ps.pkg;  
  23.                 if (pkg == null) {  
  24.                     pkg = new PackageParser.Package(packageName);  
  25.                     pkg.applicationInfo.packageName = packageName;  
  26.                     pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;  
  27.                     pkg.applicationInfo.publicSourceDir = ps.resourcePathString;  
  28.                     pkg.applicationInfo.sourceDir = ps.codePathString;  
  29.                     pkg.applicationInfo.dataDir = getDataPathForPackage(packageName, 0).getPath();  
  30.                     pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;  
  31.                 }  
  32.                 PackageInfo xhwPackageInfo2 = generatePackageInfo(pkg, PackageManager.GET_SIGNATURES, UserHandle.getCallingUserId());  
  33.             if(xhwPackageInfo2 != null){  
  34.                 xhwSigns = xhwPackageInfo2.signatures;   
  35.             }  
  36.             }  
  37.         // reset flag
  38.         mIsInstallApkFlag = false;  
  39. 相關推薦

    android指定簽名apk才能安裝

    最近專案有需求: 只有使用特定簽名籤的apk才可以安裝,其他任何apk都不能安裝(root版,使用adb push進去的除外),以供以後參考。 我們已經知道的是:Android對每一個Apk檔案都會進行簽名,在Apk檔案安裝時,系統會對其簽名信息進行比對

    Android原始碼筆記--APK解除安裝過程

                Android中應用的解除安裝主要是通過PackageManager中提供的deletePackage()函式來解除安裝,該函式通過IPC呼叫到Pms的deletePackage()函式,繼而呼叫到deletePac

    Android studio簽名打包後安裝出現解析包有問題

    用Android studio簽名打包後安裝在一些手機上解析包出現問題,因為不涉及網路從伺服器下載安裝包,所以很大情況是由於手機系統版本過低造成。基於此,as開發預設會使用最新的SDK,所以要修改一下安裝在裝置最低版本,在build.gradle檔案中修改,一般

    解決android studio 簽名打包後安裝失敗的問題

    剛開始學簽名打包,按照教程點選開啟連線一步步的做下去,過程蠻簡單的,結果最後一步出現了一個錯誤上圖                                                  這個錯誤可以讓我崩潰,因為花了我一上午的時間去解決言歸正傳1.首先檢視minS

    android 內建apk 解除安裝後開機自動恢復的實現

    最近刷了個ROM 發現裡面有幾個內建APK,在 /system/app/ 我用 RE管理器刪除後,重新開機,莫名其妙有恢復了 我擦,按照我目前對安卓系統的瞭解,我才應該是某個開機啟動程式,在開機的時候釋放,於是我苦苦搜尋此程式未果 於是我想,android 基於 lin

    Android 生成簽名apk與多渠道打包

    一、生成簽名apk 之前我們都是通過Android Studio來將程式安裝到手機上的,而它背後實際的工作流程是Android Studio會將程式程式碼打包成一個APK檔案,然後將這個檔案傳送到手

    android jarsigner 簽名apk簡單使用說明

    jarsigner構成解析: jarsigner -verbose -keystore 簽名包路徑-signedjar apk簽名之後存放路徑 未簽名的apk檔案路徑 簽名包的別稱 舉例: jarsigner -verbose -keystore D:\test\juesK

    Android Studio 2.3 以後給apk簽名打包後安裝失敗的問題

    本人java小白,最近一直在學習java,然後接觸到AS,apk簽名打包完成並顯示打包成功(具體簽名步驟看Android Studio 程式簽名打包),在驗證簽名打包是否真的成功,發現結果顯示沒有簽名。如下圖: 谷歌搜尋了一些解決方法,發現 官網上的解釋: 標紅的地方已經提到

    android studio生成簽名apk後在手機上安裝不了

    我的應用在debug時可以正常執行,但是生成簽名apk後放到手機裡總是安裝失敗。 原因1:在Build選單下點選Select Build Variant彈出對話方塊後,看看你的Module的Build Variant是否是release,是debug的話改為release。

    android studio 簽名遇到的坑(apk無法安裝安裝後閃退)

    今天需要拿出一個版本提測,打包好以後發給測試,測試反饋安裝上以後無法開啟,一開啟就閃退。 在網上找了些資料,也有遇到同樣問題的小夥伴,在此學習總結一下; 1.android studio 打包簽名後無法安裝到手機,總是安裝失敗。這時可能是在打包的時候沒有勾選圖中兩個。 2

    Android給已生成的安裝apk用自己的keystore檔案簽名

    一、用cmd命令指定到自己安裝的jdk的bin目錄下        快捷鍵開始選單鍵+R進入圖一介面,輸入cmd,進入命令視窗, 二、準備好你自己的keystore檔案的,複製你的keys

    android studio2.3以後給apk簽名打包後安裝失敗的問題[INSTALL_PARSE_FAILED_NO_CERTIFICATES]

    自己的Android studio(windows平臺上)剛剛更新到2.3版本,在沒有充分了解它的新變化的情況下,使用的時候難免會遇到一些問題,比如gradle的問題可能是大家最常見的,不過解決的一般思路和之前(例如2.1更新到2.2之類的)沒太大區別,本文要說不是gra

    有的系統區apk需要對其系統簽名才能正常使用。

    tput 簽名 系統簽名 pem nap ava idp uil 兩個文件 韓夢飛沙 韓亞飛 [email protected]/* */ yue31313 han_meng_fei_sha 向方案公司索要platform.x509.pem 和plat

    Android 檢查手機上是否安裝指定的軟件(根據包名檢測)

    gem ++ info add 包名 boolean nta avi ray Android檢查手機上是否安裝了指定的軟件(根據包名檢測) /** * 檢查手機上是否安裝了指定的軟件 * @param context * @param packageName

    android v2簽名、渠道包安裝失敗

    android 7.0開始增加了v2簽名,能夠加速app的安裝結束。 v2簽名機制:v2是android 7.0開始引入,使用SHA256雜湊值校驗,會對每個檔案的二進位制位元組進行校驗,對應用提供更安全的保護,不管簽名後對檔案做了任何修改,都會導致在android 7.0以上的機型安裝失敗

    android 下載apk安裝apk(適配android 7.0)

        為適配7.0以後系統,首先需要在AndroidManifest.xml檔案中application節點下定義provider,如下:   <provider          android:nam

    通過Android studio生成apk安裝失敗

    自己寫了個東西虛擬機器除錯通過,想在手機測試一下,找到apk檔案,傳到手機發現如圖所示-_-||。 我日這什麼情況 讓後百度,谷歌 ---------------------------------------------------------------------

    具有系統簽名APK實現APK靜默安裝

    針對具有系統簽名許可權的APK(系統運用)要實現對其它第三方APK靜默安裝可用如下程式碼實現 1、manifest中許可權申請 <uses-permission android:name="android.permission.INSTALL_PACKAGES" />

    unity+android:大版本更新安裝下好的apk,相容任意安卓5.0,7.0,8.0版本

    Android Studio 1:在專案的res目錄下建立xml目錄,再建立file_paths.xml檔案。 <?xml version="1.0" encoding="utf-8"?> <paths> <root-pa

    android APK應用安裝解除安裝

    一:APK安裝解除安裝路徑及方式 APK是類似Symbian Sis或Sisx的檔案格式。通過將APK檔案直接傳到Android模擬器或Android手機中執行即可安裝。 1· Android應用安裝方式 1. 系統應用安裝――開機時完成,沒有安裝介面 2. 網路下載應用安裝