1. 程式人生 > >深入瞭解Intel保護模式

深入瞭解Intel保護模式

學習逆向工程也快一年的時間了,從開始的16位真實模式下的記憶體定址模型到32位下保護模式記憶體的模型,真實模式下的較為簡單,段地址*16+偏移地址就是定址的記憶體,但是保護模式下就遠遠沒有這麼簡單了。很簡單的一個例子,windows下支援多程序,並且程序之間是相互隔離的,不允許隨意的將一個程序的資料寫入到另外一個程序的空間中,並且每個時刻CPU只允許執行一個程式,何以為見呢?

開啟OD,分別用OD載入兩個程式,而且是兩個不同的程序,就看程式碼段的資料,假設我們檢視0x0041F69A處的指令,我們發現兩個程序的資料是不一樣的,這裡也會讓我們感到奇怪,為什麼兩個程序處在相同地址處的資料不同呢?當然我們知道是保護機制中隔離在作怪,但是他是如何做到隔離的呢?為什麼不能隨意的向另外一個程序的空間中寫入值呢?所以就這幾天的學習情況對一下幾個問題進行討論:

1.OD或者其他偵錯程式中的地址到底是個什麼樣的地址?虛擬地址,線性地址和實體地址間的聯絡又是什麼?
2.Windows系統是如何做到每個程序地址空間的隔離的?
3.傳說中的GDT,LDT表的作用?
4.虛擬地址是如何對映到實體地址的?
5.如何通過虛擬地址找到程序實際所在的實體地址?
6.如何通過實驗來驗證windows中某個程序中的一個虛擬地址就是實體記憶體中的地址呢?
7.如何通過修改對映關係來達到在保護模式下,兩個不同的程序可以寫入到對方程序的物理空間中呢?

首先還是得簡單介紹一下保護模式下的兩種保護機制:分段和分頁。這個應該都比較好理解,將記憶體中的資料進行分段,不同型別的資料處於不同的段中,比如程式碼段就處於程式碼段的記憶體中,資料就處於資料段的程式碼中等等。對於分頁呢,我的理解是,將記憶體按照一定的大小劃分區域,比如按照4KB大小,將記憶體分為N塊,每塊就稱為是一頁。不知道這麼理解是不是正確的。

然後一個比較不同的方面就是在保護模式下,段暫存器(CS,DS,ES,SS,FS,GS)不再作為定址用,因為只有16位,而且每個暫存器都是32位的,足以進行定址的操作了。當然,這裡段暫存器我們也稱為段選擇器。這裡,段選擇器就不再像真實模式下進行定址了,而是為一個索引,索引一個二進位制的結構,這個結構中包含了每一段的細節,比如說程式碼段具有哪些許可權,什麼許可權的程序可以訪問它(Ring3 Or Ring0)。當然這個結構我們稱為段描述表,其中的項稱為段描述符

當然啦這樣的描述符表就是全域性描述符表(GDT)和區域性描述符表(LDT)了。也就是傳說中的GDT和LDT了,當然每個系統中只存在一個GDT,並且是必須存在的,而LDT是可選擇的,並且每個任務都有一個不同的LDT,這次我們主要集中在GDT上。下面看一下段選擇器的結構及GDT的結構:

描述符

上面圖還是非常清晰的,我們可以看到段選擇器包含了當前程序請求的特權,位0表示當前程序請求許可權,即是ring0還是ring3,而且一般也只用到這兩個許可權,位2表示的是使用GDT還是LDT來存放段描述符的,位3到位15就是存放索引的位置。

GDT存放在哪裡呢?Intel中有個48位的暫存器GDTR,存放的就是GDTR的地址,應該是從系統初始化的時候就開始存在了,並且這個結構也只有特定的許可權程序進行才能進行讀寫操作,GDTR中,低16位表示的是GDT的大小(以位元組為單位),其餘32位儲存了GDT的起始線性地址,即第一個位元組的線性地址。然後就是段描述符,是如下的結構:

段描述符

