最近打算专攻Android逆向,在这里记录一下最开始的Android基础知识

安卓的四大组件

Activity、Service(服务)、BroadcastReceiver(广播接收器)、Content Provider(内容提供者)

Activiy

Activity 是 Android 应用中负责用户界面和交互的核心组件。每个应用至少有一个 Activity,它通常作为应用的启动点,用于展示 UI 并处理用户输入。Activity 通过生命周期方法管理与用户的交互,并通过 Intent 在多个 Activity 之间进行跳转。
主要功能

  • 负责用户界面的展示和用户的交互。
  • 每个应用至少有一个 Activity,通常应用的启动点就是一个 Activity
  • 可以通过 Intent 在不同的 Activity 之间进行跳转。

Service

Service 是一个在后台运行的应用组件,它不与用户直接交互,但可以在后台执行长时间的任务。比如,下载文件、播放音乐或进行网络请求等。Service 主要用于执行需要长时间运行的操作,或者即使用户切换到其他应用时,服务也能继续运行。

主要功能

  • 负责执行后台任务,通常不需要用户交互。
  • 可以在主线程之外执行长时间运行的操作,如下载文件、播放音乐。
  • 可以与其他组件(如 Activity)通信,或者通过广播来通知事件。

BroadcastReceiver

BroadcastReceiver 用于接收和处理广播消息。广播是 Android 系统中用于传递信息的机制,BroadcastReceiver 可以监听特定的广播事件并作出响应。例如,接收系统广播(如设备开机完成、Wi-Fi 状态变化等),或者应用发送的广播。可以用于不同页面间的通信!

主要功能

  • 接收系统或应用发送的广播消息。
  • 可以在不与用户交互的情况下执行操作,例如网络连接状态变化、系统启动等。
  • 广播可以是系统广播,也可以是应用内部的广播。

Content Provider

ContentProvider 用于跨应用共享数据。它提供了一个统一的接口,使得一个应用可以访问另一个应用的数据。ContentProvider 可以封装数据库操作、文件操作或者其他数据存储方式,并通过 ContentResolver 提供访问权限。

主要功能

  • 提供一个访问数据的接口,可以是本地数据库、共享文件、或是其他数据存储方式。
  • 使得应用能够访问其他应用的数据,同时对外暴露统一的 API。
  • 通过 ContentResolver 进行访问,允许应用进行 CRUD(增、删、改、查)操作。

Intent 机制与组件间通信

Intent 直译”意图”,是 Android 中组件之间通信的信使
作用:作用:在组件之间(Activity、Service、Broadcast)传递消息、跳转、启动、通信
Activity ──Intent──→ Activity (页面跳转)
Activity ──Intent──→ Service (启动服务)
Activity ──Intent──→ Broadcast (发送广播)

Intent 分为两种主要类型:显式和隐式

显式 Intent

显式 Intent 明确指定目标组件的类名,通常用于同一应用内的组件交互。例如,启动一个特定的 Activity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Intent intent = new Intent(this, TargetActivity.class);
startActivity(intent);
// 跨应用跳转(知道对方包名和类名)
Intent intent = new Intent();
intent.setClassName(
"com.tlamb96.kgbmessenger", // 目标包名
"com.tlamb96.kgbmessenger.LoginActivity" // 目标类名
);
startActivity(intent);
// 使用 ComponentName
ComponentName component = new ComponentName(
"com.example.app",
"com.example.app.MainActivity"
);
Intent intent = new Intent();
intent.setComponent(component);
startActivity(intent);

显式 Intent 适用于明确知道目标组件的情况,效率高且意图清晰。

隐式 Intent

隐式 Intent 不指定具体的目标组件,而是描述一个通用的操作(如“打开网页”或“分享文本”),由系统根据 Intent 的内容匹配适合的组件。其他应用也可以响应隐式 Intent。例如:

1
2
3
4
// 打开网页
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://www.example.com"));
startActivity(intent);

匹配流程:

隐式 Intent 发出


系统扫描所有已安装应用的 AndroidManifest.xml


找到所有声明了匹配 intent-filter 的组件

