218
京東網上商城
Windows 核心編程研究係列之二:讀取指定物理內存地址中的內容
[原創/討論]Windows核心編程研究係列之二:
讀取指定物理內存地址中的內容
關鍵字:windows內核,物理內存
大家知道在windows NT中,如果已知虛擬地址可以通過
進程頁表或者內核提供的MmGetPhysicalAddress來取得對應的
物理地址。
現在我們反過來看一下,如果已知一個物理內存地 址 (假設地址有效),如何取得物理地址中的內容呢?經過一番思考後,我發現一個方法,但我這裏先賣個關子,為什麼呢?
因為我覺得這個方法有些繁瑣。經過和csdn的各位高手討論
之後,加上本人的一共總結出3種方法,現在想和大家分享一下,
下麵不再廢話,立即進入正題J
[方法1]:使用內核提供的MmMapIoSpace函數
原來內核早就提供了很簡單的接口,就是MmMapIoSpace函數,不過在DDK文檔中看到該函數的說明如下:
PVOID MmMapIoSpace(
IN PHYSICAL_ADDRESS PhysicalAddress,
IN ULONG NumberOfBytes,
IN MEMORY_CACHING_TYPE CacheType );
它隻有3個形參,這和實際Masm32v9.0聲明的4個形參有所
不同,為了確定,我通過 IDA反匯編證實該函數確實有4個形參。經過測試,我猜測中間的ULONG NumberOfBytes參數實際由64位字節的(兩個雙字)高低兩部分組成,即在Masm32v9.0中有:
PVOID MmMapIoSpace(
IN PHYSICAL_ADDRESS PhysicalAddress,
IN ULONG NumberOfBytesHighPart,
IN ULONG NumberOfBytesLowPart,
IN MEMORY_CACHING_TYPE CacheType );
這樣的話調用就很簡單了:
invoke MmMapIoSpace,_phyaddr,0,4,MmNonCached
若成功該函數返回影射後的虛擬地址,否則返回NULL。這樣就可以間接達到讀取物理地址中內容的第一個方法。但可能我對參數功能的猜測也有錯誤,如果有誤請指出。不勝感謝。
[方法2]:通過操作物理內存對象來完成到虛擬地址的影射
簡單的說這個方法的基本思想如下:
a :取得本進程句柄;
b :取得物理內存對象的句柄;
c :將物理內存地址影射到進程的虛擬地址空間中。
下麵是我從C改寫後的匯編關鍵代碼:
;***************************************************************************
GetValByPhyAddr proc uses esi edi ebx _phyaddr
local hpmem:dword
local hp:dword
local dwsize:dword
local dwbase:dword
local dwret:dword
local cid:CLIENT_ID
local stLR:LARGE_INTEGER
local ObjAttrsMem:OBJECT_ATTRIBUTES
local ObjAttrsP:OBJECT_ATTRIBUTES
mov dwbase,0
mov dwsize,4
push _phyaddr
pop stLR.LowPart
mov stLR.HighPart,0
invoke PsGetCurrentProcessId
mov cid.UniqueProcess,eax
mov cid.UniqueThread,0
invoke InitObjAttrs,addr ObjAttrsP,0
;取得本進程句柄
Invoke ZwOpenProcess,addr hp,PROCESS_DUP_HANDLE,/
addr ObjAttrsP,addr cid
invoke InitObjAttrs,addr ObjAttrsMem,addr devphymem
;取得物理對象的句柄
Invoke ZwOpenSection,addr hpmem,/
SECTION_MAP_READ or SECTION_MAP_WRITE,/
addr ObjAttrsMem
;將物理內存地址影射到進程的虛擬地址空間中
invoke ZwMapViewOfSection,hpmem,hp,addr dwbase,/
0,4,addr stLR,addr dwsize,1,/
MEM_TOP_DOWN,PAGE_READWRITE
mov edx,dwbase
mov eax,[edx] ;取得影射後對應虛擬地址中的內容
mov dwret,eax
;釋放資源
invoke ZwUnmapViewOfSection,hp,addr dwbase
invoke ZwClose,hpmem
invoke ZwClose,hp
mov eax,dwret
ret
GetValByPhyAddr endp
;***************************************************************************
[方法3]:關閉CPU分頁機製達到直接讀取物理地址的目的
第3種方法就是我前麵賣關子的方法J ,這種方法不依賴於OS,了解保護模式的朋友都知道:進入保護模式後如果關閉分頁機製則CPU就會將線形地址直接解釋成物理地址。
關閉分頁很簡單,隻需3行匯編代碼:
mov eax,cr0
and eax,7fffffffh
mov cr0,eax
打開分頁同樣很簡單:
mov eax,cr0
oreax,80000000h
mov cr0,eax
既然這麼簡單,為什麼我在前麵說這個方法有些繁瑣呢?原因之一是如果僅僅關閉分頁就會使原來依賴於分頁的windows變得一團糟,馬上會發生著名的藍屏現象,不爽哦!L
那要怎麼做呢?經過我的嚐試,發現有3點非常重要:
1 :要保證windows處在較高的IRQL級別,防止關閉分頁後
被打斷;
2 :要將處理分頁、讀取物理地址的指令塊放到線形地址等於
物理地址的頁中;
3 :要做好數據的恢複工作。
第1點和第3點都容易理解,可能有人會疑問第2點,為什麼要放到線形地址等於物理地址的空間中呢?原因其實也很簡單,就是一旦關閉分頁,所有地址都將以物理地址來解釋,如果先前的
虛擬地址和物理地址不相同那麼很可能就會發生執行錯誤指令流的問題。(當然也可以不相同,隻要你能保證關分頁後能執行正確指令即可。)
那麼如何將物理地址和虛擬地址設置為相同呢?我的方法是將虛擬地址對應地頁表PTE中的物理頁基址改為包容即可。
我隨機選擇了一個虛擬地址 0x1c00000 ,為了簡單它正好是頁麵的一個基址。下麵我構造了它的PTE使得其中的物理也幀指向它:
mov edx,0ffdf0000h
mov eax,[edx]
mov tmp0,eax ; 保存原始值
;mov dword ptr [edx],1c00027h
mov dword ptr [edx],1c00007h
;初始化PTE
mov edx,0c03ff7c0h
mov eax,[edx]
and eax,0fffff000h
or eax,7h
mov edx,0c030001ch
mov ebx,[edx]
mov tmp1,ebx ; 保存原始值
mov dword ptr [edx],eax
;刷新TLB
mov eax,cr3
mov cr3,eax
最後兩句指令在我前一篇: <<Windows內核編程研究一:改變進程PTE>>中有過說明,這裏就不解釋了。
結束了PTE的設置後,下麵就是將指令塊拷貝到指定位置,代碼如下:
mov ecx,slen
mov esi,subasm
mov edi,1c00000h
cld
rep movsb
而subasm指令塊完成的就是實際設置分頁和讀取物理地址內容的工作,如下:
subasm:
mov eax,cr0
and eax,7fffffffh ;關閉分頁機製
mov cr0,eax
jmp SHORT PageC
PageC:
mov edx,[ecx]
mov eax,cr0
or eax,80000000h ;打開分頁機製
mov cr0,eax
jmp SHORT PageO
PageO:
jmp edi
slen = $ - subasm
借用一句話作為結尾“…一切都那麼清楚明白,然而卻無法透徹理解。理解就是改變,就是超越自己已有的認識。”
感謝CSDN熱心朋友提供的方法和意見,給我很好的啟發。
末尾,感謝各位觀賞,如有誤謬之處請不吝指出,不勝感謝。希望有同好的朋友能夠一起討論,一起交流。
Email: 19796174@qq.com
QQ: 19796174
最後“預告”一下我的第3篇文章:
<<Windows核心編程研究係列之三:突破windows共享文件打開限製>>
主要內容:
很多用No_Share打開的文件,正常情況下不能在其他進程用
CreateFile打開,或者是僅僅用FILE_SHARE_READ打開的
文件不能再以寫入目而打開,那麼如何繞過windows的這種保護呢?敬請期待。J
感謝觀賞,拜拜!
Mydo(侯佩|hopy|福信克|FreeThink)
2006年12月19日晚於合肥溫馨的家中J
最後更新:2017-04-02 00:00:28