跳转到正文
Shane Blog
返回

APK 签名验证:换了签名的包为什么装不上去

APK 签名验证:换了签名的包为什么装不上去

折腾 APK 的时候经常会遇到”签名不一致,无法安装”这种报错,尤其是想拿一个改过的包去覆盖安装原版应用的时候。这篇聊聊 APK 签名到底在验证什么,为什么这道检查这么”较真”。

每个 APK 出厂都要签名

安卓规定,任何一个能被安装的 APK 文件,在打包完成后都必须经过数字签名才能安装——没签名的 APK,系统会直接拒绝安装。这个签名的载体是开发者自己持有的一份密钥(签名证书),不同发行渠道的正规做法是同一个开发者用同一份密钥,给自己所有版本的 App 签名。

签名的核心作用不是加密内容,而是提供两个层面的保证:一是完整性,证明这个 APK 打包完成之后没有被篡改过(哪怕改一个字节,签名校验都会失败);二是身份认证,证明这个包确实是持有对应密钥的那个开发者发布的,而不是别人冒充的。

覆盖安装时,系统在比对什么

安卓有一条规则:如果设备上已经装了某个包名(比如 com.example.app)对应的 App,想拿一个新的 APK 去覆盖安装同一个包名,系统会先比对新旧两个 APK 的签名证书是否一致。只有签名一致,才允许覆盖安装(这样才能保留原来的用户数据、权限授予状态);如果签名不一致,系统会直接拒绝这次安装,提示”签名冲突”一类的错误。

这也是为什么破解版、汉化版这类经过第三方修改重新打包的 APK,经常没法直接覆盖装到已有原版 App 的设备上——因为重新打包的过程通常会替换掉原开发者的签名证书,换成打包者自己的证书,新旧签名对不上,唯一的办法是先卸载原版,再安装修改版。

为什么不能只看包名

单纯校验包名,任何人都能发布一个包名完全一样、内容却是恶意代码的 App,冒充成正版应用去覆盖安装、窃取原 App 已经积累的权限和数据。加上签名比对之后,除非拿到了原开发者的私钥,否则没法伪造出一份能通过校验的签名,这道机制本质上是防冒名顶替、防篡改分发的关键一环。

APK 签名方案的演进

安卓的签名方案本身也经历过几次迭代,从最早基于 JAR 签名机制的 v1,到后来引入的 v2(整个 APK 文件维度做完整性校验,弥补了 v1 只校验单个文件、容易被局部篡改的漏洞)、v3(支持签名密钥轮换)、v4(配合增量安装场景优化校验速度)。新方案通常向下兼容,一个 APK 可以同时用多个版本的方案签名,系统会按能力选择校验路径,但核心逻辑始终是那两点:内容没被动过、身份对得上。

Play 商店的”签名双轨制”

如果开发者通过 Google Play App Bundle 发布应用,实际提交给用户设备的 APK,签名可能是由 Google 托管的一套独立密钥重新签署的,和开发者本地打包时用的上传密钥是两回事。这也是为什么同一个 App,从 Play 商店装的和从开发者官网直接下载的安装包,有时候签名并不完全相同——这个话题之前聊 Telegram 官网版和商店版区别的时候也提到过类似的现象。

小结

APK 签名验证解决的是”这个包到底是不是它声称的那个开发者发的、内容有没有被动过手脚”这两个问题。覆盖安装时系统比对签名一致性,本质上是在保护已经装在设备上的那份数据和权限,不被一个内容可能完全不同的”同名冒充者”顶替掉。这也是为什么修改过的第三方包,大多绕不开”先卸载再安装”这一步。


分类:
标签:
分享此文章:

上一篇
Android 权限模型简史:从安装时全给到用时才问
下一篇
刷入一个自定义 ROM,手机里到底发生了什么