[原创/讨论] Windows 核心编程研究系列之二:读取物理内存地址中的内容

大熊猫侯佩
iOS开发领域优质创作者
博客专家认证
2006-12-19 10:04:34
[原创/讨论] Windows 核心编程研究系列之二:
读取指定物理内存地址中的内容
关键字:windows内核,物理内存

大家知道在windows NT中,如果已知虚拟地址可以通过
进程页表或者内核提供的MmGetPhysicalAddress来取得对应的
物理地址。
现在我们反过来看一下,如果已知一个物理内存地 址 (假设地址有效),如何取得物理地址中的内容呢?经过一番思考后,我发现一个方法,但我这里先卖个关子,为什么呢?
因为我觉得这个方法有些繁琐。经过和csdn的各位高手讨论
之后,加上本人的一共总结出3种方法,现在想和大家分享一下,
下面不再废话,立即进入正题 

[方法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种方法就是我前面卖关子的方法  ,这种方法不依赖于OS,了解保护模式的朋友都知道:进入保护模式后如果关闭分页机制则CPU就会将线形地址直接解释成物理地址。

关闭分页很简单,只需3行汇编代码:

mov eax,cr0
and eax,7fffffffh
mov cr0,eax

打开分页同样很简单:

mov eax,cr0
or eax,80000000h
mov cr0,eax

既然这么简单,为什么我在前面说这个方法有些繁琐呢?原因之一是如果仅仅关闭分页就会使原来依赖于分页的windows变得一团糟,马上会发生著名的蓝屏现象,不爽哦!
那要怎么做呢?经过我的尝试,发现有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: kf2b@hotmail.com
Kf2b@msn.com
QQ: 411987378

最后“预告”一下我的第3篇文章:
<<Windows核心编程研究系列之三:突破windows共享文件打开限制>>

主要内容:
很多用No_Share打开的文件,正常情况下不能在其他进程用
CreateFile打开,或者是仅仅用FILE_SHARE_READ打开的
文件不能再以写入目而打开,那么如何绕过windows的这种保护呢?敬请期待。

感谢观赏,拜拜!
(特别感谢keiy,AthlonxpX86,ly_liuyang,wangk等各位朋友的
热情讨论,排名不分先后(笑))

Mydo(侯佩|hopy|福信克|FreeThink)
2006年12月19日晚于合肥温馨的家中

(备注:第1篇文章
Windows 核心编程研究系列之一(改变进程 PTE)
观赏地址:
http://community.csdn.net/Expert/topic/5124/5124747.xml?temp=.2020075

欢迎各位到本人的博客观赏彩图版:

http://blog.csdn.net/mydo/
http://hopy.blogchina.com
)

...全文
2979 82 打赏 收藏 转发到动态 举报
写回复
用AI写文章
82 条回复
切换为时间正序
请发表友善的回复…
发表回复
大熊猫侯佩 2007-01-25
  • 打赏
  • 举报
回复
up
大熊猫侯佩 2007-01-14
  • 打赏
  • 举报
回复
已发,请到汇编区观赏

http://community.csdn.net/Expert/topic/5295/5295089.xml?temp=.5842401

同样欢迎大家到我的博客观赏彩图版:

http://blog.csdn.net/mydo/
soft_biao 2007-01-14
  • 打赏
  • 举报
回复
最后“预告”一下我的第3篇文章:
<<Windows核心编程研究系列之三:突破windows共享文件打开限制>>

主要内容:
很多用No_Share打开的文件,正常情况下不能在其他进程用
CreateFile打开,或者是仅仅用FILE_SHARE_READ打开的
文件不能再以写入目而打开,那么如何绕过windows的这种保护呢?敬请期待。

我想到的方法和AthlonxpX86(一坨屎)想的第二种方法一样,直接操作硬盘数据,就根本不用理会操作系统的什么保护机制,不过这种方法有点麻烦的是文件系统不只一种,如FAT32或者NTFS等,两者差别有点大,有杀鸡用牛刀的感觉
hongqi162 2007-01-11
  • 打赏
  • 举报
回复
up
zoologist 2007-01-11
  • 打赏
  • 举报
回复
看不懂,收藏
VirtualDesktop 2007-01-01
  • 打赏
  • 举报
回复
@_@
“[方法3]:关闭CPU分页机制达到直接读取物理地址的目的”

这个方法太恐怖了!!!
longge520 2007-01-01
  • 打赏
  • 举报
回复
MARK
laowang2 2006-12-30
  • 打赏
  • 举报
回复
@_@
colorslife 2006-12-29
  • 打赏
  • 举报
回复
mark,学习
AthlonxpX86 2006-12-29
  • 打赏
  • 举报
回复
哦,明白了
blastzgd 2006-12-28
  • 打赏
  • 举报
回复
Mark.
yjgx007 2006-12-27
  • 打赏
  • 举报
回复
唉,有时间写 个操作系统吧...
qwertxp 2006-12-27
  • 打赏
  • 举报
回复
牛人~~~学习学习~
大熊猫侯佩 2006-12-27
  • 打赏
  • 举报
回复
0:

"关闭中断是操作系统在内核中实现原子操作的一种很有用的技术,可以使核心代码不被任何中断打断,你把代码的IRQL提的再高也没用,那是软件中断等级,任何的硬件中断都能打断你的代码。"

据我所知,IRQL 0-2(被动级,APC,DPL) 级是软件中断级,之上应该是硬件中断级,时钟中断
应该是硬件级吧?我将Irql提升超过时钟中断后,时钟中断无法被响应,
我将irql提升到最高的high_level后,用一个死锁,整个系统挂起。

1:
这样子改变了寻址模式,那么代码段寻址模式也被改变,相当于IP被打乱,你的代码是不是能够正常运行,我在理论上讲有点怀疑

这正是我创建虚拟地址和物理地址相等页的原因,而且我测试代码流程和我预想的一致,
顺利取回了phy addr 中的内容,并且顺利返回。
AthlonxpX86 2006-12-27
  • 打赏
  • 举报
回复
关闭中断是操作系统在内核中实现原子操作的一种很有用的技术,可以使核心代码不被任何中断打断,你把代码的IRQL提的再高也没用,那是软件中断等级,任何的硬件中断都能打断你的代码。另外我还有点疑问,你的代码
mov eax,cr0
and eax,7fffffffh
mov cr0,eax

打开分页同样很简单:

moveax,cr0
oreax,80000000h
movcr0,eax
这样子改变了寻址模式,那么代码段寻址模式也被改变,相当于IP被打乱,你的代码是不是能够正常运行,我在理论上讲有点怀疑
dongyi940333 2006-12-26
  • 打赏
  • 举报
回复
学习!努力!
大熊猫侯佩 2006-12-26
  • 打赏
  • 举报
回复
首先感谢AthlonxpX86的讨论:

0:
"所以如果在之前关闭中断,在之后打开中断就好了,这个方法我想在X86-32上应该是个不错的方法."

你是指在关分页之前先关中断,然后开分页之后再开中断是么?

1:
"这也有些问题,如果虚拟地址 0x1c00000 已经分配了内存,那么你在操作系统不知道的情况下修改隐射表,将导致内存泄露,而且比较严重哦,进程结束后都找不回丢失的内存,除非操作系统关闭.另外楼主你验证下你修改隐射表后,delete 0x1c00000看看会不会出现什么异常,如果0x1c00000没有隐射物理内存的话,那你就不能修改隐射表,而是先要创建,这就很复杂了,加上隐射表恢复应该是必要的"

我在修改后,上升到 High_Level(Irql31)级别,完成相关操作后,
马上恢复原来PTE属性,我想在这当中不会有问题。

2:
我知道的有两种方法;
打开卷设备,然后根据FAT32或者NTFS协议,可以绕开操作系统的文件系统驱动,操作磁盘文件.这是从虚拟机上学到的技巧.用这种方法可以饶开操作系统删除不能删除的病毒文件,这种方法对于作了虚拟磁盘驱动作保护的系统也没有办法
另一种更底层,有人已经有成功的东西了,就是直接给IDE发命令配合FAT32或者NTFS协议,直接饶开操作系统读写磁盘,这种风险很高,但基本上无法防范,除非做自己的硬件IDE控制器

能否给出两种方法的大致思路,我的方法好像和上面两者都不太一样。

希望继续讨论 :)
zhulei5 2006-12-26
  • 打赏
  • 举报
