ApkVerifier的基础使用

本文介绍如何使用ApkVerifier获取APK的签名信息。

引入

scss 复制代码
implementation("com.android.tools.build:apksig:8.2.2")

使用

ini 复制代码
val verifier: ApkVerifier = ApkVerifier.Builder(inputFile).build()
val result = verifier.verify()
val isSuccess = result.isVerified

inputFile为输入Apk的文件路径,构造一个新的Builder来验证提供的 APK 文件,该验证器旨在密切模仿 Android 平台的行为。这是为了使验证器能够用于检查 APK 的签名是否需要在 Android 上进行验证。

使用verifier.verify()获取结果。如果结果的ApkVerifier.Result.isVerified()返回true ,则可以认为 APK 已验证。验证结果还包括错误、警告以及有关签名者的信息(例如签名证书)

通过ApkVerifier.Result.errors获取错误信息。

vbscript 复制代码
var error = ""
result.errors.filter { it.issue == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY }
                    .forEach {
                        error += it.toString() + "\n"
                    }

后续使用ApkVerifier.Result.v(1/2/3)SchemeSigners获取签名方案,并获取信息

ini 复制代码
if (result.v1SchemeSigners.isNotEmpty()) {
                    for (signer in result.v1SchemeSigners) {
                        val cert = signer.certificate ?: continue
                        if (signer.certificate.type == "X.509") {
                            val subject = cert.subjectX500Principal.name
                            val validFrom = cert.notBefore.toString()
                            val validUntil = cert.notAfter.toString()
                            val publicKeyType = (cert.publicKey as? RSAPublicKey)?.algorithm ?: ""
                            val modulus = (cert.publicKey as? RSAPublicKey)?.modulus?.toString(10) ?: ""
                            val signatureType = cert.sigAlgName
                            val md5 = getThumbPrint(cert, "MD5") ?: ""
                            val sha1 = getThumbPrint(cert, "SHA-1") ?: ""
                            val sha256 = getThumbPrint(cert, "SHA-256") ?: ""
                            val apkVerifier = model.ApkVerifier(1, subject, validFrom, validUntil, publicKeyType, modulus, signatureType, md5, sha1, sha256)
                            list.add(apkVerifier)
                        }
                        signer.errors.filter { it.issue == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY }
                            .forEach {
                                error += it.toString() + "\n"
                            }
                    }
                }

V2和V3同理

ini 复制代码
                if (result.v2SchemeSigners.isNotEmpty()) {
                    for (signer in result.v2SchemeSigners) {
                        val cert = signer.certificate ?: continue
                        if (signer.certificate.type == "X.509") {
                            val subject = cert.subjectX500Principal.name
                            val validFrom = cert.notBefore.toString()
                            val validUntil = cert.notAfter.toString()
                            val publicKeyType = (cert.publicKey as? RSAPublicKey)?.algorithm ?: ""
                            val modulus = (cert.publicKey as? RSAPublicKey)?.modulus?.toString(10) ?: ""
                            val signatureType = cert.sigAlgName
                            val md5 = getThumbPrint(cert, "MD5") ?: ""
                            val sha1 = getThumbPrint(cert, "SHA-1") ?: ""
                            val sha256 = getThumbPrint(cert, "SHA-256") ?: ""
                            val apkVerifier = model.ApkVerifier(2, subject, validFrom, validUntil, publicKeyType, modulus, signatureType, md5, sha1, sha256)
                            list.add(apkVerifier)
                        }
                        signer.errors.filter { it.issue == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY }
                            .forEach {
                                error += it.toString() + "\n"
                            }
                    }
                }
