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

            麒麟子

            ~~

            導航

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統計

            常用鏈接

            留言簿(12)

            隨筆分類

            隨筆檔案

            Friends

            WebSites

            積分與排名

            最新隨筆

            最新評論

            閱讀排行榜

            評論排行榜

            討論會:一個不是問題的問題!

             

             1#include <iostream>
             2using namespace std;
             3void test( void )
             4{
             5 cout << "Success!" << endl;
             6}

             7int main( void )
             8{
             9 int a[ 1 ];
            10 int* p = (int*)&a[0]+3;
            11
            12 *=  ( int )test;
            13 return 0;
            14}

            15
            16


            首先,這個不是特性,也不是什么BUG,也不是什么,純屬娛樂! 對了,請大家不要用Release模式等會進行優化的編譯方案。
            很明顯,上面的a和p都是臨時變量,并且沒有使用。。優化就啥都沒了。 我用的是VS 2005  其它環境。

            執行時,輸出 Success!

            提示: 輸出時會DOWN掉,不過不影響結果的查看!


            不知道各位有何高見!
            我心中也有一個答案。但先不說,大家一起來討論。。。 共同完成這篇貼子。 隨后,大家的高端回復會以如下方式出現
            如果不希望最后出現在這里,請大家注明。 默認情況下,表示同意!

            ID:XXXX
            解釋:*****************


            =======================
            ID:XXXXX
            解釋:********************

            posted on 2010-05-06 12:41 麒麟子 閱讀(2127) 評論(38)  編輯 收藏 引用 所屬分類: Programming

            評論

            # re: 討論會:高手們都來看看,這個如何解釋。 2010-05-06 12:54 夢在天涯

            什么也沒有輸出吧1

            那估計輸出了也是隨即的!  回復  更多評論   

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

            不會有輸出。也不會出現CORE DUMP  回復  更多評論   

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

            。。。這不就是指針段內偏移指向函數了么
            而且是和編譯器有關的,不同的編譯器生成的結果不一定相同。
            這是bug,不是特性。  回復  更多評論   

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

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

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

            @skykrnl
            嗯,過程是這樣的。。 但我想看看大家目前到底有多無聊。能把這個問題提升到一個什么樣的層次! 一起來吧,哈哈  回復  更多評論   

            # 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:28 小時候可靚了

            @打醬油的
            嗯,自己構造,只要地址偏移正確就OK啦!  回復  更多評論   

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

            在VS中,我們還可以這樣

            #include <iostream>
            using namespace std;
            void test( void )
            {
            cout << "Success!" << endl;
            }
            int main( void )
            {
            _asm
            {
            mov dword ptr[ebp+4],offset test;把test的地址給返回地址
            }
            return 0;
            }  回復  更多評論   

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

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

            不難想象在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 14:57 春續

            *p = ( int )test;

            這句沒看明白。
              回復  更多評論   

            # 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 15:30

            典型的 "撞大運編程"  回復  更多評論   

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

            @Kevin Lynx
            int a;
            int *p
            這兩個是臨時變量

            a 的地址是 ebp -8
            p 的地址是 ebp-4
            所以,&a[0]+3其實就是 ebp-8+ 3*4 = ebp+4  回復  更多評論   

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

            @壞
            撞大運和這可不一樣。 這是明明知道的后果!  回復  更多評論   

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

            @小時候可靚了
            a 的地址是 ebp -8
            p 的地址是 ebp-4

            這兩個結論從何而來?何況,為什么要+3?

            ps,話說這樣N多回復會給你BLOG增加不少積分啊 :D  回復  更多評論   

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

            @Kevin Lynx
            都說了,這個程序是故意寫出來的。不是撞大運撞的。 +3是為了正好得到我們的偏移地址! 上面那個結論,就是臨時變量在棧上分配內存分成那樣的撒。至于BLOG的分,我不知道這回事!  回復  更多評論   

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

            @Kevin Lynx
            p的地址大于a。
            所以a在棧頂,p在a下面。還有個push ebp,接下來就是返回地址。
            正好三個。  回復  更多評論   

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

            @飯中淹
            嗯,就是這樣的。 不過如果你在DEBUG下看的話,會發現a不在棧頂。 DEBUG會多分一些  回復  更多評論   

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

            @小時候可靚了
            {
            int a;
            int b;
            int c;
            }
            按我的理解,c應該在棧頂,而不是a。但是實際上跟蹤你的代碼來看,a確實在棧頂,在p后添加變量int i ,又有意外:
            a : 0x0012ff74
            &p:0x0012ff78
            &i:0x0012ff70
              回復  更多評論   

            # re: 討論會:高手們都來看看,這個如何解釋。[未登錄] 2010-05-06 16:15

            @小時候可靚了
            在我這里gcc和BCB都是無任何輸出的。
            隨便在前面加個局部變量VC也同樣無輸出。
            這不就是撞大運么....  回復  更多評論   

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

            @壞
            需要適當調整 3 這個偏移量

            ps,當然也取決于編譯器生成的指令。鑒于目前我也不明白為什么偏移是3,看起來LZ也無法給出詳細的說明,這個3很有可能只是個巧合。

            1、除了push ebp外可能還有壓入其他寄存器的值(保存寄存器信息)
            2、a理論上應該不在棧頂,就像我例子中的i,而p應該在棧頂
              回復  更多評論   

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

            @Kevin Lynx
            棧頂是低地址~~  回復  更多評論   

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

            @小時候可靚了
            這個不需要你重申,我更不希望我來重申我的問題:
            解釋下這個:
            int a[1];
            int *p;
            int i;

            a : 0x0012ff74
            &p:0x0012ff78
            &i:0x0012ff70

            注意p在中間 。  回復  更多評論   

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

            @Kevin Lynx
            這個巧合是建立在剛剛那個代碼上的。。這個+3,是人為構造的。 不管+幾,我們就是想把他指向main的返回地址。

            不過呢,在編譯器環境條件眾多的情況下, 如 @壞 所說,真是撞大運。

            至于合理的解釋,上面有兄弟給了答案了。。。  回復  更多評論   

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

            @Kevin Lynx
            其實我貼出來,同樣是想看到關于這個臨時空間的解釋。。你知道嗎?在我的機器上是這樣的。
            0x0012ff60
            0x0012ff54
            0x0012ff48

            如果我能一一解釋清楚,我就不讓大家討論了。。。 嘿嘿  回復  更多評論   

            # 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、p、i三者的相對地址和其定義順序存在差別?(難道編譯器對數組的處理要特殊點?)
              回復  更多評論   

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

            @小時候可靚了
            0x0012ff60 a
            0x0012ff54 p
            0x0012ff48 i ???
            如果是這樣的話,那這個才是正確的排列地址啊。詭異的是我那個情況。  回復  更多評論   

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

            @Kevin Lynx
            可是,他們的差值很鬼異!  回復  更多評論   

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

            @小時候可靚了
            剛想補上這句,差距都是12.。。- -
            我這邊差距都是4,正常差距,但是順序詭異。。。  回復  更多評論   

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

            唉,淡定吧。這種情況讓我頭疼。  回復  更多評論   

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

            汗。。- - 。。偶然間看到LZ 博客HGE一欄居然轉載有我N久以前亂寫的東西,真巧啊。。  回復  更多評論   

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

            @Kevin Lynx
            是啊,以前在學校的時候,搗鼓了兩天HGE。  回復  更多評論   

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

            又是offset.....看了王爽匯編之后,你一定會發現這復雜的世界又是多么的和諧  回復  更多評論   

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

            @zuhd
            王爽的我沒看過耶!!! 汗!!!  回復  更多評論   

            # re: 討論會:高手們都來看看,這個如何解釋。[未登錄] 2010-05-11 21:49 海邊沫沫

            高手好多哦。你們想得太復雜了。

            我認為這一句
            *p = ( int )test;
            調用了test函數,只不過test函數沒有返回值,且p指向非法內存,所以給*P賦值就會犯錯,于是程序就會掛掉。

            樓主說的特性是不是test和test()是一樣的啊?  回復  更多評論   

            # re: 討論會:高手們都來看看,這個如何解釋。[未登錄] 2010-05-11 22:02 海邊沫沫

            我發現我上面的結論錯了。剛才把代碼輸入到VS2008,調試了一下。發現:
            *p=(int)test;確實只是把test的地址放到了*p里面,而不是調用test();

            而在return的時候調用了test,然后出錯。

            說明*p這個非法內存訪問是真的改變了main函數返回后執行的下一條指令的地址。  回復  更多評論   

            久久成人影院精品777| 久久国产精品99久久久久久老狼| 亚洲va国产va天堂va久久| 久久久久国产| 成人精品一区二区久久| 久久99热精品| 日韩精品无码久久一区二区三| 亚洲精品国产字幕久久不卡 | 久久久人妻精品无码一区| 久久久久久久久久久| 久久天天躁狠狠躁夜夜躁2014| 久久精品无码一区二区app| 久久精品日日躁夜夜躁欧美| 久久不见久久见免费影院www日本| 久久国产精品久久国产精品| 久久久久久精品成人免费图片| 久久综合精品国产二区无码| 久久综合九色综合久99| 亚洲国产小视频精品久久久三级| 久久夜色精品国产亚洲| 久久久久久夜精品精品免费啦| 久久国产亚洲精品| 国产精品亚洲综合久久| 久久久久久噜噜精品免费直播| 91精品国产乱码久久久久久| 人妻精品久久久久中文字幕一冢本| 久久久久免费精品国产| 午夜欧美精品久久久久久久| 久久精品亚洲一区二区三区浴池| 精品无码久久久久久午夜| 亚洲AV无码1区2区久久| 99久久久精品| a级毛片无码兔费真人久久| 久久久不卡国产精品一区二区| 久久婷婷午色综合夜啪| 中文字幕久久波多野结衣av| 久久久久一区二区三区| 2021国产精品午夜久久| 国产精品一区二区久久精品| 亚洲国产成人久久一区WWW| 国产精品久久久久久久人人看|