├── 只有一个匹配 → 直接启动
├── 多个匹配 → 弹出选择器让用户选
└── 没有匹配 → 抛出 ActivityNotFoundException

APK核心文件结构

AndroidManifest.xml

AndroidManifest.xml 是每个Android应用不可或缺的配置文件,它包含了应用的关键信息。我们可以把它看作是应用的“蓝图”或“说明书”,它向系统声明了应用的基本属性、组件以及权限等。

AndroidManifest.xml 详细讲解

每个 Android 应用必须有且仅有一个 AndroidManifest.xml位于项目根目录:app/src/main/AndroidManifest.xml

作用:告诉 Android 系统”这个应用是什么、能做什么、需要什么”

完整结构总览

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<manifest> <!-- 根元素 -->

<uses-permission/> <!-- 权限申请 -->
<permission/> <!-- 自定义权限 -->
<uses-feature/> <!-- 硬件/软件特性要求 -->
<uses-sdk/> <!-- SDK版本要求 -->

<application> <!-- 应用全局配置 -->

<activity> <!-- 界面组件 -->
<intent-filter/>
<meta-data/>
</activity>

<service> <!-- 后台服务 -->
<intent-filter/>
</service>

<receiver> <!-- 广播接收器 -->
<intent-filter/>
</receiver>

<provider> <!-- 内容提供者 -->
<grant-uri-permission/>
</provider>

<meta-data/> <!-- 全局元数据 -->

</application>

</manifest>

实例讲解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//XML 声明
<?xml version="1.0" encoding="utf-8"?>

//根元素,每个 APK 有且仅有一个,xmlns:android → 引入 Android 命名空间
//所有 android:xxx 属性都依赖这个声明,没有它,所有属性都会报错
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
//内部版本号
android:versionCode="1"
//对外展示的版本号
android:versionName="1.0"
//应用的唯一标识符(包名)
package="com.tlamb96.spetsnazmessenger">
//SDK版本要求
<uses-sdk
//最低支持的 SDK 版本
android:minSdkVersion="17"
//目标 SDK 版本
android:targetSdkVersion="25"/>
//应用全局配置
<application
//全局UI主题
android:theme="@style/AppTheme"
//应用名称,引用 res/values/strings.xml 中的字符串
android:label="@string/app_name"
//应用图标
android:icon="@mipmap/ic_kgb_launcher_icon"
//是否允许通过 ADB 备份应用数据
android:allowBackup="true"
//RTL = Right To Left(从右到左),支持阿拉伯语、希伯来语、波斯语等从右到左排列的语言
android:supportsRtl="true"
//圆形图标
android:roundIcon="@mipmap/ic_kgb_launcher_icon">
//声明第一个 Activity:主界面,android:name → 完整类路径
<activity android:name="com.tlamb96.kgbmessenger.MainActivity">
//表示该Activity响应的Intent
<intent-filter>
//启动应用时的主动作,标记此 Activity 为应用主入口,整个应用有且仅有一个 MAIN + LAUNCHER 组合,没有此组合则应用不会出现在桌面
<action android:name="android.intent.action.MAIN"/>
//标记为Launcher,标记此 Activity 在桌面启动器中显示图标与 action.MAIN 配合,构成完整的桌面入口声明,用户点击桌面图标
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
//第二个 Activity,极简声明,没有任何附加属性
<activity android:name="com.tlamb96.kgbmessenger.MessengerActivity"/>
//第三个 Activity
<activity android:name="com.tlamb96.kgbmessenger.LoginActivity"/>
//全局元数据,用于存储键值对配置信息,可被代码通过 PackageManager 读取
<meta-data
//配置项名称:支持库版本
android:name="android.support.VERSION"
//配置的值:版本号 25.4.0
android:value="25.4.0"/>
</application>
</manifest>

classes.dex

classes.dex 文件包含了应用程序的可执行代码。它是应用的Dalvik字节码文件,也是Android应用在运行时通过 Dalvik虚拟机ART(Android Runtime) 解释执行的核心文件。每个Android应用中,所有的Java源代码都经过编译后形成一个或多个DEX(Dalvik Executable)文件,这些文件包含了应用的业务逻辑和代码实现。
Android 5.0+ 用 ART 取代 Dalvik,但字节码格式没变,仍然叫 Dalvik 字节码 / DEX 字节码