是一個64位的結構,最上面的結構是高32位,下面的結構是低32位的結構,其中主要的幾個位置就DPL,表示引用段的許可權,其他位的作用上圖描述的非常清楚,不再多說。下面我們就來看看GDT的結構,我在xp sp3下作的實驗,偵錯程式核心模式的,否則看不到GDTR及其結構,首先在虛擬機器中用OD載入一個程式,我們來看看每個段暫存器的值是多少:

od1

換了幾個不同的程式,發現在ring3層的程式,CS為0x1B,SS為0x23,ring0下就沒有繼續看了,我們拿CS做例子吧,將CS做分解:0000000000011  0 11

第1,2位為3(0B11),第2位為0,最高位為3,可以看出表示的是引用的段許可權為最低,並且存放在GDT中,那我們就看看GDT長啥樣子的:

1 kd> r gdtr
2 gdtr=8003f000
3 kd> r gdtl
4 gdtl=000003ff

這裡使用gdtr來表示GDT手位元組地址,gdtl表示的是GDT中索引的個數,下面我們就來看看GDT表中的資料,如果單單使用dd檢視的話太不直觀,windbg中我們可以使用dg命令來檢視GDT中的結構和值,第一個引數為索引開始值,第二個引數為要檢視索引結束值:

1 kd> dg 0 3f8
2 P Si Gr Pr Lo
3 Sel    Base     Limit     Type    l ze an es ng Flags
4 ---- -------- -------- ---------- - -- -- -- -- --------
5 0000 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
6 0008 00000000 ffffffff Code RE    0 Bg Pg P  Nl 00000c9a
7 0010 00000000 ffffffff Data RW    0 Bg Pg P  Nl 00000c92
8 0018 00000000 ffffffff Code RE    3 Bg Pg P  Nl 00000cfa
9 0020 00000000 ffffffff Data RW    3 Bg Pg P  Nl 00000cf2
10 0028 80042000 000020ab TSS32 Busy 0 Nb By P  Nl 0000008b
11 0030 ffdff000 00001fff Data RW    0 Bg Pg P  Nl 00000c92
12 0038 00000000 00000fff Data RW Ac 3 Bg By P  Nl 000004f3
13 0040 00000400 0000ffff Data RW    3 Nb By P  Nl 000000f2
14 0048 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
15 0050 8054af00 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
16 0058 8054af68 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
17 0060 00022f40 0000ffff Data RW    0 Nb By P  Nl 00000092
18 0068 000b8000 00003fff Data RW    0 Nb By P  Nl 00000092
19 0070 ffff7000 000003ff Data RW    0 Nb By P  Nl 00000092
20 0078 80400000 0000ffff Code RE    0 Nb By P  Nl 0000009a
21 0080 80400000 0000ffff Data RW    0 Nb By P  Nl 00000092
22 0088 00000000 00000000 Data RW    0 Nb By P  Nl 00000092
23 0090 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
24 0098 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
25 00A0 821b2350 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
26 00A8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
27 00B0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
28 00B8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
29 00C0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
30 00C8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
31 00D0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
32 00D8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
33 00E0 f871a000 0000ffff Code RE Ac 0 Nb By P  Nl 0000009f
34 00E8 00000000 0000ffff Data RW    0 Nb By P  Nl 00000092
35 00F0 804fb688 000003b7 Code EO    0 Nb By P  Nl 00000098
36 00F8 00000000 0000ffff Data RW    0 Nb By P  Nl 00000092
37 0100 f8397400 0000ffff Data RW Ac 0 Bg By P  Nl 00000493
38 0108 f8397400 0000ffff Data RW Ac 0 Bg By P  Nl 00000493
39 0110 f8397400 0000ffff Data RW Ac 0 Bg By P  Nl 00000493
40 0118 00008003 0000f120 <Reserved> 0 Nb By Np Nl 00000000

我們檢視CS和SS所在段的資訊:

1 kd> dg 1b
2 P Si Gr Pr Lo
3 Sel    Base     Limit     Type    l ze an es ng Flags
4 ---- -------- -------- ---------- - -- -- -- -- --------
5 001B 00000000 ffffffff Code RE    3 Bg Pg P  Nl 00000cfa
6 kd> dg 23
7 P Si Gr Pr Lo
8 Sel    Base     Limit     Type    l ze an es ng Flags
9 ---- -------- -------- ---------- - -- -- -- -- --------
10 0023 00000000 ffffffff Data RW    3 Bg Pg P  Nl 00000cf2

