获取Apk的签名信息

QuibblerQuibbler 2024-03-15 约 11 分钟 2617 次阅读

获取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
    }

根据加密类型,一般有三种签名信息:MD5、SHA1、SHA256。

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

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w