APK编译及安全防御

One 什么是APK

APK是AndroidPackage的缩写,即Android安装包(apk),能够经过将APK文件直接传到Android模拟器或手机中执行便可安装。APK的本质是一个zip的压缩包,用压缩软件打开后就能够看到里面的文件以及结构。java

APK的文件组成:android

  • AndroidManifest.xml:清单文件,主要包含四大组件注册信息,应用权限,和元数据等信息,此文件列出了应用的名称、版本、访问权限和引用的库文件。安全

  • classes.dex:Dalvid虚拟机上运行的字节码文件,咱们在将java代码编译成class字节码文件后,经过android SDK提供的工具将class转换成dex字节码,dex文件可能有多个。数据结构

  • META—INF: 包含 CERT.SF 和 CERT.RSA 签名文件,以及 MANIFEST.MF 清单文件。CERT.SF、MANIFEST.MF是对资源作的SHA1 hash处理,CERT.RSA包含有公钥证书和签名。app

  • res:包含未编译到 resources.arsc 中的资源例如:布局xml、图片、动画等。函数

  • resources.arsc 打包工具会提取此 XML 内容,将其编译为二进制文件形式,并将相应内容进行归档。此内容包括语言字符串和样式,以及未直接包含在 resources.arsc 文件中的内容(例如布局文件和图片)的路径。工具

  • lib/:包含特定于处理器软件层的编译代码。此目录包含每种平台类型的子目录,如 armeabi、armeabi-v7a、arm64-v8a、x8六、x86_64 和 mips布局

Two APK编译

2.1 编译流程

由上图可知,APK打包的流程主要有以下几个步骤:学习

  1. 打包资源文件,生成R.java文件。
  2. 处理aidl文件,生成对应的java文件。
  3. 工程源码编译,生成.class文件,把.class文件编译为.dex文件。
  4. 代码文件和资源文件打包生成APK。
  5. 对apk文件进行签名。
  6. zip对齐,apk中的每一个文件进行4个字节对齐操做,优化启动相应速度。

2.1.1. 打包资源文件,生成R.java文件

  • 工具aapt优化

  • 输入

    • res
    • assets
    • AndroidManifest.xml
    • Android基础库(Android.jar)文件
  • 过程

    • 编译res和assets目录下的资源并生成resources.arsc文件。
    • 调用ResourceTable.cpp文件中的parseAndAddEntry方法生成R.java文件。
    • 对res目录下的xml文件进行编译,这样处理过的xml文件就被简单“加密”了。
  • 输出

    • resources.arsc文件
    • R.java文件
  • 总结

    • assets和res/raw资源被原封不动地打包进APK,其它的资源都会被编译或者处理,除了assets资源以外,其余的资源都会被赋予一个资源ID。利用该特色,在apk加固时,能够把加密后的dex、so文件放到该目录。
    • R.java是java层面寻找资源的id表,resources.arsc是程序运行时用到的资源表。
    • APK运行时会根据设备的不一样属性(如屏幕密度)寻址,resource.arsc就是经过相同的ID,根据不一样的配置索引找到最佳资源。

2.1.2. 处理aidl文件,生成对应的java文件

这个主要是在aidl接口文件,经过SDK提供的AIDL工具生成相应的java文件,供程序调用,没有用到aidl的工程,并不会有这个过程

2.1.3. 工程源码编译

  • 工具

    • javac: 把java文件编译为.class文件的工具。
    • dx: 把.class文件打包为.dex文件的工具。
  • 输入

    • R.java
    • AIDL生成的java文件
    • 库jar文件,Android.jar
  • 输出

    • dex文件
  • 总结:

    • 这个过程主要是javac将java文件编译成class文件,再经dx工具转换成dex文件,压缩常量池,消除冗余信息等。

2.1.4. 打包生成APK

  • 工具

    • apkbuilder
  • 输入

    • 打包后的资源文件
    • 打包后的类文件,主要是dex文件
    • libs文件,包括so文件
  • 过程

    • 主要流程是先以resources.arsc文件为基础生成一个apk,而后调用ApkBuilderMain.java中的addSourceFolder方法添加工程资源,处理包括res和assets目录中的文件,添加完资源后调用addResourceFromJar方法往apk中写入依赖库,接着调用addNativeLibraries方法添加工程libs目录下的native库,最后调用sealApk关闭Apk文件。
  • 输出

    • 未签名的.apk文件

