• <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>

            麒麟子

            ~~

            導航

            <2010年4月>
            28293031123
            45678910
            11121314151617
            18192021222324
            2526272829301
            2345678

            統計

            常用鏈接

            留言簿(12)

            隨筆分類

            隨筆檔案

            Friends

            WebSites

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            討論會結貼

            前幾天發了一篇關于一個緩沖區溢出問題的討論。原文地址

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

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

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

            下面是一些博友的回復,也可以跳轉到 原文地址 查看更多

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

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

             

             

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

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

            #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指令所做的事情來看,更涉及到函數調用在編譯器以及目標機器指令問題。不過因為這里不存在虛擬機問題,都是x86,也就只針對callret而言:

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

            ;main
            xxx
            xxx
            ret

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

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

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

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

             

             

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

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

             

             

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

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

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

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

             

             

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

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

            話說回來,仔細分析的話,我突然發覺:
            int* p = (int*)&a[0]+3;
            這里為什么會是3呢?跟了下匯編,發覺直接被翻譯為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莫名其妙地出現在棧頂,而不是p,(而在我舉的包含i的例子中,作為出現在最后定義的i卻莫名其妙地出現在棧頂),加上這個push ebp,就出現了3。

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

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

            評論

            # re: 討論會結貼 2010-05-09 22:44 ztz0223

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

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

            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的棧內容改寫了
            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
              回復  更多評論   

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

            @ztz0223
            嗯,是這樣的?。。?nbsp; 回復  更多評論   

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

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

            ~ ztz0223

            個人覺得搞這個問題有點無聊。當然這是必備功。  回復  更多評論   

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

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

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

            其實大致的內容,知道的人很多。 某些細節問題,就不一定了。  回復  更多評論   

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

            飄過
              回復  更多評論   

            伊人久久大香线蕉无码麻豆| 亚洲AV日韩精品久久久久| 国产午夜精品久久久久免费视| 国产成人久久精品一区二区三区| 久久精品国产亚洲AV久| 91久久婷婷国产综合精品青草| 国产精品久久久久天天影视| 久久人妻少妇嫩草AV蜜桃| 久久久噜噜噜久久中文字幕色伊伊 | 国产精品99精品久久免费| 国产精品久久免费| 久久精品国产精品亚洲下载| 久久精品青青草原伊人| 99久久精品国产高清一区二区| 久久精品国产一区二区三区不卡| 久久久国产打桩机| 久久精品国产亚洲AV不卡| 欧美噜噜久久久XXX| 久久99精品久久久久久野外| 亚洲精品无码久久千人斩| 99久久免费国产精品| 人妻久久久一区二区三区| 蜜臀久久99精品久久久久久| 99久久精品日本一区二区免费| 久久伊人中文无码| 四虎国产精品免费久久久| 亚洲精品乱码久久久久久按摩| 久久精品国产一区二区电影| 久久久久亚洲av无码专区| 久久精品国产精品亚洲人人| 99久久婷婷免费国产综合精品| 亚洲欧美日韩精品久久亚洲区 | 一级做a爰片久久毛片看看| 久久ZYZ资源站无码中文动漫| 久久人人爽人人爽人人av东京热| 久久精品国产99久久香蕉| 国产一久久香蕉国产线看观看| 久久精品无码一区二区无码| 久久99热只有频精品8| 无码人妻久久一区二区三区免费| 一本一道久久a久久精品综合 |