Linux ASLR的实现
ASLR大家都會聽說過,但是Linux平臺下應(yīng)用程序的ASLR的情況是怎么樣的呢?我在這里將ASLR分為幾個小的部分來闡述,包括了棧的隨機化,堆的隨機化,mmap的隨機化,以及pie程序運行時的主模塊隨機化。目的是為了知道隨機化了哪些比特,隨機了多少比特。
我在這里以Linux 4.11.4進行分析,以x64為代表,分析通過靜態(tài)觀察內(nèi)核的源代碼和動態(tài)調(diào)試內(nèi)核源代碼結(jié)合。在這里分析的是用戶態(tài)程序的ASLR,由于用戶態(tài)程序的ASLR是在程序加載執(zhí)行過程中完成的,所以分析的起點應(yīng)該是程序的加載執(zhí)行。程序的加載執(zhí)行從execve系統(tǒng)調(diào)用開始,到do_execve,到do_exeveat_common[1],因此就沿著這條主線一直走下去。
按照這個主線看下去,第一個見到的隨機化是mmap的隨機化[2],mmap有兩種方式,早期是從低地址空間向高地址空間分配,如今是從高地址空間向低地址空間分配。mmap隨機的位數(shù)由mmap_rnd_bits表示,在64位下是28比特,經(jīng)過計算在64位平臺下mmap的基地址是:page_align(0x7ffbf8000000-rand),而其中的rand在是28比特的數(shù)字左移12位。當(dāng)mmap的基地址確定后,在各個系統(tǒng)中,程序運行起來時各個模塊(不包括pie程序的主模塊、但包括各個動態(tài)鏈接庫)與mmap的基地址的偏移是固定的,因此這些模塊加載地址的隨機化也在28比特。
緊接著是棧的隨機化,棧的隨機化在3個地方有涉及。第一是[3],在這里將STACK_TOP進行了隨機化。沒隨機化前的STACK_TOP的值是0x00007ffffffff000L,棧的隨機化的位數(shù)由STACK_RND_MASK決定,STACK_RND_MASK在x64下是0x3fffff,也就是說棧的隨機位數(shù)是22比特,經(jīng)過計算,這里將STACK_TOP的值隨機化為page_align(0x00007ffffffff000L-rand),而其中rand是22比特的隨機數(shù)左移12位(即0到0x3fffff個頁大小)。第二是[4],這里將STACK_TOP減去0或者1個頁大小。第三個是[5],將棧內(nèi)存高地址隨機減去了0到8192,并進行了16字節(jié)對齊[5]。下圖是一個程序運行中棧布局的圖,1和2分別是兩處隨機化。
如果程序是pie的,那么程序主模塊也會被隨機化,見[8],這里主模塊基地址被隨機化為ELF_PAGESTART(0x555555554aaa+rand),rand由arch_mmap_rnd生成,和mmap隨機化的位數(shù)是一樣的,都是28比特。
下面是堆的隨機化,堆空間的位置由start_brk和brk確定[6],程序運行最初start_brk和brk指向同一個位置,即data/bss段的下一個頁面。堆的隨機化的實現(xiàn)在[7],start_brk被隨機化為[old_start_brk, old_start_brk+0x02000000)中頁面對齊的值。
調(diào)試內(nèi)核使用的是qemu,關(guān)于如何調(diào)試Linux內(nèi)核網(wǎng)上有很多的文章。前期的準(zhǔn)備就是一個編譯好的Linux kernel、一個已經(jīng)安裝了Linux系統(tǒng)的硬盤鏡像和一個gdb調(diào)試器。關(guān)于編譯Linux kernel,盡可能少的編譯優(yōu)化對于調(diào)試會有不少幫助,但是Linux kernel并不能整體在-O0下編譯,但是可以對單個源碼文件或者單個函數(shù)以-O0形式進行編譯,我們針對性地選擇哪些不要優(yōu)化[9][10]。關(guān)于準(zhǔn)備安裝了Linux系統(tǒng)的硬盤鏡像,一種是自己手動創(chuàng)建硬盤并進行安裝系統(tǒng)[12],例外一種就是使用網(wǎng)上已經(jīng)存在的硬盤鏡像,我用的是網(wǎng)上已經(jīng)存在的Ubuntu Cloud Images[11]。關(guān)于gdb調(diào)試器,依賴于guest系統(tǒng)是什么系統(tǒng),如果guest系統(tǒng)是ARM Linux,那么就需要一個ARM平臺下的GDB。一種方法是手動的交叉編譯,另外一種就是安裝gdb-multiarch,它支持多種平臺下的GDB。
附一下我用的命令行:qemu-system-x86_64 -s -S -hda xenial-server-cloudimg-amd64.img -initrd initrd.img-4.4.0-78-generic -kernel arch/x86/boot/bzImage -drive file=fat:rw:/media/sf_E_DRIVE/tools/mykey/ -redir tcp:5555::22 -append 'root=/dev/sda rw init=/usr/lib/cloud-init/uncloud-init ds=nocloud mem=1024M'
?
[1] http://elixir.free-electrons.com/linux/v4.11.4/source/fs/exec.c
[2] http://elixir.free-electrons.com/linux/v4.11.4/source/arch/x86/mm/mmap.c
[3] http://elixir.free-electrons.com/linux/v4.11.4/source/fs/binfmt_elf.c
[4] http://elixir.free-electrons.com/linux/v4.11.4/source/fs/exec.c
[5] https://lwn.net/Articles/631631/
[6] https://sploitfun.wordpress.com/2015/02/11/syscalls-used-by-malloc/
[7] http://elixir.free-electrons.com/linux/v4.11.4/source/fs/binfmt_elf.c
[8] http://elixir.free-electrons.com/linux/v4.11.4/source/fs/binfmt_elf.c
[9] http://www.alterawiki.com/wiki/Debug_Kernel
[10] https://stackoverflow.com/questions/29151235/how-to-de-optimize-the-linux-kernel-to-and-compile-it-with-o0
[11] http://cloud-images.ubuntu.com/
[12] https://stackoverflow.com/questions/29151235/how-to-de-optimize-the-linux-kernel-to-and-compile-it-with-o0
總結(jié)
以上是生活随笔為你收集整理的Linux ASLR的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDUOJ----4501小明系列故事—
- 下一篇: CSS的边框与补白