Android 7.0中新签名对多渠道打包的影响详解

老签名多渠道打包原理

前言

由于Android7.0发布了新的签名机制,加强了签名的加固,导致在新的签名机制下无法通过美团式的方式再继续打多渠道包了。不过在说新的签名机制对打包方案的
影响和为什么会影响我们原有的打包机制之前,需要先简单理解下打包原理和签名在整个打包过程中的作用。

Android打包流程

Android打包过程大致如图所示,整个流程就是将Java代码,资源文件以及第三方库整合成一个Apk文件,并对整合后的文件进行签名和优化对齐。整个过程可以简

单分为以下几个步骤:

  1. 资源预编译  为每一个非assert资源生成一个ID并保存在一个R文件中。
  2. Java文件编译  把手动编写的Java文件和前面步骤生成的Java文件一起编译成.class文件
  3. Dex文件生成  把前面生成的class文件和第三方库的class文件一起整合成.dex文件,相当于所有.class文件的索引表,可以通过这个文件找到每一个.class文件
  4. 资源文件打包  对资源进行大小进行优化,并把所有有ID的资源对应的配置信息收录生成resource.arsc文件中,相当于资源的索引表。
  5. APK文件生成  把之前生成的.dex文件和resource.arsc文件以及资源文件(res文件,里面包含一些已编译成二进制的文件如布局文件等和一些未编译成二进制的文件如图片等)和未分配ID的文件(assert文件)等整合成一个APk文件(特殊的.zip文件)。
  6. 签名  对生成的APK进行签名,添加唯一标识,从而保证能够正常安装和覆盖安装,不会被恶意覆盖,以及说明APK的来源和拥有者。
  7. 对齐处理  对APK中一些资源的二进制上的位置进行调整,从而加快APk运行时的速度。

APK生成的步骤大概就是这个样子,我们不需要纠结一些细节上的实现,只要大概了解这些流程就能理解后面我们打包方案的原理了。当然,这么看会觉得APK

是一个很神奇的文件,能够安装并且运行。其实,APK只是一中比较特别的.zip文件而已,只是它可以被我们的Android机器识别并且安装成一个应用,我们可以把APK文件解压出来看一下里面的内容。

可以看到文件内容和我们前面说的基本一致,接下来再看看最重要的一个文件夹,就是第三章图里的文件,这些文件都在META-INF文件夹里,这就是我们在签名过程中加入的文件来作为APK的唯一标识。那么这对我们打包优化来说有什么意义呢,这里先保留下悬念,待会儿来说。在了解这个之前必须先把签名这件事情说清楚。

签名的作用和原理

签名的作用

Android App在开发时都有一个唯一的标识,我们把它叫做包名,比如大客户端的包名是com.Quanr,包名就像身份证号一样,是和每一个人一一对应的,在把App安装时机器也是通过包名来识别应用的,一个机器中不能存在两个包名一样的应用,这就是App在机器中的唯一性。我们在给App升级的时候,比如覆盖安装,就是通过包名来进行识别和对应的覆盖,这样才能保证App可以顺利升级而不会覆盖了其他的App,同样,别的App包名不同也无法覆盖我们的App。虽然Android提供了一套包名识别机制,但仅有包名就可以了吗。试想一下,如果别人用我们的包名新建一个App想要覆盖我们的App亦或是不法分子破解我们的
App往里面添加一些自己的内容,比如内嵌广告来牟利,把篡改过的App再发出去让用户覆盖安装,我们可能会受到巨大的损失。当然这种事情是不会发生的,Google为每一个App增加了一个签名机制,就像我们去银行办理业务,不但要提供身份证,还要签字画押,身份证号大家都可以看到,但签字画押只有自己才能做,别人是无法模仿的,App正是通过这种机制保证了自身的唯一性和安全性。

那么,签名是如何做到这些的呢。

签名的原理

对Apk签名有好几种工具,但原理都是大同小异的,这里拿signapk这个工具来说,对apk签名只要用这个工具附带一些参数以及我们的唯一的签名文件就可以完成了,直接使用工具签名是很简单的,我们更需要关注的是它的原理和具体是怎么实现的,这样才能帮助我们从中找出打渠道包的秘密。在使用签名工具之前我们必须准备好签名要用的私钥和公钥(a–(私钥)–>b–(公钥)–>a,最好用图片展示),然后再用签名工具对apk签名,之后签名流程会在apk里新建META-INF文件夹并在里面生成三个文件,这三个文件就是签名的关键和验证的依据。

