请支持作者原创:
https://mr-cao.gitbooks.io/Android/content/android-traces.html点击打开链接
Android PackageManager
本文章围绕着Android的包管理机制,着重分析Android的包格式(包括签名),以及应用程序的安装,升级以及卸载过程。
1. Android APK文件
Android的应用程序以后缀名为apk的文件发布。APK文件中包含应用程序的代码和资源数据,清单文件以及签名信息。APK文件格式扩展于JAR格式,而JAR文件格式又是扩展自ZIP格式。所以,可以使用ZIP解压工具,打开APK文件。
├── AndroidManifest.xml (1) ├── classes.dex (2) ├── lib (3) │ ├── armeabi │ │ └── libhello-jni.so │ ├── armeabi-v7a │ │ └── libhello-jni.so │ ├── mips │ │ └── libhello-jni.so │ └── x86 │ └── libhello-jni.so ├── META-INF (4) │ ├── CERT.RSA │ ├── CERT.SF │ └── MANIFEST.MF └── resources.arsc (5)
<1>:AndroidManifest.xml文件中包含了应用程序的组件,包名,版本等信息。
<2>:classes.dex是应用的可执行代码。
<3>:对于使用了ndk编程的应用来说,APK中还有lib文件夹,这个文件夹下面存放的是适配各个平台的共享库。
<4>:包含应用的签名和清单文件,这部分内容后面还会讲述。
<5>:对于可编译的资源,最后都编译好后,打包进了resources.arsc文件,比如string和style。对于编译好的APK文件,可以使用aapt工具查看资源表。
更多aapt的用法,参考aapt -help。
1.1. APK签名
与APK签名相关的文件都位于META-INF目录下。下面会对三个文件做一些简单的分析,关于加密解密算法的实现,超出了本文的范围,这里不会涉及到。
1.1.1. MANIFEST.MF
后缀名为.MF的文件,里面存放的是打包在APK中的文件的Message digest(消息摘要)。
Manifest-Version: 1.0 Created-By: 1.0 (Android) Name: AndroidManifest.xml SHA1-Digest: bbFIUGA27QAiLBforTb0B+GeAk8= Name: lib/armeabi-v7a/libhello-jni.so SHA1-Digest: imJ95BzGT7rI57k7xMnRNBKysgo= Name: lib/x86/libhello-jni.so SHA1-Digest: /QM7n8FQYZ7gTjHAfsNzcoPZsnY= Name: lib/mips/libhello-jni.so SHA1-Digest: A2WeX1JI3csDX8v/PapWe97Gx9k= Name: resources.arsc SHA1-Digest: rzak75eaqS4baaz+03KawAATuNk= Name: lib/armeabi/libhello-jni.so SHA1-Digest: 3SGVYUG2+pMhNqB7K5m/T4iA+K8= Name: classes.dex SHA1-Digest: 8XJt/CggZUAQU6ULBavrzodpwok=
对于APK包中的文件先使用hash函数获取Message Digest,然后采用base64编码得到的结果作为文件的最终Message Digest。MANIFEST.MF中的每一条目都是由Name和SHA1-Digest组成。Name对应的是文件名,SHA1-Digest对应的文件的Message Digest。
可以使用如下的命令生成Message Digest:
$ openssl sha1 -binary HelloJni/classes.dex | openssl base64
1.1.2. CERT.SF文件
CERT.SF文件中存放的也是Message Digest。与上面MANIFEST.MF文件对应的CERT.SF文件内容如下:
Signature-Version: 1.0 Created-By: 1.0 (Android) SHA1-Digest-Manifest: PDEMo/mMNPiPsuYop2qQpb9VjX0=1 Name: AndroidManifest.xml SHA1-Digest: sbIUZUy5AB2lb4RMZzyqlf+JEuw= Name: lib/armeabi-v7a/libhello-jni.so SHA1-Digest: cP7n4f23m5CWostVb5+C65095Oo= Name: lib/x86/libhello-jni.so SHA1-Digest: vFuCcAZFIQgcEkc6a6L395gkbdQ= Name: lib/mips/libhello-jni.so SHA1-Digest: 98f4yVRHgXH5cKKnufCTK7EbUVs= Name: resources.arsc SHA1-Digest: OynBh/Tw+yCvo6RPdC5subo2+HE= Name: classes.dex SHA1-Digest: NTB2dedbG357wxDmiiD7dHTFp6E= Name: lib/armeabi/libhello-jni.so SHA1-Digest: mjzjxE6Pt0Lrz4k5PeKTONgSh5A=
CERT.SF中的第一条内容来自对MANIFEST.MF文件Message Digest的结果;其他的条目分别是对MANIFEST.MF中对应的条目做Message Digest.下面的命令展示了这一过程:
通过上面例子的结果,可以知道,CEART.SF中的内容来自于对MANIEST.MF文件以及文件中的条目做Message Digest的结果。
1.1.3. CERT.RSA 文件
CERT.RSA文件中存放着CERT.SF的数字签名,以及签名证书。如果存在多个.SF和.RSA文件,那么每一对的文件名都需要匹配。比如CERT1.SF对应着CERT1.RSA,CERT2.SF对应CERT2.RSA。
可以使用如下命令查看CERT.RAS文件中存放的证书.
openssl pkcs7 -inform DER -in HelloJni/META-INF/CERT.RSA -noout -print_certs -text
使用下面命令提取证书:
openssl pkcs7 -inform DER -print_certs -in HelloJni/META-INF/CERT.RSA -out cert.pem
使用如下命令打印证书内容:
openssl x509 -in cert.pem -noout -text
可以使用如下命令验证SF文件的有效性:
openssl smime -verify -in HelloJni/META-INF/CERT.RSA -inform DER -content HelloJni/META-INF/CERT.SF -CAfile cert.pem