閱讀300 返回首頁    go 技術社區[雲棲]


Windows 核心編程研究係列之一(-改變進程PTE屬性-)[已補完]

 

Windows 核心編程研究係列之一

-改 變 進 程 PTE 屬性-

         這是我研究windows 核心編程的第一篇正式文章,之所以叫核心編程而不叫內核編程,是我覺得從字麵上來看核心(core)比內核(kernel)更靠近windows中心,當然隻是偶本人的看法的拉。

         我們知道在 win NT 中,係統把每個進程的虛擬4G空間分為兩大部份,低2G歸用戶所有,高2G歸係統所有。用戶不得訪問係統的空間,連讀都不行,更別說寫了!低2G的用戶空間也並不是都能寫入的。現在我要說一個特殊的區域:在每個進程虛擬地址 0x7ffe0000 開始的一段空間稱為 USER_SHARED 區域,他和虛擬地址空間0xffdf0000指向同一物理地址空間,這片區域的長度為 0x2d8。所以不同進程的這一虛擬地址空間被映射到同一個物理地址空間,如果可以寫入該區域就可以實現係統中所有進程共享數據的目的,注意是所有進程!但可惜的是雖然0x7ffe0000在低2G的空間,歸用戶所有,但它隻能讀不能寫,寫他的後果如圖1所示。

                                                   

                                                     1

很不爽哦!我前不久在網上看到一篇可以讀寫物理內存的文章,其實現的思想是:

1 通過係統特權API取得 System Object PhysicalMemory 的寫權限;

2 通過分析 MmGetPhysicalAddress寫出其在 ring3 下的偽代碼,從而得到任意虛擬地址映射的實際物理地址

3 寫入物理地址

我用匯編重寫後好像不能實現其目的,編譯運行原來VC++代碼也不成功。但據作者說他可以運行成功。因為這篇文章寫得較早,我懷疑是 windows 在後來的PACK中關閉了這個通道。但隻是猜測,也不排除還有我未考慮到的因素,希望搞成功過的朋友談談具體的過程。

         我實現的是另一種方法,其主要思想是:

1 找到該虛擬地址在進程頁表中的位置;

2 將對應頁表項第2位改為1

每個進程的頁表被映射到其虛擬地址空間的 0xc0000000 0xc003fffff 空間中。經過簡單的計算後得到其頁表項位置為:

0xc0000000 + 0x1FFF80 = 0xC01FFF80 察看其內容如圖2所示,其最低3位決定了它存在,屬於用戶區域,但是隻讀不能寫入!

                                      

                                        2

我們下麵要做的也非常簡單,就是打開其寫入標誌,使其可寫。

就是將 0x25 改為 0x27 。關鍵代碼如下:

mov   ebx,0c01fff80h

     mov   edx,[ebx]

     mov   al,27h

     mov   byte ptr [ebx],al

     mov   eax,cr3

     mov   cr3,eax

通過一個 kernel driver 注入,修改成功。下麵就是在ring3中修改 0x7ffe0080的內容,以下是代碼:

mov   ebx,7ffe0080h

     mov   eax,12345678h

     mov   dword ptr [ebx],eax

執行結果可以用任意ring3調試器來證實,就是在調試任意程序時察看其進程地址0x7ffe0080都會發現其值被改為 0x12345678。圖3是驗證情況。

                                                       

3

到這裏貌似可以告一段落了,但是還有更值得挖掘的東西,那就是在ring3種直接改寫高2GB的係統內核區域,下麵馬上將給出的是就是關於改寫0x80000000 0xffffffff 內核區域的方法,敬請期待。

OK,讓我們進入這一部分,其實有了上麵的基礎,這個就變得輕而易舉了。但是要注意的是:

 

1 要改寫的 0x80000000 0xffffffff 區域屬於內核,可能

 

搞不要就要ODBS;

 

2 要修改的不單單是 PTE 還有頁目錄表項

 

 

現在我們選擇寫入的位置,上麵說過的 0xffdf0000 ~ 0xffdf02d8 是個不錯的選擇,因為除了開頭一段最好別碰以外,後麵都是“自由”區域,寫入因該沒什麼問題。我們首先

4

 

要確定修改的頁目錄項的位置,它可以通過 0xc03000000 + 0xffc 算出等於 0xc0300ffc,如圖4,將63改為67。然後再找到

 

頁表項的位置,通過 0xc0000000 + 0x3FF7C0 = 0xC03FF7C0,同樣的要將63改為67,關鍵代碼為:

 

 

mov   ebx,0C0300FFCh

 

     mov   edx,[ebx]

 

     mov   al,67h

 

     mov   byte ptr [ebx],al

 

     mov   eax,cr3

 

     mov   cr3,eax

 

     mov   ebx,0C03FF7C0h

 

     mov   edx,[ebx]

 

     mov   al,67h

 

     mov   byte ptr [ebx],al

 

     mov   edx,[ebx]

 

     mov   eax,cr3

 

     mov   cr3,eax

 

    

 

Thats All Right !!!,讓我們看下實際的效果,如圖5所示。

5

 

 

至此我們已經成功地在ring3中修改了用戶區隻讀區域,和位於內核的“不可見”區域。嗬嗬,西遊記至此終~真的終麼?當然隻是joke了,嗬嗬。

 

 

 

最後更新:2017-04-02 00:00:27

  上一篇:go 淺析拷貝構造函數
  下一篇:go Ant and Flex 用Ant編譯MXML文件 - 螞蟻咬斷鬆緊帶(^_^)