简体   繁体   中英

How to get signature of a sideloaded APK from PackageInstaller

I am trying to build a custom Android (based on AOSP 7.1) for a device. I would like to get the signature of apps that is to be sideloaded via USB. The apps are not installed on the system yet. My eventual goal is to compare the signature of an APK vs platform signature like this: https://gist.github.com/scottyab/b849701972d57cf9562e

I found many guides, including this one - How to get APK signing signature?

and followed the comment by Shengfeng Li on the accepted answer - "You need to push the not installed apk to the location where you program can get the apk such as SD_CARD, then use context.getPackageManager().getPackageAchiveInfo(NOT_INSTALL_APK_PATH,PackageManager.GET_SIGNATURES) .signatures[0] to get its hashCode. and compare them"

I am modifying the PackageInstaller app that is in AOSP ( https://github.com/aosp-mirror/platform_packages_apps_packageinstaller/blob/master/src/com/android/packageinstaller/PackageInstallerActivity.java ).

I modified the processPackageUri function of the PackageInstallerActivity.java like this (added PackageManager.GET_SIGNATURES flag):

case SCHEME_FILE: {
    File sourceFile = new File(packageUri.getPath());
    PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);

    // Check for parse errors
    if (parsed == null) {
        Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
        showDialogInner(DLG_PACKAGE_ERROR);
        setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
        return false;
    }
    mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
            PackageManager.GET_PERMISSIONS|PackageManager.GET_SIGNATURES, 0, 0, null,
            new PackageUserState());

    as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
} break;

Signature validation function

public boolean validateAppSignature() throws NameNotFoundException {
        boolean sigMatch = false;

        try {
            for (Signature signature : mPkgInfo.signatures) {
                // SHA1 the signature
                String sha1 = getSHA1(signature.toByteArray());
                // check if it matches hardcoded value
                sigMatch = PLATFORM_SIGNATURE.equals(sha1);
                if (sigMatch){
                  return sigMatch;  
                }
            }
        } catch (Exception e) {
                e.printStackTrace();
            }

        return false;

}

I hope to get the hash of the signature of the APKs but it is throwing this error, (from adb logcat) W System.err: java.lang.NullPointerException: Attempt to get length of null array

probably from the try part for (Signature signature : mPkgInfo.signatures) . I suspect that PackageParser.generatePackageInfo part is wrong and it is not returning any signature. Can someone enlighten me please? Thanks a lot.

Addendum: I found that the PackageInstaller app was indeed getting no signatures. I traced the codes and found the following in src/com/android/packageinstaller/PackageUtil.java :

public static PackageParser.Package getPackageInfo(File sourceFile) {
    final PackageParser parser = new PackageParser();
    try {
        return parser.parsePackage(sourceFile, 0);
    } catch (PackageParserException e) {
        return null;
    }
}

parsePackage function is from frameworks/base/core/java/android/content/pm/PackageParser.java which like this:

public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackage(packageFile, flags);
        } else {
            return parseMonolithicPackage(packageFile, flags);
        }
    }

It accepts flags but PackageUtil.java passes no flags to it and I think that's the reason I am not getting any signatures of the apk files. I think I may need to call collectCertificates(Package, int) from PackageParser.java if I want the signatures.

Am I on the right track? Your inputs are highly appreciated.

I managed to solve this, thanks to the comment by @ChrisStratton. I needed to call collectCertificates from PackageInstallerActivity.java , like so:

case SCHEME_FILE: {
    File sourceFile = new File(packageUri.getPath());

    PackageParser.Package parsed = PackageUtil.getPackageInfoMod(sourceFile, PackageManager.GET_PERMISSIONS|PackageManager.GET_SIGNATURES);

    // Check for parse errors
    if (parsed == null) {
        Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
        showDialogInner(DLG_PACKAGE_ERROR);
        setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
        return false;
    }
    else {
        try {
            PackageParser.collectCertificates(parsed, PackageManager.GET_SIGNATURES);
        } 
            catch (Exception e) {
            e.printStackTrace();
        }
    }
    mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
            PackageManager.GET_PERMISSIONS|PackageManager.GET_SIGNATURES, 0, 0, null,
            new PackageUserState());
    as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
} break;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM