应用安全 --- APK 虚拟内存布局
1. Android进程虚拟内存空间概览
Android基于Linux内核,每个应用进程都有独立的虚拟地址空间: 64位Android进程虚拟内存布局(简化版): 0x0000000000000000 - 0x0000555555554000 [用户空间下限]
├── 0x0000000000000000 - 0x0000000000001000 [NULL页,不可访问]
└── 0x0000000000001000 - 0x0000555555554000 [用户代码段起始区域] 0x0000555555554000 - 0x00007fffffffffff [主要用户空间]
├── 代码段 (.text)
├── 数据段 (.data, .bss)
├── 堆 (Heap)
├── 内存映射区 (mmap)
├── 共享库区域
└── 栈 (Stack) 0x8000000000000000 - 0xffffffffffffffff [内核空间]
2. APK加载过程中的内存布局
2.1 应用启动时的内存分配
典型Android应用内存布局: [低地址]
0x0000000000400000 - app_process64 (Zygote fork出来的进程)
0x0000000012c00000 - linker64 (动态链接器)
0x0000006f00000000 - [匿名内存区域]
0x0000007000000000 - [共享库加载区域开始]
├── 0x0000007000000000 - libc.so
├── 0x0000007001000000 - libm.so
├── 0x0000007002000000 - libdl.so
├── 0x0000007003000000 - libart.so (ART虚拟机)
├── 0x0000007010000000 - libandroid_runtime.so
└── 0x0000007020000000 - [应用特定的native库] 0x0000007100000000 - [ART堆区域]
├── Image Space (boot.art)
├── Zygote Space
├── Allocation Space (应用对象)
└── Large Object Space 0x0000007fff000000 - [栈区域]
[高地址]
2.2 DEX文件在内存中的布局
DEX文件内存映射: /data/app/com.example.app/base.apk
├── classes.dex → 映射到内存
│ ├── 0x7030000000 - DEX Header
│ ├── 0x7030001000 - String Pool
│ ├── 0x7030010000 - Type Definitions
│ ├── 0x7030020000 - Method Definitions
│ └── 0x7030100000 - Code Items ├── classes2.dex → 单独映射
└── lib/arm64-v8a/
├── libnative1.so → 0x7040000000
└── libnative2.so → 0x7041000000
3. SO库的详细内存布局
3.1 ELF文件段映射
单个SO文件在内存中的布局: libnative.so (基址: 0x7040000000)
├── ELF Header [0x7040000000 - 0x7040000040]
├── Program Headers [0x7040000040 - 0x7040000200]
├── .text (代码段) [0x7040001000 - 0x7040050000] (可执行)
├── .rodata (只读数据) [0x7040050000 - 0x7040060000] (只读)
├── .data (已初始化数据) [0x7040061000 - 0x7040062000] (读写)
├── .bss (未初始化数据) [0x7040062000 - 0x7040063000] (读写)
├── .got (全局偏移表) [0x7040063000 - 0x7040064000] (读写)
├── .plt (过程链接表) [0x7040064000 - 0x7040065000] (可执行)
└── .dynamic (动态信息) [0x7040065000 - 0x7040066000] (只读)
3.2 内存权限设置
# 通过 /proc/[pid]/maps 可以看到实际布局
cat /proc/12345/maps 7040000000-7040001000 r--p 00000000 fd:00 12345 /data/app/.../lib/arm64/libnative.so
7040001000-7040050000 r-xp 00001000 fd:00 12345 /data/app/.../lib/arm64/libnative.so
7040050000-7040060000 r--p 00050000 fd:00 12345 /data/app/.../lib/arm64/libnative.so
7040061000-7040063000 rw-p 00060000 fd:00 12345 /data/app/.../lib/arm64/libnative.so
7040063000-7040064000 rw-p 00000000 00:00 0 [anon:.bss]
4. ART虚拟机内存布局
4.1 Java堆结构
ART堆内存布局: [Image Space] - 0x7100000000
├── boot.art (系统类)
└── boot-framework.art [Zygote Space] - 0x7110000000
├── 预加载的系统类
└── 字符串常量池 [Allocation Space] - 0x7120000000
├── Young Generation (新生代)
│ ├── Eden Space
│ └── Survivor Space
└── Old Generation (老年代) [Large Object Space] - 0x7200000000
└── 大对象存储区域 [Non-Moving Space] - 0x7300000000
└── 不可移动对象
4.2 方法编译和缓存
编译后的代码布局: [OAT文件映射] - 0x7400000000
├── OAT Header
├── DEX文件数据
├── 编译后的机器码
│ ├── Method 1 机器码
│ ├── Method 2 机器码
│ └── ...
└── GC Maps [JIT编译缓存] - 0x7500000000
├── 热点方法机器码
└── 优化后的代码
5. 内存保护和隔离机制
5.1 ASLR (地址空间布局随机化)
每次启动时基址都会变化: 启动1: libnative.so → 0x7040000000
启动2: libnative.so → 0x7f8a000000
启动3: libnative.so → 0x7c15000000
5.2 内存权限控制
权限标志说明:
r-- : 只读
r-x : 只读+可执行 (代码段)
rw- : 读写 (数据段)
--- : 不可访问 (保护页)
6. 动态加载和链接
6.1 延迟绑定机制
函数调用过程: 应用调用 native_function()
↓
PLT表中的跳转指令
↓
GOT表查找实际地址
↓
如果未解析,调用动态链接器
↓
链接器解析符号并更新GOT
↓
跳转到实际函数地址
6.2 共享库依赖关系
依赖链示例: app_process64
├── linker64
├── libc.so
├── libm.so
├── libart.so
│ ├── libsigchain.so
│ └── libbacktrace.so
└── 应用SO库
├── libssl.so
├── libcrypto.so
└── 其他依赖库
7. 实际内存布局查看方法
你可以通过以下方式查看实际的内存布局: # 查看进程内存映射
adb shell cat /proc/$(pidof com.shizhuang.duapp)/maps # 查看进程状态
adb shell cat /proc/$(pidof com.shizhuang.duapp)/status # 使用Frida查看模块信息
Process.enumerateModules().forEach(function(module) {
console.log(module.name + ": " + module.base + " - " + module.size);
});
这种内存布局设计确保了: 安全性:通过权限控制和ASLR防止攻击
效率性:共享库减少内存占用
隔离性:每个进程有独立的虚拟地址空间
灵活性:支持动态加载和卸载
这就是为什么你的dump工具能够通过Frida准确定位和提取SO文件的原理基础
应用安全 --- APK 虚拟内存布局的更多相关文章
- android 分区layout以及虚拟内存布局-小结
摘要 简述启动过程的内存分配,各个映像的烧写,加载,logo的刷新,文件系统mount. DRAM:外部RAM: ISRAM:内部RAM(128K),(PL会跑在ISRAM里面,去初始化DRAM,lo ...
- ndk学习之C语言基础复习----虚拟内存布局与malloc申请
在这一次中来学习一下C语言的内存布局,了解它之后就可以解释为啥在用malloc()申请的内存之后需要用memset()来对内存进行一下初始化了,首先来了解一下物理内存与虚拟内存: 物理内存:通过物理内 ...
- Linux arm64的虚拟内存布局
原创翻译,转载请注明出处. 页表转换arm64在硬件体系结构上支持4级的每页大小为4K的页表转换,也支持3级的页大小64KB的页表转换.在linux arm64中,如果页的大小为4KB,使用3级页表转 ...
- linux内存管理解析1----linux物理,线性内存布局及页表的初始化
主要议题: 1分页,分段模式及实模式 2Linux分页 3linux内存线性地址空间布局及物理内存空间布局 4linux页表初始化及代码解析 1.1.1内存寻址和保护模式 在X86平台上,内存控制单元 ...
- XV6操作系统代码阅读心得(四):虚拟内存
本文将会详细介绍Xv6操作系统中虚拟内存的初始化过程. 基本概念 32位X86体系结构采用二级页表来管理虚拟内存.之所以使用二级页表, 是为了节省页表所占用的内存,因为没有内存映射的二级页表可以不用分 ...
- apk 解包 打包
APK应用程序的解包.修改.编辑.汉化.打包及应用 前两讲主要讲玩机的最基本的知识,集中在如何刷机.本讲是进级的内容,来谈谈与apk应用程序有关的知识,内容包括akp文件的解包.打包.反编辑.解析.汉 ...
- XV6源代码阅读-虚拟内存管理
Exercise1 源代码阅读 1.内存管理部分: kalloc.c vm.c 以及相关其他文件代码 kalloc.c:char * kalloc(void)负责在需要的时候为用户空间.内核栈.页表页 ...
- 一步一图带你深入理解 Linux 虚拟内存管理
写在本文开始之前.... 从本文开始我们就正式开启了 Linux 内核内存管理子系统源码解析系列,笔者还是会秉承之前系列文章的风格,采用一步一图的方式先是详细介绍相关原理,在保证大家清晰理解原理的基础 ...
- Dump类型说明
通过使用windbg提供DbgHelp库中的MiniDumpWriteDump函数在程序崩溃时写dump文件记录程序当时状态,为后续分析问题提供现场. 该函数提供了DumpType参数,让程序员根据具 ...
- 通往WinDbg的捷径(二)
原文:http://www.debuginfo.com/articles/easywindbg2.html译者:arhat时间:2006年4月14日关键词:CDB WinDbg 保存 dumps 在我 ...
随机推荐
- SqlServer复制和订阅(实现主从同步) -九五小庞
1.登录必须是服务器名称不能是ip 2.订阅服务器不需要提前创建数据库 复制方: (1).展开要发布的数据库节点,找到复制下的本地发布 (2).右击本地发布,选择本地发布 (3.下一步选择要发布的数据 ...
- win10/win7升级win11?看这里有方法
有不少深度技术之家的小伙伴都说他们使用的win10系统或者win7系统为什么还不能升级win11系统?其实,这个跟微软推送的机制有关的,下面,深度系统小编就来分享使用任意win10.win8.win7 ...
- 从Mono脚本生成Entity:深入理解Unity DOTS中的Archetype、Chunk与Entity结构设计
Unity 的 DOTS(Data-Oriented Technology Stack)是面向性能极致优化的一种架构范式,其底层结构设计并非偶然,而是深思熟虑的结果.本篇文章将从开发者最熟悉的入口-- ...
- 我的代码出现幻觉?说好的a = 1; x = b,怎么成了x = b; a = 1?
有序性:代码执行的幻觉 前面讲到通过缓存一致性协议,来保障共享变量的可见性.那么是否还有其他情况,导致对共享变量操作不符合预期结果.可以看下面的代码: private int a, b; privat ...
- X-ECharts:Vue项目中数据可视化的终极利器
X-ECharts:Vue项目中数据可视化的终极利器 在当今数据驱动的时代,数据可视化对于任何应用程序来说都至关重要.ECharts作为一款广泛使用的开源可视化库,为我们提供了丰富的图表类型和灵活的配 ...
- 0基础入门Android端实时聊天
ZEGO 提供 ZIM + RTC 服务联动的场景解决方案,公开语聊房.秀场直播等业务场景搭建的示例源码,帮助开发者能在极短的时间内搭建完美的业务场景. ZIM SDK 提供了如下接入方案: 在此方案 ...
- react 僵尸孩子问题
React Zombie Child 是指在 React 组件中的一个常见问题.当一个父组件被销毁时,它的子组件可能仍然存在于内存中,这些子组件被称为"僵尸子组件". 这种情况通常 ...
- Flutter SizeTransition:让你的UI动画更加丝滑
在Flutter开发中,动画是提升用户体验的重要手段.今天我们来深入探讨一个强大而优雅的动画组件--SizeTransition,它能让你的UI元素在尺寸变化时呈现出流畅的过渡效果. SizeTran ...
- MyEMS能源管理系统后台配置-成本中心管理
MyEMS开源能源管理系统适用于建筑.工厂.商场.医院.园区的电.水.气等能源数据采集.分析.报表,还有光伏.储能.充电桩.微电网.设备控制.故障诊断.工单管理.人工智能优化等可选功能. 本文介绍My ...
- LInux下mysql数据库安装
第一步.下载数据库 再建好的文件夹下面 wget https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.29-linux-glibc2.12-x86 ...