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
,如下圖所示:
-
-
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載入虛擬內存中後,就如下圖所示:
-
- 蘋果從
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
-
-
用Hopper等工具靜態分析出某個函數在虛擬內存中的函數地址,這裏的函數地址是靜待分析出來的,也就是未經過ASLR偏移的地址,並不能直接用於打斷點,如下圖所示,
-[BaseMsgContentViewController SendTextMessageToolView:]
函數的未ASLR偏移的函數地址是0x1002aec90
-
-
使用LLDB指令
breakpoint set -a 函數地址
,給某個函數打斷點,這裏的函數地址指的是虛擬內存中的真實函數地址,也就是說這裏的函數地址,是ASLR偏移量+靜待分析的函數地址,也就是0x1002aec90+0x27c0000
,完整的LLDB指令就是breakpoint set -a 0x1002aec90+0x27c0000
,如下圖所示:
-
- 打完斷點之後,當App觸發此斷點時,就會卡住,以便我們輸入LLDB調試,例如,我這裏對微信的發送消息的方法
-[BaseMsgContentViewController SendTextMessageToolView:]
打了斷點,之後每次發消息時都會卡主,以便我們繼續輸入LLDB指令調試
- 打完斷點之後,當App觸發此斷點時,就會卡住,以便我們輸入LLDB調試,例如,我這裏對微信的發送消息的方法
- 如果不想要斷點了,可以用
breakpoint delete 斷點編號
刪除斷點;可以通過breakpoint list
命令,列出所有的斷點編號
- 如果不想要斷點了,可以用