libvmi虛擬機器自省原始碼分析 一

2021-07-08 13:48:59 字數 2836 閱讀 3027

libvmi是乙個c庫,它提供了對正在執行中的底層虛擬機器的執行細節進行監視的功能,監視的功能是由觀察記憶體細節,陷入硬體事件和讀取cpu暫存器來完成的。這種方式被稱作虛擬機器自省(virtual machine introspection)

libvmi所提供的種種功能中,最主要的是記憶體自省功能,記憶體自省能允許使用者從dom0監控(也就是讀取記憶體資料)以及控制(也就是改寫記憶體資料)作業系統。

上圖是通過libvmi獲取核心符號的流程,主要有以下過程組成:

1. 應用程式請求檢視核心符號。

2. libvmi通過系統的system.map獲取核心符號的虛擬位址。

3. 找到虛擬位址所對應的核心頁目錄,並獲取對應的頁表。

4. 通過頁表找到正確的資料頁。

5. 資料頁被返回給libvmi。

6. libvmi將資料返回給vmi應用程式。

用libvmi獲取linux核心符號表的原始碼分析

首先來分析example下的map-symbol.c程式,這個程式可以在記憶體中找到指定的核心符號,並將核心符號所在的記憶體頁列印出來。在分析原始碼的時候,我們盡可能減少無關緊要的**,而只保留關鍵部分的**進行分析。

/*map-symbol.c*/

#define page_size 1 << 12

int main(int argc, char **argv)

/*獲取符號在記憶體頁中的起始位址 */

if (page_size != vmi_read_ksym(vmi, symbol, memory, page_size))

vmi_print_hex(memory, page_size);

vmi_destroy(vmi);

return

0;}

總體上來看對符號記憶體進行dump的過程主要有以下幾點:

以上過程中的初始化是乙個很重要的步驟,vmi_instance_t vmi是對應初始化的例項,下面我們就來分析它的初始化過程。vmi_init函式經過一層封裝,實際上後最後會呼叫vmi_init_private()函式,這個函式會設定vmi的cache(vmi為了提高系統的執行效率用雜湊表構建了三種對映作為快取,分別是pid–>dtb,dtb是乙個實體地址,symbol–>虛擬位址,虛擬位址–>實體地址),設定執行模式,連線到xen/kvm等虛擬機器,獲得虛擬機器記憶體大小,作業系統型別,記憶體布局等資訊,這些資訊都會在後面的**中起到很大的作用,後續很多功能都直接依賴於初始化後的vmi中儲存的一系列資訊。附錄一中列出的vmi_instance_t的具體定義及其解釋。接下來查詢symbol對應的虛擬位址,由於linux的核心符號的虛擬位址已經在系統的system.map中規定了,而且在vmi初始化的過程中就讀取了guest的system.map,因此在這個檔案中對符號名進行匹配就可以獲取到符號的虛擬位址了,下面是這個過程的**,可以看到,**先是在sym–>虛擬位址的快取中進行查詢,當沒有找到後才去system.map中讀取,並且將讀取到的結果快取到符號cache中。這樣就獲取到了乙個符號的虛擬位址,接下來還要進行讀取這個虛擬位址內容的過程。

addr_t vmi_translate_ksym2v (vmi_instance_t vmi, char *symbol)

}if (ret)

}return ret;

}

虛擬位址轉換成實體地址的功能由所以主要的記憶體轉換工作主要是由vmi_translate_kv2p(vmi, vaddr + buf_offset)完成,這段**會讀取cr3暫存器裡的值,然後根據這個值查詢系統的頁表進行一次四級頁表的查詢操作,獲得gpa然後將這個值交給底層虛擬機器(讀取記憶體函式,該函式會根據當前執行的虛擬機器是kvm還是xen自動呼叫對應的物理記憶體讀取介面函式),底層虛擬機器一般會經過ept或npt進行對映,最後讀取到物理記憶體的內容。其實原理上還是經過了一次四級頁表的walk。

ept對映物理記憶體主要的的流程是:

1. cpu首先查詢guest cr3指向的l4頁表;

2. 由於guest cr3給出的是gpa,cpu需要查ept頁表;

3. 如果ept頁表中不存在該位址對應的查詢項,則guest mode產生ept violation異常由vmm來處理;

4. 獲取l4頁表位址後,cpu根據gva和l4頁表項的內容,來獲取l3頁表項的gpa;

5. 如果l4頁表中gva對應的表項顯示為缺頁,那麼cpu產生page fault,直接交由guest kernel處理,注意這裡不會產vm-exit;

6. 獲得l3頁表項的gpa後,cpu同樣查詢ept頁表,過程和上面一樣;

7. l2,l1頁表的訪問也是如此,直至找到最終於與gpa對應的hpa。

完成位址轉換後就要對轉換出的位址中的內容進行讀取

c

void * driver_read_page(vmi_instance_t vmi, addr_t page)

else

} 整體上的**呼叫樹為

c

vmi_read_page (vmi_instance_t vmi, addr_t frame_num)

} }

從以上可以看出,經過一番呼叫之後,最終memory_cache_insert(vmi, paddr)提供了讀取記憶體的功能,可以看出來libvmi的思路,就是先從cache中讀取,如果cache中不存在的話,就把對映到的內容insert進cache中。然後繼續經過一系列呼叫,最終通過xc_map_foreign_range

Python虛擬機器原始碼分析(1) 開篇

現在我們即將進入python原始碼分析之旅。寫這個系列的具體原因呢 我們學會了基本的python語法或者具備一定了一定python經驗後,會被python快速的開發能力 強大的動態能力吸引,同時python各種語法,各種高階語言特性,這一切python都是如何做到的?成了很多人的疑問。與其糾結於分析...

XenServer虛擬機器擴容LVM磁碟分割槽

說明 xenserver裡面安裝的虛擬機器,分割槽的時候採用的是lvm磁碟分割槽 需求 現在需要擴容虛擬機器根分割槽 具體操作 一 使用xencenter增大虛擬機器磁碟容量,如下圖所示 增大當前磁碟到590gb 注意 必須在虛擬機關機狀態下進行 二 檢視硬碟容量 df h 可以看到此時根分割槽還是...

XenServer 虛擬機器擴容LVM磁碟分割槽的方法

說明 xenserver裡面安裝的虛擬機器,分割槽的時候採用的是lvm磁碟分割槽 需求 現在需要擴容虛擬機器根分割槽 程式設計客棧 具體操作 一 使用xencenter增大虛擬機器磁碟容量,如下圖所示 增大當前磁碟到50gb 注意 必須在虛擬機關機狀態下進行 二 檢視硬碟容量 df h 可以看到此時...