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

相关推荐
zgscwxd8 小时前
如何运行Composer安装PHP包 安装JWT库
composer·jwt库
凡人的AI工具箱18 天前
每日学习30分轻松掌握CursorAI:多文件编辑与Composer功能
人工智能·python·学习·ai·ai编程·composer·cursor
至天25 天前
Laravel 新 WebSocket 服务 Reverb 使用指南
websocket·php·laravel·broadcast·composer·队列·reverb
新知图书1 个月前
使用Composer初始化ThinkPHP 8应用
php·composer
vvw&1 个月前
如何在 Ubuntu 22.04 上安装和使用 Composer
linux·运维·服务器·前端·ubuntu·php·composer
冷子夜1 个月前
Composer指定php版本执行(windows)
开发语言·php·composer
itinymeng2 个月前
Windows环境下Composer的安装和使用说明
windows·php·composer
007php0072 个月前
php项目的sdk封装成composer包的创建与发版
运维·开发语言·nginx·golang·github·php·composer
loong_XL2 个月前
AI在线免费视频工具4:AI视频编辑ai-video-composer
人工智能·音视频·composer
IAM四十二3 个月前
Jetpack Compose State 你用对了吗?
android·android jetpack·composer