[原創]360網盾 廣告攔截模組崩潰分析

仙果發表於2012-12-10
360網盾 廣告攔截模組崩潰分析
宣告:此Bug不是本人發現的,所做的工作是對Bug成因進行分析,分析的過程中自己學到了很多東西,
在此感謝提供此Bug的壇友:xuecniao,是你讓我有了這次鍛鍊的機會。
分析過程是逆向分析的,希望能和大家多多交流。其中有錯誤之處歡迎指正。
1.分析環境:
Windwos XP SP3_CN(虛擬機器)
360安全衛士8.7.2002(最新版)
備用木馬庫版本:2012.11.3.1

工具:
IDA 5.5
Windbg
OD

2.分析過程
樣本程式碼如下:
xp3系統,ie8,360安全衛士-7.6.0.1130
<A href="file:///c:\windows\system32\BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB">按一下</A> 

<a> 標籤的 href 屬性用於指定超連結目標的 URL。
首先這是一個惡意的URL連結,正常情況下IE處理這個請求但不會崩潰,開啟360安全衛士以後,IE崩潰,使用Windbg除錯,發現以下地址報錯
65448f26 8b4c2404        mov     ecx,dword ptr [esp+4]
65448f2a 66833900        cmp     word ptr [ecx],0         ds:0023:00000000=????
65448f2e 8d4102          lea     eax,[ecx+2]
65448f31 740a            je      Adfilter!OnTrayMsg+0x2119b (65448f3d)

0:008> r
eax=00000000 ebx=00000000 ecx=00000000 edx=000000c0 esi=0211e354 edi=02b24c14
eip=65448f2a esp=0211e170 ebp=0211e1ac iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
Adfilter!OnTrayMsg+0x21188:
65448f2a 66833900        cmp     word ptr [ecx],0         ds:0023:00000000=????

ecx為0,自然程式在讀取[eax]的內容,觸發一個記憶體不可讀的異常,IE發生崩潰。
檢視這個Adfilter的相關資訊:
		0:008> !lmi Adfilter
		Loaded Module Info: [adfilter] 
				 Module: Adfilter
		   Base Address: 65400000
			 Image Name: C:\Program Files\360\360safe\safemon\Adfilter.dll
		   Machine Type: 332 (I386)
			 Time Stamp: 4f558bc0 Tue Mar 06 12:00:00 2012
				   Size: ab000
			   CheckSum: b1275
		Characteristics: 210e  
		Debug Data Dirs: Type  Size     VA  Pointer
					 CODEVIEW    45,     0,   a8000  [Debug data not mapped] - Can't validate symbols, if present.
			 Image Type: FILE     - Image read successfully from debugger.
						 C:\Program Files\360\360safe\safemon\Adfilter.dll
			Symbol Type: EXPORT   - PDB not found
			Load Report: export symbols

        確認是360網盾的一個DLL檔案,並且DLL檔案屬性資訊可以檢視到“360網盾 廣告攔截模組”,
        使用IDA載入Adfilter.dll進行靜態分析,跳轉到崩潰程式碼,發現如下資訊:
       
	.text:65448F26 ; =============== S U B R O U T I N E =======================================
	.text:65448F26
	.text:65448F26 ; Attributes: library function
	.text:65448F26
	.text:65448F26 ; size_t __cdecl wcslen(const wchar_t *Str)
	.text:65448F26 _wcslen         proc near               ; CODE XREF: sub_654012C5+61p
	.text:65448F26                                         ; sub_65402AB1+D4p ...
	.text:65448F26
	.text:65448F26 Str             = dword ptr  4
	.text:65448F26
	.text:65448F26                 mov     ecx, [esp+Str]
	.text:65448F2A                 cmp     word ptr [ecx], 0
	.text:65448F2E                 lea     eax, [ecx+2]
	.text:65448F31                 jz      short loc_65448F3D
	.text:65448F33
	.text:65448F33 loc_65448F33:                           ; CODE XREF: _wcslen+15j
	.text:65448F33                 mov     dx, [eax]
	.text:65448F36                 inc     eax
	.text:65448F37                 inc     eax
	.text:65448F38                 test    dx, dx
	.text:65448F3B                 jnz     short loc_65448F33
	.text:65448F3D
	.text:65448F3D loc_65448F3D:                           ; CODE XREF: _wcslen+Bj
	.text:65448F3D                 sub     eax, ecx
	.text:65448F3F                 sar     eax, 1
	.text:65448F41                 dec     eax
	.text:65448F42                 retn
	.text:65448F42 _wcslen         endp

        顯然IDA已經把函式名提示出來:wcslen(const wchar_t *Str),檢視引數可以發現,只有一個引數,為wchar_t 型的字串指標,