我們可以看出這裡第五列為段的訪問許可權,和我們手工的出來的結果相同,當然這裡我們可以看出來,這裡我們根本沒有分段,環0和環3的起始結束地址都是從(00000000-ffffffff),所有的段描述符都指向同一個段,所以windows並沒有有使用Intel硬體平臺為其提供的所有附屬專案。所以我猜測windows下虛擬地址和線性地址的值是相同的。而且我也發現其實GDT在程序間隔離也沒起到太大的作用,因為這裡GDT也只是起到檢視段的許可權的作用,當然也有門的一些資訊,我們這裡不討論門,以上也都是我個人的理解,如果有誤也希望各位進行指出。

下面就是分頁保護,這個就和程序地址間的隔離關係就比較大了,我們都知道,32位下每個程序分配的空間為4GB,當然這個4GB只是程序看到的,感覺到的,是虛擬地址當然這個地址也是線性地址,並不是都能使用,比如說我們看到指令的地址都處於00400000開始位置,如果到00200000的話還能訪問嗎?基本上是不行的,你可以用OD嘗試一下,這裡的位置是不可訪問的,執行到此位置就會發生異常,當然如果都能訪問的話那豈不是相當恐怖的一件事情!你一個程序就全部佔了4GB空間,你讓其他程序怎麼辦?而且你的實體記憶體很大情況下也不會有4GB的,像我的虛擬機器也就只有512MB呢。猜想00200000這個地址應該是被對映到別的程序的空間裡面了,是很有可能的。當然對映絕非那麼簡單的對映。

啟動分頁後,線性地址空間被分為幾個固定長度的儲存塊,這些塊被稱為頁(大小可以是4KB,2MB或者4MB),當然我們實際中使用的頁大小都為4KB,當然如果不啟動分頁的話線性地址就是實體地址,但是啟動後就不一樣了,這個線性地址不再是一個簡單的地址了,這32位被分成了不同的部分,每個部分有不同的含義,如下:

ye

一個線性地址被分為3個部分,第一個部分(0-11位)才是偏移,第三個部分(22-31位)指定了頁目錄的陣列結構的項,這些項被稱為頁目錄項(PDE),並且頁目錄的第一個位元組地址,即其開始位置的實體地址(不是線性地址)存放在CR3暫存器中,當然如果都是線性地址的話那還怎麼到真實的記憶體中查詢值呢?由於索引一共就10位,所以一個頁目錄最多儲存1024個PDE,每個PDE儲存了頁表的二級陣列結構的起始實體地址(不是線性地址),即PDE儲存了頁表第一個位元組的實體地址。第二個部分(12-21位)指定了頁表中特定的項,頁表中的項被順序排列成陣列,稱為頁表項(PTE),當然,一個頁表最多能儲存1024個PTE。當然,每個PTE儲存的就是記憶體頁的第一個實體地址,如果將第一個部分(0-11位)的值和PTE提供的物理基址相加,就可以得到實體記憶體中第一個位元組的地址了。具體關係見下面的圖:

xianxing

要注意的是CR3,PDE和PTE中的值都是實體地址!通過CR3來查詢程序頁目錄的實體地址,所以存在如下關係:CR3相當於我的電腦,PDE相當於根目錄,PTE相當於磁碟(C,D,E),就是一個索引的關係,通過索引我們就可以找到線性地址所對應的實體地址了,下面看看PDE和PTE的結構:

PTE

如果要分析記憶體保護的話,重要的幾項就是U/S標誌和W標誌。U/S定義了兩個基於頁的不同特權級:使用者和超級使用者。如果該位被清0,則PTE指向的頁(或在給定PDE之下的頁被分配為超級使用者許可權)。W標誌位用於指明一個頁或者一組頁是隻讀還是可寫,如果W位標誌被置位,表明該頁(或該頁組)可寫可讀。

