kprobe工作原理

kprobe工作原理

 

kprobe的工作過程大致如下:

1)註冊kprobe。註冊的每個kprobe對應一個kprobe結構體,該結構中記錄着插入點(位置),以及該插入點本來對應的指令original_opcode;

2)替換原有指令。使能kprobe的時候,將插入點位置的指令替換爲一條異常(BRK)指令,這樣當CPU執行到插入點位置時會陷入到異常態;

3)執行pre_handler。進入異常態後,首先執行pre_handler,然後利用CPU提供的單步調試(single-step)功能,設置好相應的寄存器,將

                                    下一條指令設置爲插入點處本來的指令,從異常態返回;

4)再次陷入異常態。上一步驟中設置了single-step相關的寄存器,所以originnal_opcode剛一執行,便會二進宮:再次陷入異常態,此時將single-step

                                  清除,並且執行post_handler,然後從異常態安全返回。

步驟2),3),4)便是一次kprobe工作的過程,它的一個基本思路就是將本來執行一條指令擴展成執行kprobe->pre_handler ---> 指令 ---> kprobe-->post_hander這樣三個過程。下面詳細解釋每個過程:

指令替換過程:

上圖中藍色區域表示內存,紅色標明瞭地址,綠色部分代表一條指令,上圖的意思是,內存0xfffffc000162914處存放一條指令是0xa9bd7bfd。那麼,現在我註冊了一個kprobe,探測點是sys_write函數,該函數的起始位置就是0xffffffc000162914,現在我要使能kprobe了,那麼我要做的就是把0xffffffc000162914處原來的指令0xa9bd7bfd替換成一條BRK指令,即上圖所表示的一個移花接木過程。你可能會好奇原來的指令0xa9bd7bfd存在哪裏?存在kprobe結構體的opcode域!這樣當不再使能kprobe的時候,我再恢復回去。

觸發BRK指令:

上面把人家指令給改了,那麼CPU執行到BRK必然會引發內核陷入BRK異常狀態:

藍色部分依舊錶示內存,綠色部分表示指令,紅色表示CPU,上圖表示CPU執行到0xffffffc000162914(sys_write)處,該處指令爲BRK,於是內核陷入異常態。在異常態中,內核通過BRK指令的錯誤碼判斷這是一個kprobe異常,於是進入了kprobe處理函數。kprobe異常處理函數會根據發生異常的地址來找到對應的kprobe(kprobe的addr域記錄着地址),執行kprobe的pre_handler函數,然後設置single-step相關的寄存器,爲下一步執行原指令時發生single-step異常作準備。那麼緊接着就是設置原指令的地址了,我們知道0xffffffc000162914處已經被替換成了BRK指令,原指令保存在kprobe結構體中,怎麼保證下一步執行到原指令呢?最簡單的做法是申請一塊內存,然後將原指令複製到這塊內存開始處,設置PC寄存器爲該內存的首地址,這樣當代碼從異常態返回時,執行的第一條指令便是原指令了!

原指令得到執行,二進宮

經過上面一個步驟,pre_handler得到了執行,從異常態返回之後,原指令也得到了執行,但是由於設置了single-step模式,所以執行完原指令,馬上又陷入了異常態,二進宮:

這次進入異常態後,先清一下single-step相關的寄存器,確保下次從異常返回時的指令不會由於single-step發生三進宮,然後執行post_handler,最後將地址0xfffffc000162918寫入到PC寄存器,爲什麼是這個數值呢?它正是緊接着0xffffffc000162914的下一條指令的地址,有沒有發現,至此我們已經完成了pre_handler->原指令->post_handler這樣三個階段,也就是說kprobe要做的事情都做完了,此時的工作就是收拾下殘局,返回到正常的指令流程,我們的探測點在0xffffffc000162914處,下一條指令應該就是0xffffffc000162918了,所以把此值寫入PC寄存器,讓一切恢復正軌!

kprobe工作結束,走上正軌

上面把PC設置成了0xffffffc000162918,所以從異常態返回時,CPU就走上了正軌接着朝下面執行了,一個BRK指令引發的反應在此就告一段落了,但是每次當CPU執行到0xffffffc000162914處,都會觸發上面的一連串操作,kprobe的機制也就是從一個BRK指令開始了。

注:

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

由於kprobe涉及到程序指令的修改,這部分和體系結構相關,我選擇的體系結構ARM64,如本文的BRK指令等均是ARM64中的概念,

x86中INT3與之對應。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章