反彙編中,ecx是一個字串指標,指向一串字元,而在程式中,
65448f26 8b4c2404        mov     ecx,dword ptr [esp+4]
ecx為空,即空指標,空指標引用出錯導致的IE崩潰。
使用VC程式碼進行演示:
	#include <Windows.h>

	int _tmain(int argc, _TCHAR* argv[])
	{
		WCHAR* p = NULL;

		wcslen(p);

		return 0;
	}

        上述程式碼肯定會觸發一個異常。

        現在為止,知道了是什麼地方導致的IE崩潰,但是傳遞給wcslen()函式空指標的原因何在,之前為什麼沒有檢測到空指標,這些疑問需要解決,
分析的過程中也繞了一個彎路,以下是繞的彎路的分析過程:
從00d615e4 函式處呼叫Adfilter.dll中程式碼
Breakpoint 0 hit
eax=65461620 ebx=00175c90 ecx=00000001 edx=000000c0 esi=0211e260 edi=02b24bf8
eip=00d615e4 esp=0211e1b4 ebp=0211e1e0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
IEFRAME!IEIsProtectedModeProcess+0x580b:
00d615e4 ff5018          call    dword ptr [eax+18h]  ds:0023:65461638=65405c64


繼續往上分析發現。。。
下這個斷點,然後得到當 eax=0時跳轉到錯誤處理流程。
 bp 65405cb9 "r eax;gc"

 .text:65405CA3                 mov     edi, [ebp+8]
.text:65405CA6                 mov     ecx, edi
.text:65405CA8                 call    sub_65405AA8
.text:65405CAD                 test    eax, eax
.text:65405CAF                 jz      short loc_65405C9C
.text:65405CB1                 mov     eax, [ebp+0Ch]
.text:65405CB4                 sub     eax, 0FAh
.text:65405CB9                 jz      loc_65405F75    ; eax=0x0,在這裡跳轉到錯誤處理流程
....
.text:65405F75 loc_65405F75:                           ; CODE XREF: .text:65405CB9j
.text:65405F75                 mov     eax, [ebp+8]
.text:65405F78                 push    dword ptr [eax+1Ch]
.text:65405F7B                 lea     edi, [eax+1Ch]
.text:65405F7E                 call    sub_654026F7
.text:65405F83                 push    dword ptr [edi]
.text:65405F85                 call    sub_65402612
.text:65405F8A                 mov     eax, [esi]
.text:65405F8C                 pop     ecx
.text:65405F8D                 pop     ecx
.text:65405F8E                 mov     eax, [eax+58h]
.text:65405F91                 push    ebx
.text:65405F92                 mov     [ebp+1Ch], eax
.text:65405F95                 mov     al, [ebp+0Bh]
.text:65405F98                 lea     ecx, [ebp-28h]
.text:65405F9B                 mov     [ebp-28h], al
.text:65405F9E                 call    ?_Tidy@?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@AAEX_N@Z ; std::basic_string<ushort,std::char_traits<ushort>,std::allocator<ushort>>::_Tidy(bool)
.text:65405FA3                 mov     eax, [ebp+1Ch]
.text:65405FA6                 mov     [ebp-4], ebx
.text:65405FA9                 test    byte ptr [eax+1], 40h
.text:65405FAD                 mov     eax, [eax+8]    ; 正常情況兄下[eax+8]儲存有字串的指標
.text:65405FB0                 jz      short loc_65405FC4
.text:65405FB2                 mov     eax, [eax]
.text:65405FB4                 push    eax             ; Str
.text:65405FB5                 mov     [ebp+1Ch], eax
.text:65405FB8                 call    _wcslen         ; 這裡呼叫出錯函式

當eax=oxfa時,執行.text:65405CB4                 sub     eax, 0FAh 後eax=0,跳轉到錯誤的執行流程。。。
breakpoint 9 redefined
eax=ffffff6f
eax=ffffff6f
eax=ffffff6f
eax=ffffff6f
eax=ffffff6f
eax=ffffff6f
eax=ffffff6f
eax=ffffff6c
eax=ffffff6f
eax=00000000
Breakpoint 8 hit
eax=00000000 ebx=00000000 ecx=0211e1a0 edx=000000c0 esi=0211e354 edi=02b24d08
eip=65405f75 esp=0211e178 ebp=0211e1ac iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
Adfilter!IsInWhiteList+0x7ef:
65405f75 8b4508          mov     eax,dword ptr [ebp+8] ss:0023:0211e1b4=02b24d08


以下為除錯時使用的一些命令
bp 65405C64 "r ‘poi(ebp+0x0c)’;'gc'"
bp 65405C64 ".echo begin ######### ;dd poi(ebp+0c);.echo end ##############;gc"

bp 65405CA8 ".echo begin ######### ;dd poi(ebp+0c);.echo end ##############;gc"

bp 65405CA8 ".echo begin ######### ;dd poi(ebp+0c);.echo end ##############;gc"
begin #########
000000fa  ???????? ???????? ???????? ????????
0000010a  ???????? ???????? ???????? ????????
0000011a  ???????? ???????? ???????? ????????
0000012a  ???????? ???????? ???????? ????????
0000013a  ???????? ???????? ???????? ????????
0000014a  ???????? ???????? ???????? ????????
0000015a  ???????? ???????? ???????? ????????
0000016a  ???????? ???????? ???????? ????????

bp 65405CA6 ".echo begin ######### ;dd poi(ebp+0c);.echo end ##############;gc"
bp 65405C7B ".echo begin ######### ;dd poi(ebp+0c);.echo end ##############;gc"
bp 65405C64 ".echo begin ######### ;dd poi(ebp+0c);.echo end ##############;gc"
begin #########
0211e260  00000003 000000fa 00d61078 00000000
0211e270  e3540001 00000211 00000000 00000000
0211e280  d4af0000 021100d5 0211e430 00000000
0211e290  0211e368 00d5d454 001758d0 000000fa
0211e2a0  0211e354 0211e430 00000000 0000400c
0211e2b0  0000400b 0000400b 00000000 0211e430
0211e2c0  00000000 0000400c 00000000 0211e40c
0211e2d0  00000000 0000400c 00000000 0211e3ec
end ##############
Breakpoint 8 hit
eax=00000000 ebx=00000000 ecx=0211e1a0 edx=000000c0 esi=0211e354 edi=02b24d08
eip=65405f75 esp=0211e178 ebp=0211e1ac iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
Adfilter!IsInWhiteList+0x7ef:
65405f75 8b4508          mov     eax,dword ptr [ebp+8] ss:0023:0211e1b4=02b24d08

如下地址寫入了0xfa
.text:00D5D46C ; __stdcall IConnectionPoint_InvokeWithCancel(x, x, x, x, x)
.text:00D5D46C _IConnectionPoint_InvokeWithCancel@20 proc near
.text:00D5D46C                                         ; CODE XREF: DoInvokeParamHelper(IUnknown *,IConnectionPoint *,int *,void * *,long,uint,...)+7Ap
.text:00D5D46C
.text:00D5D46C var_30          = dword ptr -30h
.text:00D5D46C var_2C          = dword ptr -2Ch
.text:00D5D46C var_1E          = dword ptr -1Eh
.text:00D5D46C var_E           = dword ptr -0Eh
.text:00D5D46C var_8           = dword ptr -8
.text:00D5D46C var_4           = dword ptr -4
.text:00D5D46C arg_0           = dword ptr  8
.text:00D5D46C arg_4           = dword ptr  0Ch
.text:00D5D46C arg_8           = dword ptr  10h
.text:00D5D46C arg_C           = dword ptr  14h
.text:00D5D46C arg_10          = dword ptr  18h
.text:00D5D46C
.text:00D5D46C                 mov     edi, edi
.text:00D5D46E                 push    ebp
.text:00D5D46F                 mov     ebp, esp
.text:00D5D471                 sub     esp, 30h
.text:00D5D474                 mov     eax, [ebp+arg_4]
.text:00D5D477                 mov     [ebp+var_2C], eax ; 寫入0xfa
.text:00D5D47A                 mov     eax, [ebp+arg_8]
.text:00D5D47D                 mov     [ebp+var_1E], eax
.text:00D5D480                 mov     eax, [ebp+arg_C]
.text:00D5D483                 mov     [ebp+var_8], eax
.text:00D5D486                 mov     eax, [ebp+arg_10]
.text:00D5D489                 mov     [ebp+var_4], eax
.text:00D5D48C                 lea     eax, [ebp+var_30]
.text:00D5D48F                 push    eax
.text:00D5D490                 push    [ebp+arg_0]
.text:00D5D493                 mov     [ebp+var_30], 3
.text:00D5D49A                 mov     [ebp+var_E], offset ?InvokeWithCancelProc@@YGJPAUIDispatch@@PAUSHINVOKEPARAMS@@@Z ; InvokeWithCancelProc(IDispatch *,SHINVOKEPARAMS *)
.text:00D5D4A1                 call    _IConnectionPoint_InvokeIndirect@8 ; IConnectionPoint_InvokeIndirect(x,x)
.text:00D5D4A6                 leave
.text:00D5D4A7                 retn    14h
.text:00D5D4A7 _IConnectionPoint_InvokeWithCancel@20 endp

呼叫關係:
WARNING: Stack unwind information not available. Following frames may be wrong.
0211e290 00d5d454 IEFRAME!IEIsProtectedModeProcess+0x16a1
0211e368 00d29054 IEFRAME!IEIsProtectedModeProcess+0x167b
0211e45c 00d365b0 IEFRAME!Ordinal218+0x2c1f
0211e4a4 63777bcb IEFRAME!Ordinal303+0x4052
0211f568 63776ac8 mshtml!CWebOCEvents::BeforeNavigate2+0x29f
0211f750 63776610 mshtml!CDoc::DoNavigate+0xab5
0211f870 637788a2 mshtml!CDoc::FollowHyperlink2+0xda7
0211f8f0 636b6de9 mshtml!CDoc::FollowHyperlink+0x9d

找到的相關資訊:
http://www.sonic.net/~undoc/comes_v_microsoft/Supp_Rpt_Andrew_Schulman.pdf
Connection Point APIs: A “connection point” is a mechanism related to
receiving callback notifications of given events. Microsoft has a
documented ConnectionPoint class, and in 2004 Microsoft documented
ConnectToConnectionPoint. However, there remain connection-point
related shell APIs, implemented by shlwapi.dll, and used by the IE
component shdocvw.dll, that are not documented:
IConnectionPoint_InvokeWithCancel and
IConnectionPoint_SimpleInvoke. See e.g.:
最終找到如下的一個地址,寫入了0xfa這個整數。。
函式宣告:
.text:00D28EB9 ; int __stdcall FireEvent_BeforeNavigate(struct IUnknown *punk, int, int, struct _ITEMIDLIST_ABSOLUTE *, int, int, int, void *Src, ULONG Size, int, int)
.text:00D28EB9 _FireEvent_BeforeNavigate@44 proc near  ; CODE XREF: CBaseBrowser2::_FireBeforeNavigateEvent(_ITEMIDLIST_ABSOLUTE const *,int *)+172p
.text:00D28EB9                                         ; CBaseBrowser2::FireBeforeNavigate3(IHTMLWindow2 *,IDispatch *,ushort const *,ulong,ushort const *,uchar *,ulong,ushort const *,int,int *)+88p ...
.text:00D28EB9


.text:00D28FFC                 xor     eax, eax
.text:00D28FFE                 cmp     [ebp+var_10], eax
.text:00D29001                 mov     [ebp+var_80], 3
.text:00D29007                 mov     [ebp+var_60], 8
.text:00D2900D                 mov     [ebp+var_70], si
.text:00D29011                 mov     [ebp+var_50], 8
.text:00D29017                 mov     edi, 0FAh       ; 0xfa是從這裡來的
.text:00D2901C                 jz      short loc_D29059
.text:00D2901E                 lea     ecx, [ebp+var_2C]
.text:00D29021                 push    ecx
.text:00D29022                 push    ebx
.text:00D29023                 lea     ecx, [ebp+var_50]
.text:00D29026                 push    ecx
.text:00D29027                 push    esi
.text:00D29028                 lea     ecx, [ebp+var_70]

由於以上函式都是微軟未文件化的函式,所以具體含義只能從語義上來判斷,引數等結構資訊無法得到。

        上面的分析過程花費了我很長時間來跟蹤除錯,最終發現是一個錯誤的判斷。過程是這樣的,本來以為自己找到了關鍵點,但是有一個疑問是這樣的:
既然找到了0xfa的出處,但是什麼樣的原因導致程式走到了這個流程中來,與點選的超連結有什麼樣子的一個關係,超連結是如何影響程式執行流程的,
這個疑問是始終沒有解決,也不敢妄下結論。
        下面就開始驗證自己的想法,把虛擬機器除錯環境克隆了一份出來,進行兩臺虛擬機器一起除錯,一臺是IE正常的環境,另一臺就是IE崩潰環境,
跟蹤除錯那一條指令出現了差異導致程式的執行流程發生了變化。這個時候就發現正常情況與崩潰情況下都會出現0xfa,程式都會執行到Adfilter.dll中程式碼,
區別只有傳遞給wcslen()函式的指標是否是空指標的差別。
        以下即是過程:       
現在開始查詢惡意字串是如何影響到oxfa這個流程的。。。。
s -a 0 l fffffff "file:///c:"
0378934b 66 69 6c 65 3a 2f 2f 2f 63 3a 5c 77 69 6e 64 6f 77 73  file:///c:\windows
0378935d 5c 73 79 73 74 65 6d 33 32 5c 42 42 42 42 42 42 42 42  \system32\BBBBBBBB
0378936f 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42  BBBBBBBBBBBBBBBBBB
03789381 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42  BBBBBBBBBBBBBBBBBB
03789393 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42  BBBBBBBBBBBBBBBBBB

s -u 0 l?fffffff "file:///c:"


ba w1 0211e424 "r eip;.echo check mem;dd 0211e424;.echo changed;gc"
Normal:正常情況
eip=00d28fa8
check mem
0211e424  02110000 0211e518 00000064 00000000
0211e434  00000000 00000000 00000000 ffffffff
0211e444  00000000 00000000 00175d70 00000000
0211e454  03c4afd4 00175d4c 0211e4a4 00d365b0
0211e464  00175d04 002901d0 00175d04 00c4c408
0211e474  00000000 00000040 00000000 00000000
0211e484  00000000 00000000 0211f5c8 0211f5c8
0211e494  002239d4 00202020 00000000 00175d04
changed
eip=00d28fb9
check mem
0211e424  03c4adac 00000000 00000064 00000000	03c4adac為字串指標
0211e434  00000000 00000000 00000000 ffffffff
0211e444  00000000 00000000 00175d70 00000000
0211e454  03c4afd4 00175d4c 0211e4a4 00d365b0
0211e464  00175d04 002901d0 00175d04 00c4c408
0211e474  00000000 00000040 00000000 00000000
0211e484  00000000 00000000 0211f5c8 0211f5c8
0211e494  002239d4 00202020 00000000 00175d04
changed

BUG:崩潰情況
eip=00d28fa8
check mem
0211e424  02110000 0211e518 00000064 00000000
0211e434  00000000 00000000 00000000 ffffffff
0211e444  00000000 00000000 00175ea8 00000000
0211e454  00000000 00175e84 0211e4a4 00d365b0
0211e464  00175e3c 000c025e 00175e3c 00c4ec48
0211e474  00000000 00000040 00000000 00000000
0211e484  00000000 00000000 0211f5c8 0211f5c8
0211e494  002231d4 00201820 00000000 00175e3c
changed
eip=00d28fb9
check mem
0211e424  00000000 00000000 00000064 00000000	這裡沒有字串指標存在。。。。
0211e434  00000000 00000000 00000000 ffffffff
0211e444  00000000 00000000 00175ea8 00000000
0211e454  00000000 00175e84 0211e4a4 00d365b0
0211e464  00175e3c 000c025e 00175e3c 00c4ec48
0211e474  00000000 00000040 00000000 00000000
0211e484  00000000 00000000 0211f5c8 0211f5c8
0211e494  002231d4 00201820 00000000 00175e3c
changed

可以明顯的看出來,執行到eip=00d28fb9後0211e424的這個地址又了明顯的變化。。。
正常情況下是又指標的,異常情況下沒有寫入字串的指標。。。
poi(poi(esi)+58)+8

現在來看00d28fb9是在執行什麼操作:
.text:00D28FAB                 mov     [ebp+var_40], 8
.text:00D28FB1                 call    _SysAllocString@4 ; SysAllocString(x)
.text:00D28FB6                 mov     [ebp+SystemTimeAsFileTime], eax		//這裡寫入字串指標。。。。
.text:00D28FB9                 xor     eax, eax
.text:00D28FBB                 lea     edi, [ebp+var_7E]
此時的堆疊呼叫如下:
0:008> k
ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
0211e45c 00d365b0 IEFRAME!Ordinal218+0x2b76
0211e4a4 63777bcb IEFRAME!Ordinal303+0x4052	
0211f568 63776ac8 mshtml!CWebOCEvents::BeforeNavigate2+0x29f
0211f750 63776610 mshtml!CDoc::DoNavigate+0xab5
0211f870 637788a2 mshtml!CDoc::FollowHyperlink2+0xda7
0211f8f0 636b6de9 mshtml!CDoc::FollowHyperlink+0x9d
0211f994 636b6c68 mshtml!CHyperlink::ClickAction+0x31c
0211f9a4 636b57da mshtml!CAnchorElement::ClickAction+0x10
0211f9d8 636b2be9 mshtml!CElement::DoClick+0x155
0211fa08 636b2b5a mshtml!CAnchorElement::DoClick+0x6d
0211faa4 635f1fea mshtml!CDoc::PumpMessage+0xf10

接著找寫入資料的地方

ba w1 0211e454 "r eip;.echo check mem;dd 0211e454;.echo changed;gc"

正常情況下,跟蹤到這個處理函式
.text:00D284AE ; int __stdcall ATL__CComBSTR__operator_(OLECHAR *psz)
.text:00D284AE ??4CComBSTR@ATL@@QAEAAV01@PBG@Z proc near
.text:00D284AE                                         ; CODE XREF: CDataList::SetTitle(ushort const *)+Ep
.text:00D284AE                                         ; CDocObjectHost::_PublishParsedData(int)-32DD9p ...
.text:00D284AE
.text:00D284AE psz             = dword ptr  8
.text:00D284AE
.text:00D284AE                 mov     edi, edi
.text:00D284B0                 push    ebp
.text:00D284B1                 mov     ebp, esp
.text:00D284B3                 push    esi
.text:00D284B4                 mov     esi, ecx
.text:00D284B6                 push    dword ptr [esi] ; bstrString
.text:00D284B8                 call    _SysFreeString@4 ; SysFreeString(x)
.text:00D284BD                 push    [ebp+psz]       ; psz
.text:00D284C0                 call    _SysAllocString@4 ; SysAllocString(x)
.text:00D284C5                 mov     [esi], eax
.text:00D284C7                 mov     eax, esi
.text:00D284C9                 pop     esi
.text:00D284CA                 pop     ebp
.text:00D284CB                 retn    4
.text:00D284CB ??4CComBSTR@ATL@@QAEAAV01@PBG@Z endp

        異常情況下,不會走到這個流程中。。。
堆疊資訊如下:
0:008> k
ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
0211d34c 00d288b9 IEFRAME!Ordinal218+0x2079
0211e3b0 00d28ef2 IEFRAME!Ordinal218+0x2484
0211e45c 00d365b0 IEFRAME!Ordinal218+0x2abd
0211e4a4 63777bcb IEFRAME!Ordinal303+0x4052
0211f568 63776ac8 mshtml!CWebOCEvents::BeforeNavigate2+0x29f

異常情況下的堆疊呼叫關係如下:
0:008> k
ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
0211d34c 00d288b9 IEFRAME!Ordinal218+0x2079
0211e3b0 00d28ef2 IEFRAME!Ordinal218+0x2484
0211e45c 00d365b0 IEFRAME!Ordinal218+0x2abd
0211e4a4 63777bcb IEFRAME!Ordinal303+0x4052
0211f568 63776ac8 mshtml!CWebOCEvents::BeforeNavigate2+0x29f