2.1.5. 对apk文件进行签名

  • android应用须要签名才能在设备上安装。

    • 开发时debug包会用系统自带的debug.keystore为debug包签名。
    • 正式发布时须要用公司或者项目的私钥对apk进行签名,这个私钥要妥善保管,一旦泄露,别人就能够任意修改包的内容而后从新打包签名。
  • 使用JDK自带签名工具的jarsigner:

    • jarsigner -keystore ./android.keystore -storepass password -signedjar ./signed.apk ./sign.apk android.keystore

2.1.6. zip对齐

对齐使用的是android-idk/tools目录下的zipalign工具,主要工做是将apk包中全部的资源文件起始偏移为4字节的整数倍,这样经过内存映射访问apk时的速度会更快。

2.2 编译细节流程

通过这几步的编译,输出的apk文件,最终是一个具备特定文件格式的静态文件。若是拿到该文件,分析文件格式和逆向,最终是能够分析一个破解apk的业务和流程,这就必然对apk产生安全问题。

2.3 Apk v1 & v2签名

Android 支持如下三种应用签名方案:

  • v1 方案:基于 JAR 签名。
  • v2 方案:APK 签名方案 v2(在 Android 7.0 中引入)。
  • v3 方案:APK 签名方案 v3(在 Android 9 中引入)。

2.3.1. JAR 签名v1方案

从一开始,APK 签名就是Android 的一个有机部分。该方案基于签名的JAR。 可是v1方案存在如下一些不足:

  • 签名不保护APK的某些部分,例如ZIP元数据。

  • APK验证程序须要处理大量不可信(还没有通过验证)的数据结构,而后会舍弃不受签名保护的数据,这会致使至关大的受攻击面。

  • APK 验证程序必须解压全部已压缩的条目,而这须要花费更多时间和内存。

  • 因为这些不足致使apk签名后能够进行许多修改,能够移动甚至从新压缩文件,致使一些安全事件的发生。为了解决这些问题, google在Android 7.0之后引入了V2签名方案Android 7.0 中引入了APK 签名方案v2, Android 9以后引入v3(v2+)。

2.3.2. APK 签名方案v2 & v2+

APK v2签名方案是一种全文件签名方案,该方案可以:

  • 发现对APK的受保护部分进行的全部更改;
  • 有助于加快验证速度并加强完整性保证;

使用APK签名方案v2进行签名时,会在APK文件中插入一个APK签名分块,该分块位于“ZIP中央目录”部分以前并紧邻该部分。在“APK 签名分块”内,v2签名和签名者身份信息会存储在APK签名方案v2分块中。

搭载Android 7.0 及更高版本的设备支持APK 签名方案v2(v2方案)及更高版本的方案(在Android P(Android 9) 中,v2方案已更新为v3方案,以便在签名分块中包含其余信息,但在其余方面保持相同的工做方式)。该方案会对APK的内容进行哈希处理和签名,而后将生成的“APK签名分块”插入到APK中。

在验证期间,v2+方案会将APK文件视为Blob,并对整个文件进行签名检查。对APK进行的任何修改(包括对ZIP元数据进行的修改)都会使APK签名做废。这种形式的APK验证不只速度要快得多,并且可以发现更多种未经受权的修改。新的签名格式向后兼容,所以,使用这种新格式签名的APK 可在更低版本的Android设备上进行安装(会直接忽略添加到APK 的额外数据),但前提是这些APK 还带有v1签名。

验证程序会对照存储在“APK签名分块”中的v2+签名对APK的全文件哈希进行验证。该哈希涵盖除“APK签名分块”(其中包含v2+签名)以外的全部内容。在“APK签名分块”之外对APK进行的任何修改都会使APK的v2+签名做废。v2+签名被删除的APK也会被拒绝,由于v1签名指明相应APK带有v2签名,因此Android 7.0及更高版本会拒绝使用v1签名验证APK。

Three APK反编译

3.1 概述

APK反编译,就是把编译后的APK文件经过逆向工程手段获取到原始代码和资源的一个过程。因为APK文件是一个具备固定文件格式的静态文件,并且可以解析和执行的,因此理论上能够对一个APK文件进行逆向的分析进行反编译、破解。若是一个APK没有进行安全方面的防御措施,是能够经过很简单的几步给破解掉。

3.2 经常使用工具

apktool+dex2jar+JD-GUI

