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

相关推荐
longxiangam3 天前
Composer 私有仓库搭建
php·composer
繁星无法超越18 天前
足迹Footprint——一款个性化轨迹记录安卓app
java·开发语言·科技·kotlin·composer
Hao.Zhou22 天前
phpstudy 进行 composer 全局配置
php·composer
云游云记1 个月前
php Composer 使用全攻略
开发语言·php·composer
ddsoft1231 个月前
在装配拆卸指导动画中如何制作螺栓批量旋出的逼真视频
composer·软件·solidworks
强化试剂1 个月前
Acridinium-Biotin,吖啶生物素偶联物在化学发光免疫分析中的应用逻辑
erlang·laravel·composer
符哥20081 个月前
android compose 常用组件
android·composer
泓博2 个月前
Android状态栏文字图标设置失效
android·composer
神话20092 个月前
使用 Jetpack Compose 和 ML Kit 打造现代化二维码扫描应用
android jetpack·composer
zjw_swun2 个月前
Compose原理简易实现
android·composer