發現都會呼叫0211f568 63776ac8 mshtml!CWebOCEvents::BeforeNavigate2+0x29f函式,在這個函式上下斷點,跟蹤處理流程上的變化
63776a99 ff74247c        push    dword ptr [esp+7Ch]
63776a9d 52              push    edx
63776a9e ff742428        push    dword ptr [esp+28h]
63776aa2 8b542428        mov     edx,dword ptr [esp+28h]
63776aa6 ffb42484000000  push    dword ptr [esp+84h]
63776aad ffb42480000000  push    dword ptr [esp+80h]
63776ab4 51              push    ecx
63776ab5 ff30            push    dword ptr [eax]
63776ab7 8b8c24d4000000  mov     ecx,dword ptr [esp+0D4h]
63776abe 8d442454        lea     eax,[esp+54h]
63776ac2 50              push    eax
63776ac3 e8010f0000      call    mshtml!CWebOCEvents::BeforeNavigate2 (637779c9) //斷在這裡
此時ECX中儲存了 超連結的路徑
0:008> du ecx
037c67b0  "file:///c:/windows/system32/BBBB"
037c67f0  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c6830  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c6870  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c68b0  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c68f0  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c6930  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c6970  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c69b0  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c69f0  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c6a30  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
037c6a70  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
	求得字串長度
	63777a51 8d5002          lea     edx,[eax+2]
	63777a54 668b08          mov     cx,word ptr [eax]
	63777a57 40              inc     eax
	63777a58 40              inc     eax
	63777a59 663bce          cmp     cx,si
	63777a5c 75f6            jne     mshtml!CWebOCEvents::BeforeNavigate2+0x8b (63777a54)
	63777a5e 2bc2            sub     eax,edx		//計算結果為字串長度
	63777a60 d1f8            sar     eax,1
	計算結果
	nromal:
	0:008> r eax
	eax=0000010b
	Bug:
	0:008> r eax
	eax=00000255
	....
	63777ab9 ffb580efffff    push    dword ptr [ebp-1080h]	//壓棧,把字串指標壓棧	源地址
	63777abf 8bb58cefffff    mov     esi,dword ptr [ebp-1074h] ss:0023:0211e4f4=0211f5c8
	63777ac5 832600          and     dword ptr [esi],0
	63777ac8 53              push    ebx
	63777ac9 8d85b0efffff    lea     eax,[ebp-1050h]
	63777acf 50              push    eax		//目的地址
	63777ad0 e871e2e7ff      call    mshtml!StringCchCopyW (635f5d46) 字串複製函式,
	.....
	63777bbb 8b8598efffff    mov     eax,dword ptr [ebp-1068h]
	63777bc1 8b08            mov     ecx,dword ptr [eax]
	63777bc3 83c714          add     edi,14h
	63777bc6 57              push    edi
	63777bc7 50              push    eax
	63777bc8 ff510c          call    dword ptr [ecx+0Ch]  ds:0023:00d2b850=00d36523   這裡進入iframe.dll中的處理流程
		.text:00D36592                 push    edi             ; int
		.text:00D36593                 push    [ebp+arg_20]    ; int
		.text:00D36596                 push    [ebp+Size]      ; Size
		.text:00D36599                 push    [ebp+Src]       ; Src
		.text:00D3659C                 push    eax             ; int
		.text:00D3659D                 push    [ebp+arg_10]    ; int
		.text:00D365A0                 push    ebx             ; int
		.text:00D365A1                 push    ecx             ; struct _ITEMIDLIST_ABSOLUTE *
		.text:00D365A2                 push    [ebp+ppvOut]    ; int
		.text:00D365A5                 push    dword ptr [esi+48h] ; int
		.text:00D365A8                 push    [ebp+ppvOut]    ; punk
		.text:00D365AB                 call    _FireEvent_BeforeNavigate@44 ; FireEvent_BeforeNavigate(x,x,x,x,x,x,x,x,x,x,x) //這個函式中進入不同的處理流程。。。。
				.text:00D28ED4                 lea     eax, [ebp+pcszURL]
				.text:00D28ED7                 push    eax             ; int
				.text:00D28ED8                 push    [ebp+arg_C]     ; struct _ITEMIDLIST_ABSOLUTE *
				.text:00D28EDB                 mov     [ebp+var_4.lpVtbl], esi
				.text:00D28EDE                 mov     [ebp+ppvOut], esi
				.text:00D28EE1                 mov     [ebp+var_10], esi
				.text:00D28EE4                 mov     [ebp+bstrString], esi
				.text:00D28EE7                 mov     [ebp+var_14], esi
				.text:00D28EEA                 mov     [ebp+pcszURL], esi
				.text:00D28EED                 call    ?GetEventURL@@YGXPBU_ITEMIDLIST_ABSOLUTE@@AAVCComBSTR@ATL@@@Z ; GetEventURL(_ITEMIDLIST_ABSOLUTE const *,ATL::CComBSTR &)
					.text:00D2887D                 mov     esi, [ebp+arg_4]
					.text:00D28880                 push    edi
					.text:00D28881                 jz      loc_C482EE
					.text:00D28887                 and     [ebp+psz], 0
					.text:00D2888F                 push    8000h           ; __int16
					.text:00D28894                 lea     ecx, [ebp+psz]
					.text:00D2889A                 push    ecx             ; unsigned __int16 *
					.text:00D2889B                 push    eax             ; struct _ITEMIDLIST_ABSOLUTE *
					.text:00D2889C                 call    _IEGetDisplayName@12 ; 函式返回值在正常與異常情況下不同。。。
					.text:00D288A1                 mov     edi, eax
					.text:00D288A3                 test    edi, edi
					.text:00D288A5                 jl      loc_C482EE
					.text:00D288AB                 lea     eax, [ebp+psz]
					.text:00D288B1                 push    eax             ; psz
					.text:00D288B2                 mov     ecx, esi
					.text:00D288B4                 call    ??4CComBSTR@ATL@@QAEAAV01@PBG@Z ; ATL::CComBSTR::operator=(ushort const *)
					.text:00D288B9                 cmp     dword ptr [esi], 0
					.text:00D288BC                 jz      loc_D776E4