从图中可以看到三个文件分别是:

  1. MANIFEST.MF
  2. CERT.RSA
  3. CERT.SF

接下来说说这三个文件是怎么生成的。

MANIFEST.MF

先看看它的内容,可以看到是一些Name对应的SHA1的值,很容易就能知道这个文件保存的是每一个文件对应的一个唯一的值。MANIIFEST.MF文件的功能就如刚才说的一样,在对APK签名的时候,首先会对每一个文件进行数字编码,生成一个唯一的SHA1的值,不同的文件内容不一样所对应的SHA1的值也是不同的,所以如果有人篡改了文件内容,那么相应的SHA1的值也会发生变化。在对APK进行签名的时候检查自己的每一个文件,并生成对应的SHA1值,把这些内容都保存在一个新建的MANIFEST.MF文件中,并把这个文件放到META-INF目录下,就完成了第一个签名文件的生成。

CERT.SF

在生成了一个MANIFEST.MF文件之后,就能记录下我们每一个文件的唯一值,从而保证文件不被篡改,这样虽然保证了MANIFEST中记录文件的安全,但却无法保证自身的安全,别人照样可以修改原有文件之后生成对应的SHA1值然后再修改MANIFEST文件,所以我们还要对MANIFEST进行加固,从而保证安全性。在进行完第一个文件生成后,签名工具开始生成第二个文件了,这个文件就是CERT.RSA。在这个步骤里,对上一步生成的文件继续进行一次数字编码,把结果保存在这个新生成了CERT.RSA文件的头部,在继续对MANIFEST.MF文件中各个属性块做一次数字编码,存到到CERT.SF文件的一个属性块中。

CERT.RSA

这个文件都是二进制的,生成完CERT.SF文件之后,我们用私钥对CERT.SF进行加密计算得出签名,将得到的签名和公钥的数字证书的信息一起保存到CERT.RSA中,整个签名过程就结束了。

下面再简单叙述一下Apk安装过程中的验证步骤,其实就是和生成签名文件的步骤类似:

  1. 首先检验Apk中的所有文件的数字编码和MANIFEST.MF中的数字编码一致
  2. 验证CERT.SF文件的签名信息和CERT.RSA中的内容是否一致
  3. MANIFEST.MF整个文件签名在CERT.SF文件中头属性中的值是否匹配以及验证MANIFEST.MF文件中的各个属性块的签名在CERT.SF文件中是否匹配

从上面的过程中,可以很明显的发现一个问题,在这个过程中从来就没有对META-INF里的任何文件进行数字编码和加密,因为这个文件夹是签名时生成的,在生成第一个文件MANIFEST.MF时并没有对这个文件夹里的任何文件进行数字编码,因为这个文件夹一定是空的,第二个文件是基于第一个文件生成的,第三个文件又是基于第二个生成的,所以整个过程中,这个META-INF文件夹几乎是在控制范围之外的。我们可以在里面添加一些文件从而躲过签名这个过程。这就是美团多渠道包方案的突破口。

美团通过利用签名原理来完成多渠道打包

通过前面打包过程的了解,可以知道想快速打多渠道包,就得跳过打包的阶段直接想办法对Apk文件进行修改,但这得挑战Android的签名校验规则了,不过正好,通过刚才我们对签名过程的分析,我们发现可以在META-INF文件夹里随意添加文件从而躲过签名规则的检查,这时候新方案就孕育而生了,在打包生成了一个没有渠道的Apk文件后,我们copy这个Apk并在在META-INF里添加一个文件,然后通过文件名来确定渠道号,不同的Apk里就在META-INF里添加不同的渠道名文件,即可确定不同的渠道了,之后要做的就是在我们需要渠道参数的时候直接去这个文件里拿就行了,完美的跳过了打包这个过程。那么这种方案的耗时呢?仅仅就是基于一个Apk文件的基础上复制并插入一个文件而已,这样的动作在高配的电脑里一分钟可以做900次。所以,这时候打一个渠道包要4分钟,打100个渠道包也只要四分钟加一个小零头,当然,这还不是极限,如果有900个渠道的话,一个个渠道包打包需要900x4分钟,美团方案只要5分钟,提高了好几百倍的效率,可以说美团方案在老签名下是非常完美的。

