zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

安卓逆向_1 --- 逆向环境配置、APK 文件结构、APK 打包流程

安卓流程文件配置打包 环境 结构 ---
2023-09-11 14:13:59 时间

 

哔哩哔哩:https://www.bilibili.com/video/BV1UE411A7rW?p=1

Android 逆向工程师系统培训‹第九期›( 课程目录 ):https://ke.yijincc.com/course-21.htm

安卓逆向工程师:https://ke.yijincc.com/profession/1.htm

 

 

打造年轻人的第一套安卓逆向环境!

 

原味镜像介绍文章:https://mp.weixin.qq.com/s/gBdcaAx8EInRXPUGeJ5ljQ
原味镜像介绍视频:https://www.bilibili.com/video/BV1qQ4y1R7wW/
下载地址:
谷歌盘:https://drive.google.com/drive/folders/1AdZ1x5G9CcJGXiLqGL9mhDJWlRz8KZl_?usp=sharing
GoFile:https://gofile.io/d/GeqM2O
百度盘:链接:https://pan.baidu.com/s/1anvG0Ol_qICt8u7q5_eQJw 提取码:3x2a
阿里盘:http://49.235.84.125:8080/r0env
登录时用户名:root 密码:toor

 

 

1. 逆向环境配置

 

1. java 开发环境:java jdk、java jre

        java jdk 最好安装 jdk8 的最新版本,如果安装更高的 java 版本,一些逆向工具可能使用不了。

        安装 java jdk8 的时候会自动弹出 对应 jre 的安装。

