能力值:
( LV4,RANK:50 )
2 楼
小聪的动作好快啊,不错不错,顺便问下,那个symbol从哪下的?
能力值:
( LV12,RANK:300 )
3 楼
调试方法:
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 ?? ???
能力值:
( LV3,RANK:30 )
4 楼
膜拜楼主
看的话还是知道点皮毛,但都不知道从哪开始学起
能力值:
( LV3,RANK:30 )
5 楼
速度很快,厉害
能力值:
( LV4,RANK:50 )
6 楼
发现和CVE-2009-1136好像,几乎同出一辙,难道是同一个人挖出来的。。。
能力值:
( LV12,RANK:300 )
7 楼
貌似我之前曾经遇到过一个毒网是利用这个的,但是当时在我实机的IE8上没效果,所以直接扔掉了,现在看了相关公告才知道原来IE6和7才有效。
能力值:
( LV12,RANK:300 )
8 楼
https://www.mysonicwall.com/sonicalert/searchresults.aspx?ev=article&id=213
找到了又一个页面对该漏洞的简要描述,看来与我的分析是相映证的。
能力值:
(RANK:860 )
9 楼
昨天刚把POC从MSF中导出来,今天就看到分析了
哇哈哈
看来我慢了一步
能力值:
( LV3,RANK:20 )
10 楼
^_^,看见分析了,很好很好,lz很强大
能力值:
( LV2,RANK:10 )
11 楼
楼主好强大!
能力值:
( LV2,RANK:10 )
12 楼
强悍.....
能力值:
(RANK:300 )
13 楼
无话可说只有膜拜了...
能力值:
( LV2,RANK:10 )
14 楼
完全不懂
能力值:
( LV2,RANK:10 )
15 楼
小聪我爱你..
能力值:
(RANK:10 )
16 楼
请楼主分享下发布漏洞提示的一些网站,http://www.milw0rm.com/停下后就不知去哪了
能力值:
( LV2,RANK:10 )
17 楼
强帖要留名呀
能力值:
( LV5,RANK:60 )
18 楼
完全看不懂,支持小聪大牛
能力值:
( LV12,RANK:310 )
19 楼
膜拜一下!楼主实在强大!
在下昨天也分析了这个sample, 最终结果和楼主的一样,但因为是新手,感觉自己走了很多弯路,在这里想请教楼主一点问题:
我是从发生问题的地方回溯,花了好大的功夫才定位到CPersistUserData::setAttribute这个函数的,楼主能否分享一下,您是怎么知道要找CPersistUserData::setAttribute这个函数的呢,mshtml和jscript这两个dll里的类和函数,以及他们之间的调用关系,这些有没有相应的参考资料呢?
还望楼主不吝赐教,在此先谢过楼主了
能力值:
( LV2,RANK:10 )
20 楼
LZ很无私哈,连调试细节都贴出来了,强烈支持这样的共享精神。
能力值:
( LV12,RANK:300 )
21 楼
其实我对IE浏览器内核也是不懂的,也苦于这方面的资料缺乏,很多东西都是在调试过程中自己推敲的。
内存破坏这种类型的定位起来也确实比较麻烦,因为造成破坏的位置和最终触发的位置之间可能有很大距离。也就是说当调试器捕获到异常时,我们面对的已经是一个最后的现场,而我们要做的就是要还原它的整个过程。
要做到这一点,我想一般有顺向和逆向两种方法。
顺向是建立在对相应程序机制和代码的理解上,比如如果分析者对IE浏览器内核运作很了解,也就是说懂得IE是怎么执行脚本的,脚本代码是怎么跟实际的代码执行过程联系起来的,那么通过阅读PoC,当看到脚本通过addBehavior把body标签和UserData绑定并通过循环调用setAttribute来实现时,很可能很快就意识到了CPersistUserData::setAttribute是关键。对于那些深入了解浏览器机制的专家来说,或者就是这样的。
但是我就不行了,应该说我是硬钻到漏洞分析这个领域上来的,我对IE内核的实现机制基本不懂,甚至对这些类的构成方式如虚函数表,也是在这个过程中慢慢学会的。我凭借的就只有以汇编为基础的调试能力了,只能从逆向者的角度来操作它了。
对于逆向的方法,处理这种的一般步骤,我想应该是:1.捕获异常,看到最后的状态;2.尝试往前走找到一个未被破坏的初始点可以定位到相关内存未被破坏前的状态;3.找到了初始点,就可以使用写入断点来找到内存被修改也就是被重用的位置;4.对于一般的类对象,有相应的函数进行减小访问计数并最终释放的工作,对该函数进行研究,使用条件断点等捕捉到它对相应的对象进行减小访问计数的那个时刻;5.第4步成功捕捉到后,用栈回溯等就可以确定它是被谁调用的,这样就确定了破坏的位置;6.结合调试结果和脚本内容以及各个类的关系推敲。
其中第2步是第一个门槛。就像软件注册破解要找到关键代码一样,往往没有定式,只能靠摸索和观察以及一点运气,因此往往相当一部分时间是耗在这里的。
就我调试的过程而言,我是经历了这几步:
1. 直接windbg加载IE执行代码,触发异常回到调试器,这时的栈回溯可看到触发异常的代码是被jscript!IDispatchExGetDispID调用的,这样在这个函数上下断,一开始断下时并不是在最后溢出时,但是对前面那些正常的流程的调试可以让我了解这个函数相关的代码原本是在做什么,也即进一步找到了TearoffThunk7就是最终溢出的函数,以及这是有关TearoffThunk类的内存破坏。
2. 通过让程序一次又一次地断在jscript!IDispatchExGetDispID,我欣喜地找到内存破坏前后的更多信息,即前面提到的原来是COmWindowProxy::s_apfnIDispatchEx后来变成CWindow::s_apfnIHTMLPrivateWindow3导致了异常,更重要的是让我发现了程序第一次在jscript!IDispatchExGetDispID断下时它所操作的对象正是最后因为被破坏导致问题的那个对象,这样我就找到了一个未被破坏的初始点
3. 接下来就是利用硬件写入断点等一步步逼近的问题了,就像我前面说的,在第一次jscript!IDispatchExGetDispID断下之后,我找到了将被修改的类对象,我在原来为COmWindowProxy::s_apfnIDispatchEx的地方下硬件写入断点,断点断下便直接找到了修改它的位置,也即CreateTearoffThunk,这时再用栈回溯,CPersistUserData::setAttribute就蹦出来了。
4. 通过对CreateTearoffThunk的观察,我发现它是在mshtml.dll中自己保存一个立即可用的缓冲区的指针(参见我前面分析的第8点CreateTearoffThunk对InterlockedExchange的调用中的offset lpMem),通过IDA中这个指针的交叉参考,我发现了mshtml!PlainRelease正是将访问计数减为0的类对象指针挂到这里的函数(参见前面分析第7点),这样就找到了把类对象访问计数减少和“释放”的函数,从而也证实这个重用是这两个函数内部之间的“协作”,而不是走一般的直接从堆中获取或释放回堆中的路径。
5. 通过对mshtml!PlainRelease下条件断点,我捕捉到它把类对象访问计数减为0并“释放”的时刻,此时一个栈回溯,CPersistUserData::setAttribute又蹦出来了。
6. 最终确定CPersistUserData::setAttribute的重要性并对其调试,从而弄清细节。
通过这两次对内存破坏型漏洞的分析调试(这一次和前一次的IE极光漏洞),我个人认为还是有一些技巧的。
首先关键的是弄清楚被破坏的内存原来是保存什么东西的。
像这两次漏洞,被破坏的内存都是类对象的内容,所以首先要弄清楚,它到底原来是哪个类。比较简单的情形是对于有虚函数表的类,只要看它的虚函数表,就可以大致确定它是哪一个类。应该说这次比上次要容易一些,这次通过那个TearoffThunk7函数所在的表很容易找到相应的函数表位置,而上一次IE极光漏洞,内存破坏后连原来的虚函数表指针都没了,从而我当时一下子不知道它就是CTreeNode。
找到虚函数表位置或者知道它是哪个类,目的是找到它的构造函数、析构函数等等,构造函数本身就是一个该内存刚刚构建的初始点,而由于这些类的使用访问计数来标记和释放的机制,析构函数或者是减少访问计数的函数,则往往是导致这块内存被“提前释放”的直接执行者,找到他们也就找到了操纵访问计数的监测点,在此处断下后用栈回溯往往就可以窥探到内存破坏发生的过程和因果链。
对于因为访问计数的问题被提前释放,一般是某些该增加访问计数的地方没有增加或某些操作在程序没有预料到的情况下减少了访问计数(或者说在不该释放的地方释放了)。这次的iepeers漏洞属于后者,相对容易找一些,如我所说断到PlainRelease后一个栈回溯。极光漏洞则属于前者,相比之下更难找,因为动态调试中我们可以通过断点等手段捕捉到程序“做了什么”,但是想要知道它“没做什么”总是更难一点,更多地依赖于建立在代码理解基础上的推测,并用静态分析来证实推测了。这也是我在IE极光漏洞的分析中把那几篇参考文献放在前面并强调那不是我自己独立提出的思路的原因,因为没有那几篇文章对原理的描述,以我对IE浏览器和脚本语言架构完全不熟的情况要从原理上弄清楚基本上不太可能。
以上我想就是对付这类与类对象的引用和释放相关的内存破坏漏洞的一点经验了。
能力值:
( LV4,RANK:50 )
22 楼
不错 不错 MARK
能力值:
( LV2,RANK:10 )
23 楼
小聪牛牛好棒啊
能力值:
( LV2,RANK:10 )
24 楼
楼猪好厉害啊!加油!
能力值:
( LV2,RANK:10 )
25 楼
完全看不懂,支持小聪大牛