崩溃:
崩溃栈:
事实上只要有这么些就ok了:
不难看出来是这一句触发了崩溃:
在没有细看分析之前,大致就能猜出来是啥原因了:
1、 由上层JS解析器开始解析脚本,请看frame 17 - 16。
2、脚本解析成功,修改该元素内容为'z',元素innerHTML改变导致CFastDOM::CHTMLElement接收到了一个Trampoline_Set_innerHTML。请看frame 7 - 6。
3、Range的解析中试图向Range里面加入一个Node。
4、 也就是将A插入HEAD中间的这步:
5、
在操作对Range内数据移动时出错。
=================================
背景介绍:
1、TreePos
也即指向HTML Tree中的某个位置。
2、TreePosGap
指向两个TreePos中间,用来插入元素用的,可以想成人为的制造了一个Gap,但是TreePosGap并不是HTML Tree的一部分。
IE11的实现原型(伪代码,所以不要在意里面有时候会少了一些东西,eg:内存的分配过程):
=======================
3、调试过程:
很简单,集中在错误最后几层即可知道为啥崩了。
下短点的时候偶尔会有一些阻碍,比如
人生就是这么精彩,改为bp MSHTML!CDoc::InsertElement+0x65 即可。
重启IE11。找到tab进程,实在找不到就自己把IE设置成单进程模式吧。
调之前仔细看看是不是触发bug的那个call哦。
确认之后,看看传来的参数:
CDoc::InsertElement的原型是:
对应一下,第一个参数:
看,第一个参数是指向CAnchorElement,也就是我们的那个锚。当然CAnchorElement是派生自CElement的,所以没问题,就是它了。
dwFlags暂且不用管,是传递给InsertElementInternal的时候用的。显而易见的是这里传递了两个空的CMarkupPointer*进来。但是很不幸的是:没有校验空指针。
为了追查责任,到上一层看看。
看来eax的走向很重要啊,看看ebp-60 和 ebp-a8是怎么弄出来的。
之前确实看到有操作这两个变量的,不过最要紧的是先找到函数开头在哪儿。
看来又是这套:
获取了Anchor的Doc,然后依此生成一个CMarkupPointer,再依此生成两个CMarkupPointer,依次指示pPointerStart和pPointerEnd,可惜这个时候网页内容已经释放,这俩Pointer指向的位置变成了NULL,最后在InsertElement的时候,IE又没做有效性检查,逐层向下传,终于有一层解开了CMarkupPointer,在对CMarkupPointer指向节点的属性做判断时,导致空指针解引用崩溃。