虽然之前就知道这个两个函数是不同的,但是由于代码功能也没什么异常所以一直没太管。
前段时间扫描程序面对一个使用了新版插件的调试器无法进行内存读取,我一开始以为是被自我保护了,但是看看返回的错误码,并不是获取进程失败,而是读取的内存地址不存在。
一步一步跟下来,发现是在校验被读取地址范围的有效性时出了问题,我是用MmIsAddressVaild()做的校验,但是被判断的地址范围其实是属于Ring3层的。绝大部分时候没有问题,但是这次就有了问题。
看过msdn和wrk后,注意到MmIsAddressVaild()不仅判断内存地址是否可读,还要判断该地址是否会引起页面错误,也就是说访问该地址是否会引起内存管理器进行换页操作。在nt内核下,如果IRQL处于Dispatch级别以上,那么引发换页操作的结果是系统崩溃BSOD。但是如果IRQL是在PASS级别,那么换页当然没问题,而且如果产生内存访问异常,只要捕获并处理了异常,那么系统本身是不会受任何影响的。ProbeForRead()本身只是检测了对齐数值和内存区间是否越过用户所能访问的最高地址顶端,其他并没有多做判断。因此只要再外面使用try-except捕获异常(msdn上也明确的说明了要捕获异常,因为ProbeForRead()本身失败的话会抛出异常)就可以了。
修改后目前正常,正在测试中,:-)
虽然我对ProbeForRead()中仅仅做了对齐数值和是否越过用户顶端内存的判断,但是由于外部有异常捕获,因此没有任何问题,当然,这是IRQL为PASS级别时,如果IRQL一旦处于Dispatch级别,那么死定了……
:-)
转自:[url]http://yukei.blog.163.com/blog/static/11258770320104455523731/[/url]
__try
{
ProbeForRead( InputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
ProbeForWrite( OutputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
IoStatus->Status = GetExceptionCode();
break;
}
前段时间扫描程序面对一个使用了新版插件的调试器无法进行内存读取,我一开始以为是被自我保护了,但是看看返回的错误码,并不是获取进程失败,而是读取的内存地址不存在。
一步一步跟下来,发现是在校验被读取地址范围的有效性时出了问题,我是用MmIsAddressVaild()做的校验,但是被判断的地址范围其实是属于Ring3层的。绝大部分时候没有问题,但是这次就有了问题。
看过msdn和wrk后,注意到MmIsAddressVaild()不仅判断内存地址是否可读,还要判断该地址是否会引起页面错误,也就是说访问该地址是否会引起内存管理器进行换页操作。在nt内核下,如果IRQL处于Dispatch级别以上,那么引发换页操作的结果是系统崩溃BSOD。但是如果IRQL是在PASS级别,那么换页当然没问题,而且如果产生内存访问异常,只要捕获并处理了异常,那么系统本身是不会受任何影响的。ProbeForRead()本身只是检测了对齐数值和内存区间是否越过用户所能访问的最高地址顶端,其他并没有多做判断。因此只要再外面使用try-except捕获异常(msdn上也明确的说明了要捕获异常,因为ProbeForRead()本身失败的话会抛出异常)就可以了。
修改后目前正常,正在测试中,:-)
虽然我对ProbeForRead()中仅仅做了对齐数值和是否越过用户顶端内存的判断,但是由于外部有异常捕获,因此没有任何问题,当然,这是IRQL为PASS级别时,如果IRQL一旦处于Dispatch级别,那么死定了……
:-)
转自:[url]http://yukei.blog.163.com/blog/static/11258770320104455523731/[/url]
__try
{
ProbeForRead( InputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
ProbeForWrite( OutputBuffer, sizeof( ULONG ), sizeof( ULONG ) );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
IoStatus->Status = GetExceptionCode();
break;
}