回复
mark
AthlonxpX86 2006-12-26
  • 打赏
  • 举报
回复
佩服楼主的钻研精神.不错
我也说点我的理解
关闭分页很简单,只需3行汇编代码:

mov eax,cr0
and eax,7fffffffh
mov cr0,eax

打开分页同样很简单:

mov eax,cr0
or eax,80000000h
mov cr0,eax

这个方法不行的原因是在打开和关闭分页的期间因为任务调度产生问题,操作系统产生主动式任务调度主要是依靠定时器中断,所以如果在之前关闭中断,在之后打开中断就好了,这个方法我想在X86-32上应该是个不错的方法.


那么如何将物理地址和虚拟地址设置为相同呢?我的方法是将虚拟地址对应地页表PTE中的物理页基址改为包容即可。
我随机选择了一个虚拟地址 0x1c00000 ,为了简单它正好是页面的一个基址。下面我构造了它的PTE使得其中的物理也帧指向它:

这也有些问题,如果虚拟地址 0x1c00000 已经分配了内存,那么你在操作系统不知道的情况下修改隐射表,将导致内存泄露,而且比较严重哦,进程结束后都找不回丢失的内存,除非操作系统关闭.另外楼主你验证下你修改隐射表后,delete 0x1c00000看看会不会出现什么异常,如果0x1c00000没有隐射物理内存的话,那你就不能修改隐射表,而是先要创建,这就很复杂了,加上隐射表恢复应该是必要的

最后“预告”一下我的第3篇文章:
<<Windows核心编程研究系列之三:突破windows共享文件打开限制>>

主要内容:
很多用No_Share打开的文件,正常情况下不能在其他进程用
CreateFile打开,或者是仅仅用FILE_SHARE_READ打开的
文件不能再以写入目而打开,那么如何绕过windows的这种保护呢?敬请期待。

我知道的有两种方法;
打开卷设备,然后根据FAT32或者NTFS协议,可以绕开操作系统的文件系统驱动,操作磁盘文件.这是从虚拟机上学到的技巧.用这种方法可以饶开操作系统删除不能删除的病毒文件,这种方法对于作了虚拟磁盘驱动作保护的系统也没有办法
另一种更底层,有人已经有成功的东西了,就是直接给IDE发命令配合FAT32或者NTFS协议,直接饶开操作系统读写磁盘,这种风险很高,但基本上无法防范,除非做自己的硬件IDE控制器
Torch009 2006-12-25
  • 打赏
  • 举报
回复
好东西,收藏。
加载更多回复(62)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