resources.arsc

resources.arsc 文件包含了应用程序的所有编译后的资源映射信息。这个文件并不存储实际的资源内容(如图片或字符串),而是存储资源与资源ID的映射关系。例如,它会保存应用中的字符串、颜色、尺寸、样式等信息以及这些资源的ID。通过这个文件,Android系统能够在应用运行时快速访问和加载所需的资源。

使用jadx可以看见:
alt text

assets

assets 目录包含了应用程序的原始资源文件,这些资源不经过编译,直接以原始形式存储。通常,开发者可以在该目录中存放字体文件、音频文件、HTML文件等,应用在运行时通过API来读取这些资源。例如,游戏可能会将所有的地图文件或纹理图像存放在此目录中。通过AssetManager API,应用可以访问这些文件。

lib

lib 目录包含了本地库文件,通常是通过 JNI(Java Native Interface) 与C/C++编写的本地代码。这些库文件可以针对不同的硬件架构(如arm、x86等)进行编译,因此lib/目录下通常会为每个架构创建相应的子目录。这个目录中存放的本地库可以通过Java代码调用JNI接口实现与系统底层的交互。

res

res 目录包含了Android应用所需的所有资源文件。与 assets/ 目录不同,res/ 目录中的资源文件是经过编译的,按照不同类型的资源进行组织,例如:

  • drawable/:存放图像资源(如PNG、JPEG等格式的图片)。

  • layout/:存放XML格式的布局文件,定义界面的结构。

  • values/

    :存放各种配置文件,定义应用的常量、颜色、字符串等资源。例如:

    • strings.xml:存储应用的文本字符串。
    • colors.xml:存储应用使用的颜色资源。
    • styles.xml:存储样式资源。
      alt text

values/目录下,除了strings.xmlcolors.xml等常见资源文件,还会有像dimens.xml(尺寸定义文件)和attrs.xml(自定义属性)等资源文件。

META-INF

META-INF 目录与Java的JAR文件类似,用于存放APK文件的元数据,如签名文件、校验信息等。

表格总结

文件名 核心作用
AndroidManifest.xml 应用核心配置文件,向系统声明基本属性、组件、权限等关键信息。
classes.dex 应用可执行核心文件,存储Java/Kotlin编译后的字节码,供Dalvik/ART虚拟机执行。
resources.arsc 存储编译后资源与资源ID的映射关系,帮助系统快速加载所需资源。
assets 存放未编译的原始资源,可通过AssetManager API读取(如字体、音频等)。
lib 存放JNI相关的C/C++本地库文件,按硬件架构分类,实现底层交互。
res 存放经编译的各类资源,按类型组织,包含strings、colors等资源文件。
META-INF 存放APK的元数据,包括签名文件、校验信息等。

Android 签名机制 v1、v2、v3、v4

参考文章:Android 签名机制 v1、v2、v3Android 签名机制 v4

Gradle 构建系统

Gradle 是 Android 开发的官方构建工具,负责把你的源代码、资源文件、依赖库打包成 APK

构建脚本文件

1
2
3
4
5
MyApp/
├── build.gradle ← 项目级(根目录)
├── settings.gradle ← 项目结构声明
└── app/
└── build.gradle ← 模块级(最重要)

模块级 build.gradle 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
android {
compileSdk 34 // 编译用的 SDK 版本

defaultConfig {
applicationId "com.example.app" // 包名(逆向时很关键)
minSdk 21
targetSdk 34
versionCode 1 // 内部版本号
versionName "1.0" // 显示版本号
}

buildTypes {
release {
minifyEnabled true // 是否开启混淆/压缩
proguardFiles ... // 混淆规则文件
}
debug {
debuggable true // 调试模式
}
}
}
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.9.0' // 第三方库
}

参考文章(52 条消息) Android基础知识——四大组件 - 知乎
[原创]Android逆向0基础入门-APK全面解析,动调与脱壳-Android安全-看雪安全社区|专业技术交流与安全研究论坛