免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
使用C編譯器產(chǎn)生清晰的二進制文件
一.向函數(shù)傳遞參數(shù):
1.C函數(shù)調(diào)用慣例:參數(shù)是以反序壓入棧中的.
(1)調(diào)用函數(shù)(caller)把函數(shù)的參數(shù)一個一個地按反序壓入棧(從右向左,所以第一個被指定的函數(shù)參數(shù)最后一個被壓進去).
(2)然后調(diào)用函數(shù)執(zhí)行一個caller指令把控制權(quán)交給被調(diào)函數(shù)(callee).
(3)被調(diào)函數(shù)收到控制權(quán),一般地(這并不是必要的,因為有的函數(shù)不必去訪問它們的參數(shù)),先把ESP中的值放入EBP中,以使EBP成為一個基址指針,從而用EBP去訪問棧中的參數(shù).然而調(diào)用函數(shù)也可能做了這個,所以慣例是EBP必須被任何C函數(shù)保存.因此被調(diào)用者函數(shù),如果它要把EBP作為一個幀指針,必須先把以前的值壓入棧.
(4)被調(diào)函數(shù)然后就可以用EBP去訪問它的參數(shù)了.在[EBP]處的雙字(dword)存放了先前壓入的EBP的值.下一個雙字[EBP+4],存入了返回地址,它是由CALL隱式地壓入的.
真正的參數(shù)從[EBX+8]開始.最左邊的參數(shù)由于是最后入棧的,可用這個偏移量進行訪問;余下的參數(shù),在余下的更高的偏移量上.因此,在像printf這樣的函數(shù)里,它可以跟可變的函數(shù)參數(shù).但我們可以找到它的第一個參數(shù),從而知道余下的參數(shù)的個數(shù)和類型.
(5)被調(diào)函數(shù)也可能希望減低ESP的大小,以給局部變量分配空間,這些局部變量將用EBP的負偏移量進行訪問.
(6)被調(diào)函數(shù)如果想返回一個值給調(diào)用函數(shù),應(yīng)當把其值放到AL,AX或EAX中,這取決于返回值的大小.浮點數(shù)一般放在ST0中.
(7)一旦被調(diào)函數(shù)完成了任務(wù),如果它已經(jīng)分配了本地??臻g,它把ESP的值從EBP中恢復(fù)然后彈出原來EBP的值,最后通過RET返回.
(8)當調(diào)用函數(shù)從被調(diào)函數(shù)重新得到控制權(quán)的時候,函數(shù)的參數(shù)認然在棧中,所以一般可以將ESP加上一個常數(shù)來移除它們(而不是選用一系列慢的POP指令).所以,如果一個函數(shù)偶然地輸入與原形不一樣的錯誤的參數(shù)個數(shù),棧仍然能回到一個智能的狀態(tài).因為調(diào)用函數(shù)知道壓入了多少個參數(shù),所以它也能正確地移掉它們.
2.例子:
char res;/*global variable*/
char f(char a,char b);/* function prototype*/
int main(){/*entry point */
res=f(0x12,0x23); /*function call*/
}
char f(char a,char b){ /*function definition*/
return a+b; /*return code*/
}
它將會產(chǎn)生如下的二進制代碼:
00000000 55 push ebp
00000001 89E5 mov ebp,esp
00000003 6A23 push byte+0x23
00000005 6A12 push byte+0x12
00000007 E810000000 call 0x1c
0000000C 83c408 add esp,byte+0x8
0000000F 88c0 mov al,al
00000011 880534120000 mov [0x1234],al
00000017 C9 leave
00000018 C3 ret
00000019 8D7600 lea esi,[esi+0x0]
0000001C 55 push ebp
0000001D 89E5 mov ebp,esp
0000001F 83EC04 sub esp,byte+0x4
00000022 53 push ebx
00000023 8B5508 mov edx,[ebp+0x8]
00000026 8B4D0C mov ecx,[ebp+0xc]
00000029 8855FF mov [ebp-0x1],dl
0000002C 884DFE mov [ebp-0x2],cl
0000002F 8A45FF mov al,[ebp-0x1]
00000032 0245FE add al,[eb0-0x2]
00000035 0FBED8 movsx ebx,al
00000038 89D8 mov eax,ebx
0000003A EB00 jmp short 0x3c
0000003C 8B5DF8 mov ebx,[ebp-0xi]
0000003F C9 leave
00000040 C3 ret
3.剖析:
在壓入兩個字節(jié)的參數(shù)到棧中后,隨即有一個調(diào)用在0X1C處的函數(shù)的CALL.這個函數(shù)首先將esp減4個字節(jié),作為本地變量使用.然后這個函數(shù)把函數(shù)參數(shù)拷貝到本地.然后a+b被計算并存放在eax中返回.
二.賦值:
main(){
unsigned int i=251;
}
當我們把這個編譯成平的二進制文件時,我們得到:
00000000 55 push ebp
00000001 89E5 mov ebp,esp
00000003 83EC04 sub esp,byte+0x4
00000006 C745FCFB000000 mov dword [ebp-0x4],0xfb
0000000D C9 leave
0000000E C3 ret
當我們把賦值語句改成:
unsigned int i=-5;
我們在地址0x6處得到了下面的指令:
00000006 C745FCFBFFFFFF mov dword [ebp-0x4],0xfffffffb
現(xiàn)在讓我們看一看有符號整數(shù).語句:int i=251;
產(chǎn)生:
00000006 C745FCFB000000 mov dword [ebp-0x4],0xfb
一個使用負數(shù)的語句:
int i=-5;
產(chǎn)生了:
00000006C745FCFBFFFFFF mov dword [ebp-0x4],0xfffffffb
看起來像是有符號和無符號的賦值被一樣對待了.
三.把signed char轉(zhuǎn)換成signed int:
main(){
char c=-5;
int i;
i=c;
}
產(chǎn)生了如下的二進制文件:
00000000 55 push ebp
00000001 89E5 mov ebp,esp
00000003 83EC08 sub esp,byte+0x8
00000006 0645FFFB mov byte [ebp-0x1],0xfb
0000000A 0FBE45EF movsx eax,byte [ebp-0x1]
0000000E 8945F8 mov [ebp-0x8],eax
00000011 C9 leave
00000012 C3 ret
剖析:
首先我們看到在地址0x3處在棧中為本地變量c和i保留了8個字節(jié).編譯器使用8個字節(jié)以使其對齊整數(shù)i.然后我們可以看到charc被0xfb填充,也就是-5(0xfb=251,251-256=-5).注意編譯器使用[ebp-0x1]而不是使用[ebp-0x4].這是由于小端表示法的緣故.下一個movsx才真真正做了從signed char到 signedint的轉(zhuǎn)換.MOVSX指令對源操作數(shù)進行符號擴展然后拷貝到目標操作數(shù).在leave前的最后一個指令把存儲在eax中的數(shù)據(jù)傳到int i中.
四.將signed int轉(zhuǎn)換成signed char
main(){
char c;
int i=-5;
c=i;
}
將產(chǎn)生如下的二進制代碼:
00000000 55 push esb
00000001 89E5 mov ebp,esp
00000003 83EC08 sub esp,byte+0x8
00000006 C745F8FBFFFFFF mov dword [ebp-0x8],0xfffffffb
0000000D 8A45F8 mov al,[ebp-0x8]
00000010 8845FF mov [ebp-0x1],al
00000013 C9 leave
00000014 C3 ret
剖析:c=i這句只有在值在-128(-2^7)到127(2^7-1)之間的時候才有意義。因為它必須要在signedchar的范圍內(nèi)。0xfffffffb實際上就是-5。當我們只看那個不太重要的0xfb字節(jié)并把它變成一個signedchar時,我們同樣也可以得到-5.所以從一個signed int轉(zhuǎn)換成一個signed char我們也可以只用一個簡單的mov指令.
五.把unsigned char轉(zhuǎn)換為unsigned int
main(){
unsigned char c=5;
unsigned int i;
i=c;
}
將產(chǎn)生如下的二進制文件:
00000000 55 push ebp
00000001 89E5 mov ebp,esp
00000003 83EC08 sub esp,byte+0x8
00000006 C645FF05 mov byte [ebp-0x1],0x5
0000000A 0FB645FF movzx eax,byte [ebp-0x1]
0000000E 8945F8 mov [ebp-0x8],eax
00000011 C9 leave
00000012 C3 ret
剖析:除了在0xA處的指令外,我們得到了和從signed char到signed int一樣的代碼。這里我們的指令是movzx。MOVZX將源操作數(shù)零擴展,然后拷貝到目標操作數(shù)。
六.把unsigned int轉(zhuǎn)換為unsigned char
main(){
unsigned char c;
unsigned int i=251;
c=i;
}
將產(chǎn)生如下的二進制代碼:
00000000 55 push ebp
00000001 89E5 mov ebp,esp
00000003 83EC08 sub esp,byte+0x8
00000006 C745F8FB000000 mov dword [ebp-0x8],0xfb
0000000D 8A45F8 mov al,[ebp-0x8]
00000010 8845FF mov [ebp-0x1],al
00000013 C9 leave
00000014 C3 ret
剖析:整數(shù)的值嚴格限制在0到255(2^8-1)之間。這是因為unsigned char不能處理更大的數(shù)了。在0xD處的mov是真正做轉(zhuǎn)換的指令,它和從signed int到signed char的轉(zhuǎn)換是一樣的。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
把ida的匯編代碼扒到VC中
C/C++之深入分析inline函數(shù)
通過一段匯編,加深對寄存器ESP和EBP的理解
函數(shù)調(diào)用堆棧
深度剖析函數(shù)四個部分(返回值,參數(shù),函數(shù)名,函數(shù)體)
棧幀
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服