This vulnerability exists only in IE9, which will prevent you from downloading embedded files in CHM and testing on machines without KB2586448 Update installed.
First, create a new 1.html file with the following content:
<A href = "1.rar"> 1.rar</a>
Then, compile it into CHM together with a 1.rar file using HTML Help Workshop.
Open the chmclick 1.rar link, or enter mk: @ MSITStore: XXX (specific path) \ 1.chm::/ 1.rarin the IE Address Bar. An error is reported for debugging.
Stops at CDownloadUtilities: marshalbindcontexttostream, which prepares for downloading the 1.rar file.
The statement is as follows:
HRESULT CDownloadUtilities: financialbindcontexttostream (CInterThreadMarshal ** ppITM <eax>, CDownloadThreadParam * pDTP, wchar_t * szURL, IBindCtx * pBC)
Simple Analysis of Its code
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 + 10 h]; 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 + 74 h (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 + 10 h]; 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 + 74 h (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: financialbindcontexttostream + 0C6h (7003D300h); if (FAILED (hr) goto 7003D300h
7003D2B3 mov eax, dword ptr [edi]; eax = * ppITM
7003D2B5 cmp eax, ebx
7003D2B7 je CDownloadUtilities: financialbindcontexttostream + 89 h (7003D2C3h); goto 7003D2C3h
7003D2B9 mov ecx, dword ptr [ebp + 8]; ecx = pDTP
7003D2BC mov dword ptr [ecx + 18 h], eax; * (pDTP + 18 h) = 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 + 99 h (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 + 18 h], eax; * (pDTP + 18 h) = eax
7003D2DB mov dword ptr [ebp-4], 8007000Eh; hr = 8007000Eh
7003D2E2 cmp eax, ebx
7003D2E4 je CDownloadUtilities: financialbindcontexttostream + 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 = codecomalinterthreadinterfaceinstream (& 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 lcieuniiedframe (6FF9CD1Fh)
7003D305 test al, al
7003D307 je CDownloadUtilities: MarshalBindContextToStream + 128 h (7003D362h)
7003D309 lea eax, [ebp-0Ch]
7003D30C push eax
7003D30D call dword ptr [_ imp_CoCreateUserBroker (6FE925A4h)]
7003D313 test eax, eax
7003D315 js CDownloadUtilities: MarshalBindContextToStream + 128 h (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 _ codecomalinterthreadinterfaceinstream @ 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 + 14 h]
7003D336 mov esi, dword ptr [ebp + 0Ch]
7003D339 cmp eax, ebx
7003D33B je CDownloadUtilities: MarshalBindContextToStream + 109 h (7003D343h)
7003D33D mov ecx, dword ptr [eax]
7003D33F push eax
7003D340 call dword ptr [ecx + 8]
7003D343 mov dword ptr [edi + 14 h], esi
7003D346 cmp esi, ebx
7003D348 je CDownloadUtilities: MarshalBindContextToStream + 116 h (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]
7003d1_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
Simple rewrite to C ++ code
HRESULT CDownloadUtilities: financialbindcontexttostream (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 + 18 h) = * ppITM;
* PpITM = NULL;
}
Else
{
IStream ** ppStm = new LPSTREAM;
If (ppStm)
{
* PpStm = 0;
}
Else
{
PpStm = NULL;
}
* (PDTP + 18 h) = ppStm;
Hr = 8007000Eh;
If (ppStm)
{
Hr = codecomalinterthreadinterfaceinstream (& IID_IBindCtx, pUnk, ppStm );
}
}
PUnk-> Release ();
}
}
// Omit
Return hr;
}
First, the function calls the pBC-> QueryInterface to obtain the IUnknown interface pUnk of the pBC object. Because IBindCtx only inherits from IUnknown, The IUnknown interface and IBindCtx interface address are actually the same. When downloading the CHM embedded file, the szURL parameter of the CDownloadUtilities: MarshalBindContextToStream function is a string in the shape of mk: XXX. Therefore, the pUnk-> Release function call sets pUnk = NULL, while the original pUnk count is 1, pUnk-> Release completely releases the pBC object, so the function calls CreateAsyncBindCtxEx to obtain the pBC object again. The pBC is updated, but the pUnk is still NULL, in addition, the function completely releases * ppITM object and sets * ppITM = NULL. Therefore, the function then calls the codecomalinterthreadinterfaceinstream column set interface pointer, but the second The parameter is pUnk, but pUnk = NULL. It should actually be the pBC. This is not a big problem. The pUnk-> Release that follows is the root cause, because pUnk = NULL, the pUnk virtual function table pointer is used to cause access violation and the program reports an error. Fortunately, the pUnk was set to NULL before, otherwise the consequences would be worse. The solution should be to use the pBC. When the szURL parameter is not a string such as mk: XXX, no problem occurs.
KB2586448 changed CreateAsyncBindCtxEx (0, 0, 0, 0, & pBC, 0) to CreateAsyncBindCtxEx (0, 0, 0, 0, 0, & pUnk, 0 ).
The function declaration is changed to HRESULT CDownloadUtilities: MarshalBindContextToStream (IBindCtx * pBC <eax>, CInterThreadMarshal ** ppITM <ecx>, CDownloadThreadParam * pDTP, wchar_t * szURL)
Author: Recycle Bin