但是一般情況下,我們記憶體是開啟PAE分頁的,CR4暫存器中有個PAE標誌位,如果開啟電話那麼線性地址就被分為4個部分而不是3個部分,具體見下面的圖,PAE的效果就是可以將處理器訪問的實體記憶體擴充到4GB以上,使可用的地址線達到52條:

pdpaePDPT索引就是頁目錄指標表(PDPT),共兩位,一共可以有4個數組,其中的4個數組被稱為PDPTE。當然此時分頁的暫存器和不開啟PAE情況下作用也是相同的,CR3指向PDPT的實體地址,當然此時CR3並不是儲存實體地址所有52為,因為很多位都為0,所以沒必要所有都儲存進去,尋找實體地址的過程如下:

pdpt這裡我們發現將線性地址轉換為實體地址的過程和不開啟PAE時候的情況是基本上相同的,並且如果開啟PAE分頁,那麼PDPTE,PDE和PTE都是64位的,並且標誌位幾乎完全相同,最重要的在於其實實體地址在大小上是可變的,而且根據當前處理器可用的地址線數量進行變化:

64pdpte當然重要的還是CR3暫存器,CR3暫存器儲存頁目錄表首位元組的實體地址。如果每個程序都有自己CR3副本,並且把該副本作為核心維護排程上下文的一部分,則兩個程序完全會出現擁有相同的線性地址,就像我們OD除錯的那樣,但是最終對映到的實體地址一定是不相同的!不知道在哪看到的,程序切換的時候CR3的值也發生相應的改變,這樣CPU就可以切換到不同的程序空間中了,因為每個程序都是具有自己的空間,而且相互隔離的。還有一個CR0暫存器,其中的WP(防寫)如果置為的話那麼超級程式碼也無法寫入只讀的保護區域,需要將保護位置為0才行,比如ssdt表,如果我們直接在核心中修改其地址的話肯定會藍屏的,需要將CR0的WP位變為0,下面為這些控制暫存器的結構圖:

kzjcq結構還是相當清晰的,還有要注意的是,如果開啟PAE分頁的話,CR3暫存器的位會發生相應的改變:

paecr3這裡我們發現,PDPT的地址只使用了27位,那如何表示一個52位的地址呢?其實很簡單,我們只需要將後面沒使用的位全部填充為0就可以了。在不開啟PAE分頁的情況下,PTE的最高那20位表示的為頁基址,比如0x12345,那麼後面的位我們可以看做包含著0,即0x12345[0][0][0],如果不含隱式0,這個地址有時稱作頁幀號(PNF),頁幀表示無力記憶體中的一個區域,用於存需要佔用實體記憶體的頁。

windows下每個程序都分配了一個自己專用的CR3控制暫存器的值,並且CR3控制暫存器有頁目錄20位的PFN,所以每個程序都有自己的頁目錄,相關的CR3值儲存在程序KPROESS的DirectoryTableBase這個欄位中,KPROCESS是EPROCESS的子結構,什麼是子結構呢?這裡表示KPROCESS和EPROCESS部分有重疊:

1 kd> !process 0 0
2 **** NT ACTIVE PROCESS DUMP ****
3 PROCESS 821b9830  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
4 DirBase: 00b18000  ObjectTable: e1000c98  HandleCount: 279.
5 Image: System
6
7 PROCESS 81c57760  SessionId: none  Cid: 0224    Peb: 7ffd4000  ParentCid: 0004
8 DirBase: 08c40020  ObjectTable: e13f8fb8  HandleCount:  19.
9 Image: smss.exe
10
11 PROCESS 81fe6648  SessionId: 0  Cid: 0264    Peb: 7ffd5000  ParentCid: 0224
12 DirBase: 08c40040  ObjectTable: e1524858  HandleCount: 344.
13 Image: csrss.exe
14
15 PROCESS 8211d020  SessionId: 0  Cid: 027c    Peb: 7ffd6000  ParentCid: 0224
16 DirBase: 08c40060  ObjectTable: e1516968  HandleCount: 509.
17 Image: winlogon.exe
18
19 PROCESS 820fdae0  SessionId: 0  Cid: 02ac    Peb: 7ffdb000  ParentCid: 027c
20 DirBase: 08c40080  ObjectTable: e17ea610  HandleCount: 266.
21 Image: services.exe
22
23 PROCESS 820bed78  SessionId: 0  Cid: 02c8    Peb: 7ffdf000  ParentCid: 027c
24 DirBase: 08c400c0  ObjectTable: e17eae98  HandleCount: 331.
25 Image: lsass.exe
26
27 PROCESS 81f4d770  SessionId: 0  Cid: 0368    Peb: 7ffd8000  ParentCid: 02ac
28 DirBase: 08c400e0  ObjectTable: e1a81188  HandleCount:  25.
29 Image: vmacthlp.exe
30
31 PROCESS 81cd0ca8  SessionId: 0  Cid: 0374    Peb: 7ffd9000  ParentCid: 02ac
32 DirBase: 08c40100  ObjectTable: e17509d8  HandleCount: 199.
33 Image: svchost.exe
34
35 PROCESS 81cb5a98  SessionId: 0  Cid: 03c4    Peb: 7ffdd000  ParentCid: 02ac
36 DirBase: 08c40120  ObjectTable: e1aceaa0  HandleCount: 252.
37 Image: svchost.exe
38
39 PROCESS 81c57da0  SessionId: 0  Cid: 0420    Peb: 7ffd3000  ParentCid: 02ac
40 DirBase: 08c40140  ObjectTable: e1ac9c08  HandleCount: 1137.
41 Image: svchost.exe
42
43 PROCESS 81c7e4d8  SessionId: 0  Cid: 0460    Peb: 7ffd8000  ParentCid: 02ac
44 DirBase: 08c40160  ObjectTable: e1ae2328  HandleCount:  71.
45 Image: svchost.exe
46
47 PROCESS 81cf98e0  SessionId: 0  Cid: 047c    Peb: 7ffdc000  ParentCid: 02ac
48 DirBase: 08c40180  ObjectTable: e16ed958  HandleCount: 203.
49 Image: svchost.exe
50
51 PROCESS 821001c0  SessionId: 0  Cid: 05e8    Peb: 7ffd4000  ParentCid: 05c0
52 DirBase: 08c401e0  ObjectTable: e1481e00  HandleCount: 418.
53 Image: explorer.exe
54
55 PROCESS 81fcb5e8  SessionId: 0  Cid: 0638    Peb: 7ffd9000  ParentCid: 02ac
56 DirBase: 08c40200  ObjectTable: e1524728  HandleCount: 138.
57 Image: spoolsv.exe
58
59 PROCESS 820f4da0  SessionId: 0  Cid: 0718    Peb: 7ffd6000  ParentCid: 05e8
60 DirBase: 08c401a0  ObjectTable: e17cd9a0  HandleCount: 135.
61 Image: vmtoolsd.exe
62
63 PROCESS 81f60c08  SessionId: 0  Cid: 0740    Peb: 7ffd9000  ParentCid: 05e8
64 DirBase: 08c40260  ObjectTable: e2046a38  HandleCount:  77.
65 Image: ctfmon.exe
66
67 PROCESS 81c4b650  SessionId: 0  Cid: 00b4    Peb: 7ffda000  ParentCid: 02ac
68 DirBase: 08c40220  ObjectTable: e1ff58c0  HandleCount: 275.
69 Image: vmtoolsd.exe
70
71 PROCESS 81e23a20  SessionId: 0  Cid: 040c    Peb: 7ffd3000  ParentCid: 02ac
72 DirBase: 08c40300  ObjectTable: e14b3080  HandleCount:  99.
73 Image: TPAutoConnSvc.exe
74
75 PROCESS 8202ba80  SessionId: 0  Cid: 0694    Peb: 7ffdc000  ParentCid: 02ac
76 DirBase: 08c40320  ObjectTable: e1e1a2a8  HandleCount: 107.
77 Image: alg.exe
78
79 PROCESS 81ac2da0  SessionId: 0  Cid: 04ec    Peb: 7ffdc000  ParentCid: 0420
80 DirBase: 08c40340  ObjectTable: e1d4f8f0  HandleCount:  39.
81 Image: wscntfy.exe
82
83 PROCESS 8204f410  SessionId: 0  Cid: 06ec    Peb: 7ffde000  ParentCid: 040c
84 DirBase: 08c40360  ObjectTable: e1e93e40  HandleCount:  71.
85 Image: TPAutoConnect.exe
86
87 PROCESS 81ce5650  SessionId: 0  Cid: 05b4    Peb: 7ffde000  ParentCid: 0420
88 DirBase: 08c402e0  ObjectTable: e14f6820  HandleCount: 142.
89 Image: wuauclt.exe
90
91 PROCESS 81aed818  SessionId: 0  Cid: 01b0    Peb: 7ffda000  ParentCid: 05e8
92 DirBase: 08c40240  ObjectTable: e1a680e8  HandleCount:  60.
93 Image: ?á°????a[LCG].exe
94
95 PROCESS 820f1340  SessionId: 0  Cid: 0254    Peb: 7ffd6000  ParentCid: 05e8
96 DirBase: 08c400a0  ObjectTable: e12ac518  HandleCount:  15.
97 Image: monitor.exe

