当前位置 博文首页 > KOOKNUT的博客:ProbeForRead&&ProbeForWrite(Windows内
上篇博文提到了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源码