新签名方式对现有方案的影响

在Android 7.0 之后,Google为了增强签名的安全性,采用了新的签名验证规则,不是针对每个文件来进行数字编码了,如图所示:

新的签名方式是根据zip文件结构来进行签名的,Apk文件本质上就是一个.zip文件,如图所示,在被签名前可以分为三块内容。

  1. 压缩文件实体数据 包含所有的元素具体数据
  2. 核心目录数据 包含所有元数据的相对偏移量
  3. 目录结束标志 包含目录数据的偏移位置和相关目录详情记录

下图中蓝色的部分代表Contents of ZIP entries,粉色的部分代表Central Directory。

File Entry表示一个文件实体,一个压缩文件中有多个文件实体。

文件实体由一个头部和文件数据组成(压缩后的,压缩算法在头部有说明)

Central Directory由多个File header组成,每个File header都保存一个文件实体的偏移

文件最后由一个叫End of central directory的结构结束。

再看看End of Central Directory的作用,它记录了Central Directory相对于头部的偏移位置,再看看我们的新签名数据Apk Signing Block是放在Contents of ZIP entries和Central Directory之间的,它是根据未签名的ZIP文件三个模块的所有内容进行编码签名后产生的一个唯一的数据,可以按照前面说的数字编码来理解,这三块任何内容发生改变后所产生的这块的数据都是不一致的,所以在签名之后无法对Apk的任何内容进行修改,不过我们前面也没修改过Apk签名之外的内容,所以这个时候是不是可以考虑修改Apk Signing Block这块内容呢,我们在后面再追加一个小尾巴。显然这个方法也不行了,前面说过最后有一个叫End of Central Direcotry的部分,记录着Central Direcotry相对与ZIP文件起始位置的偏移,正好APK Signing Block位于Central Direcotry前面,如果改变APK Signing Block的长度那么Central Direcotry相对于头部的偏移就改变了,内容就会和Endof Central Directory里记录的不一样,整个Apk包就被破坏了。那么是不是可以修改这个偏移呢,显然不行,修改过这个偏移之后Apk Signing Block也会变,然后只有拥有签名文件的开发者才能得到对的APK Signing Block数据,想要篡改这个的人只能望洋兴叹了。这就是新签名机制的作用原理。在这套新的机制下,我们老的签名可能就要进行适当的修改了。

改进方案的思路

前面说过了,我们新的打包方案在新的签名机制下又要捉襟见肘了(当然,如果你还采用老签名的话那么就不需要考虑这个问题了),不过,Google有张良计,我们还有过墙梯~

之前说过添加渠道包有好几种方式:

  1. 直接修改代码,一个渠道包改一次代码,然后再打包
  2. 不直接修改代码,放出一个渠道参数在打包之前动态改变然后再打包
  3. 修改打包完成后的文件通过跳过签名校验加入渠道号
  4. 现在这三种方式都不行了,没关系,我们还有第四中。

之前分析过,如果修改了zip文件的任何模块内容,APK Signing Block都会发生改变,从而无法再绕过签名机制。

不过这个不要紧,签名机制只是为了保障我们Apk的安全,我们显然不是想恶意篡改App,我们可是开发者,手握着签名文件的私钥和公钥,既然签名机制绕不过去,那么我们就直接修改Apk包然后重新进行签名就行了。虽然这样的效率没有绕过签名机制效率高,但相比于好几分钟的打包过程,这些时间也是可以接受的。一般重新签名大概需要三四秒的时间,相对与我们四分钟的打包流程,显然还是可以接受和继续使用的。

当然,这只是基于我们签名机制想出来的一个方案,之前和大家分析了打包和签名的整个流程和机制,也许还有更好的方式可以从中挖掘出来,这就需要我们集思广益了,仔细分析和思考这些流程和原理,也许你就能找出更好的解决方案来继续优化我们的打包方案~

总结

以上就是关于Android7.0新签名对多渠道打包影响的全部内容棩䍖,希望本文的内容对给我Android开发者们能带来一定的帮助,如果有疑问大家可以留言交流

(0)

