kprobe原理解析(二)


上一篇文章和大家簡要說明了下kprobe到底應該怎樣用,那么現在我們就揭開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與之對應。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM