MS11-081中IE9导致的一个CHM漏洞简单分析
这个漏洞只存在于IE9,会导致无法下载CHM中内嵌的文件,在没有安装KB2586448更新的机器上测试
首先新建一个1.html文件,内容如下
<a href = "1.rar">1.rar</a>
然后和一个1.rar文件用HTML Help Workshop一起编译成CHM
打开CHM点击1.rar链接,也可以在IE地址栏输入mk:@MSITStore:XXX(具体路径)\1.chm::/1.rar,报错调试
停在CDownloadUtilities::MarshalBindContextToStream函数内,这个函数为下载1.rar文件做一些准备工作
声明如下
HRESULT CDownloadUtilities::MarshalBindContextToStream(CInterThreadMarshal **ppITM<eax>, CDownloadThreadParam *pDTP, wchar_t *szURL, IBindCtx *pBC)
简单分析下其代码
CDownloadUtilities::MarshalBindContextToStream(CInterThreadMarshal **ppITM<eax>, CDownloadThreadParam *pDTP, wchar_t *szURL, IBindCtx *pBC):
7003D23A mov edi,edi
7003D23C push ebp
7003D23D mov ebp,esp
7003D23F sub esp,0Ch ;HRESULT hr<[ebp-4h]>, IUnknown *pUnk<[ebp-8h]>, IEUserBroker *pIEUB<[ebp-0Ch]>
7003D242 push ebx
7003D243 push esi
7003D244 push edi
7003D245 lea edx,[ebp-8] ;edx = &pUnk
7003D248 push edx ;&pUnk
7003D249 mov edi,eax ;edi = ppITM
7003D24B mov eax,dword ptr [ebp+10h] ;eax = pBC
7003D24E mov ecx,dword ptr [eax] ;ecx = pBC->lpVtbl
7003D250 push offset __GUID_0000000e_0000_0000_c000_000000000046 (6FF65DA8h) ;&IID_IUnknown
7003D255 push eax ;pBC
7003D256 call dword ptr [ecx] ;eax = pBC->lpVtbl->QueryInterface(pBC, &IID_IUnknown, &pUnk)
7003D258 xor ebx,ebx
7003D25A mov dword ptr [ebp-4],eax ;hr = eax
7003D25D cmp eax,ebx
7003D25F jl CDownloadUtilities::MarshalBindContextToStream+0C6h (7003D300h) ;if (FAILED(hr)) goto 7003D300h
7003D265 push 3
7003D267 push offset string L"mk:" (70019BB4h)
7003D26C push dword ptr [ebp+0Ch]
7003D26F call dword ptr [__imp___wcsnicmp (6FE91364h)]
7003D275 add esp,0Ch
7003D278 test eax,eax
7003D27A jne CDownloadUtilities::MarshalBindContextToStream+74h (7003D2AEh) ;if (_wcsnicmp(szURL, L"mk:", 3)) goto 7003D2AEh
7003D27C mov eax,dword ptr [ebp-8] ;eax = pUnk
7003D27F mov ecx,dword ptr [eax] ;ecx = pUnk->lpVtbl
7003D281 push eax ;pUnk
7003D282 call dword ptr [ecx+8] ;pUnk->lpVtbl->Release(pUnk)
7003D285 push ebx ;0
7003D286 lea eax,[ebp+10h] ;eax = &pBC
7003D289 push eax ;&pBC
7003D28A push ebx ;0
7003D28B push ebx ;0
7003D28C push ebx ;0
7003D28D push ebx ;0
7003D28E mov dword ptr [ebp-8],ebx ;pUnk = 0
7003D291 call dword ptr [__imp__CreateAsyncBindCtxEx@24 (7023B14Ch)] ;eax = CreateAsyncBindCtxEx(0, 0, 0, 0, &pBC, 0)
7003D297 mov esi,dword ptr [edi] ;esi = *ppITM
7003D299 mov dword ptr [ebp-4],eax ;hr = eax
7003D29C cmp esi,ebx
7003D29E je CDownloadUtilities::MarshalBindContextToStream+74h (7003D2AEh) ;if (*ppITM == 0) goto 7003D2AEh
7003D2A0 call CInterThreadMarshal::~CInterThreadMarshal (701D7894h) ;(*ppITM)->~CInterThreadMarshal()(this<esi>)
7003D2A5 push esi
7003D2A6 call operator delete (6FEA35D9h) ;delete *ppITM
7003D2AB pop ecx
7003D2AC mov dword ptr [edi],ebx ;*ppITM = 0
7003D2AE cmp dword ptr [ebp-4],ebx
7003D2B1 jl CDownloadUtilities::MarshalBindContextToStream+0C6h (7003D300h) ;if (FAILED(hr)) goto 7003D300h
7003D2B3 mov eax,dword ptr [edi] ;eax = *ppITM
7003D2B5 cmp eax,ebx
7003D2B7 je CDownloadUtilities::MarshalBindContextToStream+89h (7003D2C3h) ;goto 7003D2C3h
7003D2B9 mov ecx,dword ptr [ebp+8] ;ecx = pDTP
7003D2BC mov dword ptr [ecx+18h],eax ;*(pDTP + 18h) = eax
7003D2BF mov dword ptr [edi],ebx ;*ppITM = 0
7003D2C1 jmp CDownloadUtilities::MarshalBindContextToStream+0BDh (7003D2F7h)
7003D2C3 push 4
7003D2C5 call operator new (6FE9E771h) ;eax = new LPSTREAM
7003D2CA pop ecx
7003D2CB cmp eax,ebx
7003D2CD je CDownloadUtilities::MarshalBindContextToStream+99h (7003D2D3h) ;if (eax == 0) goto 7003D2D3h
7003D2CF mov dword ptr [eax],ebx ;[eax] = 0
7003D2D1 jmp CDownloadUtilities::MarshalBindContextToStream+9Bh (7003D2D5h)
7003D2D3 xor eax,eax
7003D2D5 mov ecx,dword ptr [ebp+8] ;ecx = pDTP
7003D2D8 mov dword ptr [ecx+18h],eax ;*(pDTP + 18h) = eax
7003D2DB mov dword ptr [ebp-4],8007000Eh ;hr = 8007000Eh
7003D2E2 cmp eax,ebx
7003D2E4 je CDownloadUtilities::MarshalBindContextToStream+0BDh (7003D2F7h) ;if (eax == 0) goto 7003D2F7h
7003D2E6 push eax
7003D2E7 push dword ptr [ebp-8] ;pUnk
7003D2EA push offset _IID_IBindCtx (6FF2AB8Ch)
7003D2EF call (701FF7F2h) ;eax = CoMarshalInterThreadInterfaceInStream(&IID_IBindCtx, pUnk, eax)
7003D2F4 mov dword ptr [ebp-4],eax ;hr = eax
7003D2F7 mov eax,dword ptr [ebp-8] ;eax = pUnk
7003D2FA mov ecx,dword ptr [eax] ;ecx = pUnk->lpVtbl
7003D2FC push eax ;pUnk
7003D2FD call dword ptr [ecx+8] ;pUnk->lpVtbl->Release(lpVtbl)
7003D300 call LCIEUnifiedFrame (6FF9CD1Fh)
7003D305 test al,al
7003D307 je CDownloadUtilities::MarshalBindContextToStream+128h (7003D362h)
7003D309 lea eax,[ebp-0Ch]
7003D30C push eax
7003D30D call dword ptr [__imp_CoCreateUserBroker (6FE925A4h)]
7003D313 test eax,eax
7003D315 js CDownloadUtilities::MarshalBindContextToStream+128h (7003D362h)
7003D317 lea eax,[ebp+0Ch]
7003D31A push eax
7003D31B push dword ptr [ebp-0Ch]
7003D31E push offset _IID_IEUserBroker (6FF37F6Ch)
7003D323 call dword ptr [__imp__CoMarshalInterThreadInterfaceInStream@12 (6FE91FECh)]
7003D329 mov dword ptr [ebp-4],eax
7003D32C cmp eax,ebx
7003D32E jne CDownloadUtilities::MarshalBindContextToStream+11Fh (7003D359h)
7003D330 mov edi,dword ptr [ebp+8]
7003D333 mov eax,dword ptr [edi+14h]
7003D336 mov esi,dword ptr [ebp+0Ch]
7003D339 cmp eax,ebx
7003D33B je CDownloadUtilities::MarshalBindContextToStream+109h (7003D343h)
7003D33D mov ecx,dword ptr [eax]
7003D33F push eax
7003D340 call dword ptr [ecx+8]
7003D343 mov dword ptr [edi+14h],esi
7003D346 cmp esi,ebx
7003D348 je CDownloadUtilities::MarshalBindContextToStream+116h (7003D350h)
7003D34A mov eax,dword ptr [esi]
7003D34C push esi
7003D34D call dword ptr [eax+4]
7003D350 mov eax,dword ptr [ebp+0Ch]
7003D353 mov ecx,dword ptr [eax]
7003D355 push eax
7003D356 call dword ptr [ecx+8]
7003D359 mov eax,dword ptr [ebp-0Ch]
7003D35C mov ecx,dword ptr [eax]
7003D35E push eax
7003D35F call dword ptr [ecx+8]
7003D362 mov eax,dword ptr [ebp-4]
7003D365 pop edi
7003D366 pop esi
7003D367 pop ebx
7003D368 leave
7003D369 ret 0Ch
7003D36C nop
7003D36D nop
7003D36E nop
7003D36F nop
7003D370 nop
简单改写成C++代码
HRESULT CDownloadUtilities::MarshalBindContextToStream(CInterThreadMarshal **ppITM<eax>, CDownloadThreadParam *pDTP, wchar_t *szURL, IBindCtx *pBC)
{
IEUserBroker *pIEUB;
IUnknown *pUnk;
HRESULT hr;
if (SUCCEEDED(hr = pBC->QueryInterface(&IID_IUnknown, &pUnk)))
{
if (!_wcsnicmp(szURL, L"mk:", 3))
{
pUnk->Release();
pUnk = NULL;
hr = CreateAsyncBindCtxEx(0, 0, 0, 0, &pBC, 0);
if (*ppITM)
{
(*ppITM)->~CInterThreadMarshal();
delete *ppITM;
*ppITM = NULL;
}
}
if (SUCCEEDED(hr))
{
if (*ppITM)
{
*(pDTP + 18h) = *ppITM;
*ppITM = NULL;
}
else
{
IStream **ppStm = new LPSTREAM;
if (ppStm)
{
*ppStm = 0;
}
else
{
ppStm = NULL;
}
*(pDTP + 18h) = ppStm;
hr = 8007000Eh;
if (ppStm)
{
hr = CoMarshalInterThreadInterfaceInStream(&IID_IBindCtx, pUnk, ppStm);
}
}
pUnk->Release();
}
}
//omit
return hr;
}
首先函数调用pBC->QueryInterface获得pBC对象的IUnknown接口pUnk,由于IBindCtx只继承自IUnknown,所以IUnknown接口和IBindCtx接口地址实际相同,当下载CHM内嵌的文件时,CDownloadUtilities::MarshalBindContextToStream函数的szURL参数为形如mk:XXX的字符串,所以函数调用pUnk->Release又设pUnk=NULL,而pUnk原本的计数应为1,pUnk->Release彻底释放了pBC对象,于是函数调用CreateAsyncBindCtxEx重新获得pBC对象,pBC是更新了但pUnk仍然为NULL,此外函数又彻底释放了*ppITM对象并设*ppITM=NULL,于是之后函数会调用CoMarshalInterThreadInterfaceInStream列集接口指针,但调用时第二个参数为pUnk,但pUnk=NULL,实际应为pBC,这还不是大问题,紧跟着的pUnk->Release才是祸根,由于pUnk=NULL,取pUnk的虚函数表指针造成访问违例,程序报错,不过幸好之前pUnk设为了NULL,不然后果就更糟糕了,解决方法应该是换用pBC。当szURL参数不是形如mk:XXX的字符串时就不会产生问题了。
KB2586448把CreateAsyncBindCtxEx(0, 0, 0, 0, &pBC, 0);改成了CreateAsyncBindCtxEx(0, 0, 0, 0, &pUnk, 0);解决了问题
函数声明改成了HRESULT CDownloadUtilities::MarshalBindContextToStream(IBindCtx *pBC<eax>, CInterThreadMarshal **ppITM<ecx>, CDownloadThreadParam *pDTP, wchar_t *szURL)
作者:Recycle Bin
上一篇: python语法使用的小技巧