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

            小明思考

            高性能服務(wù)器端計(jì)算
            posts - 70, comments - 428, trackbacks - 0, articles - 0
              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            vc6函數(shù)調(diào)用淺析

            Posted on 2005-12-14 16:53 小明 閱讀(3404) 評(píng)論(5)  編輯 收藏 引用 所屬分類: C/C++
            今天研究了一下vc6函數(shù)調(diào)用,看看vc6調(diào)用函數(shù)時(shí)候都做了什么。有些意思。

            我寫(xiě)下了如下代碼:
            int fun(int a,int b)
            {
                
            int i = 3;
                
            return a+b+i;
            }

            int main()
            {
                
            int a = 1,b=2;
                
            int result ;
                result 
            = fun(1,2);
                
            return result;
            }

            非常簡(jiǎn)單。反匯編后(Debug版)變成這樣

            1:    int fun(int a,int b)
            2:    {
            00401020   push        ebp
            00401021   mov         ebp,esp
            00401023   sub         esp,44h
            00401026   push        ebx
            00401027   push        esi
            00401028   push        edi
            00401029   lea         edi,[ebp-44h]
            0040102C   mov         ecx,11h
            00401031   mov         eax,0CCCCCCCCh
            00401036   rep stos    dword ptr [edi]
            3:        int i = 3;
            00401038   mov         dword ptr [ebp-4],3
            4:        return a+b+i;
            0040103F   mov         eax,dword ptr [ebp
            +8]
            00401042   add         eax,dword ptr [ebp+0Ch]
            00401045   add         eax,dword ptr [ebp-4]
            5:    }
            00401048   pop         edi
            00401049   pop         esi
            0040104A   pop         ebx
            0040104B   mov         esp,ebp
            0040104D   pop         ebp
            0040104E   ret

            7:    int main()
            8:    {
            00401060   push        ebp
            00401061   mov         ebp,esp
            00401063   sub         esp,4Ch
            00401066   push        ebx
            00401067   push        esi
            00401068   push        edi
            00401069   lea         edi,[ebp-4Ch]
            0040106C   mov         ecx,13h
            00401071   mov         eax,0CCCCCCCCh
            00401076   rep stos    dword ptr [edi]
            9:        int a = 1,b=2;
            00401078   mov         dword ptr [ebp-4],1
            0040107F   mov         dword ptr [ebp
            -8],2
            10:       int result ;
            11:       result = fun(1,2);
            00401086   push        2
            00401088   push        1
            0040108A   call        @ILT
            +5(fun) (0040100a)
            0040108F   add         esp,
            8
            00401092   mov         dword ptr [ebp-0Ch],eax
            12:       return result;
            00401095   mov         eax,dword ptr [ebp-0Ch]
            13:   }
            00401098   pop         edi
            00401099   pop         esi
            0040109A   pop         ebx
            0040109B   add         esp,4Ch
            0040109E   cmp         ebp,esp
            004010A0   call        __chkesp (004010c0)
            004010A5   mov         esp,ebp
            004010A7   pop         ebp
            004010A8   ret

            我們主要來(lái)看看函數(shù)調(diào)用部分

            1.參數(shù)壓棧
            push 2
            push 1
            參數(shù)從右向左壓棧(__cdcel),esp遞減

            2.調(diào)用函數(shù)
             call        @ILT+5(fun) (0040100a)
            這條指令會(huì)把下一行代碼的地址壓棧,也就是函數(shù)返回地址。同時(shí)跳轉(zhuǎn)到函數(shù)入口處

            3.進(jìn)入函數(shù)體
            push        ebp
            mov         ebp,esp
            首先保存ebp的地址,然后把esp保存到ebp中去
            00401023   sub         esp,44h
            00401026   push        ebx
            00401027   push        esi
            00401028   push        edi
            減小stack的指針(注意,stack是從內(nèi)存的高端向低端生長(zhǎng)的),為局部變量保留一些空間,這里的44h不是固定的,由編譯器計(jì)算得來(lái)
            00401029   lea         edi,[ebp-44h]
            0040102C   mov         ecx,11h
            00401031   mov         eax,0CCCCCCCCh
            00401036   rep stos    dword ptr [edi]
            用0xCC填充局部變量空間。這是Debug模式特有的,如果是字符串,你就看到被初始化成"燙燙燙燙燙燙"
            至此,整個(gè)堆棧變成
            |-----------------|
            |    局部變量2   |
            |-----------------|
            |    局部變量1    |<----ebp-4
            |-----------------|
            |    old ebp          |<----ebp
            |-----------------|
            | 函數(shù)返回地址| <----ebp+4
            |-----------------|
            |      參數(shù)1         | <----ebp+8
            |-----------------|
            |      參數(shù)2         |
            |-----------------|

            Next:
            int i = 3;
            00401038   mov         dword ptr [ebp-4],3
            這里你看到[ebp-4]就是第一個(gè)局部變量i了
            0040103F   mov         eax,dword ptr [ebp+8]
            00401042   add         eax,dword ptr [ebp+0Ch]
            00401045   add         eax,dword ptr [ebp-4]
            [ebp+8],[ebp+0Ch]分別是a和b了

            4.函數(shù)返回
            函數(shù)的結(jié)果都是放在eax中(ps:你可以在vc的watch窗口輸入@EAX,就可以直接看到函數(shù)返回值了)
            00401048   pop         edi
            00401049   pop         esi
            0040104A   pop         ebx
            0040104B   mov         esp,ebp
            0040104D   pop         ebp
            0040104E   ret
            把edi,esi,ebx恢復(fù),然后恢復(fù)esp,ebp,這時(shí)函數(shù)的返回地址就在棧頂,調(diào)用ret就可以返回了。


            那如果改變函數(shù)的返回地址會(huì)怎樣?
            ok,我們修改一下代碼:
            #include <stdio.h>
            void fun2()
            {
                printf(
            "fun2() called");
            }

            int fun(int a,int b)
            {
                
            int i = 3;
                printf(
            "return address:0x%x\n",&i+2);
                printf(
            "fun2 address:0x%x\n",&fun2);
                
            /*int *p = (int*)&fun2;
                __asm
                {
                    mov ebx,p
                    mov dword ptr[ebp+4],ebx
                }
            */
                
            *(&i+2)=(int)&fun2; //modify return address
                return a+b+i;
            }

            int main()
            {
                
            int a = 1,b=2;
                
            int result ;
                result 
            = fun(1,2);
                
            return result;
            }

            Wow,這時(shí),我們就會(huì)發(fā)現(xiàn)fun2被調(diào)用了。這就是Buffer overrun(緩沖溢出)所做的事情吧。


            5.最后一步,調(diào)用者調(diào)整堆棧指針
            call        @ILT+5(fun) (0040100a)
             add         esp,8
            為什么要調(diào)整呢,因?yàn)檎{(diào)用之前push兩個(gè)參數(shù)進(jìn)入棧,現(xiàn)在要恢復(fù)它
             mov         dword ptr [ebp-0Ch],eax
            這句話就是享用函數(shù)調(diào)用的果實(shí)了(EAX保存了函數(shù)的返回值)

            ------end--------


            Feedback

            # re: vc6函數(shù)調(diào)用淺析  回復(fù)  更多評(píng)論   

            2005-12-14 18:41 by 夢(mèng)在天涯
            怎么反匯編啊?老大指點(diǎn)一下啊 !

            # re: vc6函數(shù)調(diào)用淺析  回復(fù)  更多評(píng)論   

            2005-12-15 10:40 by 小明
            在vc調(diào)試狀態(tài)下,debug工具條最右邊的一個(gè)按鈕就可以顯示匯編代碼。

            也可以使用IDA Pro來(lái)看

            還可以用 dumpbin /disasm /section:.text your.exe來(lái)看

            ......

            # re: vc6函數(shù)調(diào)用淺析  回復(fù)  更多評(píng)論   

            2006-04-17 14:23 by Stone Jiang
            @夢(mèng)在天涯
            生成匯編指令可以從編譯器上設(shè)置
            /FA

            C/C++ -->OutputFiles -->Assember Output

            # re: vc6函數(shù)調(diào)用淺析  回復(fù)  更多評(píng)論   

            2008-09-13 08:54 by ayh
            F10
            然后點(diǎn)DEBUG工具欄
            的最后一個(gè)按鈕 就可以啦

            # re: vc6函數(shù)調(diào)用淺析  回復(fù)  更多評(píng)論   

            2012-04-27 17:37 by jianc
            樓主NX
            欧美777精品久久久久网| 欧美一级久久久久久久大片| 久久SE精品一区二区| 免费久久人人爽人人爽av| 亚洲精品tv久久久久久久久 | 99精品国产在热久久| 亚洲AV无码久久精品狠狠爱浪潮 | 亚洲伊人久久成综合人影院| 久久久久久久综合日本| 亚洲第一极品精品无码久久| 国产精品99久久久久久宅男 | 久久综合中文字幕| 欧美成人免费观看久久| 99久久无色码中文字幕| 无夜精品久久久久久| 久久亚洲综合色一区二区三区| 亚洲另类欧美综合久久图片区| 久久99精品久久久久久| 久久久久久综合网天天| 久久亚洲电影| 亚洲一区二区三区日本久久九| 少妇精品久久久一区二区三区| 久久久久人妻精品一区三寸蜜桃 | 香港aa三级久久三级老师2021国产三级精品三级在 | 激情综合色综合久久综合| 精品国产VA久久久久久久冰| 色妞色综合久久夜夜| 久久久精品波多野结衣| 久久久久久综合一区中文字幕| 无码人妻久久一区二区三区 | 久久久久久久久无码精品亚洲日韩| 国产亚洲精午夜久久久久久| 久久精品国产99国产精偷| 久久久久亚洲av无码专区| 久久精品国产亚洲AV蜜臀色欲 | 久久综合亚洲色HEZYO国产| 伊人热人久久中文字幕| 亚洲国产精品人久久| 夜夜亚洲天天久久| 国内精品伊人久久久久影院对白 | 国产成人精品白浆久久69|