最終是 call    _IEGetDisplayName@12 此函式正常情況下與崩潰情況下的返回值不同,導致了執行流程的不同,最終導致Adfilter.dll呼叫wcslen()函式出錯。。。
IEGetDisplayName最終呼叫:
	.text:00C3589B                 push    [ebp+cwchBuf]   ; cwchBuf
	.text:00C3589E                 push    esi             ; pwszDst
	.text:00C3589F                 push    [ebp+arg_4]     ; int
	.text:00C358A2                 push    [ebp+ppidlLast] ; int
	.text:00C358A5                 push    [ebp+ppv]       ; int
	.text:00C358A8                 call    _DisplayNameOfW@20 ; DisplayNameOfW(x,x,x,x,x)
		.text:00C35784                 mov     eax, [ebp+arg_0]
		.text:00C35787                 mov     esi, [ebp+pwszDst]
		.text:00C3578A                 and     word ptr [esi], 0
		.text:00C3578E                 mov     ecx, [eax]
		.text:00C35790                 lea     edx, [ebp+var_10C]
		.text:00C35796                 push    edx
		.text:00C35797                 push    [ebp+arg_8]
		.text:00C3579A                 push    [ebp+arg_4]
		.text:00C3579D                 push    eax
		.text:00C3579E                 call    dword ptr [ecx+2Ch] ; 這裡返回了0x8007006f錯誤,執行的函式是SHELL32!ILRemoveLastID()
	ILRemoveLastID()函式解釋如下:
	Removes the last SHITEMID structure from an ITEMIDLIST structure,

至此此次360網盾 廣告攔截模組 的bug才算分析完畢,其中也有一些不太明白的地方,但程式基本的處理流程就是這樣的。現在可以總結一下這個360bug的觸發原因了。。。

三.總結
        前前後後花了很長時間來分析這個bug,也走了很長的彎路。
        360網盾的廣告攔截模組給IE註冊了很多個回撥函式,但在處理回撥的資料時存在問題,直接引用並下發IE ieframe.dll的GetEventURL()函式的返回值,
並沒有判斷返回值是否為空情況的情況存在,傳遞給了wcslen()函式,導致IE崩潰。
Assay_Bug.txt
上傳的附件:

相關文章