第一章:引言与背景
Android逆向工程,作为一种深入分析Android应用程序的技术,主要目的就是通过分析应用的代码、资源和行为来理解其功能、结构和潜在的安全问题。它不仅仅是对应用进行破解或修改,更重要的是帮助开发者、研究人员和安全人员发现并解决安全隐患。
本文主要对整个安卓逆向入门的体系进行整理,解决一些安卓逆向时候的痛点问题!每个知识点都会有对应的例题下载,或者前文对应刷题的链接,在刷题中学习,才可以更快的掌握知识!
下面是本文的关键点:
- APK逆向工具:工欲善其事,必先利其器(这部分可以掠过,只做了工具的下载地址和简单介绍)
- APK的基本结构(详细解析了每个文件的作用和目的)
- Android逆向分析中的基础(解决没有安卓开发基础学习安卓逆向时候的痛点问题)
- 如何找出APP的程序的入口点?
- 如何识别是否加壳,并且简单脱壳?
- 如何寻找一个页面的xml布局文件?
- 如何确定按钮所绑定的函数?
- 如何寻找app中涉及到的资源文件?
- 什么是java层逆向,什么是Native层逆向?
- 安卓系统中的四大组件是如何在逆向题目中被应用的?
- 最后进行了安卓体系的梳理!
第二章:APK逆向工具:工欲善其事,必先利其器
1.1 雷电模拟器运行APK
雷电模拟器,作为安卓模拟器的佼佼者,一直以来备受用户青睐。它不仅可以让你在PC上畅快运行安卓应用,还能提供与手机端接近的使用体验,让你在开发、调试乃至游戏娱乐中都能游刃有余。安装雷电模拟器其实并不复杂,但要确保顺利完成,还是有一些细节需要关注。
相关使用:雷电模拟器的使用 - 搜索
下载地址:雷电模拟器官网_安卓模拟器_电脑手游模拟器
1.2 ADB的使用
ADB(Android Debug Bridge),简直是安卓开发者和逆向工程师的“瑞士军刀”。无论是调试、安装应用,还是进行日志分析,ADB都是不可或缺的工具。你可能会认为ADB只是一个命令行工具,然而它的强大远超你的想象。
相关使用:ADB安装及使用详解(非常详细)从零基础入门到精通,看完这一篇就够了-CSDN博客
下载地址:https://dl.google.com/android/repository/platform-tools-latest-windows.zip
1.4 使用JADX反编译APK
JADX是一款非常流行且功能强大的APK反编译工具,它能够将APK中的DEX文件(即Dalvik Executable文件)反编译成可读的Java源代码。JADX的优势不仅仅在于它的易用性,还在于它的反编译效果非常优秀,能够清晰地显示反编译后的Java代码,帮助开发者和安全人员深入理解应用的内部逻辑。
JADX的优点:
- 易用性:图形界面的设计使得操作简单直观,适合初学者和经验丰富的开发者。
- 高效的反编译效果:JADX能够将DEX文件反编译成非常接近原始Java代码的源代码,对于Java层的应用分析尤为高效。
- 支持多种格式:除了反编译Java代码,JADX还支持查看APK中的资源文件(如图片、XML文件等),让你能够全面了解应用的构成。
相关使用:APK反编译工具jadx - chuyaoxin - 博客园
下载地址:https://down.52pojie.cn/Tools/Android_Tools/jadx-1.5.0.zip
1.5 使用GAD进行APK反汇编
GAD(Google Android Disassembler)是一个专注于APK底层字节码分析的工具。与JADX不同,GAD更多侧重于字节码级别的反汇编,它能够帮助安全研究人员和开发者深入到应用的最底层,查看其具体的机器码和执行逻辑。GAD特别适用于那些对字节码和汇编语言感兴趣的逆向工程师,它可以帮助我们获得应用中深层次的行为信息。
GAD的优点:
- 底层分析能力:GAD能够提供非常详细的底层字节码分析,帮助你更深入地理解应用的执行过程。
- 适用于高级分析:如果你需要分析复杂的应用行为或破解复杂的加密算法,GAD提供的反汇编信息可以帮助你做出准确的判断。
相关使用:[原创]GDA使用手册-Android安全-看雪-安全社区|安全招聘|kanxue.com
下载地址:https://down.52pojie.cn/Tools/Android_Tools/GDA4.11.zip
1.6 JEB进行APK反汇编
JEB的魅力在于其高精度的反汇编能力。它不仅能解析传统的DEX文件,还能处理各类复杂的文件格式,包括加固过的APK、经过混淆处理的代码,甚至是一些非标准的Android文件结构。它像一把锐利的刀刃,切开了应用的“外壳”,揭示其最核心的部分。
JEB的优点:
- 强大的反汇编能力:JEB不仅仅局限于常规的字节码反汇编,它能够对各种复杂和非标准格式的APK进行深入分析。
- 支持多种文件格式 :JEB支持广泛的文件格式解析,除了DEX文件,还包括PE(Portable Executable)、ELF、Java字节码等多种格式。
- 高级功能与插件支持 :JEB的插件架构极为强大,用户可以根据自己的需求,定制化扩展JEB的功能。
相关使用:第36讲: 使用Jeb工具反编译安卓APK_jeb反编译工具-CSDN博客
下载地址:https://down.52pojie.cn/Tools/Android_Tools/JEB_Decompiler_3.19.1_Professional.rar
1.7 IDA进行反汇编
进入IDA的世界,你将步入一个顶级的反汇编领域。IDA(Interactive Disassembler)是众多逆向工程师手中的“神器”,无论是操作系统、应用程序还是嵌入式系统,它都能提供无与伦比的反汇编支持。
IDA的优势:
- 精确的反汇编能力:IDA能反汇编几乎所有的二进制文件格式,展示底层机器码及其执行路径,让逆向分析更加精准。
- 高度可扩展:IDA支持插件开发,用户可以根据需求扩展其功能,实现个性化分析。
- 复杂任务支持:IDA特别适合进行复杂的逆向分析任务,如破解软件、分析恶意代码等。
相关使用:菜鸟的逆向工程学习之路——逆向工具IDA的使用_ida工具-CSDN博客
下载地址:https://down.52pojie.cn/Tools/Disassemblers/IDA_Pro_v8.3_Portable.zip
1.8 Frida脱壳工具的使用
Frida 是一个强大的动态分析工具,广泛应用于反向工程和安全测试中,尤其是在对 Android 应用进行脱壳(解除保护)时,它能够帮助研究人员通过动态注入脚本来分析应用程序的行为。以下是使用 Frida 进行脱壳的环境配置和基本步骤。
环境配置:
首先,确保你已经安装了 Frida 及其相关工具,可以通过以下命令进行安装:
pip install frida # 安装 Frida 主库
pip install frida-tools # 安装 Frida 的工具集,提供命令行工具
pip install frida-dexdump # 安装 frida-dexdump,用于分析 APK 文件的 dex 内容
这些工具将帮助你在 Android 环境中启动和操作 Frida Server,以及进行 APK 分析等操作。
Frida 的环境搭建并不复杂,特别是在虚拟设备(如雷电模拟器)和 Android Debug Bridge (ADB) 的支持下。具体的搭建流程可以参考以下链接:
- Frida入门教程:基于逍遥模拟器和 ADB 环境搭建
这个教程将详细介绍如何安装和配置 Frida 环境,并提供如何在模拟器和实际设备上运行 Frida Server 和脚本的操作步骤。
第三章:APK解析基础
在深入理解Android应用的工作原理和内部结构之前,我们首先需要了解应用打包的核心文件——APK(Android Package)。APK 文件是Android操作系统中的应用程序包,它包含了应用的所有资源、代码和必要的配置文件。可以把APK看作一个容器,其中集成了Android应用的所有组成部分。
为了能够更深入地分析和理解Android应用的结构,我们可以将APK文件拆解为多个关键组件。每个组件在应用运行中都扮演着不同的角色,理解这些组件有助于我们全面掌握应用的运行机制,甚至为后续的逆向分析和漏洞挖掘打下基础。
APK的基本结构
实际上,APK 文件是以 ZIP 格式进行压缩打包的,因此,我们可以像操作普通的ZIP文件一样,使用解压工具对其进行解压。通过解压后查看APK文件的目录结构,我们能够清晰地了解每个组成部分的作用。以下是一个典型的APK文件的结构示例:
APK 文件通常包括以下几个主要部分:
- AndroidManifest.xml
- classes.dex
- resources.arsc
- assets/
- lib/
- res/
- META-INF/
接下来,我们将详细解析这些文件和目录的作用及其内容。
将一个apk进行解压,可以发现如下结构的文件目录,测试案例下载:攻防世界-Mobile-easy-so
1.AndroidManifest.xml(关键核心)
AndroidManifest.xml 是每个Android应用不可或缺的配置文件,它包含了应用的关键信息。我们可以把它看作是应用的“蓝图”或“说明书”,它向系统声明了应用的基本属性、组件以及权限等。AndroidManifest.xml中包括以下重要部分:
- 应用的包名(package):每个Android应用都有一个唯一的包名,通过包名来区分不同的应用。
- 应用的组件(Activities, Services, Broadcast Receivers, Content Providers):声明应用包含哪些组件,以及这些组件的属性和功能。
- 权限声明:列出应用所需的权限,如访问网络、读取存储、使用相机等。
- 应用主题和图标:定义应用的UI样式、图标等。
- 最小SDK版本和目标SDK版本:确定应用能在什么版本的Android系统上运行。
详细解析Manifest中的关键字段
<manifest>
:包含整个应用的包信息及权限定义。package
: 定义了应用的包名,通常为反向域名格式,如com.example.app
。android:versionCode
: 定义应用的版本号。android:versionName
: 定义应用的版本名称。
<application>
:包含应用的核心配置,如主题、图标等。android:icon
: 定义应用的图标。android:label
: 定义应用的名称。android:theme
: 应用的UI主题。
<activity>
:声明应用的各个界面(Activity),以及这些Activity的属性和行为。android:name
: Activity的类名。android:label
: Activity的标签。android:theme
: Activity特有的UI主题。
<uses-permission>
:声明应用所需要的权限,如访问网络、发送短信等。<intent-filter>
:定义组件的功能和响应的事件,如Activity的启动方式或Broadcast Receiver接收的广播类型。
2. classes.dex
classes.dex 文件包含了应用程序的可执行代码。它是应用的Dalvik字节码文件,也是Android应用在运行时通过 Dalvik虚拟机 或 ART(Android Runtime) 解释执行的核心文件。每个Android应用中,所有的Java源代码都经过编译后形成一个或多个DEX(Dalvik Executable)文件,这些文件包含了应用的业务逻辑和代码实现。
在Android 5.0(Lollipop)之后,Google引入了 ART(Android Runtime) 代替了传统的Dalvik虚拟机,ART的执行方式比Dalvik更高效,支持Ahead-of-Time(AOT)编译和即时编译(JIT)策略。
这部分比较难可以拓展阅读一下,相关文档:
3. resources.arsc
resources.arsc 文件包含了应用程序的所有编译后的资源映射信息。这个文件并不存储实际的资源内容(如图片或字符串),而是存储资源与资源ID的映射关系。例如,它会保存应用中的字符串、颜色、尺寸、样式等信息以及这些资源的ID。通过这个文件,Android系统能够在应用运行时快速访问和加载所需的资源。
使用jadx可以看见:
4. assets/
assets/ 目录包含了应用程序的原始资源文件,这些资源不经过编译,直接以原始形式存储。通常,开发者可以在该目录中存放字体文件、音频文件、HTML文件等,应用在运行时通过API来读取这些资源。例如,游戏可能会将所有的地图文件或纹理图像存放在此目录中。通过AssetManager
API,应用可以访问这些文件。
5. lib/
lib/ 目录包含了本地库文件,通常是通过 JNI(Java Native Interface) 与C/C++编写的本地代码。这些库文件可以针对不同的硬件架构(如arm、x86等)进行编译,因此lib/
目录下通常会为每个架构创建相应的子目录。这个目录中存放的本地库可以通过Java代码调用JNI接口实现与系统底层的交互。
下面是一个案例进入lib进入到目录中得到以下目录结构,不同架构的手机拥有不同的操汇编代码所以使用四种架构的汇编分别实现一次:
├─arm64-v8a
│ libcyberpeace.so
│
├─armeabi-v7a
│ libcyberpeace.so
│
├─x86
│ libcyberpeace.so
│
└─x86_64
libcyberpeace.so
6. res/
res/ 目录包含了Android应用所需的所有资源文件。与 assets/ 目录不同,res/ 目录中的资源文件是经过编译的,按照不同类型的资源进行组织,例如:
- drawable/:存放图像资源(如PNG、JPEG等格式的图片)。
- layout/:存放XML格式的布局文件,定义界面的结构。
- values/:存放各种配置文件,定义应用的常量、颜色、字符串等资源。例如:
strings.xml
:存储应用的文本字符串。colors.xml
:存储应用使用的颜色资源。styles.xml
:存储样式资源。
在values/
目录下,除了strings.xml
、colors.xml
等常见资源文件,还会有像dimens.xml
(尺寸定义文件)和attrs.xml
(自定义属性)等资源文件。
可以在文件夹目录中找到也可以在jadx里面查看:
7. META-INF/
META-INF/ 目录与Java的JAR文件类似,用于存放APK文件的元数据,如签名文件、校验信息等。此目录主要包括以下文件:
- MANIFEST.MF:存放APK的清单文件,包含关于APK文件本身的信息。
- CERT.RSA:包含APK文件的数字签名。
- CERT.SF:存放APK文件的签名摘要。
这些文件确保了APK的完整性和安全性,保证APK文件没有被篡改,且来自合法的开发者。
下面是一个示例:
第四章:Android逆向分析中的基础
Android 逆向分析是一个深入挖掘应用内部工作原理的过程,通常用于漏洞挖掘、恶意软件分析或应用的安全性研究。在这章中,我们将深入探讨 Android APK 的反编译与结构分析,剖析壳分析与绕过技术,以及如何对资源与布局文件进行分析。我们还会涉猎 Java 层的逆向技巧,以及如何在 Native 层执行逆向工程。每一部分都将逐一分析和讲解,以帮助读者在 Android 逆向分析中取得更好的突破。
1. APK反编译与结构分析:如何找出程序的入口点
在进行 Android 逆向时,首先需要对 APK 文件进行反编译和结构分析。理解 APK 的基本结构至关重要,因为它帮助我们定位关键组件和入口点。一个典型的 APK 文件包含多个元素,如 AndroidManifest.xml
、DEX 文件、资源文件和库文件等。
定位入口点实战案例
目标: 学习如何反编译 APK 文件并分析其结构,找出应用程序的入口点。
文章: android apk入口分析_5.apk的程序入口界面 - CSDN博客
实战案例:BUU刷题-简单注册器
更详细的WP:BUUCTF之简单注册器(RE) - Eip的浪漫 - 博客园
首先梳理一下基本app的逆向流程:
1.将apk拖入JADX后寻找到AndroidManifest.xml文件:
下面给出AndroidManifest.xml文件的详细注释:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1" <!-- 应用版本代码,用于区分不同版本的更新 -->
android:versionName="1.0" <!-- 应用版本名称,通常为可见版本号 -->
package="com.example.flag"> <!-- 应用包名,唯一标识应用 -->
<!-- 使用的最低 SDK 版本和目标 SDK 版本 -->
<uses-sdk
android:minSdkVersion="8" <!-- 设置应用的最低 SDK 版本,表示应用可在 SDK 8 或以上的设备上运行 -->
android:targetSdkVersion="19"/> <!-- 设置应用的目标 SDK 版本,表示应用针对 SDK 19 的优化 -->
<application
android:theme="@style/AppTheme" <!-- 设置应用的主题 -->
android:label="@string/app_name" <!-- 设置应用的名称 -->
android:icon="@drawable/ic_launcher" <!-- 设置应用的图标 -->
android:debuggable="true" <!-- 设置应用是否可调试,调试模式下可以进行调试 -->
android:allowBackup="true"> <!-- 设置是否允许应用数据备份 -->
<!-- 定义应用的主 Activity -->
<activity
android:label="@string/app_name" <!-- 设置 Activity 的名称 -->
android:name="com.example.flag.MainActivity"> <!-- 定义该 Activity 的完整类名 -->
<!-- 配置启动该 Activity 的 Intent Filter -->
<intent-filter>
<action android:name="android.intent.action.MAIN"/> <!-- 指定这是应用的主入口 -->
<category android:name="android.intent.category.LAUNCHER"/> <!-- 表明该 Activity 是启动器中的入口 -->
</intent-filter>
</activity>
</application>
</manifest>
在 Android 应用中,AndroidManifest.xml
文件是至关重要的,它定义了应用的所有组件以及组件之间的关系,包括应用的入口点。打开反编译后的 APK 中的 AndroidManifest.xml
文件,查找 <activity>
标签,它们通常定义了应用的各个 Activity(包括启动 Activity)。
入口点通常由以下两个标记表示:
<action android:name="android.intent.action.MAIN" />
:标记这是应用的主入口。<category android:name="android.intent.category.LAUNCHER" />
:表示该 Activity 会出现在应用启动器中(即桌面)。
所以最终得出该app的程序入口点代码是在android:name="com.example.flag.MainActivity"
处!
2.成功寻找到activity的代码入口处,开始分析activity的生命执行流程:
根据android:name="com.example.flag.MainActivity"
字段成功找到Activity的功能实现代码位置,一个Activity的生命周期是:onCreate()
->onStart()
->onResume()
->onPause()
->onStop()
->onDestroy()
,所以可以先锁定omCreate函数,锁定app加载的主要逻辑!
3.开始分析按钮的逻辑代码,成功解析出需要输入的内容:
在主要逻辑中可以发现界面中的一个按钮绑定了一个onclick按钮点击事件:
该函数用于处理用户点击事件,验证输入框中的文本是否符合特定规则,如果符合规则,则对一个预定义的字符串进行一系列字符运算和逆序处理,最终显示一个特定格式的“flag”;否则,显示错误提示“输入注册码错误”。
也就是说我们只需要输入一个正确的字符串就可以成功拿到flag!
将代码提取出来分析:
button.setOnClickListener(new View.OnClickListener() {
// from class: com.example.flag.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
int flag = 1;
String xx = editview.getText().toString();
if (xx.length() != 32 || xx.charAt(31) != 'a' || xx.charAt(1) != 'b' || (xx.charAt(0) + xx.charAt(2)) - 48 != 56) {
flag = 0;
}
if (flag == 1) {
char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
x[2] = (char) ((x[2] + x[3]) - 50);
x[4] = (char) ((x[2] + x[5]) - 48);
x[30] = (char) ((x[31] + x[9]) - 48);
x[14] = (char) ((x[27] + x[28]) - 97);
for (int i = 0; i < 16; i++) {
char a = x[31 - i];
x[31 - i] = x[i];
x[i] = a;
}
String bbb = String.valueOf(x);
textview.setText("flag{" + bbb + "}");
return;
}
textview.setText("输入注册码错误");
}
});
}
这里的逻辑代码就很清晰了:
int flag = 1;
String xx = editview.getText().toString();
if (xx.length() != 32 || xx.charAt(31) != 'a' ||