Android 文件系统详解
2026-06-29
📚 目录
1. Android 文件系统概述
1.1 文件系统类型
主要文件系统
- ext4: 主要文件系统(Android 4.0+)
- f2fs: Flash-Friendly File System(部分设备)
- vfat: FAT32(外部存储)
分区结构
Android 设备存储
├── /system # 系统分区(只读)
├── /data # 数据分区(可读写)
├── /cache # 缓存分区
├── /vendor # 厂商分区(Android 8.0+)
└── /sdcard # 外部存储(模拟或物理)
1.2 挂载点
查看挂载信息
# 查看所有挂载点
adb shell mount
# 输出示例:
# /dev/block/platform/soc/1da4000.ufshc/by-name/system on /system type ext4 (ro,seclabel,relatime)
# /dev/block/platform/soc/1da4000.ufshc/by-name/userdata on /data type ext4 (rw,seclabel,nosuid,nodev,noatime)
挂载选项说明
- ro: 只读(read-only)
- rw: 可读写(read-write)
- noatime: 不更新访问时间
- seclabel: SELinux 安全标签
- nosuid: 不允许 setuid
- nodev: 不允许设备文件
2. 系统目录结构
2.1 根目录 (/)
主要目录
/ # 根目录
├── system/ # 系统文件
├── data/ # 用户数据
├── cache/ # 缓存
├── vendor/ # 厂商文件
├── proc/ # 进程信息
├── sys/ # 系统信息
├── dev/ # 设备文件
├── sdcard/ # 外部存储
├── storage/ # 存储挂载点
├── mnt/ # 临时挂载点
└── acct/ # 进程统计
2.2 /system 目录
目录结构
/system/
├── app/ # 系统应用 APK
├── priv-app/ # 特权系统应用
├── framework/ # 框架 JAR 文件
│ ├── framework.jar
│ ├── framework-res.apk
│ └── ...
├── lib/ # 系统库(32位)
├── lib64/ # 系统库(64位)
├── bin/ # 系统二进制文件
├── xbin/ # 扩展二进制文件
├── etc/ # 配置文件
├── fonts/ # 字体文件
├── media/ # 媒体文件
├── usr/ # 用户数据
└── build.prop # 系统属性
重要文件
# 查看系统属性
cat /system/build.prop
# 查看系统应用
ls /system/app/
ls /system/priv-app/
# 查看系统库
ls /system/lib/
ls /system/lib64/
2.3 /data 目录
目录结构
/data/
├── data/ # 应用数据目录
│ └── <package_name>/
│ ├── files/ # 应用文件
│ ├── databases/ # 数据库
│ ├── shared_prefs/ # SharedPreferences
│ ├── cache/ # 缓存
│ └── lib/ # 应用库
├── app/ # 安装的 APK
│ └── <package_name>/
│ └── base.apk
├── dalvik-cache/ # Dalvik 缓存(旧版本)
├── app-private/ # 私有应用数据
├── system/ # 系统数据
│ ├── packages.xml # 已安装包信息
│ ├── users/ # 用户信息
│ └── ...
└── local/ # 本地数据
应用数据目录
# 查看应用数据(需要 root)
ls -la /data/data/com.example.app/
# 查看应用文件
ls /data/data/com.example.app/files/
# 查看数据库
ls /data/data/com.example.app/databases/
# 查看 SharedPreferences
ls /data/data/com.example.app/shared_prefs/
2.4 /proc 目录
虚拟文件系统
/proc 是一个虚拟文件系统,提供内核和进程信息。
重要文件
# 进程信息
/proc/<pid>/
├── cmdline # 命令行参数
├── environ # 环境变量
├── maps # 内存映射
├── status # 进程状态
├── stat # 统计信息
└── fd/ # 文件描述符
# 系统信息
/proc/
├── version # 内核版本
├── cpuinfo # CPU 信息
├── meminfo # 内存信息
├── mounts # 挂载信息
└── ...
查看进程内存映射
# 查看进程内存映射
cat /proc/<pid>/maps
# 输出示例:
# 12c00000-12c01000 r-xp 00000000 103:09 1441794 /system/lib/libc.so
# 地址范围 权限 偏移 设备 inode 文件路径
2.5 /sys 目录
系统信息
/sys/
├── class/ # 设备类
├── devices/ # 设备信息
├── kernel/ # 内核信息
└── ...
2.6 外部存储
目录结构
/sdcard/ # 主外部存储(可能是符号链接)
/storage/
├── emulated/ # 模拟存储
│ └── 0/ # 用户 0 的存储
├── sdcard0/ # 物理 SD 卡(如果有)
└── usbdisk/ # USB 存储(如果有)
外部存储路径
// 获取外部存储目录
File externalStorage = Environment.getExternalStorageDirectory();
// /storage/emulated/0 或 /sdcard
// 获取应用外部存储目录
File appExternalDir = getExternalFilesDir(null);
// /storage/emulated/0/Android/data/<package_name>/files
3. APK 文件结构
3.1 APK 文件格式
APK 本质
APK(Android Package)文件实际上是一个 ZIP 压缩文件,包含应用的所有资源。
基本结构
app.apk (ZIP 格式)
├── META-INF/ # 签名和清单信息
│ ├── MANIFEST.MF # 清单文件
│ ├── CERT.SF # 签名文件
│ └── CERT.RSA # 证书文件
├── AndroidManifest.xml # 应用清单(二进制 XML)
├── classes.dex # DEX 字节码文件
├── resources.arsc # 编译后的资源索引
├── res/ # 资源文件目录
│ ├── layout/ # 布局文件
│ ├── values/ # 值资源
│ ├── drawable/ # 图片资源
│ ├── mipmap/ # 应用图标
│ └── ...
└── assets/ # 原始资源文件(可选)
3.2 META-INF 目录
签名文件
# MANIFEST.MF - 清单文件
# 包含所有文件的 SHA-1 摘要
# CERT.SF - 签名文件
# 包含 MANIFEST.MF 的签名
# CERT.RSA - 证书文件
# 包含公钥证书
查看签名信息
# 使用 jarsigner 查看
jarsigner -verify -verbose -certs app.apk
# 使用 apksigner 查看(Android SDK)
apksigner verify --print-certs app.apk
3.3 AndroidManifest.xml
二进制 XML 格式
AndroidManifest.xml 在 APK 中是二进制格式(AXML),需要工具解析。
解析工具
# 使用 aapt
aapt dump xmltree app.apk AndroidManifest.xml
# 使用 apktool
apktool d app.apk
# 输出到 app/AndroidManifest.xml(文本格式)
# 使用 axml2xml(Python 工具)
axml2xml AndroidManifest.xml
重要信息
- 包名(package)
- 版本信息(versionCode, versionName)
- 权限声明(uses-permission)
- 组件声明(activity, service, receiver, provider)
- 应用配置(application)
3.4 classes.dex
DEX 文件
- 格式: Dalvik Executable
- 内容: 编译后的 Java/Kotlin 代码
- 位置: classes.dex(主文件),classes2.dex, ...(多 DEX)
查看 DEX 信息
# 使用 dexdump
dexdump classes.dex
# 使用 baksmali(反编译为 Smali)
baksmali d classes.dex -o output/
# 使用 jadx(反编译为 Java)
jadx -d output/ app.apk
3.5 resources.arsc
资源索引
- 格式: 二进制资源表
- 内容: 资源 ID 到资源值的映射
- 用途: 快速查找资源
解析资源
# 使用 aapt
aapt dump resources app.apk
# 使用 apktool
apktool d app.apk
# 输出到 app/res/ 目录
3.6 res/ 目录
资源类型
res/
├── layout/ # 布局文件(XML)
├── values/ # 值资源(XML)
│ ├── strings.xml
│ ├── colors.xml
│ ├── dimens.xml
│ └── ...
├── drawable/ # 图片资源
│ ├── ic_launcher.png
│ └── ...
├── mipmap/ # 应用图标(多分辨率)
│ ├── mipmap-mdpi/
│ ├── mipmap-hdpi/
│ └── ...
├── raw/ # 原始资源文件
└── ...
资源 ID
// 资源 ID 格式:0x7f0a0001
// 7f: 应用资源标识
// 0a: 资源类型(如 layout)
// 0001: 资源索引
// 在代码中使用
R.layout.activity_main // 0x7f0a0001
R.id.button // 0x7f0a0002
R.string.app_name // 0x7f0b0001
3.7 assets/ 目录
原始资源
- 格式: 原始文件(不编译)
- 访问: 使用 AssetManager
- 用途: 存储需要直接读取的文件
访问 assets
// 读取 assets 文件
AssetManager am = getAssets();
InputStream is = am.open("file.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = reader.readLine();
4. DEX 文件格式
4.1 DEX 文件结构
基本结构
DEX 文件
├── Header # 文件头
├── String Table # 字符串表
├── Type Table # 类型表
├── Proto Table # 方法原型表
├── Field Table # 字段表
├── Method Table # 方法表
├── Class Table # 类表
├── Data Section # 数据区
└── Link Section # 链接区(可选)
4.2 DEX 文件头
Header 结构
struct DexHeader {
u1 magic[8]; // "dex\n035\0" 或 "dex\n036\0"
u4 checksum; // 校验和
u1 signature[20]; // SHA-1 签名
u4 fileSize; // 文件大小
u4 headerSize; // 头大小
u4 endianTag; // 字节序标记
u4 linkSize; // 链接区大小
u4 linkOff; // 链接区偏移
u4 mapOff; // 映射表偏移
u4 stringIdsSize; // 字符串 ID 数量
u4 stringIdsOff; // 字符串 ID 表偏移
u4 typeIdsSize; // 类型 ID 数量
u4 typeIdsOff; // 类型 ID 表偏移
// ... 更多字段
};
查看 DEX 头
# 使用 hexdump 查看
hexdump -C classes.dex | head -20
# 使用 dexdump
dexdump -h classes.dex
4.3 字符串表
字符串存储
- 格式: UTF-8 编码,以 null 结尾
- 索引: 字符串 ID 表指向字符串数据区
- 用途: 类名、方法名、字段名等
解析字符串
# Python 示例
def read_string(dex_file, string_id):
# 读取字符串 ID 表
string_id_offset = read_u32(dex_file, string_id * 4 + string_ids_off)
# 读取字符串数据
string_data = read_string_data(dex_file, string_id_offset)
return string_data
4.4 类定义
类结构
struct DexClassDef {
u4 classIdx; // 类型索引
u4 accessFlags; // 访问标志
u4 superclassIdx; // 父类索引
u4 interfacesOff; // 接口偏移
u4 sourceFileIdx; // 源文件索引
u4 annotationsOff; // 注解偏移
u4 classDataOff; // 类数据偏移
u4 staticValuesOff; // 静态值偏移
};
访问标志
- ACC_PUBLIC: 0x1
- ACC_PRIVATE: 0x2
- ACC_PROTECTED: 0x4
- ACC_STATIC: 0x8
- ACC_FINAL: 0x10
- ACC_SYNCHRONIZED: 0x20
- ACC_NATIVE: 0x100
4.5 方法定义
方法结构
struct DexMethod {
u2 methodIdx; // 方法 ID
u2 accessFlags; // 访问标志
u4 codeOff; // 代码偏移
};
方法代码
struct DexCode {
u2 registersSize; // 寄存器数量
u2 insSize; // 参数数量
u2 outsSize; // 输出参数数量
u2 triesSize; // try 块数量
u4 debugInfoOff; // 调试信息偏移
u4 insnsSize; // 指令大小
u2 insns[]; // 指令数组
};
4.6 Dalvik 字节码
指令格式
- 格式: 16 位或 32 位指令
- 操作码: 8 位操作码
- 操作数: 寄存器、常量、方法引用等
常见指令
opcode 指令 说明
0x00 nop 空操作
0x01 move 移动数据
0x12 const 加载常量
0x1a const-string 加载字符串
0x6e invoke-virtual 调用虚方法
0x0e return-void 返回 void
0x0f return 返回值
查看字节码
# 使用 baksmali
baksmali d classes.dex -o output/
# 输出 Smali 代码
.method public onCreate(Landroid/os/Bundle;)V
.registers 2
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.line 10
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
return-void
.end method
5. OAT/ART 运行时
5.1 ART vs Dalvik
Dalvik(旧版本)
- Android 4.4 及之前
- JIT 编译: 运行时编译
- DEX 文件: 直接执行 DEX 字节码
ART(Android 5.0+)
- AOT 编译: 安装时编译为本地代码
- OAT 文件: 编译后的本地代码
- 性能提升: 启动速度更快
5.2 OAT 文件格式
OAT 文件结构
OAT 文件
├── OAT Header # OAT 文件头
├── DEX 文件 # 原始 DEX 文件
├── OAT Class # OAT 类信息
├── OAT Method # OAT 方法信息
└── Native Code # 编译后的本地代码
OAT 文件位置
# 系统应用 OAT
/data/dalvik-cache/arm64/system@app@<package>@classes.dex@classes.oat
# 用户应用 OAT
/data/dalvik-cache/arm64/data@app@<package>@base.apk@classes.dex@classes.oat
5.3 OAT 文件分析
查看 OAT 信息
# 使用 oatdump(需要 root)
oatdump --oat-file=classes.oat
# 使用 readelf(查看 ELF 结构)
readelf -h classes.oat
OAT 文件特点
- ELF 格式: OAT 文件是 ELF 格式
- 包含 DEX: 原始 DEX 文件嵌入在 OAT 中
- 本地代码: 包含编译后的 ARM/x86 代码
5.4 ART 运行时文件
相关文件
/data/dalvik-cache/
├── arm64/ # 64位 ARM 架构
│ └── system@app@...@classes.dex@classes.oat
├── arm/ # 32位 ARM 架构
└── ...
/data/app/
└── <package>/
└── oat/
└── <arch>/
└── base.odex # 优化的 DEX
提取 DEX
# 从 OAT 文件中提取 DEX
oatdump --oat-file=classes.oat --export-dex-to=output/
# 或使用工具
python oat2dex.py classes.oat
6. 文件系统操作
6.1 使用 adb 操作
基本命令
# 列出文件
adb shell ls /data/data/
# 查看文件内容
adb shell cat /data/data/com.example.app/files/config.txt
# 复制文件到 PC
adb pull /data/data/com.example.app/files/config.txt ./
# 复制文件到设备
adb push config.txt /sdcard/
# 删除文件
adb shell rm /sdcard/file.txt
# 修改权限
adb shell chmod 644 /sdcard/file.txt
需要 root 的操作
# 切换到 root
adb root
# 重新挂载为可写
adb remount
# 现在可以修改系统文件
adb shell rm /system/app/SomeApp.apk
6.2 使用 Python 脚本
文件操作
import subprocess
# 执行 adb 命令
def adb_shell(command):
result = subprocess.run(['adb', 'shell', command],
capture_output=True, text=True)
return result.stdout
# 读取文件
def read_file(path):
content = adb_shell(f'cat {path}')
return content
# 列出目录
def list_dir(path):
files = adb_shell(f'ls -la {path}')
return files.split('\n')
6.3 使用 Frida
文件操作
// 读取文件
var File = Java.use("java.io.File");
var file = File.$new("/sdcard/file.txt");
var fis = Java.use("java.io.FileInputStream").$new(file);
var bis = Java.use("java.io.BufferedInputStream").$new(fis);
var bytes = [];
var b;
while ((b = bis.read()) !== -1) {
bytes.push(b);
}
var content = String.fromCharCode.apply(null, bytes);
console.log(content);
// 写入文件
var fos = Java.use("java.io.FileOutputStream").$new(file);
var bos = Java.use("java.io.BufferedOutputStream").$new(fos);
var contentBytes = [72, 101, 108, 108, 111]; // "Hello"
for (var i = 0; i < contentBytes.length; i++) {
bos.write(contentBytes[i]);
}
bos.flush();
bos.close();
7. 权限与安全
7.1 文件权限
Linux 权限
# 权限格式:rwxrwxrwx
# 所有者 组用户 其他用户
# r=读, w=写, x=执行
# 查看权限
ls -l /data/data/com.example.app/
# 修改权限
chmod 644 file.txt # rw-r--r--
chmod 755 script.sh # rwxr-xr-x
chmod 600 secret.txt # rw-------
SELinux 上下文
# 查看 SELinux 上下文
ls -Z /data/data/com.example.app/
# 输出示例:
# u:object_r:app_data_file:s0:c512,c768
7.2 应用沙箱
数据隔离
- 每个应用有独立的数据目录
- 应用无法直接访问其他应用的数据
- 需要权限才能访问系统资源
数据目录权限
# 应用数据目录(需要 root 或应用 UID)
/data/data/<package_name>/
# 权限:drwx------ (700)
# 所有者:应用 UID
7.3 存储权限
Android 10+ 作用域存储
- 应用私有目录: 无需权限
- 媒体文件: 需要 READ_MEDIA_* 权限
- 其他文件: 需要 MANAGE_EXTERNAL_STORAGE 权限
权限声明
<!-- Android 10 之前 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Android 10+ -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
8. 逆向分析中的应用
8.1 APK 分析流程
基本流程
- 获取 APK: 从设备提取或下载
- 解压 APK: 查看文件结构
- 分析清单: 解析 AndroidManifest.xml
- 反编译 DEX: 使用 jadx 或 apktool
- 分析资源: 查看 res/ 目录
- 分析 Native: 分析 SO 文件
工具链
# 1. 解压 APK
unzip app.apk -d app_extracted/
# 2. 解析 AndroidManifest.xml
aapt dump xmltree app.apk AndroidManifest.xml
# 3. 反编译 DEX
jadx -d output/ app.apk
# 4. 分析资源
aapt dump resources app.apk
# 5. 分析 SO 文件
file app_extracted/lib/arm64-v8a/libnative.so
readelf -h app_extracted/lib/arm64-v8a/libnative.so
8.2 提取应用数据
提取 APK
# 从设备提取 APK
adb shell pm path com.example.app
# package:/data/app/com.example.app/base.apk
adb pull /data/app/com.example.app/base.apk ./
# 或使用包管理器
adb shell pm list packages
adb shell pm path com.example.app
提取数据文件
# 需要 root
adb root
adb pull /data/data/com.example.app/ ./
# 提取数据库
adb pull /data/data/com.example.app/databases/ ./
# 提取 SharedPreferences
adb pull /data/data/com.example.app/shared_prefs/ ./
8.3 分析 DEX 文件
反编译工具
# 使用 jadx(推荐)
jadx -d output/ app.apk
# 使用 apktool
apktool d app.apk -o output/
# 使用 baksmali
baksmali d classes.dex -o output/
分析字节码
# 使用 dexdump
dexdump -d classes.dex > classes.dump
# 使用 jadx GUI
jadx-gui app.apk
8.4 分析 OAT 文件
提取 DEX
# 从 OAT 提取 DEX
oatdump --oat-file=classes.oat --export-dex-to=output/
# 或使用工具
python oat2dex.py classes.oat
分析本地代码
# 使用 IDA Pro 或 Ghidra
# OAT 文件是 ELF 格式,可以直接加载
8.5 文件系统取证
提取关键信息
# 提取已安装应用列表
adb shell pm list packages > packages.txt
# 提取应用权限
adb shell dumpsys package com.example.app > package_info.txt
# 提取系统属性
adb shell getprop > build_prop.txt
# 提取进程信息
adb shell ps > processes.txt
9. 实用工具
9.1 命令行工具
aapt (Android Asset Packaging Tool)
# 查看 APK 信息
aapt dump badging app.apk
# 查看清单
aapt dump xmltree app.apk AndroidManifest.xml
# 查看资源
aapt dump resources app.apk
# 列出文件
aapt list app.apk
apktool
# 反编译
apktool d app.apk -o output/
# 重新打包
apktool b output/ -o new_app.apk
dexdump
# 转储 DEX 信息
dexdump classes.dex
# 反汇编
dexdump -d classes.dex
9.2 GUI 工具
jadx
# 命令行
jadx -d output/ app.apk
# GUI
jadx-gui app.apk
Android Studio
- 可以打开 APK 文件
- 查看 DEX 文件
- 分析资源
9.3 Python 工具
解析 DEX
# 使用 androguard
from androguard.core.bytecodes import apk
a = apk.APK('app.apk')
print(a.get_package())
print(a.get_activities())
print(a.get_permissions())
解析 AndroidManifest.xml
# 使用 axml2xml
from axmlparserpy import axmlprinter
ap = axmlprinter.AXMLPrinter(open('AndroidManifest.xml', 'rb').read())
print(ap.get_buff())
10. 总结
10.1 核心知识点
- 系统目录: /system, /data, /proc 等
- APK 结构: ZIP 格式,包含 DEX、资源等
- DEX 格式: Dalvik 字节码文件格式
- OAT/ART: Android 5.0+ 的运行时格式
- 文件操作: adb, Python, Frida 等工具
- 权限安全: 文件权限、SELinux、应用沙箱
10.2 逆向分析要点
- APK 分析: 解压、反编译、分析清单
- DEX 分析: 反编译为 Java/Smali
- 资源分析: 提取和分析资源文件
- 数据提取: 从设备提取应用数据
- OAT 分析: 从 OAT 提取 DEX
10.3 学习建议
- 动手实践: 分析真实的应用
- 使用工具: 熟悉各种分析工具
- 理解格式: 深入理解文件格式
- 关注安全: 了解权限和安全机制
评论
- 还没有评论,来说点什么吧。