哔哩哔哩:https://www.bilibili.com/video/BV1UE411A7rW?p=1
Android 逆向工程师系统培训‹第九期›( 课程目录 ):https://ke.yijincc.com/course-21.htm
安卓逆向工程师:https://ke.yijincc.com/profession/1.htm
1. java 开发环境:java jdk、java jre
java jdk 最好安装 jdk8 的最新版本,如果安装更高的 java 版本,一些逆向工具可能使用不了。
安装 java jdk8 的时候会自动弹出 对应 jre 的安装。
2. 安卓开发环境:安卓 sdk、ndk
安卓sdk 和 ndk 直接解压就行,不需要进行安装,但是需要配置环境变量。
安卓 sdk 的安装:可以直接下载 安卓 jdk 进行安装,也可以下载 android studio (安卓开发 IDE ) 通过 IDE 进行安装
通过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 进行安装
APK 是 Android PacKage 的缩写,即 Android 安装包。apk 文件也就是 Android 打包流程的产物。那么 apk 是一个什么类型的文件?它包含了一些什么内容? 弄清楚了这些,我们就可以带着目的性,去分析打包流程,可以更好的关注 apk 文件中的这些内容是在打包流程的哪个过程中产生,以及是如何产生的。
众所周知,apk 文件本质上其实是一个 zip 格式的压缩包。想要知道其中包含了什么,改后缀然后用解压缩工具即可打开任何一个APK文件。 如果有 代码混淆 和 加密,通过普通解压缩工具打开里面的文件或目录会看到各种乱码。
apk 概览
图示:
这里解压了某个未经过 加固加壳 或者 其他手段加密的 Android 安装包文件,以下为结果截图:
https://www.sohu.com/a/149758866_675634
主要注意红色标注部分,这一些文件和文件夹是一个 Android 应用基本都具备的。而其他的一些文件和文件夹则是一些第三方库,或者是其他一些代码生成的。 接下来,依次大概介绍一下这些文件和文件夹的作用。
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 包的完整性。再说 CERT.RSA:这个文件保存了公钥和加密方式的信息。最后说 CERT.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 出来也是非常有意思的。
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–>打包–>签名和对齐
来一张外国大神的图片(注:这张图少了签名的步骤)
流程图:
重点关心的是
aapt -> aidl -> javac -> dx(dex) -> apkbuilder -> jarsigner -> zipalign
步骤中提到的工具如下表:
名称 | 功能介绍 | 在操作系统中的路径 |
aapt | Android 资源打包工具 | ${ANDROID_SDK_HOME}/platform-tools/appt |
aidl | Android接口描述语言转化为.java文件的工具 ( aidl 全名 Android Interface Definition Language,即Android接口定义语言 ) |
${ANDROID_SDK_HOME}/platform-tools/aidl |
javac | Java 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。
下面各个工具在打包中的用法:
编译打包步骤:
上述流程都是Android Studio在编译时调用各种编译命令
自动完成的
编译 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 资源编译
资源索引
aapt 给每一个非 assets 目录的资源定义一个资源ID,它是一个4字节(byte = 32bit)的数字,格式是PPTTNNNN,PP代表资源所属的包(package),TT代表资源的类型(Type),NNNN代表这个类型下面的资源名称(Entry ID)。
代码编译和打包
(当然,有很多工程没有用到AIDL,那这个过程就可以省了)
将 .aidl 文件生成 .java 文件需要用到 AndroidSDK 自带的 aidl 工具,此工具具体参数如下:
-I search path for import statements.
-d generate dependency file.
-p file created by --preprocess to import.
-o base output folder for generated files.
-b fail when trying to compile a parcelable.
值得注意的是:这个工具的参数与参数值之间不能有空格,Google也有对工资不满意的工程师!
例子:
javac 命令用法如下:
其中,可能的选项包括:
-g 生成所有调试信息
-g:none 不生成任何调试信息
-g:{lines,vars,source} 只生成某些调试信息
-nowarn 不生成任何警告
-verbose 输出有关编译器正在执行的操作的消息
-deprecation 输出使用已过时的 API 的源位置
-classpath <路径> 指定查找用户类文件和注释处理程序的位置
-cp <路径> 指定查找用户类文件和注释处理程序的位置
-sourcepath <路径> 指定查找输入源文件的位置
-bootclasspath <路径> 覆盖引导类文件的位置
-extdirs <目录> 覆盖安装的扩展目录的位置
-endorseddirs <目录> 覆盖签名的标准路径的位置
-proc:{none,only} 控制是否执行注释处理和/或编译。
-processor [,,...]要运行的注释处理程序的名称;绕过默认的搜索进程
-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
将工程 bin目录下的 class 文件编译成 classes.dex,Android 虚拟机只能执行 dex 文件。
例子:
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}
通过 jarsigner 命令用证书文件对未签名的 APK 文件进行签名
【输入】未签名的.apk文件
【输出】签名的.apk文件
【工具】jarsigner
用法:jarsigner [选项] jar 文件别名
jarsigner -verify [选项] jar 文件
[-keystore ] 密钥库位置
[-storepass <口令>] 用于密钥库完整性的口令
[-storetype <类型>] 密钥库类型
[-keypass <口令>] 专用密钥的口令(如果不同)
[-sigfile <文件>] .SF/.DSA 文件的名称
[-signedjar <文件>] 已签名的 JAR 文件的名称
[-digestalg <算法>] 摘要算法的名称
[-sigalg <算法>] 签名算法的名称
[-verify] 验证已签名的 JAR 文件
[-verbose] 签名/验证时输出详细信息
[-certs] 输出详细信息和验证时显示证书
[-tsa ] 时间戳机构的位置
[-tsacert <别名>] 时间戳机构的公共密钥证书
[-altsigner <类>] 替代的签名机制的类名
[-altsignerpath <路径列表>] 替代的签名机制的位置
[-internalsf] 在签名块内包含 .SF 文件
[-sectionsonly] 不计算整个清单的散列
[-protected] 密钥库已保护验证路径
[-providerName <名称>] 提供者名称
[-providerClass <类> 加密服务提供者的名称
[-providerArg <参数>]] ... 主类文件和构造函数参数
只需要按步骤生成 MANIFEST.MF, CERT.RSA,CERT.SF 并放入META-INF 文件夹即可。
(不进行对齐处理是不能发布到Google Market的)
【输入】签名后的.apk文件
【输出】对齐后的.apk文件
【工具】zipalign工具
知道了这些细节之后,我们就可以实现很多我们想实现东西了,比如:自动化,我们可以使用某种脚本,像Windows下的批处理,linux下的Bash,Java下的Ant,Python、Perl这样的脚本语言,甚至直接用Java、.net这们的强类型语言也是可以的。
以上便是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包的五种方式:
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/app 目录之下,数据目录则被安放在 /data/data/pkg_name(包名) 目录之中。而卸载过程则相反,进行删除相关文件处理。
/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 库/data/dalvik-cache
中,如果是ART模式,则会使用dex2oat优化成oat文件也存储在该目录下,并且文件名一样,但文件大小会大很多,因为ART模式会在安装时把dex优化为机器码,所以在ART模式下的应用运行更快,但apk安装速度相对Dalvik模式下变慢,并且会占用更多的ROM。)安装图解和过程描述:
安装过程并没有把资源文件, assets目录下文件拷贝出来,他们还在apk包里面呆着,所以,当应用要访问资源的时候,其实是从apk包里读取出来的。其过程是,首先加载apk里的resources.arsc(这个文件是存储资源Id与值的映射文件),根据资源id读取加载相应的资源。
删除安装过程:就是删除在上述三个目录下创建的文件及目录。
总体说来就两件事情:拷贝APK 和 解析APK,解析APK主要是解析 AndroidManifest.xml,以便获得它的安装信息。在安装的过程中还会这个应用分配 Linux用户ID 和 Linux用户组ID(以便它可以在系统中获取合适的运行权限)。
如果只是修改程序包的一些图片/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 应用的反编译这里仅是简单介绍一下原理和过程,明白了解一下就好。具体的方法百度一搜一大把。