ASLR 地址空间配置随机加载

ASLR 地址空间配置随机加载

ASLR通过随机放置进程关键数据区域的地址空间来防止攻击者能可靠地跳转到内存的特定位置来利用函数。

Mach-O文件结构

1
2
3
4
5
6
7
8
9
10
11
----------------
| Headers | # 存放 Mach-O的文件类型、CPU类型、Load Commands个数等 Mach-O整体的文件信息
----------------
| Load Commands | # 存放每个Segment的信息
----------------
| __TEXT | # 代码段 (函数代码在代码段)
----------------
| __DATA | # 数据段 (全局变量存放在__DATA段)
----------------
| __LINKEDIT | # 动态加载库等其他信息
----------------

可通过Mach-O或命令行size -l -m -x 可执行文件 查看

Mach-O加载到虚拟内存中的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
----------------
| __PAGEZERO | # 在Mach-O文件中不存在,加载进内存后会分配__PAGEZERO
----------------
| Headers | # 存放 Mach-O的文件类型、CPU类型、Load Commands个数等 Mach-O整体的文件信息
----------------
| Load Commands | # 存放每个Segment的信息
----------------
| __TEXT | # 代码段 (函数代码在代码段)
----------------
| __DATA | # 数据段 (全局变量存放在__DATA段)
----------------
| __LINKEDIT | # 动态加载库等其他信息
----------------

关于堆栈

堆 - 堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。比如存放alloc出来的对象。

栈 - 函数调用时会在栈空间为函数分配一段内存,存放函数中创建的局部变量。

通过Load Command分析内存地址分配

Mach-O - Load Command 中标明了内存地址分配

  • VM Address: Virtual Memory Address 虚拟内存地址
  • VMSize: Virtual Memory Size 虚拟内存占用大小
  • File Offset: 在Mach-O文件中的位置
  • File Size: 在Mach-O文件中的大小

header 和 Load Command 和代码段属于__TEXT段, arm64内存地址0x100000000, armv7 内存地址0x4000

__TEXT段是只读的,在Mach-O中的File Size和内存中的VMSize大小一致,说明整个__TEXT段是原封不动搬进内存中的

__DATA段在在Mach-O中的File Size小于内存中的VMSize大小,说明__DATA段在虚拟内存中是拉伸了

举例一个Mach-O文件

  • __PAGE_ZERO

    • VM Address: 0x0
    • VM Size: 0x100000000
  • __TEXT 只读

    • VM Address: 0x100000000
    • VM Size: 0x380C000
  • __DATA 数据段

    • VM Adress: 0x380C000
    • VM Size: 0xD4C000
  • __LINKEDIT

    • VM Adress: 0x104558000
    • VM Size: 0x2C8000

也可通过size -l -m -x 文件名 查看二进制文件所占内存大小

ASLR

内存地址的起始地址随机

函数的内存地址(VM Address) = File Offset + ASLR Offset + __PAGEZERO Size / VM Address + ASLR Offset

Hopper、IDA中的地址都是未使用ASLR的VMAddress

如何获取偏移地址( ASLR Offset)地址

在lldb环境中通过image list 获取偏移地址

1
2
3
4
5
(lldb) image list -o -f
# 输出
[ 0] 0x00000000005fc000 /var/containers/Bundle/Application/3C3035C3-3457-47D3-A0A9-4679C4CE4D92/neteasemusic.app/neteasemusic(0x00000001005fc000)
# 0x00000000005fc000 为偏移地址
# 0x00000001005fc000 为代码段地址

通过实际内存地址计算Mach-O文件地址

Mach-O文件中的地址 = 真实内存中地址 - 偏移地址 - 0x100000000(__PAGEZERO)

变量的地址

1
2
3
4
5
6
7
8
9
10
int a = 30; // 全局变量 __DATA(数据段)
- (void) test {
int b = 20; // b的地址在函数栈空间
NSObject *obj = [[NSObject alloc] init]; // alloc 动态分配的地址在堆空间 &obj(obj的指针的地址在栈空间)
NSLog(@"%p,%p,%p,%p",
&a, // 数据段
&b, // 函数栈空间
obj, // 堆空间
&obj); // 函数栈空间
}