這個命令顯示了系統中所有活動程序的列表,!process命令用於顯示一個或者多個程序的資訊,第一個引數一般為程序ID或者是分配給程序的EPROCESS塊的16進位制資訊。我們看看打印出的結果,DirBase這個變量表示的就是儲存在CR3暫存器中的實體地址PROCESS後面的16進位制數表示的是程序EPROCESS的線性地址,我們可以檢視一下monitor.exe這個程序的EPROCESS和KPROCESS值:

1 kd> dt nt!_EPROCESS 820f1340 
2 +0x000 Pcb              : _KPROCESS
3 +0x06c ProcessLock      : _EX_PUSH_LOCK
4 +0x070 CreateTime       : _LARGE_INTEGER 0x1d0c299`b24158da
5 +0x078 ExitTime         : _LARGE_INTEGER 0x0
6 +0x080 RundownProtect   : _EX_RUNDOWN_REF
7 +0x084 UniqueProcessId  : 0x00000254 Void
8 +0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x8055b158 - 0x81aed8a0 ]
9 +0x090 QuotaUsage       : [3] 0x848
10 +0x09c QuotaPeak        : [3] 0x870
11 +0x0a8 CommitCharge     : 0xb5
12 +0x0ac PeakVirtualSize  : 0x2168000
13 +0x0b0 VirtualSize      : 0x1a7e000
14 +0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0xf8bb6014 - 0x81aed8cc ]
15 +0x0bc DebugPort        : 0x81aee880 Void
16 +0x0c0 ExceptionPort    : 0xe13e20f8 Void
17 +0x0c4 ObjectTable      : 0xe12ac518 _HANDLE_TABLE
18 +0x0c8 Token            : _EX_FAST_REF
19 kd> dt nt!_KPROCESS 820f1340 
20 +0x000 Header           : _DISPATCHER_HEADER
21 +0x010 ProfileListHead  : _LIST_ENTRY [ 0x820f1350 - 0x820f1350 ]
22 +0x018 DirectoryTableBase : [2] 0x8c400a0
23 +0x020 LdtDescriptor    : _KGDTENTRY
24 +0x028 Int21Descriptor  : _KIDTENTRY
25 +0x030 IopmOffset       : 0x20ac
26 +0x032 Iopl             : 0 ''
27 +0x033 Unused           : 0 ''
28 +0x034 ActiveProcessors : 0
29 +0x038 KernelTime       : 0x16
30 +0x03c UserTime         : 1
31 +0x040 ReadyListHead    : _LIST_ENTRY [ 0x820f1380 - 0x820f1380 ]
32 +0x048 SwapListEntry    : _SINGLE_LIST_ENTRY
33 +0x04c VdmTrapcHandler  : (null)
34 +0x050 ThreadListHead   : _LIST_ENTRY [ 0x82033b78 - 0x82033b78 ]
35 +0x058 ProcessLock      : 0
36 +0x05c Affinity         : 1
37 +0x060 StackCount       : 1
38 +0x062 BasePriority     : 8 ''
39 +0x063 ThreadQuantum    : 6 ''
40 +0x064 AutoAlignment    : 0 ''
41 +0x065 State            : 0 ''
42 +0x066 ThreadSeed       : 0 ''
43 +0x067 DisableBoost     : 0 ''
44 +0x068 PowerState       : 0 ''
45 +0x069 DisableQuantum   : 0 ''
46 +0x06a IdealNode        : 0 ''
47 +0x06b Flags            : _KEXECUTE_OPTIONS
48 +0x06b ExecuteOptions   : 0x32 '2'

dt表示的就是檢視某個結構,最後的引數為要檢視EPROCESS或者KPROCESS的地址,之所以稱為子結構就是因為兩個結構是重合的!EPROCESS的第一個欄位就是KPROCESS,我們可以看見其中DirectoryTableBase的值就是DirBase的值。

好的,下面我們就來做幾個實驗:

實驗一

分別使用手工和windbg的方式將某個虛擬地址轉換為實體地址,使用windbg直接檢視實體記憶體中的內容,隨後直接修改實體地址中的內容,看看虛擬地址中的資料是否發生變化。同時使用除錯工具直接定位實體記憶體的方法。

首先我們檢視一下CR4暫存器的值,使用.formats命令可以檢視到其每位的內容:

1 kd> .formats cr4
2 Evaluate expression:
3 Hex:     000006f9
4 Decimal: 1785
5 Octal:   00000003371
6 Binary:  00000000 00000000 00000110 11111001
7 Chars:   ....
8 Time:    Thu Jan 01 08:29:45 1970
9 Float:   low 2.50132e-042 high 0
10 Double:  8.81907e-321

我們可以看到,這裡第5位為1,表示開啟PAE分頁,我們用OD附加我們經常使用的monitor.exe這個程式,載入sys時候經常用到,這裡入口如下:

erjinzhi

我們可以看到虛擬地址為0041F69A,這個也就是線性地址了,在windows下,那麼我們如何得到其實體地址呢?按照上面的PDPT轉換過程,首先我們找到程序頁面的實體地址:

1 kd> !process 820f1340 
2 PROCESS 820f1340  SessionId: 0  Cid: 0254    Peb: 7ffd6000  ParentCid: 05e8
3 DirBase: 08c400a0  ObjectTable: e12ac518  HandleCount:  15.
4 Image: monitor.exe
5 VadRoot 81b99200 Vads 53 Clone 0 Private 114. Modified 0. Locked 0.
6 DeviceMap e152fe18
7 Token                             e10c7568
8 ........................................................................................

1.轉換線性地址並得到其資訊
這裡我們可以看到,頁目錄指標表實體地址為08c400a0,我們來將0041F69A這個虛擬地址進行分解:(00 000000010 000011111 011010011010)
得到了線性地址的四個部分,PDPT頁目錄指標索引號為0,9位頁目錄索引為2(000000010),9位頁表索引為31(000011111),12位物理頁偏移量為1690(011010011010)。

2.定位頁目錄指標表並獲取頁目錄表物理頁地址
我們在dd命令前加上一個!表示後面的引數是實體地址,即檢視實體地址中的內容:

1 kd> !dd 08c400a0 
2 # 8c400a0 0d21e001 00000000 1ae9f001 00000000
3 # 8c400b0 12be0001 00000000 00c5d001 00000000
4 # 8c400c0 0a266001 00000000 0a267001 00000000
5 # 8c400d0 0a268001 00000000 0a265001 00000000
6 # 8c400e0 0a8b2001 00000000 0a8b3001 00000000
7 # 8c400f0 0a8b4001 00000000 0a8b1001 00000000
8 # 8c40100 0aa82001 00000000 0aa83001 00000000
9 # 8c40110 0aa44001 00000000 0aa81001 00000000

由於我們的頁目錄指標索引號為0,所以頁目錄的地址為0d21e001,但是我們只用到了其中的20位,所以頁目錄表實體地址的首地址為0d21e000