Linux ASLR的实现
ASLR大家都會(huì)聽說過,但是Linux平臺(tái)下應(yīng)用程序的ASLR的情況是怎么樣的呢?我在這里將ASLR分為幾個(gè)小的部分來闡述,包括了棧的隨機(jī)化,堆的隨機(jī)化,mmap的隨機(jī)化,以及pie程序運(yùn)行時(shí)的主模塊隨機(jī)化。目的是為了知道隨機(jī)化了哪些比特,隨機(jī)了多少比特。
我在這里以Linux 4.11.4進(jìn)行分析,以x64為代表,分析通過靜態(tài)觀察內(nèi)核的源代碼和動(dòng)態(tài)調(diào)試內(nèi)核源代碼結(jié)合。在這里分析的是用戶態(tài)程序的ASLR,由于用戶態(tài)程序的ASLR是在程序加載執(zhí)行過程中完成的,所以分析的起點(diǎn)應(yīng)該是程序的加載執(zhí)行。程序的加載執(zhí)行從execve系統(tǒng)調(diào)用開始,到do_execve,到do_exeveat_common[1],因此就沿著這條主線一直走下去。
按照這個(gè)主線看下去,第一個(gè)見到的隨機(jī)化是mmap的隨機(jī)化[2],mmap有兩種方式,早期是從低地址空間向高地址空間分配,如今是從高地址空間向低地址空間分配。mmap隨機(jī)的位數(shù)由mmap_rnd_bits表示,在64位下是28比特,經(jīng)過計(jì)算在64位平臺(tái)下mmap的基地址是:page_align(0x7ffbf8000000-rand),而其中的rand在是28比特的數(shù)字左移12位。當(dāng)mmap的基地址確定后,在各個(gè)系統(tǒng)中,程序運(yùn)行起來時(shí)各個(gè)模塊(不包括pie程序的主模塊、但包括各個(gè)動(dòng)態(tài)鏈接庫)與mmap的基地址的偏移是固定的,因此這些模塊加載地址的隨機(jī)化也在28比特。
緊接著是棧的隨機(jī)化,棧的隨機(jī)化在3個(gè)地方有涉及。第一是[3],在這里將STACK_TOP進(jìn)行了隨機(jī)化。沒隨機(jī)化前的STACK_TOP的值是0x00007ffffffff000L,棧的隨機(jī)化的位數(shù)由STACK_RND_MASK決定,STACK_RND_MASK在x64下是0x3fffff,也就是說棧的隨機(jī)位數(shù)是22比特,經(jīng)過計(jì)算,這里將STACK_TOP的值隨機(jī)化為page_align(0x00007ffffffff000L-rand),而其中rand是22比特的隨機(jī)數(shù)左移12位(即0到0x3fffff個(gè)頁大小)。第二是[4],這里將STACK_TOP減去0或者1個(gè)頁大小。第三個(gè)是[5],將棧內(nèi)存高地址隨機(jī)減去了0到8192,并進(jìn)行了16字節(jié)對(duì)齊[5]。下圖是一個(gè)程序運(yùn)行中棧布局的圖,1和2分別是兩處隨機(jī)化。
如果程序是pie的,那么程序主模塊也會(huì)被隨機(jī)化,見[8],這里主模塊基地址被隨機(jī)化為ELF_PAGESTART(0x555555554aaa+rand),rand由arch_mmap_rnd生成,和mmap隨機(jī)化的位數(shù)是一樣的,都是28比特。
下面是堆的隨機(jī)化,堆空間的位置由start_brk和brk確定[6],程序運(yùn)行最初start_brk和brk指向同一個(gè)位置,即data/bss段的下一個(gè)頁面。堆的隨機(jī)化的實(shí)現(xiàn)在[7],start_brk被隨機(jī)化為[old_start_brk, old_start_brk+0x02000000)中頁面對(duì)齊的值。
調(diào)試內(nèi)核使用的是qemu,關(guān)于如何調(diào)試Linux內(nèi)核網(wǎng)上有很多的文章。前期的準(zhǔn)備就是一個(gè)編譯好的Linux kernel、一個(gè)已經(jīng)安裝了Linux系統(tǒng)的硬盤鏡像和一個(gè)gdb調(diào)試器。關(guān)于編譯Linux kernel,盡可能少的編譯優(yōu)化對(duì)于調(diào)試會(huì)有不少幫助,但是Linux kernel并不能整體在-O0下編譯,但是可以對(duì)單個(gè)源碼文件或者單個(gè)函數(shù)以-O0形式進(jìn)行編譯,我們針對(duì)性地選擇哪些不要優(yōu)化[9][10]。關(guān)于準(zhǔn)備安裝了Linux系統(tǒng)的硬盤鏡像,一種是自己手動(dòng)創(chuàng)建硬盤并進(jìn)行安裝系統(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,那么就需要一個(gè)ARM平臺(tái)下的GDB。一種方法是手動(dòng)的交叉編譯,另外一種就是安裝gdb-multiarch,它支持多種平臺(tái)下的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的边框与补白