• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            麒麟子

            ~~

            導(dǎo)航

            <2010年5月>
            2526272829301
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            統(tǒng)計

            常用鏈接

            留言簿(12)

            隨筆分類

            隨筆檔案

            Friends

            WebSites

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            討論會結(jié)貼

            前幾天發(fā)了一篇關(guān)于一個緩沖區(qū)溢出問題的討論。原文地址

            當(dāng)然是飽受非意。有人說這是撞大運,有人說這是無聊。但是呢,從討論中,我們發(fā)現(xiàn)了更多的問題。學(xué)到了更多的知識。 其實許多時候我們有必要“撞大運”,但是在撞大運出問題之后,一定要弄清楚事情的原因。 博友的回復(fù)已經(jīng)充分說明了當(dāng)時的問題。 但是提出了一個新問題:就是臨時變量分配時的空間問題。
            比如說有分連續(xù)分配了3個臨時變量,卻發(fā)現(xiàn)這3個臨時變量的址址不是按變量大小連續(xù)。(如兩個INT變量間相差是12,而非預(yù)期的4) 又或者后聲明的變量地址卻跑在了前頭)。 

            這也形成了許多我提出的討論問題是撞大運的說法。 其實這個問題許多人都試過,能不能運行成功輸出success也要看編譯器版本和編譯器環(huán)境。 
            關(guān)于變量空間的問題,我想在 這篇文章 中你們能得到滿意的答案。
            并且,同樣關(guān)于本文討論的問題,我朋友的一個博文中也已經(jīng)給出了分析,并且給出了返回地址被覆蓋時,平衡堆棧的措施。 

            我的目的在于讓大家一起討論,不管這算不算是無聊,我們總會有些收獲。

            下面是一些博友的回復(fù),也可以跳轉(zhuǎn)到 原文地址 查看更多

            #
             re:
            討論會:高手們都來看看,這個如何解釋。 2010-05-06 13:11 skykrnl

            其實原理很簡單,系統(tǒng)調(diào)用 main 函數(shù)的時候先壓入了 返回地址,
            現(xiàn)在 p 恰好位于棧中返回地址處,然后你修改成了test函數(shù),main函數(shù)退出后發(fā)現(xiàn)將返回地址是test函數(shù),于是跳過去執(zhí)行啦。
            程序崩潰時必然的,你沒有ExitProcess. 

             

             

            # re: 討論會:高手們都來看看,這個如何解釋。 2010-05-06 13:25 打醬油的

            這個問題以前試驗過了,但是gcc沒有生成對main的函數(shù)調(diào)用,所以這個效果沒有出來。改一下就可以了:

            #include <iostream>
            using namespace std;
            void test( void )
            {
            cout << "Success!" << endl;
            }
            void test2(void)
            {
            int a[ 1 ];
            int* p = (int*)&a[0]+2;

            *p = ( int )test;
            }
            int main( )
            {
            test2();
            return 0;
            }

             

             

            # re: 討論會:高手們都來看看,這個如何解釋。 2010-05-06 13:58 Kevin Lynx

            這個可以從callret指令所做的事情來看,更涉及到函數(shù)調(diào)用在編譯器以及目標機器指令問題。不過因為這里不存在虛擬機問題,都是x86,也就只針對callret而言:

            不難想象在main之前的地方有如下代碼:
            ;
            壓參數(shù)
            push xxx
            push xxx
            push xxx
            call main

            ;main
            xxx
            xxx
            ret

            首先call的動作主要包括:先壓入返回地址到堆棧上(ebp指向),而c函數(shù)中,函數(shù)負責(zé)堆棧平衡,那么main中清除局部變量,改變ebp后,可以肯定ebp指向的當(dāng)前堆棧中的值就是返回地址。ret指令則是從棧頂取出該地址并執(zhí)行PC寄存器的跳轉(zhuǎn)。

            另一方面,函數(shù)調(diào)用時的運行時堆棧問題:首先棧是向下增長的,函數(shù)A調(diào)用函數(shù)B,那么首先壓入?yún)?shù)到棧中,在函數(shù)B中因為局部變量的增長棧繼續(xù)向下增長,也就是說,最終可以通過ebp的偏移取得函數(shù)A中局部變量的信息。他們貢獻同一個棧:
            --stack--
            A:local_var1
            A:local_var2
            A:ret_addr
            B:arg_var1
            B:arg_var2
            B:local_var1
            ....
            基于以上兩個條件,指針a[0]+3,則向高地址偏移了12字節(jié)的地址(3*sizeof(int)),看下main函數(shù)的參數(shù),實際上是3個:argc, argv, env。這樣偏移后,恰好就是調(diào)用main那個函數(shù)在使用call時,壓入的返回地址。

            因此,在main返回時,ret彈出的地址已經(jīng)被改變。

            ps:
            在錯誤地跳轉(zhuǎn)到test后,test執(zhí)行完去ret時,堆棧上提供的返回地址是不定的,崩潰也很正常了。

             

             

            # re: 討論會:高手們都來看看,這個如何解釋。 2010-05-06 14:03 小時候可靚了

            @Kevin Lynx
            嗯,分析得很好哦。。但是,我覺得這和main的參數(shù)沒關(guān)系。。偏移到ret_addr就已經(jīng)停下了。還沒經(jīng)過B:arg_var1 B:arg_var2 B:local_var1

             

             

            # re: 討論會:高手們都來看看,這個如何解釋。 2010-05-06 15:11 飯中淹

            1- CALL會把下一個指令的地址放進堆棧。
            2- RET
            就讓這個地址出棧,并跳轉(zhuǎn)至這個地址。
            3-
            局部變量也是在棧上的。

            代碼中,你用局部變量的地址定位到棧內(nèi)的ret返回地址,然后將其修改為TEST的函數(shù)地址。RET后,就跳轉(zhuǎn)到TEST函數(shù)了。因為沒有CALL,所以棧內(nèi)不會壓入返回地址,然后棧就亂掉了,后面依賴棧的指令,就可能會導(dǎo)致出錯。

            在一些軟件保護里面,經(jīng)常會用到這種手段,PUSH FUNCPTR, RET。這樣可以用CALL來調(diào)用函數(shù)。從而迷惑分析者。通過ESP寄存器直接操作,更讓分析者頭大。再用一些無效指令插在其中,做成花指令,就更高端了。特別是花連跳,分析者就很難一眼分辨出走向了。

             

             

            # re: 討論會:高手們都來看看,這個如何解釋。 2010-05-06 15:19 Kevin Lynx

            @小時候可靚了
            我說的是有點問題。跟參數(shù)沒關(guān)系。參數(shù)先于返回地址壓棧。- - 昏頭了。

            話說回來,仔細分析的話,我突然發(fā)覺:
            int* p = (int*)&a[0]+3;
            這里為什么會是3呢?跟了下匯編,發(fā)覺直接被翻譯為ebp+4:
            push ebp
            mov ebp, esp
            ...
            mov eax, [ebp+4]

            不是很明白這個地方。

            飯老大說得和我一樣。

             

             

            # re: 討論會:高手們都來看看,這個如何解釋。 2010-05-06 16:42 Kevin Lynx

            @小時候可靚了
            飯給的解釋是我在群里跟他談過的。
            這個解釋是我在看匯編的時候看到的:
            00401750 push ebp
            00401751 mov ebp,esp
            00401753 sub esp,0Ch
            00401756 lea eax,[ebp+4]
            00401759 mov dword ptr [p],eax

            恰好a莫名其妙地出現(xiàn)在棧頂,而不是p,(而在我舉的包含i的例子中,作為出現(xiàn)在最后定義的i卻莫名其妙地出現(xiàn)在棧頂),加上這個push ebp,就出現(xiàn)了3

            誰能給個解釋:為什么api三者的相對地址和其定義順序存在差別?

            posted on 2010-05-09 19:38 麒麟子 閱讀(1894) 評論(6)  編輯 收藏 引用 所屬分類: Programming

            評論

            # re: 討論會結(jié)貼 2010-05-09 22:44 ztz0223

            其實,整個代碼就是利用巧合把main函數(shù)的返回棧幀給改寫了。

            我把修改過后的匯編代碼貼下,整個過程就是如下:

            1 .file "call.c"
            2 .section .rodata
            3 .LC0:
            4 .string "Success\n!"
            5 .text
            6 .globl test
            7 .type test, @function
            8 test:
            9 pushl %ebp
            10 movl %esp, %ebp
            11 subl $24, %esp
            12 movl $.LC0, %eax
            13 movl %eax, (%esp)
            14 call printf
            15 movl $1, %eax
            16 leave
            17 ret
            18 .size test, .-test
            19 .globl main
            20 .type main, @function
            21 main:
            22 pushl %ebp
            23 movl %esp, %ebp
            24 leal 4(%ebp), %eax 就在這里把保存的main的棧內(nèi)容改寫了
            25 movl $test, (%eax)
            26 movl $0, %eax
            27 leave
            28 ret
            29 .size main, .-main
            30 .ident "GCC: (GNU) 4.5.0"
            31 .section .note.GNU-stack,"",@progbits
              回復(fù)  更多評論   

            # re: 討論會結(jié)貼 2010-05-09 22:54 小時候可靚了

            @ztz0223
            嗯,是這樣的!!!  回復(fù)  更多評論   

            # re: 討論會結(jié)貼[未登錄] 2010-05-10 09:14

            其實我那天也測試了。mingw要+2.
            首先是函數(shù)返回地址,然后是ebp。

            ~ ztz0223

            個人覺得搞這個問題有點無聊。當(dāng)然這是必備功。  回復(fù)  更多評論   

            # re: 討論會結(jié)貼[未登錄] 2010-05-10 09:16

            飯中淹提到的第三點正解。  回復(fù)  更多評論   

            # re: 討論會結(jié)貼 2010-05-10 09:47 小時候可靚了

            其實大致的內(nèi)容,知道的人很多。 某些細節(jié)問題,就不一定了。  回復(fù)  更多評論   

            # re: 討論會結(jié)貼 2010-05-15 08:16 夢羽蒼穹

            飄過
              回復(fù)  更多評論   

            狠狠狠色丁香婷婷综合久久五月| 国产精品国色综合久久| 大美女久久久久久j久久| 91视频国产91久久久| 久久国产成人| 亚洲精品无码久久久久去q| A狠狠久久蜜臀婷色中文网| 国内精品久久久久影院网站| 99久久精品免费看国产一区二区三区 | 精品久久久久久无码人妻蜜桃| 日本亚洲色大成网站WWW久久| 无码AV波多野结衣久久| 国产精品伦理久久久久久| 四虎国产精品成人免费久久| 久久综合中文字幕| 亚洲国产日韩欧美久久| 国产欧美一区二区久久| 久久久久高潮综合影院| 成人亚洲欧美久久久久| 人人狠狠综合久久88成人| 性做久久久久久久久| 久久se精品一区二区| 久久精品国产亚洲av麻豆图片| 成人午夜精品久久久久久久小说 | 久久精品欧美日韩精品| 久久亚洲国产成人精品无码区| 中文字幕亚洲综合久久| 一本色道久久88—综合亚洲精品| 精品久久久久久久中文字幕| 国产精品久久久久久| 久久久久AV综合网成人| 亚洲色大成网站www久久九| 伊人久久国产免费观看视频| 国内精品久久久久久久久| 久久国产精品-国产精品| jizzjizz国产精品久久| 91精品国产综合久久精品| 久久久久亚洲av无码专区| 久久久久无码精品国产| 无码人妻久久一区二区三区免费丨| 亚洲色欲久久久久综合网|