热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android应用篇app签名与加固原理分析

今天来写一下app的签名与加固的原理。签名的原理1.releaseapk的签名文件可以看到,签名打包好的apk中有一个META-INF目录,里面包括三

今天来写一下 app 的签名与加固的原理。

 

签名的原理

1. release apk 的签名文件

可以看到,签名打包好的 apk 中有一个 META-INF 目录,里面包括三个重要的文件:

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

来简单看下这三个文件的内容。

MANIFEST.MF:

Manifest-Version: 1.0
Built-By: Generated-by-ADT
Created-By: Android Gradle 2.3.0Name: res/layout/design_text_input_password_icon.xml
SHA1-Digest: YoJd6IrT+4Fi8q5etiV4CGfrcMg=Name: res/drawable-xxhdpi-v4/abc_ic_star_half_black_16dp.png
SHA1-Digest: EikVyBT5I7pmbJO2k8qF0V5hUc0=Name: solidity/ens/build/AbstractENS.bin
SHA1-Digest: 2jmj7l5rSw0yVb/vlWAYkK/YBwk=Name: res/drawable/bg_top_bar_light_theme.xml
SHA1-Digest: G1WVIvrL6vVO7cHlz5sOJM2Yw9g=Name: res/layout/activity_transaction_send.xml
SHA1-Digest: WrZZ/cTwgm92KS+iW82elSy2ets=Name: res/drawable/bg_solid_selector_light_theme.xml
SHA1-Digest: CRQNmUrjsUhbW5g0TaJQTTTg49s=Name: res/drawable/notification_bg_low.xml
SHA1-Digest: T3aVUj+I2HyqpDuAMmdpIkSA/yY=Name: res/drawable-xhdpi-v4/abc_ic_star_black_48dp.png
SHA1-Digest: pUh1yzyRb6c3D0mL7cI4wKExeTI=Name: res/layout/activity_about_us.xml
SHA1-Digest: j58VkJ7ytUJJnCLv/u8bLBZSHLc=Name: res/drawable/btn_security_keyboard_delete_selector_light_theme.xml
SHA1-Digest: 2pcdMLjyn5er5D8lZSP2LE/dLFI=Name: res/drawable/abc_list_selector_background_transition_holo_light.xml
SHA1-Digest: AdlBQF7mCKx3VlJQ4HaRjQeNXyo=Name: res/drawable-xxhdpi-v4/ic_nav_wallet_switcher.png
SHA1-Digest: g8DLztAbX8rqkub9B0fD6rwsces=Name: assets/ShareSDK.xml
SHA1-Digest: spQnpYXJlxaiSoFJKoxJuqRGow0=Name: res/color/abc_primary_text_disable_only_material_dark.xml
SHA1-Digest: 4t4rkEo1veLwAALxNPcESWEUDcg=Name: META-INF/rxjava.properties
SHA1-Digest: +hrVyVtjCoOVFh3dKfYglbzj5S8=Name: res/drawable-xxhdpi-v4/ic_nav_delete.png
SHA1-Digest: mOta3HgN3CGFfmJ5Yrp0F7Ggv5E=Name: res/mipmap-hdpi-v4/ic_launcher.png
SHA1-Digest: 6r5KrzZ9OlIwT0RuvqKZoTI3DRI=Name: res/drawable-xhdpi-v4/ic_qrcode_scan_line.png
SHA1-Digest: 1hGLNSq7gfO1cX0Nbd59GOPwh+M=// ...

MANIFEST.MF 就是逐一遍历 apk 里面的所有条目,如果是目录就跳过,如果是一个文件,就用 SHA1 或者 SHA256 消息摘要算法提取出该文件的摘要然后进行 BASE64 编码后,作为 "SHA1-Digest" 属性的值写入到 MANIFEST.MF 文件中的一个块中。该块有一个 "Name" 属性,其值就是该文件在 apk 包中的路径。

CERT.SF:

Signature-Version: 1.0
X-Android-APK-Signed: 2
SHA1-Digest-Manifest: 3PRb1OObhDRdv3ZpZ5FBNQzRGtw=
Created-By: 1.0 (Android)Name: res/layout/design_text_input_password_icon.xml
SHA1-Digest: YoJd6IrT+4Fi8q5etiV4CGfrcMg=Name: res/drawable-xxhdpi-v4/abc_ic_star_half_black_16dp.png
SHA1-Digest: EikVyBT5I7pmbJO2k8qF0V5hUc0=Name: solidity/ens/build/AbstractENS.bin
SHA1-Digest: 2jmj7l5rSw0yVb/vlWAYkK/YBwk=Name: res/drawable/bg_top_bar_light_theme.xml
SHA1-Digest: G1WVIvrL6vVO7cHlz5sOJM2Yw9g=// ...

