绝顶技术:断点+内存映射组合的CLR超强Bug?

你见过断点+内存映射,制造了一个另类隐藏极深,强悍的BUG吗?这是一个虚拟机CLR的BUG。不同于之前所遇见的BUG这次费时最多,但是问题已然清晰。本篇来看下。,友情提示:学会本篇,你就是绝级的高手,足可笑傲当世。,1.问题说明,BUG的起因在后面,先看看问题的描述。假如说遇到这样一个问题,在某个地址(以Addr1表示)下了一个断点,程序继续运行,就会某个地方抛出一个异常,首先确认的是这段运行的代码是完全没有问题的。也就是说这个异常只会在下了断点之后,才会抛出。查看堆栈,这个异常非常清晰明了,那就是程序运行过程中某个字段(filed1)的值为0。而通过这个字段也就是field1的空值去访问field1的成员变量,自然是报了异常。,问题很简单,似乎马上就找到了异常出错的地方,也就是field1==0造成的。但为什么field1会为空?它在哪里被赋值的,导致它是空值?跟下断点有什么关系?这些都没解决。,问题一:field1在哪里被赋值的?,经过跟踪发现,field1是通过Windows API的两个函数MapViewOfFileEx,MapViewOfFile进行内存映射来赋值的。这两个内存映射函数映射了两个内存地址。,MapViewOfFileEx映射的是可读,可写,可执行的内存地址(以pRX来表示)。也即是:,MapViewOfFile映射的是可读,可写的内存地址(以pRW来表示),也即是:,当往pRW内存地址写入数值,pRX也同时写入相应的数值,这就是内存映射。这里就是field1被赋值的地方。,问题二:为什么会导致field1空值?,上面说的是,在某个地址也就是上面说的Addr1这个地方下了一个断点,跟踪发现,如果不在Addr1处下断点,那么field1不等于0,也就不会报异常,如果在Addr1处下断点,那么field1等于0,导致了异常的发生。,这个BUG很诡异,难道是断点造成的?,继续跟踪发现,如果在离Addr1偏移量很远的地址下断点,则不会导致了field1==0,如果在Addr1地址上下偏移的地方下断点(也就是偏移比较近的位置),则会导致field1等于0。难道Addr1地址的上下偏移范围跟field1有一定的关联?
继续跟踪发现,field的值在Addr1地址的后面,它的值本身也是一个地址。每块内存都有一个起始地址,姑且叫Base。那么filed,Addr1,Base的组成如下图所示:,图片图片,可以看到Addr1和field1的起始地址都是Base,而Base则是被MapViewOfFileEx Windows API内存映射的起始地址。Addr1则是被映射的这块内存里面的某个函数中的某个地址。这里假如说它是程序入口Main函数的函数头地址,也可以是Main函数中间的某个地址。如下图:,图片图片,因为实际上在Addr1处下了断点,也即是在被MapViewOfFileEx映射的内存地址里面下了断点。在内存映射里面下了断点,就会导致了通过MapViewOfFile映射的内存pRW赋值的时候,pRX会被赋值不上的情况。,pRX和pRW如下图所示:,图片图片,如果把这个断点,下在MapViewOfFileEx映射的内存范围之外,则不会存在赋值不上的情况。,这里可以确定的就是,在内存映射的范围内下断点,断点会干扰内存映射范围内的数值。,2.检测上面结论是否正确,上面只是问题的分析,如果想要检验上面所述BUG问题是否正确。则需要代码加以辅助证明。,下面是一段内存映射的代码:,以上例子,进行了一个内存模拟映射。通过以上例子,观察发现。当在pRX所在地址范围内下断点,则会导致当往pRW里面赋值的时候,pRX赋值不上的情况,如下pRX地址处汇编代码:,这里来到了pRX的地址00007ff739180000处,在pRX地址向后偏移2个字节处下断点,也即00007FF739180002。,然后在pRW地址处进行赋值,如下pRW处内存展示:,这里的pRW地址是0x000001BEE1610000。,往它的第一个八字节赋值了:0010000000000000。然后看下pRX的的内存,如下:,可以看到在被MapViewOfFileEx映射的内存范围内下断点之后,pRW的赋值并不能更改pRX的值。这就导致了开头的异常BUG。,3.代码还原,通过以上理论分析和代码分析,基本上确定了,这个BUG就是断点+内存映射造成的。如果把断点下在内存映射的范围内的某个一个地址上,则会导致内存赋值的失败。如果不下断点,或者断点不在内存映射范围内,则不存在这种情况。这应该是微软Windows内核的一个BUG。以上就是全部用户态的BUG展示了,如果想要更深一些,则需要追踪Windows内核,这个有时间再研究。,这个BUG起因于,CLR调用C#入口Main的汇编代码里面下的断点,运行到.Ctor然后报了异常。这个异常的排查过程如上所示,但是依然有疑惑。就是为啥通过VS调试C#源代码则不会报这个异常。难道VS直接运行C#源代码跟CLR调用略有不同?

文章版权声明

 1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/27709.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年6月23日
下一篇 2023年7月15日