3.3 步骤

  • 拿到app.apk
  • 反编译class.dex文件 修改app.apk文件后缀为app.zip,解压app.zip文件

获得class.dex文件,使用dex2jar工具反编译为jar文件。

使用如下命令:./dex2jar.sh classes.dex

经过JD-GUI打开classes_dex2jar.jar能够看到大部分源。

经过apktool直接反编译app.apk便可看到资源文件 ./apktool d app.apk -f -o ./app3

反编译后AndroidMenifest.xml:

反编译后layout:

反编译后color文件:

至此,一个apk中全部的资源文件、代码文件所有被反编译出来,因此做为一个app开发者,为了数据、业务的安全,必需要对app进行安全处理,防止对用户形成信息、财产方面的损失,如下是几个对apk进行安全加固的处理方法。

Four APK安全加固

对于apk安全加固主要分为两个方面的安全防御:

  • 代码混淆
  • 签名对比
  • apk加壳
  • 反调试、反检测等技术
  • 其余

4.1 代码混淆

混淆代码并非让代码没法被反编译,而是将代码中的类、方法、变量等信息进行重命名,把它们改为一些毫无心义的名字。由于对于咱们而言可能CellPhone类的call()方法意味着不少信息,而A类的a()方法则没有任何意义,可是对于计算机而言,它们都是平等的,计算机不会试图去理解CellPhone是什么意思,它只会按照设定好的逻辑来去执行这些代码。因此说混淆代码能够在不影响程序正常运行的前提下让破解者对代码逻辑的理解难度加大,从而大大提高了程序的安全性。

4.2 签名对比

  • 原理

APK必须被签名才可以安装到手机中,没有被签名的apk是没法安装到设备中的。可是签名在反编译以后是获取不到的,因此只能用本身的签名文件去签名,可是在已经安装了应用设备中在安装一个签名不一致的应用会致使安装失败。

  • 应用

利用该原理,能够在程序启动的时候获取应用签名,而后和正确的签名值作比对,若是不符合就直接退出程序。

  • 破解方法

既然是在程序的入口进行签名比对,就能够反编译找到程序入口处相关的代码,进行处理删除或者把签名信息改为本身的签名值,从新打包便可解决这个问题。

4.3 dex文件加固

  • 加固原理

- 加密的源apk

- 本身的壳apk,负责解密apk,并动态加载apk的工做

- 加密工具,负责将源apk进行加密和壳dex合并成新的dex
复制代码

4.4 反调试检测(ptrace)

反调试检测是为了应对如今不少破解者使用IDA进行动态方式调试so文件,从而获取重要的信息,知道IDA进行so动态调试是基于进程的注入技术,而后使用Linux中的ptrace机制,进行调试目标进程的附加操做。ptrace机制有一个特色,若是一个进程被调试了,在它进程的status文件中有一个字段TracerPid会记录调试者的进程id值,如图所示:

查看文件:/proc/[myPid]/status,在第六行,有一个TracerPid字段,就是记录了调试者的进程id。那么就能够这么作来达到反调试的功效了:轮询遍历本身进程的status文件,而后读取TracerPid字段值,若是发现它大于0,就表明着本身的应用在被人调试,因此就立马退出程序。原理知道了,代码实现也很简单,这里用pthread建立一个线程,而后进行轮询操做: 使用pthreadcreate建立一个线程,线程启动以后执行threadfunction函数:

看看thread_funcation函数:

4.5 其它

  • Dex-Java2C:将Java代码翻译为C代码,并实施Native层的代码混淆保护。

  • So文件加壳:对SO文件进行总体加壳保护,防止IDA Pro等工具逆向分析。

  • 内存加密:防止内存数据被篡改或Dump,好比Dump解密后的Java代码。

  • 自身虚拟化保护:专业版采用代码虚拟化技术对自身代码进行保护,防止逆向分析。

对于apk安全方面的技术,层出不穷,安全攻防拉锯技术不断改进不断提高。

Five 结论

apk的编译是把咱们写的代码、资源、库文件打包成能够在Android设备上运行的过程,而为了代码、数据、业务安全诉求须要对apk进行安全防御工做。

安全攻防是魔高一尺、道高一丈,特别是金融类app须要高度重视的工做,在此与你们一块儿学习和分享。

Thanks!

做者简介

焦亚克, 民生科技有限公司用户体验技术部开发工程师。

相关文章
相关标签/搜索