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

相关推荐
小和尚敲代码4 天前
初识php库管理工具composer的体验【爽】使用phpword模板功能替换里面的字符串文本
开发语言·php·composer
十一侍卫13 天前
composer使用
android·android studio·composer
清冬暖雪1 个月前
在Fiddler中的Composer使用post方法发送非法数据
前端·fiddler·composer
那天的烟花雨1 个月前
android display 笔记(五)HWC(Hardware Composer)
android·笔记·composer
xianyinsuifeng2 个月前
AWS无服务器 应用程序开发—第十七章 Application Composer
serverless·aws·composer
fonx2 个月前
如何设置PHP wkhtmltopdf
开发语言·php·composer
liuxin334455662 个月前
深入掌握Symfony与Composer:PHP依赖管理的艺术
php·composer·symfony
一分半心动3 个月前
composer 安装如何彻底删除
android·php·composer
007php0073 个月前
PHP调用阿里云OSS的SDK封装成服务的完整指南与问题解决
java·开发语言·经验分享·笔记·git·功能测试·gpt·其他·nginx·百度·阿里云·docker·微信·chatgpt·架构·golang·系统架构·单元测试·appium·云计算·json·github·aigc·php·企业微信·文心一言·sass·课程设计·ai编程·laravel·微信公众平台·phpstorm·可用性测试·facebook·oneapi·twitter·composer·paddle·新浪微博·segmentfault·微信开放平台
007php0073 个月前
如何生成自定义二维码和实现安全便捷的扫码登录功能以及对接企业微信API
java·开发语言·经验分享·redis·笔记·git·功能测试·jmeter·其他·nginx·安全·百度·ajax·ci/cd·docker·微信·架构·golang·系统架构·单元测试·centos·github·jenkins·php·erlang·企业微信·postman·sass·课程设计·微信公众平台·safari·facebook·oneapi·twitter·composer·jira·paddle·新浪微博·lvs·segmentfault·微信开放平台