100天精通Andriod逆向——第2天:Android基础知识和jadx的使用
Posted Amo Xiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了100天精通Andriod逆向——第2天:Android基础知识和jadx的使用相关的知识,希望对你有一定的参考价值。
目录
一、android基础知识介绍
1.1 Android 历史版本
Android 4.4 以前,采用 dalvik /dvm虚拟机,代表:libdvm.so
Android 4.4,里面有 dvm和art虚拟机,可以切换 libdvm.so libart.so
Android 5.0及以后,使用art虚拟机,Android系统也开始分32位和64位 nexus5 32 6.0 --> 32位 nexus6p 64 6.0 -> 64位
详细了解,请移步:https://blog.csdn.net/u011033906/article/details/117806349
https://juejin.cn/post/7089376647576551461
1.2 apk 包文件结构
Android 应用是用 Java 编写的,利用 Android SDK 编译代码,并且把所有的数据和资源文件打包成一个 APK(Android Package)文件,这是一个后缀名为 .apk 的压缩文件,apk 文件中包含了一个 Android 应用程序的所有内容,是 Android 平台用于安装应用程序的文件。apk 就是一个压缩包,解开这个 apk 包我们可以看到以下的结构:
作用介绍如下:
- assets目录: 存放需要打包到 apk 的静态文件,该目录与 res 目录不同之处在于 assets 目录支持任意深度的子目录,我们的开发者可以根据自己的需求来任意部署文件夹的架构,而且 res 目录下的文件会在
.R
文件中生成与其对应的资源ID,assets 不会自动生成对应的id,访问的时候需要 AssetManager 类 - lib 目录: 该目录用来存放应用程序所依赖的 native 库文件,native 库一般是用 C/C++ 进行编写的,这里的 lib 库可能包含4种不同类型,根据 CPU 型号的不同,我们大体可以分为 ARM,ARM-v7a,MIPS,X86,分别对应着 ARM架构,ARM-V7架构,MIPS架构和X86架构,这些so库在apk包中构成如下图:
其中,不同的 CPU 架构对应着不同的目录,每个目录中可以存放非常多的对应版本的so库,而且这个目录的结构固定,用户只能按照这个目录来存放自己的so库。目前市场上使用的移动终端大多是基于 ARM 或者 ARM-v7a 架构的。从厂家上来分是有三种,arm,x86,MIPS,arm 系列是绝大多数手机上使用的,x86 主要是运用在平板上,而 MIPS ,基本上就没见过。 - res 目录: res 是 resource 的缩写,这个目录存放资源文件,存在这个文件夹下的所有文件都会映射到 Android 工程的
.R
文件中,生成对应的ID,访问的时候直接使用资源 ID 即R.id.filename
,res 文件夹下可以包含多个文件夹,其中 anim 存放动画文件;drawable 目录存放图像资源;layout目录存放布局文件;values 目录存放一些特征值,colors.xml 存放 color 颜色值,dimens.xml 定义尺寸值,string.xml 定义字符串的值,styles.xml 定义样式对象;xml 文件夹存放任意xml文件,在运行时可以通过 Resources.getXML() 读取;raw 是可以直接复制到设备中的任意文件,他们无需编译。 - META-INF 目录: 保存应用的签名信息,签名信息可以验证 apk 文件的完整性。AndroidSDK 在打包 apk 时会计算 apk 包中所有文件的完整性,并且把这些完整性保存到 META-INF 文件夹下,应用程序在安装的时候首先会根据 META-INF 文件夹校验 apk 的完整性,这样就可以保证 apk 中的每一个文件都不能被篡改。以此来确保 apk 应用程序不被恶意修改或者病毒感染,有利于确保 Android 应用的完整性和系统的安全性。META-INF 目录下包含的文件有 CERT.RSA,CERT.DSA,CERT.SF 和 MANIFEST.MF,其中 CERT.RSA 是开发者利用私钥对 APK 进行签名的签名文件,CERT.SF,MANIFEST.MF记 录了文件中文件的 SHA-1 哈希值。
- AndroidManifest.xml: 是 Android 应用程序的配置文件,是一个用来描述 Android 应用
整体资讯
的设定文件,简单来说,相当于 Android 应用向 Android 系统自我介绍
的配置文件,Android 系统可以根据这个自我介绍
完整地了解 apk 应用程序的资讯,每个 Android 应用程序都必须包含一个 AndroidManifest.xml 文件,且它的名字是固定的,不能修改。在开发 Android 应用程序的时候,一般都把代码中的每一个 Activity,Service,Provider 和 Receiver 在 AndroidManifest.xml 中注册,只有这样系统才能启动对应的组件,另外这个文件还包含一些权限声明以及使用的SDK版本信息等等。程序打包时,会把 AndroidManifest.xml 进行简单的编译,便于 Android 系统识别,编译之后的格式是AXML格式,如下图所示:
- classes.dex: 传统的 Java 程序,首先先把文件编译成 class 文件,字节码都保存在了 class 文件中,Java 虚拟机可以通过解释且执行这些 class 文件。然而 Dalvik 虚拟机是在 Java 虚拟机进行了优化,执行的是 Dalvik 字节码,而这些 Dalvik 字节码就是由 Java 字节码转换而来的。一般来说,Android 应用在打包的时候通过 Android SDK 中的 dx 工具将 Java 字节码转换为 Dalvik 字节码。Dx 工具可以对多个 class 文件进行合并,重组和优化,通过这些操作,可以达到减小体积,缩短运行时间的目的。
- resources.arsc: 用来记录资源文件和资源 ID 之间的映射关系,用来根据资源 ID 寻找资源。Android 的开发是分模块的,res 目录专门用来存放资源文件,当在代码中需要调用资源文件时,只需要调用 findviewbyId() 就可以得到资源文件,每当在 res 文件夹下放一个文件,aapt 就会自动生成对应的 ID 保存在
.R
文件,我们调用这个ID
就可以,但是只有这个ID
还不够,.R
文件只是保证编译程序不报错,实际上在程序运行时,系统要根据 ID 去寻找对应的资源路径,而resources.arsc
文件就是用来记录这些 ID 和资源文件位置对应关系的文件。
1.3 Android系统目录介绍
- data/data目录: 存放用户 apk 数据的目录,每个 apk 都有自己的目录,以包名命名就是在 data/data 目录下,会产生一个跟 package 一样的目录,这是一个私有目录,app 只能访问各自的目录,除非 root 权限
- data/app目录: 用户安装的 app 存放在这个目录下
- data/local/tmp: 临时目录,权限比较大
- system/app目录: 存放系统自带的 app
- system/lib 目录、system/lib64: 存放app用到的so文件
- system/bin目录: 存放shell命令
- system/framework目录: Andriod系统所用到的框架,如一些jar文件,XposedBridge.jar
- sd卡目录: 不管手机有没有存储卡都会有这个目录,app操作sd卡目录需要申请权限 /sdcard–>/storage/self/primary /mnt/sdcard /storage/emulated/0
更详细的Android系统目录介绍请参考文章:https://blog.csdn.net/abc6368765/article/details/125403212
二、jadx的使用
逆向中关键的一步就是反编译 apk 文件,将其还原成可读性高的 Java 代码,在多数情况下,我们是通过观察并分析这个 Java 代码就能找到想要的核心逻辑。工欲善其事,必先利其器。用来反编译 apk 文件的工具有很多,例如:jadx、JEB、Apktool、jda 等,不同工具的用法和定位也有所不同。
2.1 jadx 的简介
jadx 是一款使用广泛的反编译工具,可以一键把 apk 文件还原成 Java 代码,使用起来很简单,功能强大,还具有一些附加功能可以辅助代码追查。GitHub 地址为:https://github.com/skylot/jadx。主要具有如下几个功能:
- 除了反编译 apk 文件,还可以反编译 jar、class、dex、aar 等文件和 zip 文件中的 Dalvik 字节码
- 解码 AndroidManifest.xml 文件和一些来自 resources.arsc 中的资源文件
- 一些 apk 文件在打包过程中增加了 Java 代码的混淆机制,对比 jadx 提供反混淆的支持。
jadx 本身是一个命令行工具,仅仅通过 jadx 这个命令就可以反编译一个 apk 文件。除此之外,它也有配套的图形化界面工具(jadx-gui),这个使用起来更加方便,能直接以图形界面的方式打开一个 apk 文件。同时,jadx-gui 对反编译后得到的 java 代码和其他资源文件增加了高亮支持(就像在IDE中打开这些内容一样),还具有快速定位、引用搜索、全文搜索等功能。所以,我们往往直接使用 jadx-gui 完成一些反编译操作。
2.2 jadx 的安装
Windows 下直接到点击 此处 下载对应的 Release 包即可,如下图所示:
单击,下载中,如下图所示:
如果 Github 链接打不开的,可以直接从我的百度网盘中进行下载,下载链接如下:
链接:https://pan.baidu.com/s/1grSPLrlqEIUqbftVFvYbNw
提取码:tm9h
--来自百度网盘超级会员V8的分享
下载之后直接解压到自己常用的目录即可,解压之后会得到一个 bin 目录,进入 bin 目录直接运行 jdax 和 jadx-gui 即可,Windows 可以直接双击 jadx.bat 或 jadx-gui.bat 即可运行。如下图所示:
2.3 jadx 的命令
使用 jadx 的命令执行文件的反编译操作,主要是指定一些输入参数和输出参数,这些参数的设置细节直接参考参数说明即可。运行 jadx -h 命令 (以管理员身份运行cmd窗口,并且进入到jadx解压的目录),查看 jadx 命令的用法,如下图所示:
可以看到,参数 <input files>
就是输入文件的路径,其他参数如 -d 可以指定反编译后输出文件的路径, -r 可以指定不解析资源文件(能够提升整体反编译的速度)。使用下面的命令对已经下载好的 scrape-app5.apk
文件进行反编译:
jadx scrape-app5.apk -d scrape-app5
运行完毕后,本地会生成一个 scrape-app5 文件夹,还原效果还是比较理想的,就这样,我们只需要一条简单的命令就完成了对 apk 文件的反编译,其中 Java 代码的逻辑一览无遗。
2.4 jadx-gui 的使用方法
jadx-gui 是一个图形界面工具,它就像一个 IDE,支持很多方便快捷的交互式操作(例如把一个 apk 文件拖到 jadx-gui 后,它会直接打开这个软件,之后高亮显示反编译后的代码),以及代码搜索、定位等。
2.4.1 启动和反编译
在 Windows 下直接双击 jadx-gui.bat
,jadx-gui 便启动了,这是我们可以看到下图所示的界面:
可以通过文件路径打开 apk,也可以直接将 apk 文件拖到 jadx-gui 的窗口中,还可以从菜单栏中的 文件-->打开文件
调出资源管理器来打开 apk 文件。文件打开之后,稍等片刻,反编译就完成了,这是看到的界面 如下图所示:
从界面的左侧可以发现,反编译后的 Java 源代码以一个个包的形式组织在一起,另外还有资源文件,其中包括图片文件、布局文件和 AndroidManifest.xml 文件(内含 apk 文件的基本信息)等。在左侧展开想要查看的包,右侧就会出现对应的 Java 源代码,如下图所示:
可以看出,Java 源代码的还原度还是很高的。
2.4.2 保存为 Gradle 项目
我们也可以把反编译后的文件另存为 Gradle 项目,Gradle 项目就是开发版本的 Andriod 项目,如下图所示:
导出后的项目目录结构和我们在 jadx-gui 界面里看到的结构基本一致,这个项目是可以被 Android Studio 工具打开的,打开的界面如下图所示:
打开之后的代码一般没办法直接运行,因为毕竟整个项目是反编译出来的,不太可能完全还原出开发版本的 Andriod 项目。如果你对 Andriod 开发比较了解,可以尝试修改一下源码和 Gradle 配置,是可以使项目正常运行的,即使不能运行也没有太大关系,我们的目的并不是运行这个代码,而是分析其中的逻辑,所以要把目光聚焦在查找和定位目标方法与逻辑定义上,Android Studio 能够帮我们更方便地完成这些操作,当然 jadx-gui 也提供了查找和定位的相关功能,现在我们回到 jadx-gui,了解一下它的其他常见用法。
2.4.3 文本搜索
在源代码中搜索 /api/movie
字符串,可以使用 jadx-gui 提供的搜索功能,打开菜单栏里的 导航-->搜索文本
,如下图所示:
这时 jadx-gui 会显示一个搜索框,如下图所示,在 搜索文本:
下方填入 /api/movie
,同时可以从类名、方法名、变量名和代码中选择搜索位置,自行勾选即可,下方会显示搜索结果。
可以看到,搜索到了一处包含 /api/movie
字符串的位置,可以依次看一下这两处的内容,先选中搜索结果,然后点击 转到
按钮,即可跳转到对应的代码处,如下图所示:
2.4.4 查找方法的声明
鼠标右键单击任意方法名,会打开一个菜单,选择 跳到声明
,如下图所示:
这时候就会跳转到声明方法的位置。
2.4.5 查找用例—通过声明找到调用方法的位置
右击声明处的 initCrash 方法名,在打开的菜单中可以看到一个 查找用例
的选项,如下图所示:
点击之后,查找到的结果如下图所示:
搜索结果有一处,直接双击结果或者先选中结果再点击 转到按钮
,都可以跳转到对应的代码处。
2.4.6 反混淆
jadx-gui 还有一个强大的功能,就是反混淆。有时候从一些单个字母变量等并不好推测究竟是什么意思,这是 App 在编译和打包阶段做了一些混淆操作导致的结果,和 javascript 中的变量混淆非常相似。针对这个问题,jadx-gui 具有反混淆功能。我们可以打开反混淆开关,点击菜单栏中的 工具-->反混淆
,如下图所示:
反混淆能够进一步提升代码的还原度,从而让我们更方便地推敲代码中的逻辑。
2.4.7 设置选项
jadx-gui 还提供了很多功能设置,可以点击工具栏中的 首选项
按钮,如下图所示:
然后会打开一个设置页面,如下图所示:
这其实是一个总的设置页面,我们可以在这里配置 jadx-gui 的各个选项,如是否启用反混淆、反编译过程中允许的并行线程数、系统是否区分大小写、是否反编译资源文件等,这些和 jadx 的一些命令功能是一致的。
2.4.8 日志查看
在 jadx-gui 允许的过程中,还可以查看运行日志,点击工具栏中的 日志
按钮即可打开日志查看器,如下图所示:
日志查看器如下图所示,可以通过上方的选择框选择日志等级,例如这里选择了 ERROR 级别,即显示错误日志。
如果反编译过程出现了错误,就可以来这里查看错误细节。
2.5 常见问题
如果有些 apk 文件比较大,jadx-gui 反编译所需的时间和消耗的资源会更多,所以有时候在反编译过程中会提示如下错误:
java.lang.OutOfMemoryError: GC overhead limit exceeded
....
这里报了一个 OutOfMemoryError 错误,代表内存溢出,对于一些比较大的 apk 文件,是会出现这种问题的,可以尝试用以下两种方式解决:
- 增加 JVM 的最大内存:设置 JVM_OPTS,把 JVM 的最大内存调大,之后内存溢出的问题自然可以得到有效解决。
- 减小线程数:线程多了,反编译过程消耗的内存自然也会增多,可以在运行 jadx 的命令时通过 -j 命令适当将线程数量设置为更小的值。
在第2天,我们学习了 Android的一些基础知识以及 jadx、jadx-gui 的基本使用方法,利用这两个工具,我们可以非常方便地反编译 apk 文件,还原出原始的 Java 代码,从而找到我们想要的核心逻辑。今天学习的内容比较基础,需要好好掌握,之后会经常使用 jadx 来反编译 apk 文件。
以上是关于100天精通Andriod逆向——第2天:Android基础知识和jadx的使用的主要内容,如果未能解决你的问题,请参考以下文章
100天精通Andriod逆向——第5天:app逆向流程简介
100天精通Andriod逆向——第5天:app逆向流程简介