​
                if (result.v3SchemeSigners.isNotEmpty()) {
                    for (signer in result.v3SchemeSigners) {
                        val cert = signer.certificate ?: continue
                        if (signer.certificate.type == "X.509") {
                            val subject = cert.subjectX500Principal.name
                            val validFrom = cert.notBefore.toString()
                            val validUntil = cert.notAfter.toString()
                            val publicKeyType = (cert.publicKey as? RSAPublicKey)?.algorithm ?: ""
                            val modulus = (cert.publicKey as? RSAPublicKey)?.modulus?.toString(10) ?: ""
                            val signatureType = cert.sigAlgName
                            val md5 = getThumbPrint(cert, "MD5") ?: ""
                            val sha1 = getThumbPrint(cert, "SHA-1") ?: ""
                            val sha256 = getThumbPrint(cert, "SHA-256") ?: ""
                            val apkVerifier = model.ApkVerifier(3, subject, validFrom, validUntil, publicKeyType, modulus, signatureType, md5, sha1, sha256)
                            list.add(apkVerifier)
                        }
                        signer.errors.filter { it.issue == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY }
                            .forEach {
                                error += it.toString() + "\n"
                            }
                    }
                }

这样就可以获取到Apk的签名信息,界面如图

完整代码如下

ini 复制代码
    /**
     * 签名验证
     */
    fun apkVerifier(input: String) {
        launch(Dispatchers.IO) {
            updateApkVerifierState(UIState.Loading)
            val list = ArrayList<model.ApkVerifier>()
            val inputFile = File(input)
            val path = inputFile.path
            val name = inputFile.name
            val verifier: ApkVerifier = ApkVerifier.Builder(inputFile).build()
            try {
                val result = verifier.verify()
                var error = ""
                val isSuccess = result.isVerified
​
                result.errors.filter { it.issue == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY }
                    .forEach {
                        error += it.toString() + "\n"
                    }
​
                if (result.v1SchemeSigners.isNotEmpty()) {
                    for (signer in result.v1SchemeSigners) {
                        val cert = signer.certificate ?: continue
                        if (signer.certificate.type == "X.509") {
                            val subject = cert.subjectX500Principal.name
                            val validFrom = cert.notBefore.toString()
                            val validUntil = cert.notAfter.toString()
                            val publicKeyType = (cert.publicKey as? RSAPublicKey)?.algorithm ?: ""
                            val modulus = (cert.publicKey as? RSAPublicKey)?.modulus?.toString(10) ?: ""
                            val signatureType = cert.sigAlgName
                            val md5 = getThumbPrint(cert, "MD5") ?: ""
                            val sha1 = getThumbPrint(cert, "SHA-1") ?: ""
                            val sha256 = getThumbPrint(cert, "SHA-256") ?: ""
                            val apkVerifier = model.ApkVerifier(1, subject, validFrom, validUntil, publicKeyType, modulus, signatureType, md5, sha1, sha256)
                            list.add(apkVerifier)
                        }
                        signer.errors.filter { it.issue == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY }
                            .forEach {
                                error += it.toString() + "\n"
                            }
                    }
                }
​
                if (result.v2SchemeSigners.isNotEmpty()) {
                    for (signer in result.v2SchemeSigners) {
                        val cert = signer.certificate ?: continue
                        if (signer.certificate.type == "X.509") {
                            val subject = cert.subjectX500Principal.name
                            val validFrom = cert.notBefore.toString()
                            val validUntil = cert.notAfter.toString()
                            val publicKeyType = (cert.publicKey as? RSAPublicKey)?.algorithm ?: ""
                            val modulus = (cert.publicKey as? RSAPublicKey)?.modulus?.toString(10) ?: ""
                            val signatureType = cert.sigAlgName
                            val md5 = getThumbPrint(cert, "MD5") ?: ""
                            val sha1 = getThumbPrint(cert, "SHA-1") ?: ""
                            val sha256 = getThumbPrint(cert, "SHA-256") ?: ""
                            val apkVerifier = model.ApkVerifier(2, subject, validFrom, validUntil, publicKeyType, modulus, signatureType, md5, sha1, sha256)
                            list.add(apkVerifier)
                        }
                        signer.errors.filter { it.issue == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY }
                            .forEach {
                                error += it.toString() + "\n"
                            }
                    }
                }
​
                if (result.v3SchemeSigners.isNotEmpty()) {
                    for (signer in result.v3SchemeSigners) {
                        val cert = signer.certificate ?: continue
                        if (signer.certificate.type == "X.509") {
                            val subject = cert.subjectX500Principal.name
                            val validFrom = cert.notBefore.toString()
                            val validUntil = cert.notAfter.toString()
                            val publicKeyType = (cert.publicKey as? RSAPublicKey)?.algorithm ?: ""
                            val modulus = (cert.publicKey as? RSAPublicKey)?.modulus?.toString(10) ?: ""
                            val signatureType = cert.sigAlgName
                            val md5 = getThumbPrint(cert, "MD5") ?: ""
                            val sha1 = getThumbPrint(cert, "SHA-1") ?: ""
                            val sha256 = getThumbPrint(cert, "SHA-256") ?: ""
                            val apkVerifier = model.ApkVerifier(3, subject, validFrom, validUntil, publicKeyType, modulus, signatureType, md5, sha1, sha256)
                            list.add(apkVerifier)
                        }
                        signer.errors.filter { it.issue == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY }
                            .forEach {
                                error += it.toString() + "\n"
                            }
                    }
                }
​
                if (isSuccess || list.isNotEmpty()) {
                    val apkVerifierResult = ApkVerifierResult(isSuccess, path, name, list)
                    updateApkVerifierState(UIState.Success(apkVerifierResult))
                } else {
                    if (error.isBlank()) {
                        error = "APK签名验证失败"
                    }
                    updateApkVerifierState(UIState.Error(error))
                }
            } catch (e: Exception) {
                updateApkVerifierState(UIState.Error(e.message ?: "APK签名验证失败"))
                e.printStackTrace()
            }
            if (apkVerifierState is UIState.Error) {
                delay(1000)
                updateApkVerifierState(UIState.WAIT)
            }
        }
    }
