ASLR前言
以前我们用Xcode的LLDB指令打断点时,可以用方法名打断点,例如breakpoint set -n "[UIViewController touchBegin:]"
,但是我们想动态调试别人的App,就不能用方法名称了,需要用到方法的内存地址才能打,例如breakpoint set --address 0x123123123
而想知道方法的内存地址就需要学习ASLR
一、什么是ASLR?
- ASLR,全称是
Address Spce Layout Randomization
,翻译过来就是地址空间布局随机化,是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,增加了攻击者预测目的地址的难度,防止攻击者直接定位代码位置,阻止溢出攻击。
- ASLR,全称是
- 苹果从
iOS 4.3
之后引入了ASLR技术,所以想要逆向别人的App,学会ASLR是必不可少的。
- 苹果从
- ASLR的概念看着复杂,实际上非常简单,其实就是当Mach-O文件载入虚拟内存的时候,起始地址不从
0x00000000
开始了,而是随机增加一段,例如从0x50000
开始,后面的函数地址都会增加0x50000
- ASLR的概念看着复杂,实际上非常简单,其实就是当Mach-O文件载入虚拟内存的时候,起始地址不从
二、Mach-O文件的内部结构
- Mach-O文件的内部分为三个区域:
Header
、Load Commands
、Data
,如下图所示:
- Mach-O文件的内部分为三个区域:
-
Header区,存放了CPU类型、Mach-O文件的具体类型、LoadCommands的数量、LoadCommands的大小等数据,如下所示:
-
Header区,存放了CPU类型、Mach-O文件的具体类型、LoadCommands的数量、LoadCommands的大小等数据,如下所示:
-
-
Load Commands区,存放了各段的名称、各段的虚拟内存地址、各段的虚拟内存大小、各段的在Mac-O中的偏移量、各段的在Mac-O中的偏移大小等数据 ,如下图所示,重点注意看
VM Address、VM Size
、File Offset、File Size
这两组数据 。
VM Address、VM Size
记录这此段在虚拟内存的位置和大小File Offset、File Size
记录着此段在Mach-O中的位置和大小。
-
Load Commands区,存放了各段的名称、各段的虚拟内存地址、各段的虚拟内存大小、各段的在Mac-O中的偏移量、各段的在Mac-O中的偏移大小等数据 ,如下图所示,重点注意看
- Data区,存放着各段数据
三、未使用ASLR时,Mach-O文件是如何载入内存的?
- 我们观察Mach-O文件的
Load Commands
各段的描述信息,重点观察VM Address、VM Size
、File Offset、File Size
,就可以知道Mach-O在虚拟内存中是如何存放的了
- 我们观察Mach-O文件的
- 例如下图中的
LC_SEGMENT_64(__PAGEZERO)
段,我们可以看出来,PAGEZERO
段在虚拟内存中是从0x0
开始,大小是0x100000000
;PAGEZERO
段在Mach-O中是从0x0
开始,大小是0x0
,也就是说PAGEZERO
在Mach-O中实际不存在数据 ,只有加载到内存后才会展开。
- 例如下图中的
- 例如下图中的
__TEXT
段,我们可以看出来,TEXT
段在虚拟内存中从0x10000000
开始,大小是0x6B8C000
;TEXT
段在Mach-O中从0x0
开始,大小是0x6B8C000
- 例如下图中的
- 例如下图中的
__DATA
段 ,我们可以看出来,DATA
段在虚拟内存中从0x106B8C000
开始,大小是0x1820000
;TEXT
段在Mach-O中从0x6B8C000
开始,大小是0x1350000
- 例如下图中的
- 综上所述 ,我们就可以绘制出比较直观的图来表示,如下图所示:
四、使用ASLR时,Mach-O文件是如何载入内存的?
- ASLR会在虚拟内存中的最开始的位置产生了随机偏移量,每次载入内存时,偏移量都会不同,导致后续各段的地址都会增加此偏移量,以增加攻击者预测地址的难度
- 例如:ASLR产生的随机偏移量是
0x5000
,那么Mach-O载入虚拟内存中后,就如下图所示:
- 例如:ASLR产生的随机偏移量是
- 苹果从
iOS 4.3
之后引入了ASLR技术,也就说把Mach-O载入内存后,所有的地址都会经过ASLR偏移
- 苹果从
- 我们使用MachOView工具静态分析看到的
VM Address
,是未经过ASLR偏移的虚拟内存地址,也就是说MachOView中的VM Address
加上ASLR偏移量
才是虚拟内存中的真正地址
- 我们使用MachOView工具静态分析看到的
-
- 总结一下:
Hopper、IDA、MachOView等工具中的看到的地址都是未使用ASLR的VM Address,所以要想知道虚拟内存中真正地址,就需要再加上ASLR偏移量
虚拟内存中的真正地址 = ASLR偏移量 + PAGEZERO的大小 + Mach-O中的偏移量 (其中PAGEZERO的大小就是VM Size,Mach-O中的偏移量就是Offset,因为PAGEZERO到内存中才会展开,所以要加上PAGEZERO的大小)
虚拟内存中的真正地址 = ASLR偏移量 + 用工具看到的VM Address
虚拟内存中的真正地址 = ASLR偏移量 + Mach-O文件中的VM Address
Mach-O文件中的File Offset = 虚拟内存中的真正地址 - ASLR偏移量 - PAGEZERO的大小
-
想要得到ASLR偏移量,可以在使用LLDB命令
image list -o -f | grep Mach-O文件名称
,来查看加载到内存中的ASLR偏移量。(注意:ASLR是随机的,每次加载到内存都不一样)
-
想要得到ASLR偏移量,可以在使用LLDB命令
五、如何给别人的App打断点,进行调试
- 按照上一篇的方法,进入到WeChat的
lldb环境
- 按照上一篇的方法,进入到WeChat的
- 使用LLDB指令
image list -o -f | grep Mach-O文件名称
,获取ASLR偏移量,如下图所示,本次载入内存的偏移量是0x27c0000
- 使用LLDB指令
- 用Hopper等工具静态分析出某个函数在虚拟内存中的函数地址,这里的函数地址是静待分析出来的,也就是未经过ASLR偏移的地址,并不能直接用于打断点,如下图所示,
-[BaseMsgContentViewController SendTextMessageToolView:]
函数的未ASLR偏移的函数地址是0x1002aec90
- 用Hopper等工具静态分析出某个函数在虚拟内存中的函数地址,这里的函数地址是静待分析出来的,也就是未经过ASLR偏移的地址,并不能直接用于打断点,如下图所示,
- 使用LLDB指令
breakpoint set -a 函数地址
,给某个函数打断点,这里的函数地址指的是虚拟内存中的真实函数地址,也就是说这里的函数地址,是ASLR偏移量+静待分析的函数地址,也就是0x1002aec90+0x27c0000
,完整的LLDB指令就是breakpoint set -a 0x1002aec90+0x27c0000
,如下图所示:
- 使用LLDB指令
- 打完断点之后,当App触发此断点时,就会卡住,以便我们输入LLDB调试,例如,我这里对微信的发送消息的方法
-[BaseMsgContentViewController SendTextMessageToolView:]
打了断点,之后每次发消息时都会卡主,以便我们继续输入LLDB指令调试
- 打完断点之后,当App触发此断点时,就会卡住,以便我们输入LLDB调试,例如,我这里对微信的发送消息的方法
- 如果不想要断点了,可以用
breakpoint delete 断点编号
删除断点;可以通过breakpoint list
命令,列出所有的断点编号
- 如果不想要断点了,可以用