Linux內(nèi)核如何私闖進程地址空間并修改進程內(nèi)存
進程地址空間的隔離 是現(xiàn)代操作系統(tǒng)的一個顯著特征。這也是區(qū)別于 “古代”操作系統(tǒng) 的顯著特征。
進程地址空間隔離意味著進程P1無法以隨意的方式訪問進程P2的內(nèi)存,除非這塊內(nèi)存被聲明是共享的。
這非常容易理解,我舉個例子。我們知道,在原始野人社會,是沒有家庭的觀念的,所有的資源都是部落內(nèi)共享的,所有的野人都可以以任意的方式在任意時間和任何其他野人交互。類似Dos這樣的操作系統(tǒng)就是這樣的,內(nèi)存地址空間并沒有隔離。進程可以隨意訪問其它進程的內(nèi)存。后來有了家庭的觀念,家庭的資源被隔離,人們便不能私闖民宅了,人們無法以隨意的方式進入別人的家用別人的東西,除非這是主人允許的。操作系統(tǒng)進入現(xiàn)代模式后,進程也有了類似家庭的概念。但家庭的概念是虛擬的,人們只是遵守約定而不去破壞別人的家庭。房子作為一個物理基礎(chǔ)設(shè)施,保護著家庭。在操作系統(tǒng)中,家庭類似于虛擬地址空間,而房子就是頁表。鄰居不能闖入你的房子,但特權(quán)管理機構(gòu)只要理由充分,就可以進入普通人家的房子,touch這家人的東西。對于操作系統(tǒng)而言,這就是內(nèi)核可以做的事,內(nèi)核可以訪問任意進程的地址空間。當(dāng)然了,內(nèi)核并不會無故私闖民宅,就像警察不會隨意闖入別人家里一樣。但是,你可以讓內(nèi)核故意這么做,做點無賴的事情。我們來試一下,先看一個程序:
這個程序的輸出非常簡單,before和after都會輸出 “Zhejiang wenzhou pixie shi”,但是我們想把這句話給改了,怎么辦呢?顯然,test進程如果自己不改它,那就沒轍...但是可以讓內(nèi)核強制改啊,讓內(nèi)核私闖民宅就是了。接下來我寫一個內(nèi)核模塊:
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ? ?


來來來,我們來試一下:
此時,我們加載內(nèi)核模塊test.ko
在test進程拍入回車:
仔細看上面那個內(nèi)核模塊的 get_pte 函數(shù),這個函數(shù)要想寫對,你必須對你想蹂躪的進程所在的機器的MMU有一定的了解,比如是32位系統(tǒng)還是64位系統(tǒng),是3級頁表還是4級頁表或者5級?這...Linux的可玩性在于你可以自己動手,又可以讓人代勞。比如,獲取一個進程的虛擬地址的頁表項指示的物理頁面,就可以直接得到。有這樣的API嗎?有啊,別忘了一切皆文件,恰好在proc文件系統(tǒng)中,就有這么一個文件:
/proc/$pid/pagemap
讀取這個文件,得到的就是進程虛擬地址的頁表項,下圖截自內(nèi)核Doc:Documentation/vm/pagemap.txt

虛擬地址空間是每進程的,而物理地址空間則是所有進程共享的。換句話說,物理地址是全局的?,F(xiàn)在,根據(jù)Documentation/vm/pagemap.txt的解釋,寫一個程序,獲取任意進程任意虛擬地址的全局物理地址:
隨后,我們修改內(nèi)核模塊:
先運行test,然后根據(jù)test的輸出作為getphys的輸入,再根據(jù)getphys的輸出作為內(nèi)核模塊test.ko的輸入,就成了。還記得嗎?這不就是管道連接多個程序的風(fēng)格嗎?輸入一個物理地址,然后把它改了,僅此而已。通過虛擬地址獲取頁表的操作已經(jīng)由用戶態(tài)的pagemap文件的讀取并解析代勞了。
