当前位置 博文首页 > KOOKNUT的博客:ProbeForRead&&ProbeForWrite(Windows内

    KOOKNUT的博客:ProbeForRead&&ProbeForWrite(Windows内

    作者:[db:作者] 时间:2021-07-03 09:21

    上篇博文提到了Ring0层对于Ring3层地址的校验方法,我将源码中的实现放到这里:
    其中判断是否越界的那个宏:
    MmUserProbeAddress,在源码中没有找到它的定义,所以用Windbg看了看。
    Windbg:
    在这里插入图片描述

    /*
    	ProbeForRead例程检查用户模式缓冲区是否实际驻留在地址空间的用户部分中,并且是否正确对齐。
    	简而言之,就是看看这块内存是否是Ring3的内存,并不检查内存是否可读
    */
    VOID
    NTAPI
    ProbeForRead(IN CONST VOID *Address,
                 IN SIZE_T Length,
                 IN ULONG Alignment)
    {
        ULONG_PTR Last, Current = (ULONG_PTR)Address;
        PAGED_CODE();
    
        /*内存粒度对齐,一般传1*/
        if (Length != 0)
        {
            ASSERT((Alignment == 1) ||
                   (Alignment == 2) ||
                   (Alignment == 4) ||
                   (Alignment == 8) ||
                   (Alignment == 16));
    
            /* 检查粒度对齐*/
            if ((Current & (Alignment - 1)) != 0)
            {
                /*抛出*/
                ExRaiseDatatypeMisalignment();
            }
            
            /*得到尾地址*/
            Last = Current + Length - 1;
            if ((Last < Current) || (Last >= (ULONG_PTR)MmUserProbeAddress))
            {
            //用户层传输的地址区间不可以大于它能访问到的最大地址
                /* 抛出*/
                ExRaiseAccessViolation();
            }
            /*其实这个函数只是检查参数地址是否越界,并没有检查地址页面是否可以读*/
            /* ProbeForRead doesn't check if memory pages are readable! */
        }
    }
    

    这个函数检查了页面是否可以写

    VOID
    NTAPI
    ProbeForWrite(IN PVOID Address,
                  IN SIZE_T Length,
                  IN ULONG Alignment)
    {
        ULONG_PTR Last, Current = (ULONG_PTR)Address;
        PAGED_CODE();
        if (Length != 0)
        {
            ASSERT((Alignment == 1) ||
                   (Alignment == 2) ||
                   (Alignment == 4) ||
                   (Alignment == 8) ||
                   (Alignment == 16));
    
            if ((Current & (Alignment - 1)) != 0)
            {
                ExRaiseDatatypeMisalignment();
            }
    
            Last = Current + Length - 1;
            if ((Last < Current) || (Last >= (ULONG_PTR)MmUserProbeAddress))
            {
                ExRaiseAccessViolation();
            }
    
    		/*之前的动作和ProbeForRead都一样*/
            /*取到当前页的其实地址之后,加上页面大小,跨过当前页*/
            Last = PAGE_ROUND_DOWN(Last) + PAGE_SIZE;
            do
            {
                /*尝试写,字节给自己赋值*/
                *(volatile CHAR*)Current = *(volatile CHAR*)Current;
                /*从当前页起始,下一页开始写*/
                Current = PAGE_ROUND_DOWN(Current) + PAGE_SIZE;
            } while (Current != Last);//直到写到最后一页退出
        }
    }
    

    “宣父犹能畏后生,丈夫未可轻年少。”–李白
    参考资料:
    Reactos源码

    cs