2. 安卓开发环境:安卓 sdk、ndk

        安卓 sdk 和 ndk 下载完成后,直接解压,然后配置环境变量即可。。。
        也可以通过 android studio 进行 sdk 和 ndk 的安装

        通过 Android studio下载的 sdk 中没有 tools 文件夹的解决办法:
                https://blog.csdn.net/General_Ma/article/details/104707265/

        sdk 主要配置两个目录:tools、platform_tools

        ndk 的安装:官网下载 ( https://developer.android.google.cn/ndk/ )  ndk 进行安装

 

 

2. APK 文件结构

 

 

APK 是 Android PacKage 的缩写,即 Android 安装包。apk 文件也就是 Android 打包流程的产物。那么 apk 是一个什么类型的文件?它包含了一些什么内容? 弄清楚了这些,我们就可以带着目的性,去分析打包流程,可以更好的关注 apk 文件中的这些内容是在打包流程的哪个过程中产生,以及是如何产生的。

众所周知,apk 文件本质上其实是一个 zip 格式的压缩包。想要知道其中包含了什么,改后缀然后用解压缩工具即可打开任何一个APK文件。 如果有 代码混淆加密,通过普通解压缩工具打开里面的文件或目录会看到各种乱码

apk 概览

  • assets (程序资源目录)
  • META-INF(签名证书目录)
  • res(界面布局/图片资源目录)
  • AndroidManifest.xml(APK属性/权限/组件声明)
  • classes.dex(Android 虚拟机可执行字节码)
  • resources.arsc(字符串/资源索引文件)

图示:

这里解压了某个未经过 加固加壳 或者 其他手段加密的 Android 安装包文件,以下为结果截图:

https://www.sohu.com/a/149758866_675634

主要注意红色标注部分,这一些文件和文件夹是一个 Android 应用基本都具备的。而其他的一些文件和文件夹则是一些第三方库,或者是其他一些代码生成的。 接下来,依次大概介绍一下这些文件和文件夹的作用。

  • AndroidManifest.xml:这是 Android 应用的全局配置文件,它包含了这个应用的很多配置信息,例如包名、版本号、所需权限、注册的服务等。可以根据这个文件在相当程度上了解这个应用的一些信息。该文件目前状态是被编译为二进制的 XML 文件,可以通过一些工具(如 apktool)反编译后进行查看。Analyze apk 是一个很不错的 apk 分析(~~hack 入门~~)工具。我们可以通过它直接反编译看到原始的 AndroidManifest.xml 文件。

     

  • assets 文件夹:assets 文件夹用于保存需要保持原始文件的资源文件夹,开发过程中拖了什么到里面,打包完之后里面还是什么。一般用于存放音频,网页(帮助页面之类的),字体等文件。主要需要知道的点是,它与 res 文件夹的区分以及如何在应用中访问该文件夹的资源,如它可以有多级目录而 res 则只有两级。

  • dex 文件:classes.dex 文件是 Android 系统运行于 Dalvik Virtual Machine 上的可执行文件,也是Android 应用程序的核心所在。项目工程中的 Java 源码通过 javac 生成 class 文件,再通过 dx 工具转换为 classes.dex,注意到我们这里有 classes2.dex 和 classes3.dex。这是方法数超过一个 dex 的上限,分 dex 的结果。分 dex 在 Android 5.0 之前需要开发者自行完成,5.0 后 dx 自带支持。dex 文件的数据结构不算复杂,如下图所示。目前一些热补丁有关的技术,主要便是对 dex 做各种处理。

  • lib 文件夹:该目录存放着应用需要的 native 库文件。比如一些底层实现的图片处理、音视频处理、数据加密的库以 so 库的形式在该文件夹中。而该文件夹下有时会多一个层级,这是根据不同CPU 型号而划分的,如 ARM,ARM-v7a,x86等。

     

  • META-INF 文件夹:该目录的主要作用是用于保证 APK 的完整性以及安全性。该文件夹下,主要有三个文件。
            MANIFEST.MF:这个文件保存了 整个apk文件所有文件的文件名 + SHA-1后的编码值。
                                        这也就意味着,MANIFEST.MF 象征着 apk 包的完整性。
            XXX.RSA:这个文件保存了公钥和加密方式的信息。
            XXX.SF:这个文件与 MANIFEST.MF 的结构一样,只是其编码会被被私钥加密。
                               这样一来每次安装时,通过该文件夹中的文件,就可以完成验证的过程。
                               如果 apk 包被改变了,而篡改者没有私钥生成 CERT.SF,则无法完成校验。

  • res 文件夹:顾名思义,该文件夹是资源文件夹。它里面存放的所有文件都会被映射到 R 文件中,生成对应的资源 ID,便于代码中通过 ID 直接访问。其中的资源文件包括了动画(anim),图像(drwable),布局(layout),常量值(values),颜色值(colors),尺寸值(dimens),字符串(strings),自定义样式(styles)等。

  • resource.arsc 文件:这个文件可以说是所有文件中结构最复杂的。它记录了资源文件,资源文件位置(各个维度的路径)和资源 id 的映射关系。并且将所有的 string 都存放在了 string pool 中,节省了在查找资源时,字符串处理的开销。

    我们可以使用 Androdi Studio 2.2 Preview 中的新功能 Analyze apk (这个新功能用来分析 apk 非常好用,强烈推荐各位读者可以尝试一下)来看看它到底包含了些什么,一图胜过千言:

    可以看到,首先是有个 package 可选,实际上 resource.arsc 是可以包含多个 package 的资源的。 然后可以看到一个 Resource Types 的列表。这里看到的是 drawable 的 type。 右边显示了有多少个 drawable 以及多少项 configurations,以及表的具体内容为 ID - Name - 各个维度的值(在这里即是资源的路径),通过这个,我们可以完成通过 id + 对应的 configuration 获取对应资源的操作。

    而后面要提到资源混淆的原理,就是修改这里各个维度的值,并修改对应 res 里面的文件夹以及文件名实现的。

    具体其完整的数据结构比较复杂,在这里就不展开说了,有兴趣的读者可以自行查阅信息,甚至写一个 parser 出来也是非常有意思的。

 

 

总结:

 

 

3. APK 打包流程

android配置构建 官方文档

Android应用程序(APK)的编译打包过程:https://www.cnblogs.com/sjm19910902/p/6416022.html

Android APK打包流程:https://www.cnblogs.com/xunbu7/p/7345912.html
APK打包流程:https://blog.csdn.net/loongago/article/details/89646920
apk文件以及打包流程:https://blog.csdn.net/mysimplelove/article/details/93516904
浅述Android Apk打包流程:https://www.jianshu.com/p/d29c37dda256
Android 打包之流程:https://www.jianshu.com/p/d22f52a6a6fb

APK打包安装过程:https://segmentfault.com/a/1190000004916563

原创]记一次APP脱壳重打包过程:https://bbs.pediy.com/thread-220151.htm

