如何验证一个地址可否使用—— MmIsAddressValid函数分析

  又是一篇内核函数分析的博文,我个人觉得Windows的内核是最好的老师,当你想实现一个功能之前可以看看Windows内核是怎么做的,说不定就有灵感呢:)

  首先看下官方的注释说明:

/*++

Routine Description:

    For a given virtual address this function returns TRUE if no page fault
    will occur for a read operation on the address, FALSE otherwise.

    Note that after this routine was called, if appropriate locks are not
    held, a non-faulting address could fault.

Arguments:

    VirtualAddress - Supplies the virtual address to check.

Return Value:

    TRUE if no page fault would be generated reading the virtual address,
    FALSE otherwise.

Environment:

    Kernel mode.

--*/

  WDK文档中给出的功能描述是这样的:The MmIsAddressValid routine checks whether a page fault will occur for a read or write operation at a given virtual address.根据描述来看这个函数的功能只是去检查读写操作会不会触发一个页错误,但是作为一个常用函数,我们常常用这个函数来检查地址合不合法,这次就在源码里看下具体的流程,主要目的是搞清楚这个函数是怎么判断一个函数会不会触发页错误的。

 1 BOOLEAN
 2 MiIsAddressValid (
 3     IN PVOID VirtualAddress,
 4     IN LOGICAL UseForceIfPossible
 5     )
 6 {
 7     PMMPTE PointerPte;
 8
 9
10     //
11     // If the address is not canonical then return FALSE as the caller (which
12     // may be the kernel debugger) is not expecting to get an unimplemented
13     // address bit fault.
14     //
15
16     if (MI_RESERVED_BITS_CANONICAL(VirtualAddress) == FALSE) {
17         return FALSE;
18     }
19
20
21
22
23     PointerPte = MiGetPdeAddress (VirtualAddress);
24     if (PointerPte->u.Hard.Valid == 0) {
25         return FALSE;
26     }
27
28     if (MI_PDE_MAPS_LARGE_PAGE (PointerPte)) {
29         return TRUE;
30     }
31
32     PointerPte = MiGetPteAddress (VirtualAddress);
33     if (PointerPte->u.Hard.Valid == 0) {
34         return FALSE;
35     }
36
37     //
38     // Make sure we‘re not treating a page directory as a page table here for
39     // the case where the page directory is mapping a large page.  This is
40     // because the large page bit is valid in PDE formats, but reserved in
41     // PTE formats and will cause a trap.  A virtual address like c0200000 (on
42     // x86) triggers this case.
43     //
44
45     if (MI_PDE_MAPS_LARGE_PAGE (PointerPte)) {
46         return FALSE;
47     }
48
49     return TRUE;
50 }

代码出人意外的简单,很明显,这是利用了分页机制去查询。先查下页目录项是否为空,然后再看一下页表项是否为空。至于28、29行应该是判断是不是直接使用PDE作为一级表吧,但是现在应该没有这么用的吧。

 if (MI_PDE_MAPS_LARGE_PAGE (PointerPte))
{
        return TRUE;
 }

如上就是一个判断。

而MiGetPdeAddress和MiGetPteAddress 其实是两个宏,这个宏我们也可以拿来用。

#define MiGetPdeAddress(va)  \
    ((PMMPTE)(((((ULONG_PTR)(va) & VIRTUAL_ADDRESS_MASK) >> PDI_SHIFT) << PTE_SHIFT) + PDE_BASE))
#define MiGetPteAddress(va) \
    ((PMMPTE)(((((ULONG_PTR)(va) & VIRTUAL_ADDRESS_MASK) >> PTI_SHIFT) << PTE_SHIFT) + PTE_BASE))
#define VIRTUAL_ADDRESS_BITS 48
#define VIRTUAL_ADDRESS_MASK ((((ULONG_PTR)1) << VIRTUAL_ADDRESS_BITS) - 1)

注意,每个进程都有自己的进程页表和页目录但是内核在分配一个进程的地址空间时会把PD给复制一份,以便于访问。

时间: 2024-12-22 07:54:17

如何验证一个地址可否使用—— MmIsAddressValid函数分析的相关文章

如何验证一个地址可否使用——MmIsAddressValid函数分析

