Internet Explorer 11 实例分析 [1]
介绍了很多Internet Explorer的函数、类的东西了,让我们实战演练一下,分析一个至2014年10月3日微软尚未修复的Internet Explorer 11中存在的空指针引用问题。
...
等5天后发布
介绍了很多Internet Explorer的函数、类的东西了,让我们实战演练一下,分析一个至2014年10月3日微软尚未修复的Internet Explorer 11中存在的空指针引用问题。
...
等5天后发布
第四章 文档的具象实现
前几个类的介绍都不是完整的,以后有需要再补充。
免责声明:本类文章全部是我的个人理解,可能存在理解错误,如有发现,敬请指正。
4.1 介绍
CDoc910
类将是我们要详细叙述的最后一个类,它可以说是网页文档的具象实现,同时,它也会贯穿在所有的类中,在分析时经常会看到许多类都关联着CDoc *pDoc这样一个成员函数,让我们看一看CDoc的真身吧。
4.2 CDoc概述
CDoc(formknl)也就是传说中的根对象(root object),对应传统的文档视图
结构的文档部分。有些像是MFC中的CDoc,事实上Internet Explorer中也确实还有一个CView类。CDoc作为IHTMLDocument2/3接口的一个具体的实现,它自身封装了许多与Markup有关的内容,例如创建、增删Markup等等。对Markup具体的介绍请见完全解析Internet Explorer [3]、[5]以及“对Markup的介绍[译]”。
可以极为简化地说,一个CDoc管理着一组CMarkup,而CMarkup又与一组CElement有关。这个便是前几个内容之间的内在联系。
4.3 CDoc的成员变量
CDoc的成员变量列举如下,即使在日常调试中没有私有符号,我想,这依然可以作为参考,至少通过成员变量可以了解这个类具体能做什么。
元素
来看比较靠谱?)的菜单对象。4.4 CDoc的成员函数
CDoc提供了一大堆的成员函数,在这里我们将列举出部分重要或者常用的成员函数,以供参考。
有参考意义的网页
http://msdn.microsoft.com/en-us/library/aa752038%28v=vs.85%29.aspx、http://msdn.microsoft.com/en-us/library/aa741317%28v=vs.85%29.aspx、http://msdn.microsoft.com/en-us/library/bb508514%28VS.85%29.aspx由于超出博客单文章最长长度,将在这里续写第二章内容。
2.3 CElement的成员函数(续)
<script>
)、CMarkup::FRAMES_COLLECTION(<frame> <iframe>
)等。2.4 小结
CElement即元素之源,它很好的囊括了元素的基础操作,例如事件处理,转发、元素遍历、排列树等等,接下来,我们将要看到的是另一个大将:CMarkup。 在第二章中,CMarkup的身影多次出现,事实上,这个类和CElement关联颇多,现在让我们看一下它的真身。
第三章
3.1 CMarkup概述
CMarkup是最基本的Markup存储结构。HTML中的Hyper-Text Markup Language中也有一个Markup,现在我们要介绍的CMarkup所指代的就是这里面的Markup。Markup一词的来源是用蓝色铅笔将作者的草稿里面的东西特别标记出来(Marking up),在这里的意思是将文本与代码区分开来的东西。
例如,HTML中,<p>
可以表示paragraph段落,而<a>
则表示anchor超链接锚。这些“功能性的”Markup语法使他们和一般文本(Plain Text)相区分。这个就是一个Markup。这里的CMarkup可能稍有不同,向下继续阅读便可知道差距在何处。
3.2 CMarkup的部分成员变量
CMarkup也是一个重要的类,那么它的成员变量肯定也是十分重要的,以下将介绍其,以及其相关类成员变量。
1:CMarkupScriptContext
window
”,非主markup的命名空间是ms__idX(id1, id2....)。window
对象中暴露的dispid对应的,由脚本暴露的派遣项的dispid所组成的映射表。 比较绕口,也就是说window对象会暴露出许多dispid,而脚本解释引擎又会暴露许多派遣项的dispid,这两者之间的映射关系会组成一个映射表,它们就存储在这里。2: CMarkup
CMarkup
继承于CBase
。同样,它也是一个巨大无比的类,它的规模和CElement不相上下。CDoc
的内容将于第四章说明,CTreePos
和CTreeNode
两个类的内容将于第五章说明。CMarkup也是实现了大量接口,这些接口内容将在下一节介绍,现在让我们先看一看它的成员变量。
另外一提,在Internet Explorer中node的维护事实上是使用了伸展树的结构。
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作。它由Daniel Sleator和Robert Tarjan创造。它的优势在于不需要记录用于平衡树的冗余信息。在伸展树上的一般操作都基于伸展操作。
图:元素3被访问时的伸展操作,每一步都让3向根节点靠的更近 (成员变量还没写完
)
3.3 CMarkup的成员函数
split
,会导致后面的Markup就会指向无效的ich,所以这里还需要判断。chRef
一直减去前一个文本引用的cch
,这样,肯定会有一刻满足chRef < cch。同时,只要文本引用还有效,就一直将文本引用向前移动(Ref的NextTreePos),这样可以确定split的右手侧,也会顺便调整这个指针。~
meta
)。linkColor/ alinkColor/ vlinkColor
。URL
的实现。3.4 小结
CMarkup是Internet Explorer中关于document
的实现,我们可以看到CMarkup实现了document的几乎所有的属性、事件响应、样式表的操作,在下一章中,我们将介绍最后一个大类CDoc的具体实现细节。在下一章结束后,我们将同时给出一个Internet Explorer 11中的实例分析。
参考
Splay Tree
伸展树,http://zh.wikipedia.org/wiki/%E4%BC%B8%E5%B1%95%E6%A0%91
chRef
char reference的缩写
Cch
count of char的缩写
split
Split(x,S):以x为界,将伸展树S分离为两棵伸展树S1和S2,其中S1中所有元素都小于x,S2中的所有元素都大于x。首先执行Find(x,S),将元素x调整为伸展树的根节点,则x的左子树就是S1,而右子树为S2。
第二章 元素之源
2.1 CElement
介绍了mshtml的一个重量级明星CBase之后,这一步,我们需要看看一看CElement,同样,可以猜测它是很多元素的基类。事实如何?我们深入看一下这个类。
本节中,由于CElement会引入许多之前未介绍的类,因此,在这节中,当引用到一个新类的时候,我都会在之后另开一章介绍,而且会修改本文指向那一个类。
2.2 巨人CElement的结构
CElement是CBase的派生类。不同的元素通过派生和重载此类来区别。CElement作为元素的基类,结构十分庞大,从自身来说,它实现了IDispatchEx、IProvideMultipleClassInfo、IServiceProvider、IRecalcProperty、IMsoCommandTarget等接口。这些我们稍后都会看到。
CElement的成员变量中,__pvChain是其最重要的关联成员,这是一个void*格式的变量,在CElement构造时,这个变量将会被赋值。如果一个element有layout
(见参考,简单的说,就是有layout的元素自己会处理自己的大小之类的东西,参见layout _2)的话,__pvChain会指向这个layout,如果它没有layout,而它在一个树中,那么它会指向树中下一个ped
,其他情况下,它指向当前document。
__pNodeFirstBranch指向第一个分支的node
。还有两个成员变量DWORD _fMark1、DWORD _fMark2,它们用位来标记作用,分别如下:
_fMark1:
0~7 element tag; 8~14 如果旁视列表有指针的话为TRUE; 15 元素有name或者id属性; 16~31 元素锁定标记
_fMark2:
0 元素有一个Markup指针时为TRUE
1 元素有一个layout指针时为TRUE
2 有挂起状态的filter任务时为TRUE
3 有挂起状态的recalc任务时为TRUE
4 元素是一个site或者从未有过layout时为TRUE
5 元素控制着所有其下的函数运转时为TRUE
6 元素用来继承site和一些特殊格式时为TRUE
7 元素占1行,即使没有任何文字
8-11 未使用
12 元素没有边框
13 元素与tabindex关联(_aryTabIndexInfo)
14 元素有至少一个图像上下文
15 图片变化时需要强制重置大小
16 元素有关闭tag (例如<p></p>
)
17 用户创建时为FALSE,代码生成时TRUE
18 未使用
19 元素的行为像按钮
20 为init中的TestClassFlag而设置
21 元素默认就有layout
22 默认的确认按钮
23 默认的取消按钮
24 元素提交的事件被挂起
25 其他元素或者对象需要一个连接点或者设置一个事件
26 _pAA中加入了FilterCollectionPtr
27 元素有一个挂起的Exittree消息
28 GetFirstCommonAncestor会用到这个位,标记是否为第一个祖先
29-30 随机位
31 元素有style expression
为了做到普适性,这个CElement不得不称作一个巨人,下面我们介绍它的成员函数。
2.3 CElement的成员函数
notenote: onproprty事件是IE专属
<div id="txt"> www.nul.pw</div>
<script>
function d(){alert(5);}
document.getElementById('txt').onpropertychange=d();
</script>
<div id="txt"> www.nul.pw</div>
<script>
function d(){alert(5);}
p = document.createElement("div");
p.onpropertychange=d();
p.innerText="123";
document.getElementById('txt').appendChild(p);
</script>
<div id="txt"> www.nul.pw</div>
<script>
function d(){alert(5);}
p = document.createElement("div");
p.onpropertychange=d();
document.getElementById('txt').appendChild(p);
p.innerText="123";
</script>
任意
属性改变时触发的,所以这儿的判断流程十分长,例如background-image(背景图片)、list-style-image(列表图片)、z-index(顺序)、left,right,bottom,top(位置)、disabled(有效性)、visiablilty(可见性)、marginleft,right,bottom,top(边缘对齐)、clipleft,right,bottom,top(剪裁绝对元素)等等等等,几乎是所有样式操作导致属性变化都会有对应的方式来处理,这一部分可以参考w3school的对应部分。例如;clip:rect
、list-style-image
等。ZParent
全部计算完成之后,ZParentChange才会被调用,之前都一直会在队列中排着。DisplayChange
请参见CNotification
节中的内容,将在后续介绍。 )non-site
的元素上进行的z-index改变,否则z-index的改变将CSite的z-order处理函数FixZOrder来处理。根据ie版本不同而不同,ie11以及兼容性视图行为差异很大。
CView
),然后转而调用View的HitTest函数。Block Element
。CStreamWriteBuff
类)中。也就是加入一个属性="值"
的对,同时请注意到IE中的一个特性是属性中的
值
部分中的回车都不会忽略
。<script defer>
的defer,但是建议写成defer="defer"
。CHtmTag
里面取值放入bag中。bag就是AttrBag,存储属性-值对的一个“包”。onmouseover="this.style.cursor='pointer';this.style.cursor='hand'"
的"element.style.cursor"属性,在发生WM_CURSOR消息时处理消息。<
xxx>
www.nul.pw</
xxx>
的tag对。alpha/blur/dropshadow这些滤镜,ie中它们是和一个clsid对应的,使用时都要CoCreateInstance创建对应实例才可以
,其中,被实例化的对象必须标记为safe for init
、safe for script
,IPersistPropertyBag2或者IPersistPropertyBag中可以查询到SAFETY_INIT、SAFETY_SCRIPT的结果。参考
layout
http://msdn.microsoft.com/en-us/library/ie/ms530764(v=vs.85).aspx
layout #2
http://www.sitepoint.com/web-foundations/internet-explorer-haslayout-property/
ped
结构中的一个个体
node
节点
site
显示出来的一个实节点
style expression
style中包含有expression表达式
clip:rect
http://www.w3school.com.cn/cssref/pr_pos_clip.asp
list-style-image
http://www.w3school.com.cn/cssref/pr_list-style-image.asp
ZParent
, 按z-index排列的parent
non-site
是个元素,但是并没有展现出来(根本没有加入到文档里,而不是不可见之类的操作)
Block Element
块元素,块级元素生成一个元素框,(默认地)它会填充其父级元素的内容,旁边不能有其他元素。换句话说,他在元素框之前和之后生成了“分隔”符。我们最熟悉的HTML元素是p和div。
safe for init
、safe for script
http://msdn.microsoft.com/en-us/library/aa751977%28VS.85%29.aspx
Internet Explorer 是一个广泛使用的浏览器,囿于微软的闭源策略,Internet Explorer的许多特性无法被人深入理解,现在,我要大概使用40章的篇幅来完全解析一下Internet Explorer的方方面面,最终我会给出修改好的pdf,40章我是随读随写的,所以不免会有问题,请以最终的pdf为准。
历史等介绍前略
文章来源 www.nul.pw
第1章 intro
1.1 Internet Explorer的结构
关于这部分,网上有一个很经典的图,大致描述起来就是 宿主-shdocvw.dll-mshtml.dll-html文档 的四层结构
mshtml是一个活动文档解释器,或者更通俗的说,mshtml负责解析html。既然是浏览器,无论是平时的分析还是漏洞测试,页面解析这块必然是重头戏,因此mshtml.dll是我这次首先开始解析的部分。
1.2 初识CBase
mshtml.dll中,可以作为“基类”存在的类为CBase
,CBase实现了IDispatchEx、IProvideMultipleClassInfo、ISupportErrorInfo、IOleCommandTarget、ISpecifyPropertyPages这些基本的自动化接口,还有IObjectIdentity接口,用于判断两个对象是否相同。CBaseCF类实现了类厂(Class Factory)功能。
CDispParams
类用来协助CBase的实现,它用来对DISPPARAMS进行二次封装(因此无疑它继承了DISPPARAMS),方便Invoke和InvokeEx这两个函数的调用(它们有一个参数是DISPPARAMS类型)。
CDispParams的成员变量都继承自父类DISPPARAMS,为rgvarg、rgdispidNamedArgs、cArgs、cNamedArgs。
关于DISPPARAMS的定义可以参见微软MSDN的介绍*1
。其结构如下:
typedef struct FARSTRUCT tagDISPPARAMS {
VARIANTARG FAR* rgvarg; //参数数组
DISPID FAR* rgdispidNamedArgs; //已命名参数的DISPID(Dispatch identifiers)
unsigned int cArgs; //参数个数
unsigned int cNamedArgs; //已命名的参数的个数
} DISPPARAMS;
其成员函数及作用列举如下:
【1】HRESULT CDispParams::Create(DISPPARAMS*)
这个函数即会从DISPPARMS*中获取对应参数信息,参数数组的初始化值是VT_NULL,命名参数数组的初始化值是DISPID_UNKNOWN。
【2】HRESULT CDispParams::MoveArgsToDispParams (DISPPARAMS *pOutDispParams, UINT cNumArgs, BOOL fFromEnd)
这个函数的作用是把参数数组的内容给移动到pOutDispParams中。其实它虽然调用了memcpy,但是事实上只是把参数列表(CDispParams的成员变量:rgvarg[])的指针给复制到了pOutDispParams->rgvarg里,所以现在pOutDispParams和CDispParams事实上拥有了同样的对象(当然,释放的话只能释放一次)。最后一个参数指定了复制时是从最后(index: cArgs - cNumArgs)开始复制还是从最开始(index: 0)开始复制。
1.3 CBase的_pAA,大家的_pAA
在介绍CBase之前,也许非常有必要去解释一下常见的_pAA
参数,这个参数实际上是“样式属性数组的指针
”的缩写(pointer of attribute array),它是CAttrArray
类的一个实例,之所以将它提前介绍,是因为_pAA就是元素的样式表
,因此它的身影几乎贯穿在所有的类中间。CAttrArray
继承于CAttrValue
。
CAttrValue
的flags
数据结构如下:
31 24 23 16 15 8 7 0
-----------------------------------------------------------------------
| | | | |
| VT_TYPE | AAExtraBits | AATYPE |
| | | | |
-----------------------------------------------------------------------
struct AttrFlags {
BYTE _aaType;
WORD _aaExtraBits;
BYTE _aaVTType;
};
_aaType
指定了这个AA是什么类型的,_aaExtraBits
指定了这个AA的具体类型,例如important类型(“important”)、隐含式(“background: none”)之类的,最后一个_aaVTType
指定VT_TYPE
。这个类具体来说就是样式表的解析器。
CAttrArray
继承自CAttrValue(CDataAry
1.4 CBase的成员函数
run-mode
),第二组用于编辑模式(design mode
)。*2
)的帮助函数。函数接受聚合体的IUnkown接口,通过读取其IID_IProvideMultipleClassInfo接口获得一个IProvideMultipleClassInfo实例,然后调用其GetMultiTypeInfoCount获取其type info 的数量。*3
~
~
*ppDoc
(传入时类型是IHTMLDocument2** ppDoc)。InlineEvts*
。CAttrValue::SetEventsToHook其实就做了一件事:GetAAHeader()->_pEventsToHook = pEventsToHook;。~
struct VTABLEDESC*
),然后从property desc中找到对应的dispid。~
1.5 总结:CBase
CBase类是mshtml.dll中提供的一个基础类,提供了许多功能函数的支持,同时也支持重要的事件操作(例如支持javascript中的addEventListener) ,之后还会看到很多与之有关联的类,本节到此结束。
引用
1
http://msdn.microsoft.com/en-us/library/aa912051.aspx
2
http://msdn.microsoft.com/en-us/library/sdwe79a4.aspx
3
http://msdn.microsoft.com/en-us/library/asd22sd4(v=vs.94).aspx
引申
expando
http://msdn.microsoft.com/en-us/library/ie/ms533747(v=vs.85).aspx
attachEvent
http://msdn.microsoft.com/en-us/library/ie/ms536343(v=vs.85).aspx
标记
~
wait for further analysis
property
可以简单的理解为dispid