<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/papers/1026

            0x00?引言


            @瞌睡龍讓俺仔細介紹一下,所以我就把之前文章http://drops.wooyun.org/papers/1020的一節的東西單獨提出來了,之前百度瀏覽器5.0版本子窗口堆溢出的那版的程序我已經找不太到了,找到最接近的版本修復的只剩一個棧空間不足的問題而已了,這個小毛病我就擱在事后分析里面好了。

            我找到的早期版本,比如4.5版,它的內存損壞和5.x的內存損壞效果類似,而且崩潰邏輯、位置都大體相同,5.x那個小報告中我提到的“低版本程序不測試直接轉移到高版本”就是讓這一個問題橫跨幾個世紀的主要原因。

            當然,以下是我晚上幾個小時調(口)試(胡)出來的,由于家里的電腦下WDK一直失敗,所以沒用上最新科技,只用了一個很老的windbg版本,有的地方還有些問題,所以我會粘來一點之前草稿里的數據,不過我確定這個對結果沒有影響的。還有就是由于代碼上班的時候調了一點,下班后回家繼續調了后面的(俺是新開的例程),所以可能會有一些神推理名推測和超劇情發展的東西,這個請見諒。

            由于代碼實在太長,所以我會適當的標記出我在干什么,以及我想要得到什么結果,所以如果你看到了莫名其妙的黑色粗體標記,那肯定是我的注解。另外,由于這個windbg貼的代碼本身實在已經是錯綜復雜了,所以我不會一句句的解釋了,我會直接介紹函數在作甚,而且由于個人水平渣,寫的時候卡殼了多次,所以這我已經預感到難免會出問題,這個也請大家見諒,各位發現不對的話請及時糊我熊臉!

            0x01?基本需求


            一個調試器是必要的,由于涉及事后調試和即時調試,俺就使用windbg來進行啦。由于目標程序是32位的,所以我選擇了x86版的windbg。操作系統是Windows?7?sp1?簡體中文版,說是oem但是看起來像盜版系統的系統。

            然后就是幾個基本的命令,t?步入,p?步過,?gu?執行到返回,dd?查看dword,?da?查看ansi,?k?顯示調用棧,?poi?析取指針,等等,遇到新不明物種的話,windbg的F1里面的介紹是非常詳盡的。

            0x02?簡單的事后分析(介紹)


            事后分析我們就用百度瀏覽器5.0的一個棧內存不夠分導致的Stack?Buffer?Overrun為例好了,poc還是那個,口胡我第一,那么開始唄。

            0x02a?開始

            首先,我們可以確定的是我們的poc可以導致這個程序崩潰,而通常我們的目標程序也會自帶有一個dump文件,例如:

            2014030816551761511.png
            ? 圖:通常在%temp%下可能有崩潰文件,也有可能在%appdata%

            打開windbg,載入dump文件,進行簡單的!analyze?-v。顯示信息如下:

            #!bash
            The stored exception information can be accessed via .ecxr.
            (51fc.a978): Stack overflow - code c00000fd (first/second chance not available)
            eax=00000000 ebx=00000000 ecx=0046700c edx=0061e3e4 esi=000002a8 edi=00000000
            eip=77a0f8d1 esp=0061bbe0 ebp=0061bc4c iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
            ntdll!NtWaitForSingleObject+0x15:
            77a0f8d1 83c404          add     esp,4
            0:000> !analyze -v
            *******************************************************************************
            *                                                                             *
            *                        Exception Analysis                                   *
            *                                                                             *
            *******************************************************************************
            
            FAULTING_IP: 
            browsercore+dbda7
            033fbda7 8500            test    dword ptr [eax],eax
            
            EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
            ExceptionAddress: 033fbda7 (browsercore+0x000dbda7)
               ExceptionCode: c00000fd (Stack overflow)
              ExceptionFlags: 00000000
            NumberParameters: 2
               Parameter[0]: 00000000
               Parameter[1]: 00522000
            
            PROCESS_NAME:  baidubrowser.exe
            
            ERROR_CODE: (NTSTATUS) 0xc00000fd - <Unable to get error code text>
            
            EXCEPTION_CODE: (NTSTATUS) 0xc00000fd - <Unable to get error code text>
            
            EXCEPTION_PARAMETER1:  00000000
            
            EXCEPTION_PARAMETER2:  00522000
            
            NTGLOBALFLAG:  0
            
            FAULTING_THREAD:  0000a978
            
            DEFAULT_BUCKET_ID:  STACK_OVERFLOW
            
            PRIMARY_PROBLEM_CLASS:  STACK_OVERFLOW
            
            BUGCHECK_STR:  APPLICATION_FAULT_STACK_OVERFLOW_INVALID_POINTER_READ
            
            LAST_CONTROL_TRANSFER:  from 045b7a85 to 033fbda7
            
            STACK_TEXT:  
            WARNING: Stack unwind information not available. Following frames may be wrong.
            0061e2a8 045b7a85 0061e3e4 0061e634 00000001 browsercore+0xdbda7
            0061e2c4 0337100c 0061e3e4 0061e634 0061e7f4 browsercore+0x1297a85
            0061e620 03333292 0061e7f4 00000000 00000000 browsercore+0x5100c
            ……(略)
            0061fe88 001e63bf 00100000 00000000 00352318 baidubrowser+0x65da
            0061ff18 7703336a 7efde000 0061ff64 77a29f72 baidubrowser+0xe63bf
            0061ff24 77a29f72 7efde000 2a534886 00000000 kernel32!BaseThreadInitThunk+0xe
            0061ff64 77a29f45 001e6412 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
            0061ff7c 00000000 001e6412 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b
            
            
            STACK_COMMAND:  ~0s; .ecxr ; kb
            
            FOLLOWUP_IP: 
            browsercore+dbda7
            033fbda7 8500            test    dword ptr [eax],eax
            
            SYMBOL_STACK_INDEX:  0
            
            SYMBOL_NAME:  browsercore+dbda7
            
            FOLLOWUP_NAME:  MachineOwner
            
            MODULE_NAME: browsercore
            
            IMAGE_NAME:  browsercore.dll
            
            DEBUG_FLR_IMAGE_TIMESTAMP:  526f3e67
            
            FAILURE_BUCKET_ID:  STACK_OVERFLOW_c00000fd_browsercore.dll!Unknown
            
            BUCKET_ID:  APPLICATION_FAULT_STACK_OVERFLOW_INVALID_POINTER_READ_browsercore+dbda7
            
            WATSON_IBUCKET:  2118667
            
            WATSON_IBUCKETTABLE:  17
            
            WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/baidubrowser_exe/2_210_0_42889/526f3e61/browsercore_dll/10_0_0_17/526f3e67/c00000fd/000dbda7.htm?Retriage=1
            
            Followup: MachineOwner
            ---------
            

            我們可以由上得到很多重要的信息:

            例如最上層的調用棧、BUCKET信息(分類漏洞)、出錯的位置、出錯的語句、它并沒有對這個異常的處理程序等等,還有最重要的信息:我們根本沒它的符號,淦。

            0x01b?查看崩潰附近的數據

            好在它沒有做什么其他的事兒,我們查看faulting?ip附近的代碼即可知道他為什么會崩。

            #!bash
            FAULTING_IP: 
            browsercore+dbda7
            033fbda7 8500            test    dword ptr [eax],eax
            

            執行

            #!bash
            uf?browsercore+dbda7 
            

            得到:

            #!bash
            0:000> uf browsercore+dbda7
            Unable to load image C:\Program Files (x86)\baidu\BaiduBrowser\browsercore.dll, Win32 error 0n2
            *** WARNING: Unable to verify timestamp for browsercore.dll
            *** ERROR: Module load completed but symbols could not be loaded for browsercore.dll
            browsercore+0xdbd94:
            033fbd94 3bc8            cmp     ecx,eax
            033fbd96 720a            jb      browsercore+0xdbda2 (033fbda2)
            
            browsercore+0xdbd98:
            033fbd98 8bc1            mov     eax,ecx
            033fbd9a 59              pop     ecx
            033fbd9b 94              xchg    eax,esp
            033fbd9c 8b00            mov     eax,dword ptr [eax]
            033fbd9e 890424          mov     dword ptr [esp],eax
            033fbda1 c3              ret
            
            browsercore+0xdbda2:
            033fbda2 2d00100000      sub     eax,1000h
            
            browsercore+0xdbda7:
            033fbda7 8500            test    dword ptr [eax],eax  ;崩潰在此
            033fbda9 ebe9            jmp     browsercore+0xdbd94 (033fbd94)
            

            但是這是什么?看起來為什么這么像__alloca_probe的驗證代碼?對比一下實實在在的\__alloca_probe看來是沒跑了。

            #!bash
            __alloca_probe:
            push           ecx
            cmp            eax,1000h
            lea            ecx,[esp+8]
            jb             lastpage
            probepages:
            sub            ecx,1000h
            sub            eax,1000h
            test           dword ptr [ecx],eax
            cmp            eax,1000h
            jae            probepages 
            lastpage:
            sub            ecx,eax
            mov            eax,esp
            test           dword ptr [ecx],eax
            mov            esp,ecx
            mov            ecx,dword ptr [eax]
            mov            eax,dword ptr [eax+4]
            push           eax
            Ret 
            

            崩在了最后的棧校驗上。查看一下完整的調用棧,使用~*kvn查看所有線程的調用棧:

            #!bash
            0:000> ~*kvn
            
            .  0  Id: 51fc.a978 Suspend: 0 Teb: 7efdd000 Unfrozen
             # ChildEBP RetAddr  Args to Child              
            00 0061bbe0 76fa149d 000002a8 00000000 00000000 ntdll!NtWaitForSingleObject+0x15 (FPO: [3,0,0])
            01 0061bc4c 77031194 000002a8 ffffffff 00000000 KERNELBASE!WaitForSingleObjectEx+0x98 (FPO: [SEH])
            02 0061bc64 77031148 000002a8 ffffffff 00000000 kernel32!WaitForSingleObjectExImplementation+0x75 (FPO: [3,0,4])
            03 0061bc78 001056c7 000002a8 ffffffff 006e9948 kernel32!WaitForSingleObject+0x12 (FPO: [2,0,0])
            WARNING: Stack unwind information not available. Following frames may be wrong.
            04 0061dd78 00105467 ac68c25f 0010542d 7710030c baidubrowser+0x56c7
            05 0061dda0 7706fffb 0061de58 ac7abd84 00000000 baidubrowser+0x5467
            06 0061de28 77a674ff 0061de58 77a673dc 00000000 kernel32!UnhandledExceptionFilter+0x127 (FPO: [SEH])
            07 0061de30 77a673dc 00000000 0061ff64 77a1c550 ntdll!__RtlUserThreadStart+0x62 (FPO: [SEH])
            08 0061de44 77a67281 00000000 00000000 00000000 ntdll!_EH4_CallFilterFunc+0x12 (FPO: [Uses EBP] [0,0,4])
            09 0061de6c 77a4b499 fffffffe 0061ff54 0061dfa8 ntdll!_except_handler4+0x8e (FPO: [4,5,4])
            0a 0061de90 77a4b46b 0061df58 0061ff54 0061dfa8 ntdll!ExecuteHandler2+0x26 (FPO: [Uses EBP] [5,3,1])
            0b 0061deb4 77a4b40e 0061df58 0061ff54 0061dfa8 ntdll!ExecuteHandler+0x24 (FPO: [5,0,3])
            0c 0061df40 77a00133 0061df58 0061dfa8 0061df58 ntdll!RtlDispatchException+0x127 (FPO: [2,25,4])
            0d 0061df40 033fbda7 0061df58 0061dfa8 0061df58 ntdll!KiUserExceptionDispatcher+0xf (FPO: [2,0,0]) (CONTEXT @ 0061dfa8)
            0e 0061e2a8 045b7a85 0061e3e4 0061e634 00000001 browsercore+0xdbda7
            0f 0061e2c4 0337100c 0061e3e4 0061e634 0061e7f4 browsercore+0x1297a85
            10 0061e620 03333292 0061e7f4 00000000 00000000 browsercore+0x5100c
            11 0061e814 048b515c 0061e82c fffffffa 00000200 browsercore+0x13292
            12 0061e854 03334634 02ec7d94 02ec2780 02ec2780 browsercore+0x159515c
            13 0061e974 046e67c9 02ec7d94 02ec7d94 02e63c30 browsercore+0x14634
            
               1  Id: 51fc.9920 Suspend: 1 Teb: 7efda000 Unfrozen
             # ChildEBP RetAddr  Args to Child              
            00 02aff61c 76fa15e9 00000003 02aff66c 00000001 ntdll!ZwWaitForMultipleObjects+0x15 (FPO: [5,0,0])
            01 02aff6b8 770319fc 02aff66c 02aff6e0 00000000 KERNELBASE!WaitForMultipleObjectsEx+0x100 (FPO: [SEH])
            02 02aff700 770341d8 00000003 7efde000 00000000 kernel32!WaitForMultipleObjectsExImplementation+0xe0 (FPO: [5,8,4])
            
            …………blablabla
            

            然后我們可以很開心的看到:

            #!bash
            0:000> ~*kvn
            
            .  0  Id: 51fc.a978 Suspend: 0 Teb: 7efdd000 Unfrozen
             # ChildEBP RetAddr  Args to Child              
            00 0061bbe0 76fa149d 000002a8 00000000 00000000 ntdll!NtWaitForSingleObject+0x15 (FPO: [3,0,0])
            01 0061bc4c 77031194 000002a8 ffffffff 00000000 KERNELBASE!WaitForSingleObjectEx+0x98 (FPO: [SEH])
            02 0061bc64 77031148 000002a8 ffffffff 00000000 kernel32!WaitForSingleObjectExImplementation+0x75 (FPO: [3,0,4])
            03 0061bc78 001056c7 000002a8 ffffffff 006e9948 kernel32!WaitForSingleObject+0x12 (FPO: [2,0,0])
            WARNING: Stack unwind information not available. Following frames may be wrong.
            04 0061dd78 00105467 ac68c25f 0010542d 7710030c baidubrowser+0x56c7
            05 0061dda0 7706fffb 0061de58 ac7abd84 00000000 baidubrowser+0x5467
            06 0061de28 77a674ff 0061de58 77a673dc 00000000 kernel32!UnhandledExceptionFilter+0x127 (FPO: [SEH])
            07 0061de30 77a673dc 00000000 0061ff64 77a1c550 ntdll!__RtlUserThreadStart+0x62 (FPO: [SEH])
            08 0061de44 77a67281 00000000 00000000 00000000 ntdll!_EH4_CallFilterFunc+0x12 (FPO: [Uses EBP] [0,0,4])
            09 0061de6c 77a4b499 fffffffe 0061ff54 0061dfa8 ntdll!_except_handler4+0x8e (FPO: [4,5,4])
            0a 0061de90 77a4b46b 0061df58 0061ff54 0061dfa8 ntdll!ExecuteHandler2+0x26 (FPO: [Uses EBP] [5,3,1])
            0b 0061deb4 77a4b40e 0061df58 0061ff54 0061dfa8 ntdll!ExecuteHandler+0x24 (FPO: [5,0,3])
            0c 0061df40 77a00133 0061df58 0061dfa8 0061df58 ntdll!RtlDispatchException+0x127 (FPO: [2,25,4])
            0d 0061df40 033fbda7 0061df58 0061dfa8 0061df58 ntdll!KiUserExceptionDispatcher+0xf (FPO: [2,0,0]) (CONTEXT @ 0061dfa8)
            0e 0061e2a8 045b7a85 0061e3e4 0061e634 00000001 browsercore+0xdbda7
            0f 0061e2c4 0337100c 0061e3e4 0061e634 0061e7f4 browsercore+0x1297a85
            

            我們看看它的上層函數做了什么:

            #!bash
            0:000> uf 045b7a85
            No code found, aborting
            

            居然顯示沒有代碼,看來事后調試已經滿足不了我們了,不過既然跑到了_alloca_probe,那真相就只有一個了!對,在棧上分配的東西太大了,比棧還大,比棧還牛逼,于是棧不干了,結果就拋個異常罷工了。

            這只是一個小演示而已,反正我們沒符號,反正我們沒代碼,但是我們有PoC,我們需要的是實時調試,下面進入正題。

            0x03?實時調試


            下面使用的目標程序是百度瀏覽器v4.5,由于我們的poc簡單粗暴,為了防止代碼一加載就崩,我們在它崩潰前加一個alert(1),給我們和windbg一個心理準備,使得poc變成下面這樣:

            #!html
            <script>
            var s="A";
            var i=1;
            for(i=1;i<599559;i++)
            s+="A";
            alert(1);
            window.open(s);
            </script>
            

            運行瀏覽器,最好是直接把html拖圖標上,這樣之后方便我們找哪個進程容納著html,如下:

            2014030816544725513.png
            ? 圖:?暴風雨前夕

            姨媽大,給它Attach上,

            2014030816542723049.png
            ? 圖:這樣就能找到pid了

            找到對應進程的PID,然后Attach,之后按下g讓它跑起來:

            #!bash
            (9df0.3724): Break instruction exception - code 80000003 (first chance)
            eax=7ef42000 ebx=00000000 ecx=00000000 edx=77a8f8ea esi=00000000 edi=00000000
            eip=77a0000c esp=0c52fe4c ebp=0c52fe78 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
            ntdll!DbgBreakPoint:
            77a0000c cc              int     3
            0:034> g
            ……省略
            STATUS_STACK_BUFFER_OVERRUN encountered
            (9df0.3500): Break instruction exception - code 80000003 (first chance)
            eax=00000000 ebx=55b23f30 ecx=77070174 edx=0653d16d esi=00000000 edi=001b7281
            eip=7706ff55 esp=0653d3b4 ebp=0653d430 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
            kernel32!UnhandledExceptionFilter+0x5f:
            7706ff55 cc              int     3
            

            程序崩潰。查看一下是怎么產生的,執行kvn

            #!bash
            0:006> kvn
            *** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\baidu\BaiduBrowser\bdlogicmain.dll - 
             # ChildEBP RetAddr  Args to Child              
            00 0653d430 55a57789 55b23f30 34bb28ee cb44d711 kernel32!UnhandledExceptionFilter+0x5f (FPO: [SEH])
            WARNING: Stack unwind information not available. Following frames may be wrong.
            01 0653d764 5580757b 001b7281 656c6966 00000000 bdlogicmain!BrowserLogicInit+0x198229
            02 0653f500 55a4b5f4 0f1a0020 12960020 001b7281 bdlogicmain+0x757b
            03 0653f5b8 559f51a6 12700020 0653f5e4 11bef338 bdlogicmain!BrowserLogicInit+0x18c094
            04 0653f5fc 558c5b95 12700020 0653f640 559b4105 bdlogicmain!BrowserLogicInit+0x135c46
            05 0653f608 559b4105 062b2a1c 559f5040 00000000 bdlogicmain!BrowserLogicInit+0x6635
            *** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\baidu\BaiduBrowser\bdcommon.dll - 
            06 0653f640 653d18ec 0eed1240 0653f688 653d1b77 bdlogicmain!BrowserLogicInit+0xf4ba5
            07 0653f64c 653d1b77 0653f664 00f7cac9 03329ce0 bdcommon!Util::Help::GetMimeTypeByExt+0x314a
            08 0653f688 653cf6a9 ffffffff 00000000 03329ce0 bdcommon!Util::Help::GetMimeTypeByExt+0x33d5
            09 0653f6ac 653ceb15 00000001 03329bb0 03329bb0 bdcommon!Util::Help::GetMimeTypeByExt+0xf07
            0a 0653f6cc 653cf0f7 03329bb0 00000000 00000001 bdcommon!Util::Help::GetMimeTypeByExt+0x373
            0b 0653f6e0 653cefcd 03329bb0 03329bb0 653cf8d5 bdcommon!Util::Help::GetMimeTypeByExt+0x955
            0c 0653f724 653cfe36 0653f798 653d2576 03329bb0 bdcommon!Util::Help::GetMimeTypeByExt+0x82b
            0d 0653f72c 653d2576 03329bb0 c5a8d143 00000000 bdcommon!Util::Help::GetMimeTypeByExt+0x1694
            0e 0653f798 653d2a0c 0653f7d8 653dc835 032cdeb8 bdcommon!Util::Help::GetMimeTypeByExt+0x3dd4
            0f 0653f7a0 653dc835 032cdeb8 c5a8d103 00000000 bdcommon!Util::Help::GetMimeTypeByExt+0x426a
            10 0653f7d8 653dc8bf 00000000 0653f7f0 7703336a bdcommon!Util::Common::Timer::EraseTimerCallback+0x5b6b
            11 0653f7e4 7703336a 03329bb0 0653f830 77a29f72 bdcommon!Util::Common::Timer::EraseTimerCallback+0x5bf5
            12 0653f7f0 77a29f72 03329bb0 2c33d9fc 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
            13 0653f830 77a29f45 653dc85b 03329bb0 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
            

            以下行為用于將上下文定位到我們出錯的代碼上,而不是kernel32里面

            然后,由于我們在UnhandledExceptionFilter里面,我們查看一下錯誤信息,

            #!bash
             # ChildEBP RetAddr  Args to Child   
            00 0653d430 55a57789 55b23f30 34bb28ee cb44d711 kernel32!UnhandledExceptionFilter+0x5f (FPO: [SEH])
            

            UnhandledExceptionFilter該函數的定義是(msdn當然是我們的好幫手,實在不濟百度百科也湊合吧……):

            #!bash
            LONG WINAPI UnhandledExceptionFilter(
              _In_  struct _EXCEPTION_POINTERS *ExceptionInfo
            );
            

            那第一個參數必然指向_EXCEPTION_POINTERS,而該結構體的定義為:

            #!bash
            typedef struct _EXCEPTION_POINTERS {
              PEXCEPTION_RECORD ExceptionRecord;
              PCONTEXT          ContextRecord;
            } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
            

            而這則正是我們需要的內容,于是,我們先看看這個結構體在哪兒

            #!bash
            0:006> dt _EXCEPTION_POINTERS 55b23f30
            ATL80!_EXCEPTION_POINTERS
               +0x000 ExceptionRecord  : 0x55bb98a0 _EXCEPTION_RECORD
               +0x004 ContextRecord    : 0x55bb98f8 _CONTEXT
            

            然后,我們查看異常的信息

            #!bash
            0:006> .exr 0x55bb98a0
            ExceptionAddress: 5580757b (bdlogicmain+0x0000757b)
               ExceptionCode: c0000409 (Stack buffer overflow)
              ExceptionFlags: 00000001
            NumberParameters: 0
            

            設置異常上下文

            #!bash
            0:006> .cxr 0x55bb98f8
            eax=00000000 ebx=0f1a0020 ecx=34bb2841 edx=00414141 esi=12960020 edi=001b7281
            eip=5580757b esp=0653d76c ebp=0653f500 iopl=0         nv up ei pl nz ac pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
            bdlogicmain+0x757b:
            5580757b 8be5            mov     esp,ebp
            

            現在我們的異常上下文已經被更正如上。

            再回溯一次:

            #!bash
            0:006> kvn
              *** Stack trace for last set context - .thread/.cxr resets it
             # ChildEBP RetAddr  Args to Child              
            WARNING: Stack unwind information not available. Following frames may be wrong.
            00 0653f500 55a4b5f4 0f1a0020 12960020 001b7281 bdlogicmain+0x757b
            01 0653f5b8 559f51a6 12700020 0653f5e4 11bef338 bdlogicmain!BrowserLogicInit+0x18c094
            02 0653f5fc 558c5b95 12700020 0653f640 559b4105 bdlogicmain!BrowserLogicInit+0x135c46
            03 0653f608 559b4105 062b2a1c 559f5040 00000000 bdlogicmain!BrowserLogicInit+0x6635
            04 0653f640 653d18ec 0eed1240 0653f688 653d1b77 bdlogicmain!BrowserLogicInit+0xf4ba5
            05 0653f64c 653d1b77 0653f664 00f7cac9 03329ce0 bdcommon!Util::Help::GetMimeTypeByExt+0x314a
            06 0653f688 653cf6a9 ffffffff 00000000 03329ce0 bdcommon!Util::Help::GetMimeTypeByExt+0x33d5
            07 0653f6ac 653ceb15 00000001 03329bb0 03329bb0 bdcommon!Util::Help::GetMimeTypeByExt+0xf07
            08 0653f6cc 653cf0f7 03329bb0 00000000 00000001 bdcommon!Util::Help::GetMimeTypeByExt+0x373
            09 0653f6e0 653cefcd 03329bb0 03329bb0 653cf8d5 bdcommon!Util::Help::GetMimeTypeByExt+0x955
            0a 0653f724 653cfe36 0653f798 653d2576 03329bb0 bdcommon!Util::Help::GetMimeTypeByExt+0x82b
            0b 0653f72c 653d2576 03329bb0 c5a8d143 00000000 bdcommon!Util::Help::GetMimeTypeByExt+0x1694
            0c 0653f798 653d2a0c 0653f7d8 653dc835 032cdeb8 bdcommon!Util::Help::GetMimeTypeByExt+0x3dd4
            0d 0653f7a0 653dc835 032cdeb8 c5a8d103 00000000 bdcommon!Util::Help::GetMimeTypeByExt+0x426a
            0e 0653f7d8 653dc8bf 00000000 0653f7f0 7703336a bdcommon!Util::Common::Timer::EraseTimerCallback+0x5b6b
            0f 0653f7e4 7703336a 03329bb0 0653f830 77a29f72 bdcommon!Util::Common::Timer::EraseTimerCallback+0x5bf5
            10 0653f7f0 77a29f72 03329bb0 2c33d9fc 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
            11 0653f830 77a29f45 653dc85b 03329bb0 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
            12 0653f848 00000000 653dc85b 03329bb0 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])
            

            現在看起來舒服多了,我們可以清楚的看到崩潰的位置代碼如下:

            #!bash
            0:006> ub bdlogicmain+0x757b
            bdlogicmain+0x7565:
            55807565 8b4dfc          mov     ecx,dword ptr [ebp-4]
            55807568 83c40c          add     esp,0Ch
            5580756b c6441eff00      mov     byte ptr [esi+ebx-1],0
            55807570 5e              pop     esi
            55807571 33cd            xor     ecx,ebp
            55807573 33c0            xor     eax,eax
            55807575 5b              pop     ebx
            55807576 e823f82400      call    bdlogicmain!BrowserLogicInit+0x19783e (55a56d9e); 之后崩潰
            

            找到崩潰點之后,閱讀主程序代碼,了解崩潰的原因

            簡單計算可知bdlogicmain+0x7576就是我們的目標,那么我們就在這兒看一下程序是如何崩潰的吧。

            退出程序,重新打開主程序,直接Attach,然后bp?bdlogicmain+0x7576:

            #!bash
            (a6c.8b4): Break instruction exception - code 80000003 (first chance)
            eax=7ef4b000 ebx=00000000 ecx=00000000 edx=77abf8ea esi=00000000 edi=00000000
            eip=77a3000c esp=0abafe40 ebp=0abafe6c iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
            ntdll!DbgBreakPoint:
            77a3000c cc              int     3
            0:031> bp bdlogicmain+0x7576
            breakpoint 0 redefined
            0:031> bl
             0 e 62067576     0001 (0001)  0:**** bdlogicmain+0x7576
            0:031> g
            

            之后載入PoC,斷在:

            #!bash
            Breakpoint 0 hit
            eax=00000000 ebx=0bcd0020 ecx=d8dfe9d1 edx=00414141 esi=28920020 edi=001b7278
            eip=62067576 esp=002fc6fc ebp=002fe490 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
            bdlogicmain+0x7576:
            62067576 e823f82400      call    bdlogicmain!BrowserLogicInit+0x19783e (622b6d9e)
            

            我們繼續,可以看見這之中會檢查是否有調試器加載(IsDebuggerPresentStub)并拋出異常,看來這個函數應該是處理異常用的,

            #!bash
            0:000> 
            eax=27201628 ebx=0bcd0020 ecx=d8dfe9d1 edx=00414141 esi=28920020 edi=001b7278
            eip=622b7763 esp=002fc3cc ebp=002fc6f4 iopl=0         nv up ei pl nz ac pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200216
            bdlogicmain!BrowserLogicInit+0x198203:
            622b7763 ff150cf12e62    call    dword ptr [bdlogicmain!BrowserLogicInit+0x1cfbac (622ef10c)] ds:002b:622ef10c={kernel32!IsDebuggerPresentStub (756249fd)}
            0:000> 
            eax=27201628 ebx=0bcd0020 ecx=d8dfe9d1 edx=00414141 esi=28920020 edi=001b7278
            eip=756249fd esp=002fc3c8 ebp=002fc6f4 iopl=0         nv up ei pl nz ac pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200216
            kernel32!IsDebuggerPresentStub:
            756249fd eb05            jmp     kernel32!IsDebuggerPresent (75624a04)
            0:000> k
            ChildEBP RetAddr  
            002fc3c4 622b7769 kernel32!IsDebuggerPresentStub
            WARNING: Stack unwind information not available. Following frames may be wrong.
            002fc6f4 6206757b bdlogicmain!BrowserLogicInit+0x198209
            002fe490 622aeb21 bdlogicmain+0x757b
            

            那么這個bdlogicmain+0x7576附近又有什么代碼呢?既然這兒處理異常了,那肯定是之前某個地方出了問題,讓我們使用uf查看一下代碼:

            #!bash
            bdlogicmain+0x7550:
            62067550 8bb56ce2ffff    mov     esi,dword ptr [ebp-1D94h]
            62067556 56              push    esi
            62067557 8d95fcefffff    lea     edx,[ebp-1004h]
            6206755d 52              push    edx
            6206755e 53              push    ebx
            6206755f ff15c4f42e62    call    dword ptr [bdlogicmain!BrowserLogicInit+0x1cff64 (622ef4c4)]
            62067565 8b4dfc          mov     ecx,dword ptr [ebp-4]
            62067568 83c40c          add     esp,0Ch
            6206756b c6441eff00      mov     byte ptr [esi+ebx-1],0
            62067570 5e              pop     esi
            62067571 33cd            xor     ecx,ebp
            62067573 33c0            xor     eax,eax
            62067575 5b              pop     ebx
            62067576 e823f82400      call    bdlogicmain!BrowserLogicInit+0x19783e (622b6d9e) ;fails here
            6206757b 8be5            mov     esp,ebp
            6206757d 5d              pop     ebp
            6206757e c3              ret
            

            看起來這個函數很像是最終用來檢測Security?Cookie的函數。讓我們對比一下其他Security?Cookie的處理調用:

            #!bash
            mov  ecx, [ebp+SOMETHING]              ; get the adjusted cookie.
            xor  ecx, ebp                          ; un-adjust it, since
                                                   ;   ((N xor X) xor X) == N.
            call @__sec_check_cookie               ; check the cookie.
            

            不直觀嗎?看看隨便一個C++程序的編譯后結果:

            #!bash
            .text:004010D4                 mov     ecx, [ebp+var_4]  
            .text:004010D7                 xor     ecx, ebp  
            .text:004010D9                 xor     eax, eax  
            .text:004010DB                 pop     esi  
            .text:004010DC                 call    @[email protected] ; __security_check_cookie(x)   ;對比下其他程序,其實就是__security_check_cookie失敗了
            .text:004010E1                 mov     esp, ebp  
            .text:004010E3                 pop     ebp  
            .text:004010E4                 retn  
            .text:004010E4 _wmain          endp  
            

            好吧,看來我們得出第一個結論:Security?Cookie校驗失敗了。

            那我們在函數稍前的位置(除了Security?cookie?check的上一個Call)設置斷點:

            #!bash
            0:030> bp bdlogicmain+0x7550
            *** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\Baidu\BaiduBrowser\bdlogicmain.dll - 
            0:030> g
            

            重復上述步驟,斷在了:

            #!bash
            Breakpoint 0 hit
            eax=00000000 ebx=28a80020 ecx=4b8aa8e3 edx=00000420 esi=0038c220 edi=001b7278
            eip=6c3e7550 esp=0038c214 ebp=0038dfb0 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
            bdlogicmain+0x7550:
            6c3e7550 8bb56ce2ffff    mov     esi,dword ptr [ebp-1D94h] ss:002b:0038c21c=001b7278
            0:000> u
            bdlogicmain+0x7550:
            6c3e7550 8bb56ce2ffff    mov     esi,dword ptr [ebp-1D94h]
            6c3e7556 56              push    esi
            6c3e7557 8d95fcefffff    lea     edx,[ebp-1004h]
            6c3e755d 52              push    edx
            6c3e755e 53              push    ebx
            6c3e755f ff15c4f4666c    call    dword ptr [bdlogicmain!BrowserLogicInit+0x1cff64 (6c66f4c4)]
            6c3e7565 8b4dfc          mov     ecx,dword ptr [ebp-4]
            6c3e7568 83c40c          add     esp,0Ch
            

            我們可以看到有一個可能有三個參數的函數調用:

            #!bash
            6c3e7556 56              push    esi
            6c3e7557 8d95fcefffff    lea     edx,[ebp-1004h]
            6c3e755d 52              push    edx
            6c3e755e 53              push    ebx
            6c3e755f ff15c4f4666c    call    dword ptr [bdlogicmain!BrowserLogicInit+0x1cff64 (6c66f4c4)]
            

            由于沒有符號,我們只好t步入:

            #!bash
            0:000> t
            eax=00000000 ebx=28a80020 ecx=4b8aa8e3 edx=00000420 esi=001b7278 edi=001b7278
            eip=6c3e7556 esp=0038c214 ebp=0038dfb0 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
            bdlogicmain+0x7556:
            6c3e7556 56              push    esi
            0:000> dd esi
            001b7278  00000000
            

            看來第三個參數是0,

            #!bash
            0:000> t
            eax=00000000 ebx=28a80020 ecx=4b8aa8e3 edx=00000420 esi=001b7278 edi=001b7278
            eip=6c3e7557 esp=0038c210 ebp=0038dfb0 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
            bdlogicmain+0x7557:
            6c3e7557 8d95fcefffff    lea     edx,[ebp-1004h]
            0:000> 
            eax=00000000 ebx=28a80020 ecx=4b8aa8e3 edx=0038cfac esi=001b7278 edi=001b7278
            eip=6c3e755d esp=0038c210 ebp=0038dfb0 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
            bdlogicmain+0x755d:
            6c3e755d 52              push    edx
            0:000> dd edx
            0038cfac  656c6966 2f2f2f3a 552f3a45 73726573
            0038cfbc  616c422f 53547473 7365442f 706f746b
            0038cfcc  4141412f 41414141 41414141 41414141
            0038cfdc  41414141 41414141 41414141 41414141
            0038cfec  41414141 41414141 41414141 41414141
            0038cffc  41414141 41414141 41414141 41414141
            0038d00c  41414141 41414141 41414141 41414141
            0038d01c  41414141 41414141 41414141 41414141
            0:000> t
            eax=00000000 ebx=28a80020 ecx=4b8aa8e3 edx=0038cfac esi=001b7278 edi=001b7278
            eip=6c3e755e esp=0038c20c ebp=0038dfb0 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
            bdlogicmain+0x755e:
            6c3e755e 53              push    ebx
            

            第二個參數,edx現在存儲著指向我們字符串的指針,而且字符只有0x1004字節。

            看看第一個參數ebx,這是它的信息:

            #!bash
            0:000> !address 28a80020
             ProcessParametrs 007607f0 in range 00760000 00860000
             Environment 09e98c48 in range 09e10000 0a210000
                28a80000 : 28a80000 - 001b8000
                                Type     00020000 MEM_PRIVATE
                                Protect  00000004 PAGE_READWRITE
                                State    00001000 MEM_COMMIT
                                Usage    RegionUsageHeap
                                Handle   07790000
            

            它指向一片空的內存,應該是剛剛申請的,指針位于頭部后0x20個字節。

            #!bash
            0:000> ?(28c38000-28a80000)
            Evaluate expression: 1802240 = 001b8000
            

            這片內存堆的可用大小為1802240字節。

            這三個參數都知道了(1:ebx,一個很大空間的緩沖區,?2:edx,指向我們地址的指針,?3:0),繼續走,

            #!bash
            0:000> t
            eax=00000000 ebx=28a80020 ecx=4b8aa8e3 edx=0038cfac esi=001b7278 edi=001b7278
            eip=6c3e755f esp=0038c208 ebp=0038dfb0 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
            bdlogicmain+0x755f:
            6c3e755f ff15c4f4666c    call    dword ptr [bdlogicmain!BrowserLogicInit+0x1cff64 (6c66f4c4)] ds:002b:6c66f4c4={MSVCR100!strncpy (6d0e2ad0)}
            

            我們可以看到它其實是strncpy,這樣,我們就知道它的調用了。

            我們p出來:

            #!bash
            0:000> p
            eax=28a80020 ebx=28a80020 ecx=00000000 edx=00414141 esi=001b7278 edi=001b7278
            eip=6c3e7565 esp=0038c208 ebp=0038dfb0 iopl=0         nv up ei pl zr na pe nc
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200246
            bdlogicmain+0x7565:
            6c3e7565 8b4dfc          mov     ecx,dword ptr [ebp-4] ss:002b:0038dfac=4bb27741
            

            看看返回值上有什么:

            #!bash
            0:000> dd eax
            28a80020  656c6966 2f2f2f3a 552f3a45 73726573
            28a80030  616c422f 53547473 7365442f 706f746b
            28a80040  4141412f 41414141 41414141 41414141
            28a80050  41414141 41414141 41414141 41414141
            28a80060  41414141 41414141 41414141 41414141
            28a80070  41414141 41414141 41414141 41414141
            28a80080  41414141 41414141 41414141 41414141
            28a80090  41414141 41414141 41414141 41414141
            

            確實是拷貝進去了。

            0x04?試驗


            試驗環境:

            1&2、VS2010,Debug+Release,也就是分別看看文中的malloc(0)會弄出什么情況。
            3&4、gcc,Debug+Release查看malloc(0)是什么情況。
            所謂正確的實踐是檢驗真理的唯一標準,我們分別看看會產生什么問題。
            注:以下都是從調試器直接啟動的,堆是調試器友好的。
            

            0x04a?直觀的編譯、運行

            1、VC2010?Debug?+?malloc(0)

            2014030816534264313.png
            ? 返回了一個非NULL的堆。

            2014030816531984074.png
            ?

            損壞。

            2、?VC2010?Release?+?malloc(0)

            2014030816524787877.png
            ? 情形類似

            HEAP[testMalloc.exe]: Heap block at 005455B8 modified at 005455C1 past requested size of 1 Windows 已在 testMalloc.exe 中觸發一個斷點。

            其原因可能是內存損壞,這說明 testMalloc.exe 中或它所加載的任何 DLL 中有 Bug。

            原因也可能是用戶在 testMalloc.exe 具有焦點時按下了 F12。

            輸出窗口可能提供了更多診斷信息。 程序“[4256] testMalloc.exe: 本機”已退出,返回值為 0 (0x0)。

            3、gcc?Debug+malloc(0)

            2014030816522134427.png
            ? 分配了一個非NULL但是可以釋放的堆。

            2014030816515591239.png
            ? 成功覆蓋了堆的信息

            2014030816512347292.png
            ? 同樣崩潰

            4、gcc?Release+malloc(0)

            2014030816505532197.png
            ? 情形類似

            果不其然四個情況下都表明:VS和G++編譯器編譯后malloc(0)返回的不是NULL,而是一個活生生的堆,而且你動它一下,它就賴地上讓你賠錢了。

            0x04b?具體發生了什么?

            雖然和瀏覽器堆破壞的這一例不一樣,但是為了演示一下malloc(0)分配的內存到底為何不能操作,我們還是使用VC2010+Relase+malloc(0)?32位環境下的程序來試試看吧:

            0x04b.1?編譯源程序

            我們模擬一下那個創建小窗口前的一些準備工作:

            #!cpp
            // testMalloc.cpp : 定義控制臺應用程序的入口點。
            //
            
            #include "stdafx.h"
            #include <stdlib.h>
            #include <string>
            #include <windows.h>
            
            #define URL_LENGTH 26
            
            int _tmain(int argc, _TCHAR* argv[])
            {
                TCHAR * test = (TCHAR *)malloc(0); //很不幸,這兒的參數是0
                memset(test, 0x11 , URL_LENGTH); //為了方便查看,我把改成了0x11
            
                TCHAR url[27] = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 
                //正好26字,假設我們的url就是這個拉
            
                int i = WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, 0, 0,FALSE); 
                char * szTmp = new char[i];
                WideCharToMultiByte(CP_ACP, 0, url, -1, szTmp, i, 0, FALSE);
            
                memcpy(test, szTmp, i); //復制到我們的堆中
            
                free(test);
            
                return 0;
            }
            

            0x04b.2?載入windbg中:

            在wmain處下斷點,l-t之后并用p執行完malloc,然后查看當前分配來的堆的信息:

            2014030816503217634.png
            ? 可以看到當前的堆內數據如下,其中數據使用了堆的填充模式abababe8?abababab,而這看起來像是一個已分配的堆空間的末尾的填充模式(為什么呢?因為如果分配了字節的話,堆會用baadf00d這個填充模式來填充將來可能會被使用的空間,而這個abababe8?blablabla則是像是這個填充模式的末尾,或者,更像是說ANSI字符串的中止符號“”的東西):

            2014030816500856704.png
            ? 這是memset完,我們26個字符填充進去之后的效果:

            2014030816494124061.png??

            這個相當于什么?相當于在一個堆的用戶可操作區域之外做寫入操作,這樣數據就已然超出了堆的申請大小,讓它活生生的演變成了堆溢出,之后程序還會對它進行free,必然是錯上加錯。

            0x04b.3?證明我們的想法

            讓我們換一點代碼,我們把malloc(0)修改為malloc(27),重新載入。

            2014030816490529344.png

            這回,我們看到了一個新的填充模式,baadf00d?,而這正是我們之前提到的可用但是未初始化的堆空間的填充模式。

            而如此如此運行之后,程序正常退出。

            2014030816484971812.png

            0x04c?幾個小名詞

            調試友好

            當在調試器下啟動進程的時候,堆管理器將修改所有新堆的請求,并且設置創建標志,用于啟用“調試友好”的堆,這會應用到內存里面所有堆,包括默認的進程堆,這種堆與原先的最大的差異是堆塊中包含了額外的“填充模式”區域,這個區域位于用戶可訪問的部分之后,堆管理器通過這個區域來確認堆的完整性。如果這個填充模式被修改了,堆管理器會立刻中斷進入調試器內。

            填充模式

            堆管理器在分配堆時自動的使用某個填充模式來初始化某片內存,填充模式的內容取決于堆塊的狀態,當堆塊最初被返回給調用者時,堆管理器將使用填充模式來填充堆塊中用戶可訪問的部分,其中在填充模式中包含的值就是baadf00d,這表示這個堆塊雖然分配成功,但是沒有初始化。如果有程序在沒有初始化堆塊之前就對其進行解引用操作,就會產生一個存取違例的異常;如果程序正確的初始化了堆塊,那么程序將繼續執行,這個堆塊被釋放后,堆管理器將再次對堆塊中用戶可以訪問的部分進行填充,使用的值是feeefeee。設置完這些個填充模式之后,調試器將通過檢測這個填充模式的值是否被修改,來跟蹤在釋放后堆塊上所發生的訪問操作。 ?

            __alloca_probe

            這個函數在棧上分配空間,超過0x1000的每次按0x1000的大小(如果剩余未分配的大小大于0x1000的話)不斷在棧上分配內存(sub?ecx,1000h;?sub?eax,1000h;?test?[ecx],eax;?ecx是之前參數在棧中的地址,這樣可以檢測是否真的分配上了0x1000字節),test?[ecx],eax用來檢查是否棧已經不夠用了(棧的大小是固定的,所以如果分配的地址取不到的話[ecx]就會存取違例了),如果已經撐爆了通常會報告“Stack?Overrun”(也會看到Stack?Overflow)的報警。

            Security?cookie

            當應用程序啟動時,程序的cookie(4字節(dword),無符號整型)被計算出來(偽隨機數)并保存在加載模塊的.data節中,在函數的開頭這個cookie被拷貝到棧中,位于EBP和返回地址的正前方(位于返回地址和局部變量的中間)。?

            [buffer][cookie][savedEBP][savedEIP]

            在函數的結尾處,程序會把這個cookie和保存在.data節中的cookie進行比較。?
            如果不相等,就說明進程棧被破壞,進程必須被終止。?

            為了盡量減少額外的代碼行對性能帶來的影響,只有當一個函數中包含字符串緩沖區或使用_alloca函數在棧上分配空間的時候編譯器才在棧中保存cookie。另外,當緩沖區至少于5個字節時,在棧中也不保存cookie。?

            在典型的緩沖區溢出中,棧上的返回地址會被數據所覆蓋,但在返回地址被覆蓋之前,cookie早已經被覆蓋了,因此就導致了exploit的失效(但仍然可以導致拒絕服務),因為在函數的結尾程序會發現cookie?已經被破壞,接著應用程序會被結束。

            BUCKET

            微軟分類崩潰類型,用一系列牛逼算法所生成并使用的一個標識符號。

            0x05?修復


            官方是修復了,不過縱觀全局他這代碼也太粗心了,俺的最大的建議就是每個返回值都檢查一遍,千萬別嫌麻煩……

            0x06?參考資料


            Mario?Heweardt,?Daniel?Pravat?《windows高級調試》

            http://bbs.pediy.com/archive/index.php?t-126858.html

            http://msdn.microsoft.com/en-us/library/ee480951.aspx

            ?

            ?

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线