计算这个 MANIFEST.MF 文件的整体 SHA1 值,再经过 BASE64 编码后,记录在 CERT.SF 主属性块 (在文件头上) 的 "SHA1-Digest-Manifest" 属性值下。

然后,再逐条计算 MANIFEST.MF 文件中每一个块的 SHA1,并经过 BASE64 编码后,记录在 CERT.SF 中的同名块中,属性的名字是 "SHA1-Digest"。

CERT.RSA:

3082 0354 0609 2a86 4886 f70d 0107 02a0
8203 4530 8203 4102 0101 310b 3009 0605
2b0e 0302 1a05 0030 0b06 092a 8648 86f7
0d01 0701 a082 021f 3082 021b 3082 0184
a003 0201 0202 0457 5abd 4d30 0d06 092a
8648 86f7 0d01 0105 0500 3051 3110 300e
0603 5504 0713 0762 6569 6a69 6e67 3113
3011 0603 5504 0a13 0a73 7569 7368 6974
6563 6831 1330 1106 0355 040b 130a 7375
6973 6869 7465 6368 3113 3011 0603 5504
0313 0a73 7569 7368 6974 6563 6830 2017
0d31 3630 3631 3031 3331 3435 335a 180f
3330 3135 3130 3132 3133 3134 3533 5a30
// ...

把之前生成的 CERT.SF 文件,用私钥计算出签名,然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。CERT.RSA 是一个满足 PKCS7 格式的文件,可以通过 openssl 工具来查看签名证书的信息。

 

2. 签名流程

  • 对 apk 中的每个文件做一次算法 (数据摘要 + BASE64 编码),保存到 MANIFEST.MF 文件中。
  • 对 MANIFEST.MF 整个文件做一次算法 (数据摘要 + BASE64 编码),存放到 CERT.SF 文件的头属性中,再对 MANIFEST.MF文件中各个属性块做一次算法 (数据摘要+Base64编码),存到到一个属性块中。
  • 用私钥对 CERT.SF 文件做签名,然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。

 

3. 验证流程

Android 平台上所有应用程序安装都是由 PackageManangerService,Android 的安装流程非常复杂,与签名验证相关的步骤位于 下面两个类,有兴趣的可以看看:

frameworks/base/core/java/android/content/pm/PackageManagerService.java

安装应用时 PackageManagerService 会对 apk 进行签名检查,具体分为以下几步:

  • 1. 读取 CERT.RSA (证书信息包括公钥)、MANIFEST.MF、CERT.SF。
  • 2. 使用获取的公钥对 CERT.SF 解密,将解密结果和 MANIFEST.MF 进行比较,如果相同说明证书有效、MANIFEST.MF 未被更改。
  • 3. 对 apk 中所有文件内容分别进行消息摘要计算,将结果的 BASE64 编码和 MANIFEST.MF 里的相应内容进行比较,全部相同则 apk 的内容未被更改。

如何判断证书是否有效?

因为签名的时候是使用私钥对 MANIFEST.MF 进行加密保存在 CERT.SF 中,之后只需要用证书中的公钥对 CERT.SF 进行解密,将结果和 MANIFEST.MF 进行比较即可。注意,在证书正确的情况下如果更改的 apk 里面文件内容,此时以上判断还是不会通过。因为 MANIFEST.MF 保存的是 apk 里面所有文件的哈希值,只要改变了 apk 里文件内容,哈希值就会变化。


如何判断 apk 是否被更改?

在签名保证 MANIFEST.MF 有效的前提下,只要对当前 apk 所有文件的内容的哈希值的 BASE64 编码和 MANIFEST.MF 相应文件存的值进行比较即可。


如何防范被重新签名?

通过反编译工具 (apktool) 可以轻易的对 apk 进行重新签名,针对这种情况可以通过以下几个方法加强被成功重新签名的难度:

  • 对 apk 进行加壳处理,增加反编译难度。
  • 程序中对签名自行验证,可配合服务端进行。

不过没有什么是绝对安全的,只是破解的成本和收益的博弈。比如方法一可以通过出壳进行破解,只是增加了出壳的成本。方法二可以在反编译的时候通过更改相关 smali 代码绕过签名验证的地方,只是增加了反编译成本。

 

 

加固的原理

1. 加固原理解析

在该过程中涉及到3个对象,分别如下:

  • 源程序