又是一篇内核函数分析的博文,我个人觉得Windows的内核是最好的老师,当你想实现一个功能之前可以看看Windows内核是怎么做的,说不定就有灵感呢:) 首先看下官方的注释说明: /*++ Routine Description: For a given virtual address this function returns TRUE if no page fault will occur for a read operation on the address, FALSE otherwis

Android正则表达式验证邮箱地址

1 // 邮箱有效性验证 2 Pattern pattern = Pattern 3 .compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"); 4 Matcher mc = 5 pattern.matcher(RegistMail.getText().toString().trim()); 其中RegistMail为一个EditText控件,用来处理用户的邮箱输入. Android正则表达式验证邮箱地址,布布扣,bu

类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)

原理分析 当调用一个虚函数时, 编译器生成的代码会调用 虚表地址[0](param1, param2)这样的函数. 已经不是在调用函数名了. 当我们将虚表地址[n]中的函数实现改为另外的函数, 虚函数的实现就由我们来控制了. 实验 根据虚表原理, 实验一下修改自己程序的虚函数表项地址. 使编译器生成的代码执行一个虚函数A时, 执行的是我们自己定义的非虚函数B. 知识点 * 使用union赋值, 绕过编译器函数与变量强转赋值的限制 * 类成员函数指针的执行 * 修改和恢复自己的代码段属性 * 虚函

.net开发微信公众号(2)-验证服务器地址

验证服务器地址 上一篇我们说了如何开启开发者模式,填写了接收微信推送消息的URL,这一篇我们说下如何验证URL,只有验证完成了,URL才能正式启用. 上面这些是微信公众平台开发文档里说的验证方法,非常清楚,小伙伴们一看就能明白.微信只给出了PHP的代码示例.杯具. 我们就把它翻译成.net的,哈哈. 1.新建一个解决方案,起一个MVC4的项目,如下图.这里是我建好的一个解决方案,在这里简单介绍一下. WechatService:画红框的项目,是一个MVC4的项目,接收微信发来的消息以及提供了一些

C++11标准 STL正则表达式 验证电子邮件地址

转自:http://www.cnblogs.com/yejianfei/archive/2012/10/07/2713715.html 我们最经常遇到的验证,就是电子邮件地址验证.网站上常见.各种网页脚本也都常用“正则表达式”(regular expression)对我们输入的电子邮件地址进行验证,判断是否合法.有的还能分解出用户名和域名.现在用C++语言实现一下电子邮件地址验证程序,用的是C++ 11标准新增加的STL正则表达式. 源代码如下,该代码已在Visual Studio 2010上验

VBA 一个find方法的增强函数

'本函数是一个find方法的增强函数,结合FindNext和FindPrevious方法,可以返回一组符合条件的单元格的集合: '本函数返回一个Collection对象,里面储存了找到的单元格: '本函数有两个必选参数: ' 1.SearchRange 用来存放需要查找的区域: ' 2.FindWhat用来存放需要查找的值; '其余参数都是可选参数,与Find方法参数相同: '无论是否查找到单元格,都会返回一个collection对象: '我们用Collection.Count=0,来判断,没有

如何验证 Email 地址:SMTP 协议入门教程

Email 是最常用的用户识别手段. 开发者常常需要验证邮箱的真实性.一般的方法是,注册时向该邮箱发出一封验证邮件,要求用户点击邮件里面的链接. 但是很多时候(比如要搞邮件营销时),拿到的是成千上万现成的 Email 地址,不可能通过回复确认真实性,这时该怎么办呢? 答案就是使用 SMTP 协议.本文将介绍如何通过该协议验证邮箱的真假. 另外,结尾处还有一则移动端 H5 开发的培训消息,欢迎关注. 一.SMTP 协议简介 SMTP 是"简单邮件传输协议"(Simple Mail Tra

[原创]Delphi FreeAndNil 是一个过程,并不是函数

Delphi FreeAndNil 是一个过程,并不是函数,看源代码就知道,它的主要作用是清空并释放对象 procedure FreeAndNil(var Obj); var Temp: TObject; begin Temp := TObject(Obj); Pointer(Obj) := nil; Temp.Free; end; 看代码的执行顺序,先置空,再释放 置空  清空指针指向内存的地址. 释放 释放实例占用的所有资源.Free后,指针不能再使用 更新时间:2019.12.27 来源于

《Effective C 》资源管理:条款25--考虑写出一个不抛出异常的swap函数

条款25考虑写出一个不抛出异常的swap函数 条款25:考虑写出一个不抛出异常的swap函数 swap是STL中的标准函数,用于交换两个对象的数值.后来swap成为异常安全编程(exception-safe programming,条款29)的脊柱,也是实现自我赋值(条款11)的一个常见机制.swap的实现如下: namespace std{ template<typename T> void swap(T& a, T& b) { T temp(a); a=b; b=temp;