获取Apk的签名信息

Quibbler 9月前 695

获取Apk的签名信息


        篡改包名是常见的攻击手段,但修改签名是具有难度的。因此某些场景下对包进行签名校验,是安全的一种常规手段。



1、使用keytools命令

        借助keytool工具可以查看Apk的签名,该工具在JDK的\jdk\bin目录下。

    keytool.exe -printcert -jarfile ***.apk

        可以查看到Apk的签名等信息:

签名者 #1:
证书 #1:
所有者: EMAILADDRESS=bbktel@bbktel.com, CN=bbkmobile.com.cn, OU=IQOO, O=BBK, L=Dongguan View, ST=Guangdong, C=CN
发布者: EMAILADDRESS=bbktel@bbktel.com, CN=bbkmobile.com.cn, OU=IQOO, O=BBK, L=Dongguan View, ST=Guangdong, C=CN
序列号: b153730d8a352539
生效时间: Tue Sep 25 22:19:43 CST 2012, 失效时间: Sat Feb 11 22:19:43 CST 2040
证书指纹:
         SHA1: 28:3D:60:DD:CD:20:C5:6E:A1:71:9C:E9:05:27:F1:23:5A:E8:0E:FA
         SHA256: BC:C3:5D:4D:36:06:F1:54:F0:40:2A:B7:63:4E:84:90:C0:B2:44:C2:67:5C:3C:62:38:98:69:87:02:4F:0C:02
签名算法名称: SHA1withRSA (弱)
主体公共密钥算法: 2048 位 RSA 密钥
版本: 3
扩展:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: B0 EC 8F E3 EE BB A8 53   25 F3 ED 9F 8E D3 74 9D  .......S%.....t.
0010: A1 83 73 23                                        ..s#
]
[EMAILADDRESS=bbktel@bbktel.com, CN=bbkmobile.com.cn, OU=IQOO, O=BBK, L=Dongguan View, ST=Guangdong, C=CN]
SerialNumber: [    b153730d 8a352539]
]
#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:true
  PathLen: no limit
]
#3: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: B0 EC 8F E3 EE BB A8 53   25 F3 ED 9F 8E D3 74 9D  .......S%.....t.
0010: A1 83 73 23                                        ..s#
]
]
Warning:
证书 使用的 SHA1withRSA 签名算法被视为存在安全风险。此算法将在未来的更新中被禁用。

        如果是未签名的Apk则是没有以上信息的,使用Android Studio编译出来的包含有默认签名。



2、通过代码获取

        在Android中,可以借助PackageManager拿到应用的PackageInfo,从而获取签名信息。查询包名或者Apk的信息,需要一定的权限,在Android 11之后收紧了查询手机上安装应用的信息,详见包可见性引起的问题:Unable to start service Intent U=0: not found一文。

    /**
     * Return the signature information of the corresponding package
     *
     * @param context
     * @param packageName
     */
    fun getSignatures(context: Context, packageName: String): Array<Signature>? {
        return try {
            val packageInfo: PackageInfo? = context.packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
            packageInfo?.signatures
        } catch (_: PackageManager.NameNotFoundException) {
            null
        }
    }

        拿到应用的Signature信息后,需要进一步的解析其实的签名信息,转换为可读的字符串:

    /**
     * Obtain the corresponding type of string (convert the signed byte [] information to hexadecimal)
     *
     * @param sig
     * @param type
     */
    fun getSignatureString(sig: Signature, type: String): String {
        var fingerprint = "error!"
        try {
            val hexBytes: ByteArray = sig.toByteArray()
            val digest: MessageDigest = MessageDigest.getInstance(type).apply {
                reset()
                update(hexBytes)
            }
            val buffer = StringBuffer()
            val byteArray = digest.digest()
            for (i in byteArray.indices) {
                val bi = Integer.toHexString(0xFF and byteArray[i].toInt())
                if (bi.length == 1) {
                    //Fill in 0 and convert to hexadecimal
                    buffer.append("0").append(bi)
                } else {
                    //Convert to hexadecimal
                    buffer.append(bi)
                }
            }
            //Convert to uppercase
            fingerprint = buffer.toString().uppercase(Locale.getDefault())
        } catch (_: NoSuchAlgorithmException) {
        }
        return fingerprint
    }

        根据加密类型,一般有三种签名信息:MD5SHA1SHA256

    const val MD5 = "MD5"
    const val SHA1 = "SHA1"
    const val SHA256 = "SHA256"

        进一步提炼出下面的方法,方便获取对应类型的签名:

    /**
     * Returns a string of the corresponding type for a signature
     *
     * @param context
     * @param packageName
     * @param type
     */
    fun getSingInfo(context: Context, packageName: String, type: String): String {
        var signStr = "error!"
        try {
            val signs: Array<Signature>? = getSignatures(context, packageName)
            val sig: Signature = signs!![0]
            signStr = getSignatureString(sig, type)
        } catch (_: Exception) {
        }
        return signStr
    }

        使用起来也非常方便,示例,获取微信(com.tencent.mm)的签名信息:

    getSingInfo(context, "com.tencent.mm", SHA256)
    //0FE4FF85C215918396DADC7CD8CE6963339AF33D37751A56E54C7206B63A3C7C


不忘初心的阿甘
最新回复 (0)
    • 安卓笔记本
      2
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com