前面已经知道call进shellcode的代码位于mshtml!CFunctionPointer::PrivateAddRef
用IDA加载mshtml.dll,找到mshtml!CFunctionPointer::PrivateAddRef函数:
.text:42AF7811 public: virtual unsigned long __stdcall CFunctionPointer::PrivateAddRef(void) proc near
.text:42AF7811 ; DATA XREF: .text:42A3B3C4 o
.text:42AF7811
从函数头部的交叉参考进入,可以看到它被一个常量所引用:
.text:42A3B3C0 const CFunctionPointer::`vftable' dd offset CFunctionPointer::PrivateQueryInterface(_GUID const &,void * *)
.text:42A3B3C0 ; DATA XREF: CFunctionPointer::CFunctionPointer(CBase *,long)+15 o
.text:42A3B3C0 ; CElement::get_nodeType(long *)+1660 o
.text:42A3B3C4 dd offset CFunctionPointer::PrivateAddRef(void)
.text:42A3B3C8 dd offset CFunctionPointer::PrivateRelease(void)
这里可以说是一个messages dispatcher的表了,这个位置又被CFunctionPointer::CFunctionPointer所引用。CFunctionPointer::CFunctionPointer是一个类的构造函数:
.text:42AF79D9 public: __thiscall CFunctionPointer::CFunctionPointer(class CBase *, long) proc near
.text:42AF79D9 ; CODE XREF: CBase::ContextInvokeEx(long,ulong,ushort,tagDISPPARAMS *,tagVARIANT *,tagEXCEPINFO *,IServiceProvider *,IUnknown *)+AF361 p
.text:42AF79D9
.text:42AF79D9 arg_0 = dword ptr 8
.text:42AF79D9 arg_4 = dword ptr 0Ch
.text:42AF79D9
.text:42AF79D9 ; FUNCTION CHUNK AT .text:42B3F2C0 SIZE 00000020 BYTES
.text:42AF79D9
.text:42AF79D9 mov edi, edi
.text:42AF79DB push ebp
.text:42AF79DC mov ebp, esp
.text:42AF79DE push esi
.text:42AF79DF mov esi, ecx
.text:42AF79E1 call CBase::CBase(void)
.text:42AF79E1
.text:42AF79E6 mov ecx, [ebp+arg_0]
.text:42AF79E9 test ecx, ecx
.text:42AF79EB mov eax, [ebp+arg_4]
.text:42AF79EE mov dword ptr [esi], offset const CFunctionPointer::`vftable'
.text:42AF79F4 mov [esi+10h], ecx
.text:42AF79F7 mov [esi+14h], eax
.text:42AF79FA jz short loc_42AF7A19
.text:42AF79FA
.text:42AF79FC mov eax, [ecx]
.text:42AF79FE call dword ptr [eax+34h]
.text:42AF7A01 test eax, eax
.text:42AF7A03 mov [esi+18h], eax
.text:42AF7A06 jz loc_42B3F2C0
.text:42AF7A06
.text:42AF7A0C
.text:42AF7A0C loc_42AF7A0C: ; CODE XREF: CFunctionPointer::CFunctionPointer(CBase *,long)+47902 j
.text:42AF7A0C mov eax, [esi+18h]
.text:42AF7A0F test eax, eax
.text:42AF7A11 jz short loc_42AF7A19
.text:42AF7A11
.text:42AF7A13 mov ecx, [eax]
.text:42AF7A15 push eax
.text:42AF7A16 call dword ptr [ecx+4]
.text:42AF7A16
.text:42AF7A19
.text:42AF7A19 loc_42AF7A19: ; CODE XREF: CFunctionPointer::CFunctionPointer(CBase *,long)+21 j
.text:42AF7A19 ; CFunctionPointer::CFunctionPointer(CBase *,long)+38 j
.text:42AF7A19 mov eax, esi
.text:42AF7A1B pop esi
.text:42AF7A1C pop ebp
.text:42AF7A1D retn 8
那么微软怎么把这个漏洞改掉的呢?打上KB961260补丁,我们返回来看刚刚那个表:
.text:42A39708 const CFunctionPointer::`vftable' dd offset CFunctionPointer::PrivateQueryInterface(_GUID const &,void * *)
.text:42A39708 ; DATA XREF: CFunctionPointer::CFunctionPointer(CBase *,long)+15 o
.text:42A39708 ; CElement::get_nodeType(long *)+1658 o
.text:42A3970C dd offset CIVersionVectorThunk::AddRef(void)
.text:42A39710 dd offset CBase::PrivateRelease(void)
把CFunctionPointer::PrivateAddRef从表上换掉了,换成了CIVersionVectorThunk::AddRef(void),这个函数的动作:
.text:42A4156D public: virtual unsigned long __stdcall CIVersionVectorThunk::AddRef(void) proc near
.text:42A4156D ; DATA XREF: .text:42A0355C o
.text:42A4156D ; .text:42A38434 o
.text:42A4156D ; .text:42A384B4 o
.text:42A4156D ; .text:42A38534 o
.text:42A4156D ; .text:42A385BC o
.text:42A4156D ; .text:42A38644 o ...
.text:42A4156D
.text:42A4156D arg_0 = dword ptr 8
.text:42A4156D
.text:42A4156D mov edi, edi
.text:42A4156F push ebp
.text:42A41570 mov ebp, esp
.text:42A41572 mov eax, [ebp+arg_0]
.text:42A41575 inc dword ptr [eax+4]
.text:42A41578 xor eax, eax
.text:42A4157A pop ebp
.text:42A4157B retn 4
.text:42A4157B
.text:42A4157B public: virtual unsigned long __stdcall CIVersionVectorThunk::AddRef(void) endp
与之前的CFunctionPointer::PrivateAddRef对比可以发现,现在的CIVersionVectorThunk::AddRef只是设置一个引用计数(inc dword ptr [eax+4]),没有其他调用了。
同时修改的还有CFunctionPointer::PrivateRelease,在表中它的位置直接被替换成了基类的方法CBase::PrivateRelease。
看看修改前的CFunctionPointer::PrivateRelease函数:
.text:42B1E30D public: virtual unsigned long __stdcall CFunctionPointer::PrivateRelease(void) proc near
.text:42B1E30D ; DATA XREF: .text:42A3B3C8 o
.text:42B1E30D
.text:42B1E30D arg_0 = dword ptr 8
.text:42B1E30D
.text:42B1E30D mov edi, edi
.text:42B1E30F push ebp
.text:42B1E310 mov ebp, esp
.text:42B1E312 push esi
.text:42B1E313 mov esi, [ebp+arg_0]
.text:42B1E316 cmp dword ptr [esi+10h], 0
.text:42B1E31A jz loc_42B22250
.text:42B1E31A
.text:42B1E320 cmp dword ptr [esi+4], 1
.text:42B1E324 jbe loc_42B22250
.text:42B1E324
.text:42B1E32A add dword ptr [esi+8], 8
.text:42B1E32E push edi
.text:42B1E32F push esi
.text:42B1E330 call CBase::PrivateRelease(void)
.text:42B1E330
.text:42B1E335 mov edi, eax
.text:42B1E337 mov eax, [esi+10h]
.text:42B1E33A mov ecx, [eax]
.text:42B1E33C push eax
.text:42B1E33D call dword ptr [ecx+8]
.text:42B1E340 mov ecx, esi
.text:42B1E342 call CBase::SubRelease(void)
.text:42B1E342
.text:42B1E347 mov eax, edi
.text:42B1E349 pop edi
.text:42B1E349
.text:42B1E34A
.text:42B1E34A loc_42B1E34A: ; CODE XREF: CElement::get_nodeType(long *)+1627 j
.text:42B1E34A pop esi
.text:42B1E34B pop ebp
.text:42B1E34C retn 4
.text:42B1E34C
.text:42B1E34C public: virtual unsigned long __stdcall CFunctionPointer::PrivateRelease(void) endp
显然也存在与CFunctionPointer::PrivateAddRef相类似的问题,可能call进shellcode中。现在换成了CBase::PrivateRelease,同样也就是直接把对象的引用计数标志减1而已。