下图的是官网对于Android编译打包流程的介绍。

官方的介绍非常笼统,简而言之,其大致流程就是: 编译–>DEX–>打包–>签名和对齐

来一张外国大神的图片(注:这张图少了签名的步骤)

流程图:

重点关心的是

  • (1)这个过程的输入是什么?
  • (2)这个过程的输出是什么?
  • (3)这个过程使用了什么工具?至于使用什么参数,可以自己去看对应命令的帮助文件,或者在网上搜索,

aapt -> aidl -> javac -> dx(dex) -> apkbuilder -> jarsigner -> zipalign

步骤中提到的工具如下表:

名称功能介绍在操作系统中的路径
aaptAndroid 资源打包工具${ANDROID_SDK_HOME}/platform-tools/appt
aidl

Android接口描述语言转化为.java文件的工具

( aidl 全名 Android Interface Definition Language,即Android接口定义语言 )

${ANDROID_SDK_HOME}/platform-tools/aidl
javacJava Compiler${JDK_HOME}/javac或/usr/bin/javac
dex转化.class文件为Davik VM能识别的.dex文件${ANDROID_SDK_HOME}/platform-tools/dx
apkbuilder生成 apk 包 (SDK3.0 之后弃用而使用 sdklib.jar 打包 apk${ANDROID_SDK_HOME}/tools/opkbuilder
jarsigner.jar文件的签名工具${JDK_HOME}/jarsigner或/usr/bin/jarsigner
zipalign字节码对齐工具${ANDROID_SDK_HOME}/tools/zipalign

补充:apkbuilder 在 SDK3.0 之前使用 apkbuilder 去打包,在 SDK3.0 之后就弃用了,而使用 sdklib.jar 打包 apk。

下面各个工具在打包中的用法:

 

编译打包步骤:

  • 1. 打包资源文件,生成R.java文件。打包资源的工具是aapt(The Android Asset Packaing Tool)(E:\Documents\Android\sdk\build-tools\25.0.0\aapt.exe)。在这个过程中,项目中的AndroidManifest.xml文件和布局文件XML都会编译,然后生成相应的R.java,另外AndroidManifest.xml会被aapt编译成二进制。存放在APP的res目录下的资源,该类资源在APP打包前大多会被编译,变成二进制文件,并会为每个该类文件赋予一个resource id。对于该类资源的访问,应用层代码则是通过resource id进行访问的。Android应用在编译过程中aapt工具会对资源文件进行编译,并生成一个resource.arsc文件,resource.arsc文件相当于一个文件索引表,记录了很多跟资源相关的信息。
  • 2. 处理aidl文件,生成相应的Java文件。这一过程中使用到的工具是aidl(Android Interface Definition Language),即Android接口描述语言(E:\Documents\Android\sdk\build-tools\25.0.0\aidl.exe)。aidl工具解析接口定义文件然后生成相应的Java代码接口供程序调用。如果在项目没有使用到aidl文件,则可以跳过这一步。
  • 3. 编译项目源代码,生成class文件。项目中所有的Java代码,包括R.java.aidl文件,都会变Java编译器(javac)编译成.class文件,生成的class文件位于工程中的bin/classes目录下。
  • 4. 转换所有的class文件,生成classes.dex文件。dx工具生成可供Android系统Dalvik虚拟机执行的classes.dex文件,该工具位于(E:\Documents\Android\sdk\build-tools\25.0.0\dx.bat)。任何第三方的libraries.class文件都会被转换成.dex文件。dx工具的主要工作是将Java字节码转成成Dalvik字节码、压缩常量池、消除冗余信息等。
  • 5. 打包生成APK文件。所有没有编译的资源,如images、assets目录下资源(该类文件是一些原始文件,APP打包时并不会对其进行编译,而是直接打包到APP中,对于这一类资源文件的访问,应用层代码需要通过文件名对其进行访问);编译过的资源和.dex文件都会被apkbuilder工具打包到最终的.apk文件中。打包的工具apkbuilder位于 android-sdk/tools目录下。apkbuilder为一个脚本文件,实际调用的是(E:\Documents\Android\sdk\tools\lib)文件中的com.android.sdklib.build.ApkbuilderMain类。
  • 6. 对APK文件进行签名。一旦APK文件生成,它必须被签名才能被安装在设备上。在开发过程中,主要用到的就是两种签名的keystore。一种是用于调试的debug.keystore,它主要用于调试,在Eclipse或者Android Studio中直接run以后跑在手机上的就是使用的debug.keystore。另一种就是用于发布正式版本的keystore。
  • 7. 对签名后的APK文件进行对齐处理。如果你发布的 apk 是正式版的话,就必须对APK进行对齐处理,用到的工具是zipalign(E:\Documents\Android\sdk\build-tools\25.0.0\zipalign.exe)。对齐的主要过程是将APK包中所有的资源文件距离文件起始偏移为4字节整数倍,这样通过内存映射访问apk文件时的速度会更快。对齐的作用就是减少运行时内存的使用。

上述流程都是Android Studio在编译时调用各种编译命令自动完成的

 

第一步:打包资源文件,生成R.java文件

编译 R.java 类 需要用到 AndroidSDK 提供的 aapt 工具,aapt 参数众多,以下是主要参数:

 -d  one or more device assets to include, separated by commas  
 -f  force overwrite of existing files  
 -g  specify a pixel tolerance to force images to grayscale, default 0  
 -j  specify a jar or zip file containing classes to include  
 -k  junk path of file(s) added  
 -m  make package directories under location specified by -J  
 -u  update existing packages (add new, replace older, remove deleted files)  
 -v  verbose output  
 -x  create extending (non-application) resource IDs  
 -z  require localization of resource attributes marked with  
     localization="suggested"  
 -A  additional directory in which to find raw asset files  
 -G  A file to output proguard options into.  
 -F  specify the apk file to output  
 -I  add an existing package to base include set  
 -J  specify where to output R.java resource constant definitions  
 -M  specify full path to AndroidManifest.xml to include in zip  
 -P  specify where to output public resource definitions  
 -S  directory in which to find resources.  Multiple directories will be scann  

aapt 编译 R.java 文件具体如下:

需要进入应用程序目录,新建一个gen目录,没有gen目录,命令将会出现找不到文件的错误!

命令成功执行后将会在 gen 目录下生成成包结构的目录树,及 R.java 文件。

列子:

aapt 资源编译

  1. 编译assets目录和res/raw目录下的资源
  2. 编译res目录下的资源文件
  3. 给res目录下的每个资源赋予一个资源ID,生成resource.arsc资源索引文件
  4. 解析并编译AndroidMainifest.xml
  5. 资源打包成*.ap_,资源ID常量定义自R.java

资源索引

aapt 给每一个非 assets 目录的资源定义一个资源ID,它是一个4字节(byte = 32bit)的数字,格式是PPTTNNNN,PP代表资源所属的包(package),TT代表资源的类型(Type),NNNN代表这个类型下面的资源名称(Entry ID)。

  • Package ID相当于是一个命名空间,标定资源的来源。系统资源的命名空间,它的package ID等于0x01;自己的APP资源名称空间,Package ID一般定义为0x7f。
  • Type ID是指资源的类型ID。资源的类型都有animator、anim、color、drawable、layout、menu、raw、string和xml等等若干种,每一种都会被赋予一个ID。
  • Entry ID是指每一个资源在其所属的资源类型中所出现的次序。

代码编译和打包

  • AIDL -> 生成对应的java接口
  • Javac -> 生成.class文件
  • dex-> 生成dex文件
  • APkBuilder:aapt打包好的资源、dex打包好的代码文件、第三方库资源和jar文件、native -> apk

 

第二步:处理AIDL文件,生成对应的.java文件

当然,有很多工程没有用到AIDL,那这个过程就可以省了

将 .aidl 文件生成 .java 文件需要用到 AndroidSDK 自带的 aidl 工具,此工具具体参数如下:

-I<DIR>    search path for import statements.  
-d<FILE>   generate dependency file.  
-p<FILE>   file created by --preprocess to import.  
-o<FOLDER> base output folder for generated files.  
-b         fail when trying to compile a parcelable.  
值得注意的是:这个工具的参数与参数值之间不能有空格,Google也有对工资不满意的工程师! 

例子:

 

第三步:编译Java文件,生成对应的.class文件

javac 命令用法如下:

其中,可能的选项包括:  
  -g                         生成所有调试信息  
  -g:none                    不生成任何调试信息  
  -g:{lines,vars,source}     只生成某些调试信息  
  -nowarn                    不生成任何警告  
  -verbose                   输出有关编译器正在执行的操作的消息  
  -deprecation               输出使用已过时的 API 的源位置  
  -classpath <路径>            指定查找用户类文件和注释处理程序的位置  
  -cp <路径>                   指定查找用户类文件和注释处理程序的位置  
  -sourcepath <路径>           指定查找输入源文件的位置  
  -bootclasspath <路径>        覆盖引导类文件的位置  
  -extdirs <目录>              覆盖安装的扩展目录的位置  
  -endorseddirs <目录>         覆盖签名的标准路径的位置  
  -proc:{none,only}          控制是否执行注释处理和/或编译。  
  -processor <class1>[,<class2>,<class3>...]要运行的注释处理程序的名称;绕过默认的搜索进程  
  -processorpath <路径>        指定查找注释处理程序的位置  
  -d <目录>                    指定存放生成的类文件的位置  
  -s <目录>                    指定存放生成的源文件的位置  
  -implicit:{none,class}     指定是否为隐式引用文件生成类文件  
  -encoding <编码>             指定源文件使用的字符编码  
  -source <版本>               提供与指定版本的源兼容性  
  -target <版本>               生成特定 VM 版本的类文件  
  -version                   版本信息  
  -help                      输出标准选项的提要  
  -Akey[=value]              传递给注释处理程序的选项  
  -X                         输出非标准选项的提要  
  -J<标志>                     直接将 <标志> 传递给运行时系统  

例子:

javac -encoding utf-8 -target 1.5 -bootclasspath E:\Androiddev\android-sdk-windows2.2\platforms\android-3\android.jar -d bin src\com\byread\reader\*.java gen\com\byread\reader\R.java 

 

第四步:把.class文件转化成Davik VM支持的.dex文件

将工程 bin目录下的 class 文件编译成 classes.dex,Android 虚拟机只能执行 dex 文件。

例子:

 

第五步:打包生成未签名的 .apk 文件

  • 【输入】打包后的资源文件、打包后类文件(.dex文件)、libs文件(包括.so文件,当然很多工程都没有这样的文件,如果你不使用C/C++开发的话)
  • 【输出】未签名的.apk文件
  • 【工具】apkbuilder工具

apkbuilder  工具用法如下:

-v      Verbose.  
-d      Debug Mode: Includes debug files in the APK file.  
-u      Creates an unsigned package.  
-storetype Forces the KeyStore type. If ommited the default is used.  
   
-z      Followed by the path to a zip archive.  
        Adds the content of the application package.  
   
-f      Followed by the path to a file.  
        Adds the file to the application package.  
   
-rf     Followed by the path to a source folder.  
        Adds the java resources found in that folder to the application  
        package, while keeping their path relative to the source folder.  
   
-rj     Followed by the path to a jar file or a folder containing  
        jar files.  
        Adds the java resources found in the jar file(s) to the application  
        package.  
   
-nf     Followed by the root folder containing native libraries to  
        include in the application package.

列子:

apkbuilder  ${output.apk.file} -u -z  ${packagedresource.file} -f  ${dex.file}  -rf  ${source.dir}  -rj  ${libraries.dir} 

 

第六步:对未签名 .apk 文件进行签名

通过 jarsigner 命令用证书文件对未签名的 APK 文件进行签名

【输入】未签名的.apk文件
【输出】签名的.apk文件
【工具】jarsigner

用法:jarsigner [选项] jar 文件别名  
       jarsigner -verify [选项] jar 文件  
  
[-keystore <url>]           密钥库位置    
[-storepass <口令>]         用于密钥库完整性的口令    
[-storetype <类型>]         密钥库类型    
[-keypass <口令>]           专用密钥的口令(如果不同)    
[-sigfile <文件>]           .SF/.DSA 文件的名称    
[-signedjar <文件>]         已签名的 JAR 文件的名称    
[-digestalg <算法>]    摘要算法的名称    
[-sigalg <算法>]       签名算法的名称    
[-verify]                   验证已签名的 JAR 文件    
[-verbose]                  签名/验证时输出详细信息    
[-certs]                    输出详细信息和验证时显示证书    
[-tsa <url>]                时间戳机构的位置    
[-tsacert <别名>]           时间戳机构的公共密钥证书    
[-altsigner <类>]           替代的签名机制的类名    
[-altsignerpath <路径列表>] 替代的签名机制的位置    
[-internalsf]               在签名块内包含 .SF 文件    
[-sectionsonly]             不计算整个清单的散列    
[-protected]                密钥库已保护验证路径    
[-providerName <名称>]      提供者名称    
[-providerClass <类>        加密服务提供者的名称  
[-providerArg <参数>]] ... 主类文件和构造函数参数  

只需要按步骤生成 MANIFEST.MF, CERT.RSA,CERT.SF 并放入META-INF 文件夹即可。

 

第七步:对签名后的.apk文件进行对齐处理

不进行对齐处理是不能发布到Google Market的

【输入】签名后的.apk文件
【输出】对齐后的.apk文件
【工具】zipalign工具

知道了这些细节之后,我们就可以实现很多我们想实现东西了,比如:自动化,我们可以使用某种脚本,像Windows下的批处理,linux下的Bash,Java下的Ant,Python、Perl这样的脚本语言,甚至直接用Java、.net这们的强类型语言也是可以的。

 

以上便是APK打包的整个流程,我们再来总结一下:

  • 除了assets和res/raw资源被原装不动地打包进APK之外,其它的资源都会被编译或者处理;
  • 除了assets资源之外,其它的资源都会被赋予一个资源ID;
  • 打包工具负责编译和打包资源,编译完成之后,会生成一个resources.arsc文件和一个R.java,前者保存的是一个资源索引表,后者定义了各个资源ID常量。
  • 应用程序配置文件AndroidManifest.xml同样会被编译成二进制的XML文件,然后再打包到APK里面去。
  • 应用程序在运行时通过AssetManager来访问资源,或通过资源ID来访问,或通过文件名来访问。

 

 

4. APK 安装流程

Android中APK安装流程解析:https://blog.csdn.net/mysimplelove/article/details/93619361

APK安装后最终放置在了哪里?安装APP到底是怎样的一个过程?如何打开并修改APK程序包?

如果使用 WinHex 打开apk文件,从文件头就可以看出APK安装包其实就是一个zip格式的压缩包,所以我们只需将apk文件的后缀修改为 .zip 或 .rar ,就可以轻松的在电脑上打开并查看apk软件内部的文件和数据(当然你也可以使用手机R.E管理器查看)。

Android 安装 apk包的五种方式:

  • 1, 通过工具安装:R.P 或 ES等管理工具,有安装界面。
  • 2,adb install 安装,无安装界面。
  • 3,android market 在线安装,无安装界面。
  • 4,直接 copy 到系统目录/system/app下,无安装界面。此目录下的应用一般是系统自带的系统级程序和常归应用。
  • 5,pm(android 系统自带工具) 命令行安装,无安装界面。

apk 文件在安装到手机过程中,涉及到如下几个目录:

/system/framwork:    保存的是资源型的应用程序,它们用来打包资源文件。
/data/app-private:   保存受DRM保护的私有应用程序。
/vendor/app:         保存设备厂商提供的应用程序。
/system/app           ------- 系统自带的应用安装目录,获得 adb root权限才能删除
/data/app             ------- 用户程序安装的目录,安装时把 apk文件 复制到 此目录
/data/data            ------- 存放应用程序的数据
/data/dalvik-cache    将 apk 中的 dex文件 安装到 dalvik-cache 目录下
                     (dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)

/data/system:该目录下的packages.xml文件,类似于Windows的注册表,记录了系统的permissions,
            每个apk的name,codePath,,version,userid等信息,这些信息主要通过AndroidManifest.xml
            文件解析获取,解析完apk后将更新信息写入这个文件并保存到flash,下次开机的时候直接从里
            面读取相关信息并添加到内存相关列表中。当有APK安装、升级或者删除时会更新这个文件。

/data/system/packages.xml /data/system/packages.list: 
        packages.list指定了应用的默认存储位置/data/data/com.xxx.xxx;package.xml中包含了该应用 
        权限、应用包名、APK的安装位置、版本、userID等信息,并且两者都有同一个userld。之所以每个 
        应用都要一个userId,是因为Android在系统设计上把每个应用当做Linux系统上的一个用户对待, 
        这样就可以利用已有的Linux用户管理机制来设计Android应用,
        比如应用目录,应用权限,应用进程管理等。


安装过程:

当我们新安装一个应用的时候,通常系统会执行以下流程:

校验apk包签名 → 复制程序包到 /data/app 目录 → 建立 /data/data/com.xxx 数据目录 → 提取释放lib文件 → dexopt优化classes.dex处理后释放到 /data/dalvik-cache 目录

在这个过程中,Android 系统服务还会更新以下系统文件:

  • /data/system/packages.list   --  分配存储APP的uid/gid,也就是用户/所属组
  • /data/system/packages.xml  --  记录保存APP权限、签名证书、安装路径、版本信息等

由此可见,我们安装好的软件程序包被原本不动存放在 /data/app 目录之下,数据目录则被安放在 /data/data/pkg_name(包名) 目录之中。而卸载过程则相反,进行删除相关文件处理。

 

整个 apk 安装流程:

  • 复制 APK 到 /data/app 目录 下,解压(会放到 data/app/包名/ 目录下面,同时 apk 中的 so 文件 也会拷贝到此目录下的 lib 文件目录中。)并扫描安装包。而系统出厂的 apk 被放到 /system分区下,这就是没有ROOT手机前,我们无法删除系统app的原因。( 下面 是用 MT 管理器 (需要获取root 权限) 打开)
  • 资源管理器解析 APK 里的资源文件。
  • 解析 AndroidManifest.xml(Android应用程序的解析过程就是解析这个xml文件的过程)。解析的内容会被更新到/data/system/packages.xml 和 /data/system/packages.list中,packages.list 中指名了该应用默认存储的位置,packages.xml 中包含了该应用申请的权限、签名和代码所在位置等信息,并且两者都有一个 相同的 userId。之所以每个应用都有一个userId,是因为Android 在系统设计上把每个应用当作Linux系统上的一个用户对待,这样就可以利用已有的Linux上用户管理机制来设计Android应用,比如应用目录,应用权限,应用进程管理等。做完以上操作,就相当于应用在系统注册了,可以被系统识别。接下来就得保存应用的执行文件了,根据 packages.xml中指定的 codePath,创建一个目录,即/data/data/ 目录 下创建对应的 应用数据目录apk会被命名成 base.apk 并拷贝到此,其中 lib 目录用来存放 native 库
  • 然后对 dex 文件进行优化,并保存在 dalvik-cache目录 下。其命名规则是 apk路径+classes.dex。(此时应用就可以运行了,但如果每次应用运行还得去base.apk中取dex文件,效率就太低了。为了提升效率,Android系统在应用安装时还会做些优化操作,把所有可运行的dex文件单独提取放在一块并做些优化。在Dalvik模式下,会使用dexopt把base.apk中的dex文件优化为odex,存储在/data/dalvik-cache中,如果是ART模式,则会使用dex2oat优化成oat文件也存储在该目录下,并且文件名一样,但文件大小会大很多,因为ART模式会在安装时把dex优化为机器码,所以在ART模式下的应用运行更快,但apk安装速度相对Dalvik模式下变慢,并且会占用更多的ROM。
  • 将 AndroidManifest 文件解析出的四大组件信息注册到 PackageManagerService 中。
  • 安装完成后,发送广播。
  • 显示icon图标:应用程序经过PMS中的逻辑处理后,相当于已经注册好了,如果想要在Android桌面上看到icon图标,则需要Launcher将系统中已经安装的程序展现在桌面上。

安装图解和过程描述:

安装过程并没有把资源文件, assets目录下文件拷贝出来,他们还在apk包里面呆着,所以,当应用要访问资源的时候,其实是从apk包里读取出来的。其过程是,首先加载apk里的resources.arsc(这个文件是存储资源Id与值的映射文件),根据资源id读取加载相应的资源。

删除安装过程:就是删除在上述三个目录下创建的文件及目录。

总体说来就两件事情:拷贝APK解析APK,解析APK主要是解析 AndroidManifest.xml,以便获得它的安装信息。在安装的过程中还会这个应用分配 Linux用户ID 和 Linux用户组ID(以便它可以在系统中获取合适的运行权限)。

 

涉及的三个进程

  • PackageInstaller进程:PackageInstaller事实上是一个应用,它负责APK安装以及卸载过程中与用户的交互流程。
  • SystemServer进程:该进程主要运行的是系统服务,APK的安装、卸载和查询都由PackageManagerService负责,它也是Android核心系统服务的一种,在SystemServer里初始化系统服务的时候被启动。
  • DefaultContainerService进程:DefaultContainerService也是一个单独的进程,它主要负责检查和复制设备上的文件,APK的复制就是由DefaultContainerService来完成的。

 

apk 解析流程

  • Android不同类型
    /system/framwork:保存的是资源型的应用程序,它们用来打包资源文件。
    /system/app:保存系统自带的应用程序。
    /data/app:保存用户安装的应用程序。
    /data/app-private:保存受DRM保护的私有应用程序。
    /vendor/app:保存设备厂商提供的应用程序。
  • DEX的dexopt流程
    dexopt操作实际上对DEX文件在执行前进行一些优化,但是不同的虚拟机操作有所不同。
    Davlik:将dex文件优化生成odex文件,这个odex文件的后缀也是dex,保存在/data/dalvik-cache目录下。
    ART:将dex文件翻译生成oat文件

 

如何修改 & 反编译APK软件包?

如果只是修改程序包的一些图片/assets资源,直接在电脑上用解压缩工具,解压后就可以修改替换,但是重新打包后需要重新签名,否则没有签名或者签名校验不正确的应用是无法安装成功的。

而如果想要修改apk包中其他的已经编译后的文件,则需要反编译。由于 Android 本质上就是一个 Java 虚拟机,而 classes.dex 文件则是众多 .class 文件的打包集合,一般我们先要使用 dex2jar 将 classes.dex 解包为 Java jar 文件,然后再通过 JD-GUI 将 jar 文件的 .class 文件反编译为 .java 源码。

整个反编译dex的过程原理大致简单来说就是这样,但是实际操作起来难度不小,因为很多程序都经过了混淆加密处理(比如QQ,微信等等大公司的软件不可能让人分分钟反编译破解,否则整个安卓APP世界还不乱套了...)

对于apk程序包其他的一些xml布局文件,直接打开是乱码怎么办?dex字节码都能反编译成功,xml就更简单一些了。网上有很多现成的工具,比如 AXMLPrinter2.jar ,可以直接解码反编译xml文件,当然执行 .jar文件需要在电脑上事先安装好 JRE(Java运行环境)哟!

关于 Android 应用的反编译这里仅是简单介绍一下原理和过程,明白了解一下就好。具体的方法百度一搜一大把。

 

 

虚拟机