源程序也就是我们的要加固的对象,这里面主要修改的是原 apk 文件中的 classes.dex 文件和 AndroidManifest.xml 文件。

  • 壳程序

壳程序主要用于解密经过加密了的 dex 文件,并加载解密后的原 dex 文件,并正常启动原程序。

  • 加密程序

加密程序主要是对原 dex 文件进行加密,加密算法可以是简单的异或操作、反转、RC4、DES、RSA 等加密算法。

加固过程可以分为如下4个阶段:

  1. 加密阶段。
  2. 合成新的 dex 文件。
  3. 修改原 apk 文件并重打包签名。
  4. 运行壳程序加载原 dex 文件。

下面来分别分析这4个阶段。

 

2. 加密阶段

加密阶段主要是讲把原 apk 文件中提取出来的 classes.dex 文件通过加密程序进行加密。加密的时候如果使用 DES 对称加密算法,则需要注意处理好密钥的问题。同样的,如果采用非对称加密,也同样存在公钥保存的问题。

顺便来说下 dex 的结构:

这就是 dex 的文件格式了,那么 Header 中存储了什么内容呢?

 

3. 合成新的 dex 文件

这一阶段主要是讲上一步生成的加密的 dex 文件和壳 dex 文件合并,将加密的 dex 文件追加在壳 dex 文件后面,并在文件末尾追加加密 dex 文件的大小数值。

在壳程序里面,有个重要的类:ProxyApplication 类,该类继承 Application 类,也是应用程序最先运行的类。所以,我们就是在这个类里面,在原程序运行之前,进行一些解密 dex 文件和加载原 dex 文件的操作。

 

4. 修改原 apk 文件并重打包签名

在这一阶段,我们首先将 apk 解压,修复 classes.dex 和 AndroidManifest.xml 这两个文件,其他文件和文件加都不需要改动。首先,我们把解压后 apk 目录下原来的 classes.dex 文件替换成合成的新的 classes.dex 文件。然后,由于我们程序运行的时候,首先加载的其实是壳程序里的 ProxyApplication 类。所以,我们需要修改 AndroidManifest.xml 文件,指定 application 为ProxyApplication,这样才能正常找到识别 ProxyApplication 类并运行壳程序。

5. 运行壳程序加载原 dex 文件

Dalvik/ART 虚拟机会加载我们经过修改的新的 classes.dex 文件,并最先运行 ProxyApplication 类。在这个类里面,有2个关键的方法:attachBaseContext() 和 onCreate() 方法。ProxyApplication 先运行 attachBaseContext() 再运行 onCreate() 方法。

在 attachBaseContext() 方法里,主要做两个工作:

  1. 读取 classes.dex 文件末尾记录加密 dex 文件大小的数值,则加密 dex 文件在新 classes.dex 文件中的位置为:len (新classes.dex 文件) – len (加密 dex 文件大小)。然后将加密的 dex 文件读取出来,加密并保存到资源目录下。
  2. 然后使用自定义的 DexClassLoader 加载解密后的原 dex 文件。

在 onCreate() 方法中,主要做两个工作:

  1. 通过反射修改 ActivityThread 类,并将 Application 指向原 dex 文件中的 Application。
  2. 创建原 Application 对象,并调用原 Application 的 onCreate() 方法启动原程序。

 

6. 加固的优缺点

优点:

  1. 保护自己核心代码算法,提高破解/盗版/二次打包的难度。
  2. 缓解代码注入/动态调试/内存注入攻击。

缺点:

  1. 影响兼容性。
  2. 影响程序运行效率。
  3. 部分流氓、病毒也会使用加壳技术来保护自己。
  4. 部分应用市场会拒绝加壳后的应用上架。

 


推荐阅读
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 本文介绍了三种方法来实现在Win7系统中显示桌面的快捷方式,包括使用任务栏快速启动栏、运行命令和自己创建快捷方式的方法。具体操作步骤详细说明,并提供了保存图标的路径,方便以后使用。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • CentOS 6.5安装VMware Tools及共享文件夹显示问题解决方法
    本文介绍了在CentOS 6.5上安装VMware Tools及解决共享文件夹显示问题的方法。包括清空CD/DVD使用的ISO镜像文件、创建挂载目录、改变光驱设备的读写权限等步骤。最后给出了拷贝解压VMware Tools的操作。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • mac php错误日志配置方法及错误级别修改
    本文介绍了在mac环境下配置php错误日志的方法,包括修改php.ini文件和httpd.conf文件的操作步骤。同时还介绍了如何修改错误级别,以及相应的错误级别参考链接。 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
author-avatar
php小学生
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有