​
    private fun getThumbPrint(cert: X509Certificate?, type: String?): String? {
        val md = MessageDigest.getInstance(type) // lgtm [java/weak-cryptographic-algorithm]
        val der: ByteArray = cert?.encoded ?: return null
        md.update(der)
        val digest = md.digest()
        return hexify(digest)
    }
​
    private fun hexify(bytes: ByteArray): String {
        val hexDigits = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
        val buf = StringBuilder(bytes.size * 3)
        for (aByte in bytes) {
            buf.append(hexDigits[aByte.toInt() and 0xf0 shr 4])
            buf.append(hexDigits[aByte.toInt() and 0x0f])
            if (bytes.indexOf(aByte) != bytes.size - 1) {
                buf.append(':')
            }
        }
        return buf.toString()
    }

参考:Jadx

相关推荐
芝麻酱堂22 天前
CentOS7.9 安装 Composer
php·composer
DreamCoders22 天前
Composer 设置 阿里云 全量镜像
阿里云·php·laravel·composer
微刻时光1 个月前
Linux编译部署PHP环境
linux·开发语言·redis·git·php·apache·composer
pikazo1 个月前
composer详解
android·php·composer
王大爷~1 个月前
composer环境变量(phpstudy集成环境)无法使用问题
php·composer
小和尚敲代码2 个月前
初识php库管理工具composer的体验【爽】使用phpword模板功能替换里面的字符串文本
开发语言·php·composer
十一侍卫2 个月前
composer使用
android·android studio·composer
清冬暖雪3 个月前
在Fiddler中的Composer使用post方法发送非法数据
前端·fiddler·composer
那天的烟花雨3 个月前
android display 笔记(五)HWC(Hardware Composer)
android·笔记·composer
xianyinsuifeng4 个月前
AWS无服务器 应用程序开发—第十七章 Application Composer
serverless·aws·composer