最近學習了kprobe與uprobe,順便復習一下linux系統(tǒng)下進程的內存分布以加深理解。
進程空間
一個標準的32位linux程序在運行時,在內存中的空間分布如下圖所示:

.text段(代碼段):
該部分存儲程序的可執(zhí)行代碼,即cpu指令,默認情況下該段為只讀段,不可修改,但利用內核的一些機制是可以代碼段的內容,例如uprobe等機制。
.data數據段:
該部分存儲在編譯時就已經初始化了的全局和靜態(tài)變量,在程序運行時會加載到內存空間中。該部分的內容在編譯后會存在于elf程序文件中。
.bss段:
該部分存儲未初始化的全局和靜態(tài)變量,在程序運行時,該段內容會被初始化為0,在elf程序文件中不存在,但在程序運行時會占據虛擬內存空間。
堆空間:
程序中調用malloc或new分配的內存空間。按照地址從小到大的方式增長。當堆空間不足時,會通過系統(tǒng)調用brk將堆空間擴大。
動態(tài)鏈接庫 (Dynamically Linked Libraries):
當程序使用了動態(tài)鏈接庫的話,該動態(tài)鏈接庫會被加載到堆地址空間上方。
棧 (Stack):
用于存儲局部變量,函數調用信息,函數返回地址。棧地址一般從高地址向低地址增長,默認情況下棧的大小是有限制的,但可以修改。
???????? 在linux系統(tǒng)下可以通過ulimit
–a查看進程的棧大小空間,默認為8M,可以通過ulimit –s xxx修改進程默認棧大小,ulimit調整棧大小后會影響系統(tǒng)所有程序。
???????? 此外在編譯程序時也可以指定棧大?。ㄖ粫绊懏斍俺绦颍赐ㄟ^鏈接選項-Wl,-z,stack-size說明程序的棧大小。例如:

通過編譯時設置棧大小只影響當前進程,不影響其他進程(首限于系統(tǒng)硬限制,即受限于ulimit –aH查詢到的限制信息)。
???????? 在編寫代碼時如果函數遞歸層次較深或在函數內部分配的局部變量太大都會導致棧越界從而造成程序異常。
可以通過nm命令可以查看elf程序中不同符號所在的位置:

nm命令輸出的符號表類型含義如下:

Kernel空間
最高1G(32位系統(tǒng)下)空間為內核空間,用戶態(tài)程序不能直接訪問,如果訪問則出現異常。內核態(tài)代碼通過系統(tǒng)調用的方式執(zhí)行。在Linux中,所有處理器的內核空間是被映射到一個相同的、連續(xù)的物理地址上。
在linux系統(tǒng)中,每個程序的內存分布相同,使得遠程利用安全漏洞變得輕而易舉,例如利用庫函數在每個進程的內存空間中地址相同,或棧位置相同等特點攻擊。 為了避免這種情況,linux系統(tǒng)引入了地址隨機化功能,即在堆棧、內存映射段和堆的起始地址上添加偏移量,實現了堆棧、內存映射段和堆的隨機化。