前言:技術總是處在不斷發展的過程,各種技術的細節和涵義也在不斷的變遷,因而我們很難像數學給每種理論下一個嚴格的定義一樣去對待技術,這就是為什么我們對很多技術的定義甚是困惑,因為它是不嚴謹的,是在歷史的長河中不斷變遷的,在變遷的過程中又有可能是自相矛盾的。我們更應該從思想和動機去理解技術而不是定義,畢竟這是工程技術而不是嚴謹的科學理論。
以下是我對Linux中的ASLR和PIE的理解的兩個階段,對比來看很有意思,雖然很無聊 :)
Level 1
——————————————————————————————————我是分界線:)———————————————————————————————————————————————————————
根據翻閱的資料,得出以下結論,記錄以備忘:
首先,ASLR的是操作系統的功能選項,作用於executable(ELF)裝入內存運行時,因而只能隨機化stack、heap、libraries的基址;而PIE(Position Independent Executables)是編譯器(gcc,..)功能選項(-fPIE),作用於excutable編譯過程,可將其理解為特殊的PIC(so專用,Position Independent Code),加了PIE選項編譯出來的ELF用file命令查看會顯示其為so,其隨機化了ELF裝載內存的基址(代碼段、plt、got、data等共同的基址)。
其次,ASLR早於PIE出現,所以有return-to-plt、got hijack、stack-pivot(bypass stack ransomize)等繞過ASLR的技術;而在ASLR+PIE之后,這些bypass技術就都失效了,只能借助其他的信息泄露漏洞泄露基址(常用libc基址)。
最后,ASLR有0/1/2三種級別,其中0表示ASLR未開啟,1表示隨機化stack、libraries,2還會隨機化heap。
總結: ASLR(on process)、PIE(on executable)
實例驗證:
寫一個簡單的程序test.c
編譯兩個版本:
gcc -o test test.c
gcc -fpie -pie -o test-pie test.c
file查看:
root@ubuntu:/home/jiangxin/test# file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=97e4e8460d8eb27a452c49ce052e27003f89f399, not stripped
root@ubuntu:/home/jiangxin/test# file test-pie
test-pie: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=08ef21b96636a1757134e4377638022ce050b2e2, not stripped
ASLR 1 & no PIE 下查看進程內存空間:
ASLR 2 & PIE 下查看進程內存空間:
Level 2
——————————————————————————————————我是分界線:)———————————————————————————————————————————————————————
上述理解有一個明顯的缺陷,那就是PIE只是在編譯的過程中賦予了ELF加載到內存時其加載基址隨機化的功能,也就是說PIE編譯出來的ELF如果在ASLR=0的情況下,ELF的加載基址也是不會變的。
為什么呢,因為一個是能力賦予,一個是真正使用能力。
這個是有歷史原因的,ASLR剛開始設計的時候是作為操作系統功能提供的,只考慮了當時技術背景下executable加載后stack、heap、libraries的隨機化功能,因而有多種繞過方式,這一時期的ASLR的定義也就成了“對stack、heap、libraries的隨機化”。后來設計者就考慮executable的加載基址隨機化以使得bypass失效,然而這一點在技術細節上需要編譯器來實現,因此gcc開始支持PIE選項,使得編譯出來的executable像是一個特殊的so,可以被操作系統加載到隨機化的內存地址(只是可以),因而到這一階段你會發現ASLR的定義變成了“對stack、heap、libraries、executable base的隨機化”。然而你要將PIE出來的executable理解為特殊的so的話,原來的定義還是可以自圓其說的:)。
所以這是ASLR 的三個級別變成了 :0, 不開啟任何隨機化;1, 開啟stack、libraries [、executable base(special libraries -^-) if PIE is enabled while compiling] 的隨機化;2,開啟heap隨機化。
因而,我們會發現PIE編譯出來的executable如果ASLR=0的話,基址也是不會變的(有能力但沒使用),如果ASLR=1的話,即使按照ASLR定義這個級別似乎不會對heap基址隨機化,但是由於executable的基址已經隨機化了,所以heap的基址自然也就被隨機化了:)。我們不妨多做幾個實驗驗證一下:
ELF裝載入內存后的進程布局參考:
http://blog.sina.com.cn/s/blog_4ed962ae01013vhr.html
gcc PIE選項使用:
http://blog.csdn.net/ivan240/article/details/5363395