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

            Shuffy

            不斷的學(xué)習(xí),不斷的思考,才能不斷的進(jìn)步.Let's do better together!
            posts - 102, comments - 43, trackbacks - 0, articles - 19

            信息來(lái)源:中國(guó)源碼下載站

            接觸過(guò)編程的人都知道,高級(jí)語(yǔ)言都能通過(guò)變量名來(lái)訪問(wèn)內(nèi)存中的數(shù)據(jù)。那么這些變量在內(nèi)存中是如何存放的呢?程序又是如何使用這些變量的呢?下面就會(huì)對(duì)此進(jìn)行深入的討論。下文中的C語(yǔ)言代碼如沒(méi)有特別聲明,默認(rèn)都使用VC編譯的release版。 
            首先,來(lái)了解一下 C 語(yǔ)言的變量是如何在內(nèi)存分部的。C 語(yǔ)言有全局變量(Global)、本地變量(Local),靜態(tài)變量(Static)、寄存器變量(Regeister)。每種變量都有不同的分配方式。先來(lái)看下面這段代碼: 
            #include <stdio.h> 
            int g1=0, g2=0, g3=0; 
            int main() 

            static int s1=0, s2=0, s3=0; 
            int v1=0, v2=0, v3=0; 
            //打印出各個(gè)變量的內(nèi)存地址 
            printf("0x%08x\n",&v1); //打印各本地變量的內(nèi)存地址 
            printf("0x%08x\n",&v2); 
            printf("0x%08x\n\n",&v3); 
            printf("0x%08x\n",&g1); //打印各全局變量的內(nèi)存地址 
            printf("0x%08x\n",&g2); 
            printf("0x%08x\n\n",&g3); 
            printf("0x%08x\n",&s1); //打印各靜態(tài)變量的內(nèi)存地址 
            printf("0x%08x\n",&s2); 
            printf("0x%08x\n\n",&s3); 
            return 0; 

            編譯后的執(zhí)行結(jié)果是: 
            0x0012ff78 
            0x0012ff7c 
            0x0012ff80 
            0x004068d0 
            0x004068d4 
            0x004068d8 
            0x004068dc 
            0x004068e0 
            0x004068e4 
            輸出的結(jié)果就是變量的內(nèi)存地址。其中v1,v2,v3是本地變量,g1,g2,g3是全局變量,s1,s2,s3是靜態(tài)變量。你可以看到這些變量在內(nèi)存是連續(xù)分布的,但是本地變量和全局變量分配的內(nèi)存地址差了十萬(wàn)八千里,而全局變量和靜態(tài)變量分配的內(nèi)存是連續(xù)的。這是因?yàn)楸镜刈兞亢腿?靜態(tài)變量是分配在不同類型的內(nèi)存區(qū)域中的結(jié)果。對(duì)于一個(gè)進(jìn)程的內(nèi)存空間而言,可以在邏輯上分成3個(gè)部份:代碼區(qū),靜態(tài)數(shù)據(jù)區(qū)和動(dòng)態(tài)數(shù)據(jù)區(qū)。動(dòng)態(tài)數(shù)據(jù)區(qū)一般就是“堆棧”。“棧(stack)”和“堆(heap)”是兩種不同的動(dòng)態(tài)數(shù)據(jù)區(qū),棧是一種線性結(jié)構(gòu),堆是一種鏈?zhǔn)浇Y(jié)構(gòu)。進(jìn)程的每個(gè)線程都有私有的“棧”,所以每個(gè)線程雖然代碼一樣,但本地變量的數(shù)據(jù)都是互不干擾。一個(gè)堆棧可以通過(guò)“基地址”和“棧頂”地址來(lái)描述。全局變量和靜態(tài)變量分配在靜態(tài)數(shù)據(jù)區(qū),本地變量分配在動(dòng)態(tài)數(shù)據(jù)區(qū),即堆棧中。程序通過(guò)堆棧的基地址和偏移量來(lái)訪問(wèn)本地變量。 

            ├———————┤低端內(nèi)存區(qū)域 
            │ …… │ 
            ├———————┤ 
            │ 動(dòng)態(tài)數(shù)據(jù)區(qū) │ 
            ├———————┤ 
            │ …… │ 
            ├———————┤ 
            │ 代碼區(qū) │ 
            ├———————┤ 
            │ 靜態(tài)數(shù)據(jù)區(qū) │ 
            ├———————┤ 
            │ …… │ 
            ├———————┤高端內(nèi)存區(qū)域 

            堆棧是一個(gè)先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),棧頂?shù)刂房偸切∮诘扔跅5幕刂贰N覀兛梢韵攘私庖幌潞瘮?shù)調(diào)用的過(guò)程,以便對(duì)堆棧在程序中的作用有更深入的了解。不同的語(yǔ)言有不同的函數(shù)調(diào)用規(guī)定,這些因素有參數(shù)的壓入規(guī)則和堆棧的平衡。windows API的調(diào)用規(guī)則和ANSI C的函數(shù)調(diào)用規(guī)則是不一樣的,前者由被調(diào)函數(shù)調(diào)整堆棧,后者由調(diào)用者調(diào)整堆棧。兩者通過(guò)“__stdcall”和“__cdecl”前綴區(qū)分。先看下面這段代碼: 
            #include <stdio.h> 
            void __stdcall func(int param1,int param2,int param3) 

            int var1=param1; 
            int var2=param2; 
            int var3=param3; 
            printf("0x%08x\n",&para;m1); //打印出各個(gè)變量的內(nèi)存地址 
            printf("0x%08x\n",&para;m2); 
            printf("0x%08x\n\n",&para;m3); 
            printf("0x%08x\n",&var1); 
            printf("0x%08x\n",&var2); 
            printf("0x%08x\n\n",&var3); 
            return; 

            int main() 

            func(1,2,3); 
            return 0; 

            編譯后的執(zhí)行結(jié)果是: 
            0x0012ff78 
            0x0012ff7c 
            0x0012ff80 
            0x0012ff68 
            0x0012ff6c 
            0x0012ff70 

            ├———————┤<—函數(shù)執(zhí)行時(shí)的棧頂(ESP)、低端內(nèi)存區(qū)域 
            │ …… │ 
            ├———————┤ 
            │ var 1 │ 
            ├———————┤ 
            │ var 2 │ 
            ├———————┤ 
            │ var 3 │ 
            ├———————┤ 
            │ RET │ 
            ├———————┤<—“__cdecl”函數(shù)返回后的棧頂(ESP) 
            │ parameter 1 │ 
            ├———————┤ 
            │ parameter 2 │ 
            ├———————┤ 
            │ parameter 3 │ 
            ├———————┤<—“__stdcall”函數(shù)返回后的棧頂(ESP) 
            │ …… │ 
            ├———————┤<—棧底(基地址 EBP)、高端內(nèi)存區(qū)域 

            上圖就是函數(shù)調(diào)用過(guò)程中堆棧的樣子了。首先,三個(gè)參數(shù)以從又到左的次序壓入堆棧,先壓“param3”,再壓“param2”,最后壓入“param1”;然后壓入函數(shù)的返回地址(RET),接著跳轉(zhuǎn)到函數(shù)地址接著執(zhí)行(這里要補(bǔ)充一點(diǎn),介紹UNIX下的緩沖溢出原理的文章中都提到在壓入RET后,繼續(xù)壓入當(dāng)前EBP,然后用當(dāng)前ESP代替EBP。然而,有一篇介紹windows下函數(shù)調(diào)用的文章中說(shuō),在windows下的函數(shù)調(diào)用也有這一步驟,但根據(jù)我的實(shí)際調(diào)試,并未發(fā)現(xiàn)這一步,這還可以從param3和var1之間只有4字節(jié)的間隙這點(diǎn)看出來(lái));第三步,將棧頂(ESP)減去一個(gè)數(shù),為本地變量分配內(nèi)存空間,上例中是減去12字節(jié)(ESP=ESP-3*4,每個(gè)int變量占用4個(gè)字節(jié));接著就初始化本地變量的內(nèi)存空間。由于“__stdcall”調(diào)用由被調(diào)函數(shù)調(diào)整堆棧,所以在函數(shù)返回前要恢復(fù)堆棧,先回收本地變量占用的內(nèi)存(ESP=ESP+3*4),然后取出返回地址,填入EIP寄存器,回收先前壓入?yún)?shù)占用的內(nèi)存(ESP=ESP+3*4),繼續(xù)執(zhí)行調(diào)用者的代碼。參見(jiàn)下列匯編代碼: 
            ;--------------func 函數(shù)的匯編代碼------------------- 
            :00401000 83EC0C sub esp, 0000000C //創(chuàng)建本地變量的內(nèi)存空間 
            :00401003 8B442410 mov eax, dword ptr [esp+10] 
            :00401007 8B4C2414 mov ecx, dword ptr [esp+14] 
            :0040100B 8B542418 mov edx, dword ptr [esp+18] 
            :0040100F 89442400 mov dword ptr [esp], eax 
            :00401013 8D442410 lea eax, dword ptr [esp+10] 
            :00401017 894C2404 mov dword ptr [esp+04], ecx 
            ……………………(省略若干代碼) 
            :00401075 83C43C add esp, 0000003C ;恢復(fù)堆棧,回收本地變量的內(nèi)存空間 
            :00401078 C3 ret 000C ;函數(shù)返回,恢復(fù)參數(shù)占用的內(nèi)存空間 
            ;如果是“__cdecl”的話,這里是“ret”,堆棧將由調(diào)用者恢復(fù) 
            ;-------------------函數(shù)結(jié)束------------------------- 

            ;--------------主程序調(diào)用func函數(shù)的代碼-------------- 
            :00401080 6A03 push 00000003 //壓入?yún)?shù)param3 
            :00401082 6A02 push 00000002 //壓入?yún)?shù)param2 
            :00401084 6A01 push 00000001 //壓入?yún)?shù)param1 
            :00401086 E875FFFFFF call 00401000 //調(diào)用func函數(shù) 
            ;如果是“__cdecl”的話,將在這里恢復(fù)堆棧,“add esp, 0000000C” 
            聰明的讀者看到這里,差不多就明白緩沖溢出的原理了。先來(lái)看下面的代碼: 
            #include <stdio.h> 
            #include <string.h> 
            void __stdcall func() 

            char lpBuff[8]="\0"; 
            strcat(lpBuff,"AAAAAAAAAAA"); 
            return; 

            int main() 

            func(); 
            return 0; 

            編譯后執(zhí)行一下回怎么樣?哈,“"0x00414141"指令引用的"0x00000000"內(nèi)存。該內(nèi)存不能為"read"。”,“非法操作”嘍!"41"就是"A"的16進(jìn)制的ASCII碼了,那明顯就是strcat這句出的問(wèn)題了。"lpBuff"的大小只有8字節(jié),算進(jìn)結(jié)尾的’\0’,那strcat最多只能寫(xiě)入7個(gè)"A",但程序?qū)嶋H寫(xiě)入了11個(gè)"A"外加1個(gè)’\0’。再來(lái)看看上面那幅圖,多出來(lái)的4個(gè)字節(jié)正好覆蓋了RET的所在的內(nèi)存空間,導(dǎo)致函數(shù)返回到一個(gè)錯(cuò)誤的內(nèi)存地址,執(zhí)行了錯(cuò)誤的指令。如果能精心構(gòu)造這個(gè)字符串,使它分成三部分,前一部份僅僅是填充的無(wú)意義數(shù)據(jù)以達(dá)到溢出的目的,接著是一個(gè)覆蓋RET的數(shù)據(jù),緊接著是一段shellcode,那只要著個(gè)RET地址能指向這段shellcode的第一個(gè)指令,那函數(shù)返回時(shí)就能執(zhí)行shellcode了。但是軟件的不同版本和不同的運(yùn)行環(huán)境都可能影響這段shellcode在內(nèi)存中的位置,那么要構(gòu)造這個(gè)RET是十分困難的。一般都在RET和shellcode之間填充大量的NOP指令,使得exploit有更強(qiáng)的通用性。 

            ├———————┤<—低端內(nèi)存區(qū)域 
            │ …… │ 
            ├———————┤<—由exploit填入數(shù)據(jù)的開(kāi)始 
            │ │ 
            │ buffer │<—填入無(wú)用的數(shù)據(jù) 
            │ │ 
            ├———————┤ 
            │ RET │<—指向shellcode,或NOP指令的范圍 
            ├———————┤ 
            │ NOP │ 
            │ …… │<—填入的NOP指令,是RET可指向的范圍 
            │ NOP │ 
            ├———————┤ 
            │ │ 
            │ shellcode │ 
            │ │ 
            ├———————┤<—由exploit填入數(shù)據(jù)的結(jié)束 
            │ …… │ 
            ├———————┤<—高端內(nèi)存區(qū)域

            欧美成人免费观看久久| 久久99国产亚洲高清观看首页 | 狠狠色丁香婷婷久久综合不卡 | 人妻系列无码专区久久五月天| 亚洲国产成人久久精品99| 99久久国产免费福利| 国产精品视频久久| 久久精品嫩草影院| 精品一区二区久久久久久久网站| 色偷偷91久久综合噜噜噜噜| 少妇久久久久久被弄到高潮| 久久99热这里只有精品国产| 久久99精品国产麻豆不卡| 伊人久久大香线蕉精品| 欧美亚洲另类久久综合| 久久久久亚洲AV成人网人人网站| 99久久免费国产精品| 青青草国产97免久久费观看| 色播久久人人爽人人爽人人片AV| 天堂无码久久综合东京热| 久久久久久久精品成人热色戒| 亚洲性久久久影院| 无码人妻精品一区二区三区久久久| 亚洲精品tv久久久久| 久久久久免费看成人影片| 一本伊大人香蕉久久网手机| 热久久国产欧美一区二区精品| 欧美午夜A∨大片久久| 99久久国产亚洲综合精品| 国产精品禁18久久久夂久 | 欧美午夜A∨大片久久 | 久久精品国产亚洲AV忘忧草18| 久久99这里只有精品国产| 久久久久久人妻无码| 久久精品亚洲乱码伦伦中文| 中文国产成人精品久久不卡| 色噜噜狠狠先锋影音久久| 久久久黄色大片| 青青青伊人色综合久久| 久久综合亚洲欧美成人| 久久亚洲中文字幕精品一区|