相关推荐

  • Android 7.0 Nougat不得不知的11项新功能

    最近 Google 已经发布 Android 新版本 7.0 Nougat (牛轧糖) ,相信Android手机用户在未来的几个月内会收到第三方手机制造商推送的系统升级,无论你是已经下载升级的幸运者,还是焦急等待更新的用户,Android 7.0 Nougat 都有一些很棒的功能值得尝试,下面是11 项 在 Android 7.0 Nougat 系统中不可错过的功能. 1) 同时运行多个应用 Android 终于正式地支持分屏模式,通过分屏模式可以同时打开两个应用,这个功能在平板上使用起来特别方

  • Android7.0 MessageQueue详解

    Android中的消息处理机制大量依赖于Handler.每个Handler都有对应的Looper,用于不断地从对应的MessageQueue中取出消息处理. 一直以来,觉得MessageQueue应该是Java层的抽象,然而事实上MessageQueue的主要部分在Native层中. 自己对MessageQueue在Native层的工作不太熟悉,借此机会分析一下. 一.MessageQueue的创建 当需要使用Looper时,我们会调用Looper的prepare函数: public stati

  • Android 7.0调用相机崩溃详解及解决办法

    Android 7.0调用相机崩溃解决办法 错误提示: android.os.FileUriExposedException: file:///storage/emulated/0/DCIM/IMG_1041503431.jpg exposed beyond app through ClipData.Item.getUri() 处理方式 /** * Open camera */ private void showCameraAction() { if (ContextCompat.checkSe

  • Android 7.0新特性详解

    谷歌正式在I/O大会现场详细介绍了有关Android 7.0的大量信息.目前,我们已经知道,新一代Android操作系统将支持无缝升级,能够通过Vulkan API来在中低硬件配置设备上实现流 畅.游戏体验以及更多的Emoji表情.不过,Android 7.0最大也是最引人关注的还是来自运行效率上的改进. 来自I/O大会现场的PPT显示,Android N的代码减少了50%,新的代码减少50%,安卓N运行环境有了明显改善,软件运行速度提升幅度达到600%,应用安装提速75%.这意味着用户 正在迎

  • Android 7.0中拍照和图片裁剪适配的问题详解

    前言 Android 7.0系统发布后,拿到能升级的nexus 6P,就开始了7.0的适配.发现在Android 7.0以上,在相机拍照和图片裁剪上,可能会碰到以下一些错误: Process: com.yuyh.imgsel, PID: 22995 // 错误1 android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.yuyh.imgsel/cache/1486438962645.jpg ex

  • 详解Android 7.0 Settings 加载选项

    先写在前面,这说的Settings加载选项是指Settings这个应用显示在主界面的选项,这个修改需要对系统源码进行修改. Android 7.0 Settings顶部多了一个建议选项,多了个侧边栏,操作更加便捷了.       原生7.0主界面                                                          原生7.0侧边栏 Android 6.0 之前做Android 6.0开发的,都会了解到6.0的Settings加载选项是通过加载dash

  • Android7.0 工具类:DiffUtil详解

    一 概述 DiffUtil是support-v7:24.2.0中的新工具类,它用来比较两个数据集,寻找出旧数据集->新数据集的最小变化量. 说到数据集,相信大家知道它是和谁相关的了,就是我的最爱,RecyclerView. 就我使用的这几天来看,它最大的用处就是在RecyclerView刷新时,不再无脑mAdapter.notifyDataSetChanged(). 以前无脑mAdapter.notifyDataSetChanged()有两个缺点: 1.不会触发RecyclerView的动画(删

  • Android 7.0中新签名对多渠道打包的影响详解

    老签名多渠道打包原理 前言 由于Android7.0发布了新的签名机制,加强了签名的加固,导致在新的签名机制下无法通过美团式的方式再继续打多渠道包了.不过在说新的签名机制对打包方案的 影响和为什么会影响我们原有的打包机制之前,需要先简单理解下打包原理和签名在整个打包过程中的作用. Android打包流程 Android打包过程大致如图所示,整个流程就是将Java代码,资源文件以及第三方库整合成一个Apk文件,并对整合后的文件进行签名和优化对齐.整个过程可以简 单分为以下几个步骤: 资源预编译 为

  • Android Studio 3.6中新的视图绑定工具ViewBinding 用法详解

    前言 我们在Android开发的过程中总是需要获取XML布局中的ViewId,以便给其赋值进行显示,早期我们只能使用 findViewById 这个API,会导致很多的模版代码出现.2013年左右Android界大神 Jake Wharton开源了Butter Knife框架,通过Bind("viewid")方式方便开发者获取ViewId.近两年由于谷歌对Kotlin的支持,我们开始使用 Android Kotlin extensions. 在文件中导入布局文件直接引用viewId.无

  • Android多渠道打包神器ProductFlavor详解

    目录 一.什么是多渠道打包 1.多版本 2.多环境 3.多渠道 二.多渠道打包的方式(ProductFlavor&&多渠道打包插件) 1.ProductFlavor 1.1 如何是使用ProductFlavor 1.2 如何是使用ProductFlavor加载apk包 1.3 该如何获取不同渠道包的信息 1.4 使用ProductFlavor加载apk包的优缺点 2.多渠道打包插件 一.什么是多渠道打包 在不同的应用市场可能有不同的统计需求,需要为每个应用市场发布一个安装包,这里就引出了A

  • Android几种多渠道打包的步骤详解

    1.什么是多渠道打包 在不同的应用市场可能有不同的统计需求,需要为每个应用市场发布一个安装包,这里就引出了Android的多渠道打包.在安装包中添加不同的标识,以此区分各个渠道,方便统计app在市场的各种. 2.几种打包方式 友盟 UMeng Android Studio自带 美团 Walle 3.开始使用 3.1 友盟UMeng 第一步:在AndroidManifest中添加 <meta-data android:name="UMENG_CHANNEL" android:val

  • Android中APK签名工具之jarsigner和apksigner详解

    一.工具介绍 jarsigner是JDK提供的针对jar包签名的通用工具, 位于JDK/bin/jarsigner.exe apksigner是Google官方提供的针对Android apk签名及验证的专用工具, 位于Android SDK/build-tools/SDK版本/apksigner.bat 不管是apk包,还是jar包,本质都是zip格式的压缩包,所以它们的签名过程都差不多(仅限V1签名), 以上两个工具都可以对Android apk包进行签名. 1.V1和V2签名的区别 在An

  • Android笔记之:App自动化之使用Ant编译项目多渠道打包的使用详解

    随着工程越来越复杂,项目越来越多,以及平台的迁移(我最近就迁了2回),还有各大市场的发布,自动化编译android项目的需求越来越强烈,后面如果考虑做持续集成的话,会更加强烈.    经过不断的尝试,在ubuntu环境下,以花界为例,我将一步一步演示如何使用命令行,使用ant编译android项目,打包多渠道APK.    要点:    (1). 编译android的命令使用    (2). ant基本应用    (3). 多项目如何编译(包含android library)    (4). 如

  • oracle中not exists对外层查询的影响详解

    前言 最近同事发现了一个问题,在12c中跑的buffer get很高,但是在10g中跑的buffer很低.怀疑是不是12c的优化器有问题. 这个10g的环境和12c的环境,数据量大致一样,只是有很少部分的不同,但是就是这个很少部分不同,造成了not exists中的子查询返回不同的值,进而对外层查询产生不同的影响. 我们来用如下的代码模拟一下. 初始化数据: --10g drop table t1; drop table t2; create table t1 (id number,name v

  • Android Studio中一套代码多渠道打包的实现方法

    一套代码达到以下效果: 打包不同applicationId能同时安装在同一手机上 不同logo,app名称, 不同第三方SDK接入配置(例如微信分享appid,激光推送appkey) 能区分debug和release配置 使用到的功能:productFlavor和buildTypes 原理:优先级buildTypes大于productFlavor 示例:一套代码为两家银行打包apk 1. 修改build.gradle.buildTypes保持默认debug和release两种设置即可,andro

  • C#7.0中新特性汇总

    以下将是 C# 7.0 中所有计划的语言特性的描述.随着 Visual Studio "15" Preview 4 版本的发布,这些特性中的大部分将活跃起来.现在是时候来展示这些特性,你也告诉借此告诉我们你的想法! C#7.0 增加了许多新功能,并专注于数据消费,简化代码和性能的改善.或许最大的特性就是元祖和模式匹配,元祖可以很容易地拥有多个返回结果,而模型匹配可以根据数据的"形"的不同来简化代码.我们希望,将它们结合起来,从而使你的代码更加简洁高效,也可以使你更加

随机推荐