POC代码&crash
POC
crash
这里的一个小技巧是,使用js里的三角函数公式插入原POC文件,使调试能够以一句html语句为粒度进行调试。具体做法是
bp jscript!sin
bp jscript!cos
bp jscript!tan
每次命中断点说明即将调试下一句代码
分析
从第一行开始逐语句进行分析
document.createElement("sup");
参考freebuf分析的原文说
在CDocument::createElement下断,获取ld_0和ld_1的element对象地址。
理解一下在这里下断点的原因是:document是一个类,在IE内部表示为CDocument
,再根据函数名,顾名思义很容易理解在CDocument::createElement
下断点。然而,给出的图却是断在了mshtml!CElement::CElement
函数,从这里得到了element对象地址。这该怎么理解呢?只能理解为在CDocument::createElement
函数内部又调用了mshtml!CElement::CElement
函数。根据原文贴图的堆栈调用可以验证上述猜想。
根据上图,断在682a482d
,那么edi就是新创建的element的地址,为什么edi是新创建的element的地址?先看代码
mshtml!CElement::CElement:
682a480f 8bff mov edi,edi
682a4811 55 push ebp
682a4812 8bec mov ebp,esp
682a4814 53 push ebx
682a4815 8b5d0c mov ebx,dword ptr [ebp+0Ch]
682a4818 56 push esi
682a4819 57 push edi
682a481a 8bf8 mov edi,eax
682a481c 8bf7 mov esi,edi
682a481e e80c300800 call mshtml!CBase::CBase (6832782f)
682a4823 83672400 and dword ptr [edi+24h],0
682a4827 c707b0541668 mov dword ptr [edi],offset mshtml!CElement::`vftable' (681654b0)
682a482d 8b03 mov eax,dword ptr [ebx]
想了一下原因,在地址682a4827,把CElement类的虚函数指针赋值给了[edi]
,根据C++类的相关概念,那么不就说明了这是一个element类在初始化吗?想想当前函数名称CElement::CElement
,这样我们就想通了为什么在这儿下断点edi就指向我们创建的element。
同时也得出一点心得:element在IE中是一个独立的类Celement
,Cdocument
类创建一个element,也就是实例化了一个Celement对象。
在我的调试中
id0 = 070a7fd8
id1 = 05bd1fc8
- appendChild分析
document.body.appendChild(id_0);
document.body.appendChild(id_1);
在CElement::appendChild
下断。推测这样下断点的原因是因为document.body也是属于CElement类。CElement::appendChild
函数递归调用了CTreeNode::CTreeNode
函数,返回值是id0对应的CTreeNode
对象
堆栈回溯
0:005> kb 8
ChildEBP RetAddr Args to Child
0460e0f8 672d0d02 06e63fb0 00000000 05c2af30 mshtml!CTreeNode::CTreeNode
0460e198 672b1c01 05c2af30 070a7fd8 0460e1bc mshtml!CMarkup::InsertElementInternal+0x23d
0460e1d4 672b1b36 070a7fd8 00000000 00000001 mshtml!CDoc::InsertElement+0x8a
0460e268 672b2222 00000000 0460e284 0460e3b8 mshtml!CCommentElement::`scalar deleting destructor'+0x23e
0460e2d0 672b2148 08e5bfd8 00000000 0460e30c mshtml!CElement::InsertBeforeHelper+0xd1
0460e2ec 672b20fe 06cdcfd0 08e5bfd8 00000001 mshtml!CElement::insertBefore+0x3c
0460e32c 672b1436 06cdcfd0 08e5bfd8 0460e3b8 mshtml!CElement::appendChild+0x3a //----> CElement::appendChild
id0对应的CTreeNode=(05de4fb0),第一个成员就是id0的实例化对象
0:005> dc eax
05de4fb0 070a7fd8 06e63fb0 ffff0060 ffffffff .....?..`.......
05de4fc0 00000000 00000000 00000000 00000000 ................
id1 CTreeNode(08eeafb0)
0:005> dc eax
08eeafb0 05bd1fc8 06e63fb0 ffff0075 ffffffff .....?..u.......
08eeafc0 00000000 00000000 00000000 00000000 ................
- 什么又是
CTreeNode
对象?
表示DOM中element之间的父子关系的树。appendChild
将元素插入了DOM树中。
- 再回头看element
id0 element
0:005> dc 070a7fd8
070a7fd8 671b70e0 00000002 00000008 00000000 .p.g............
070a7fe8 05d1af00 05de4fb0(id0 CTreeNode) 00000060 00010200 .....O..`.......
id1 element
05bd1fc8 671dc2e8 00000002 00000008 06d7afe8 ...g............
05bd1fd8 05d1aed0 08eeafb0(id1 CTreeNode) 00000075 00010200 ........u.......
id0,id1,0x14偏移处05de4fb0
,08eeafb0
是对应的CTreeNode
- applyElement分析
id_1.applyElement(id_0);
类似于document.body.appendChild
,也是改变element之间的父子关系。查找文档
applyElement方法
语法:
object.applyElement ( oElement , sWhere )
参数:
oElement : 必选项。对象(Element)。要被添加的对象。
sWhere : 可选项。字符串(String)。(outside:默认值)。将 oElement 添加为 object 的父对象。
在mshtml!CElement::applyElement
下断,在jscript!cos
断下后继续运行,断在了applyElement
,如图看到和appendChild
的堆栈回溯差不多,new了一个CTreeNode
。然而这个CTreeNode的第一个成员指向了id0的element。
调试截图
再回头看之前的id0,id1的CTreeNode。发现id0的CTreeNode已经release掉了。id1没有realse。
那么也就是说id0换了新的CTreeNode(07079fb0)。
根据说明,现在id0是id1的树的父节点。对比前后的图,可以发现CTreeNode偏移0x4处,是指向父节点CTreeNode的指针。因为id1的CTreeNode现在指向id1的CTreeNode。进步一说明之前id0,id1偏移0x4处的06e63fb0就是body元素的CTreeNode。
接下来是一个设置,ld0的onlosecapture
(失去聚焦时执行的函数),页面清空。
再下来这句id_0[‘outerText’]="";
,这个执行之后id0会从DOM树脱离下来。Id1作为子节点也会脱离DOM树。
id0,id1CTreeNode释放了
0:005> dc 07079fb0
07079fb0 ???????? ???????? ???????? ???????? ????????????????
07079fc0 ???????? ???????? ???????? ???????? ????????????????
0:005> dc 08eeafb0
07079fb0 ???????? ???????? ???????? ???????? ????????????????
07079fc0 ???????? ???????? ???????? ???????? ????????????????
此时element(备用)
0:005> dc 070a7fd8
070a7fd8 671b70e0 00000005 00000010 08ed4fe8 .p.g.........O..
070a7fe8 05d1af01 05ca9fb0 80000060 8a010200 ........`.......
070a7ff8 00000002 05c2af30 ???????? ???????? ....0...????????
070a8008 ???????? ???????? ???????? ???????? ????????????????
070a8018 ???????? ???????? ???????? ???????? ????????????????
070a8028 ???????? ???????? ???????? ???????? ????????????????
070a8038 ???????? ???????? ???????? ???????? ????????????????
070a8048 ???????? ???????? ???????? ???????? ????????????????
0:005> dc 05bd1fc8
05bd1fc8 671dc2e8 00000001 00000008 06d7afe8 ...g............
05bd1fd8 05d1aed0 00000000 80000075 80010000 ........u.......
05bd1fe8 00000002 08f86fe8 08e12ff4 00000000 .....o.../......
05bd1ff8 00000000 00000000 ???????? ???????? ........????????
05bd2008 ???????? ???????? ???????? ???????? ????????????????
05bd2018 ???????? ???????? ???????? ???????? ????????????????
05bd2028 ???????? ???????? ???????? ???????? ????????????????
05bd2038 ???????? ???????? ???????? ???????? ????????????????
- CDoc::SetMouseCapture分析
接下来,关键点
id_0.setCapture();
id_1.setCapture();
首先,先看看crash时的堆栈调用
堆栈调用显示在CDoc::PumpMessage+0x3e4
调用的CDoc::HasContainerCapture
+0x14语句中出现的error.
重新运行程序在CDoc::SetMouseCapture
函数下断,然后不断g,发现了有意思的事情。因为tan函数,可以知道,第一次id_0.setCapture();时,只断下来一次;在id_1.setCapture();时,在crash之前却断下来3次。说明2次的执行流程并不相同,第一次正常,第二次可能会有些问题所以出现了crash。并且,在第二次的执行流程中,断下来3次,根据堆栈调用的情况来看,在id_1.setCapture();函数返回之前,向下又调用了CDoc::SetMouseCapture
函数。
在IDA里看到函数CDoc::SetMouseCapture
,分析一下这个函数
CDoc::SetMouseCapture
函数的前2个参数由eax,ecx传参,根据动态调试,eax在2次断下时先后为id0,id1的element地址。在IDA中命名为有意义的形参名。
因为2次调用lpMem都是同一个地址,且eax值非空,所以都进入LABEL_33.接下来
到了这里,情况有所不同,v11的值在id0时为空,在id1时非空。在id1非空后,创建CMessage对象,进入CDoc::PumpMessage函数。其中有函数CDoc::ReleaseDetachedCaptures,这个函数再一次以eax=0为参数调用了CDoc::SetMouseCapture函数。
因为eax=0,执行
这句是清除capture,因为id1设置capture没有完成,所以此时是清除id0的capture,这样会触发id_0.onlosecapture
设置的处理语句--清空整个页面--带来的影响是会对所有element都release掉。包括CBodyelement
进入CDoc::ReleaseDetachedCaptures前
06e63fb0 是CBodyelement的CTreeNode
从CDoc::ReleaseDetachedCaptures返回后
此时好奇这个[esp+10h]=06e63fb0是怎么来的,通过下内存写断点发现是从后面的地址跳过来的,和我看到的xp的分析不太一样
然后再接着执行几步
把已经释放了的CBodyelement的CTreeNode给edi,传递给函数CDoc::HasContainerCapture。所以出现这样的crash
mshtml!CDoc::HasContainerCapture+0x14:
673c1f60 8b0f mov ecx,dword ptr [edi] ds:0023:06e63fb0=????????