未使用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
-
VM Address
:0x10319C000 -
VM Size
:0x224000 -
- *
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 Size
、File Offset
是固定的,所以从Hopper、IDA获取到函数的内存地址后,再加上 ASLR Offset
,就是函数真实的内存地址。
我们可以通过 LLDB
打印出当前APP加载的全部模块列表,再从模块列表中找到当前APP的 Mach-O
的地址,这就是 ASLR Offset
。
一般APP的 Mach-O
是在打印出的模块列表的第0个模块,当前微信的 ASLR Offset
为 0x00000000040a4000
:
(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
都会变化。