ASLR地址空间布局随机化

/ 1

未使用ASLR的Mach-O内存分布

内存是操作系统建立起来的虚拟内存,和物理内存的地址不一样,是经过操作系统映射的内存!也就是说,虚拟内存的地址可能永远不会变,但是物理地址是随机的。

每个APP都有自己独立的虚拟内存,内存地址是不会冲突的。比如QQ和微信都可以有同一个内存地址指向自己的虚拟内存里的数据。

编译生成Mach-O文件后,函数在内存中的地址就固定了。但是函数执行后,会额外开辟栈空间来存放局部变量。

VM Address:全称Virtual Memory Address,内存地址,在内存中的位置

VM Size:全称Virtual Memory Size,内存大小,占用多少内存

File Offset:在Mach-O文件中的位置

File Size:在Mach-O文件中占据的大小


__PAGEZERO:Mach-O 加载到内存中后添加的段

__TEXT:代码段,存放Header、Load commands和函数代码

__DATA:数据段,存放全局变量

__LINKEDIT

size -l -m -x Mach-O文件路径 查看Mach-O的内存分布:

ASLR

什么是ASLR

ASLR:全称 Address Space Layout Randomization,地址空间布局随机化。

iOS4.3开始引入了ASLR技术,是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码的位置,达到阻止溢出攻击的目的的一种技术。

这并非是 iOS 独有的技术,在主流的操作系统,比如 macOS、Linux、Windows 都使用了这种技术。

使用了ASLR技术后,每次加载Mach-O函数地址都是不同的。

开启了 ASLR 的程序会在 Mach-O 头部信息中有一个 PIE 标志,去掉这个标志则可禁用 ASLR(比如 disable_aslr 工具),也就是在程序启动后,所有镜像基地址和 Mach-O 文件中的基地址一致,不会发生偏移。

➜  ~ otool -hV live4iphoneRel
live4iphoneRel:
Mach header
      magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64    ARM64        ALL  0x00     EXECUTE   178      15528   NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE

获取函数的真实内存地址

函数真实的虚拟内存地址(VM Address) = __PAGEZERO Size + File Offset + ASLR Offset

Hopper、IDA中的地址都是未使用ASLR技术的虚拟内存地址。

因为 __PAGEZERO SizeFile Offset 是固定的,所以从Hopper、IDA获取到函数的内存地址后,再加上 ASLR Offset,就是函数真实的内存地址。

我们可以通过 LLDB 打印出当前APP加载的全部模块列表,再从模块列表中找到当前APP的 Mach-O 的地址,这就是 ASLR Offset

一般APP的 Mach-O 是在打印出的模块列表的第0个模块,当前微信的 ASLR Offset0x00000000040a4000

(lldb) image list -o -f | grep WeChat
[  0] 0x00000000040a4000 /private/var/containers/Bundle/Application/1631DC7F-73E3-41BA-A694-C34BDCB7B30A/WeChat.app/WeChat(0x00000001040a4000)

代码中获取 ASLR Offset

#import <mach-o/dyld.h>

_dyld_get_image_vmaddr_slide(0);

每次重新运行APP,ASLR Offset 都会变化。