匯編語言中的函數(shù)調(diào)用參數(shù)傳遞及全局與局部變量與“基址”
作為剛往底層方向走的一只菜鳥,今天為各位分享一篇名為匯編眼中的函數(shù)調(diào)用參數(shù)傳遞以及全局、局部變量與“基址”,好了,廢話不多說,先來看看C語言代碼:
本次的分享主要以畫堆棧圖為主,通過畫圖的方式來看看這段代碼是如何運(yùn)作的
我們先寫一句匯編代碼,mov eax,eax其實(shí)這句代碼并沒有什么用,也就是將eax的值移入eax中,這句代碼對(duì)于我們的作用僅作為斷點(diǎn),我們F5運(yùn)行下程序并且切換到反編譯界面
右鍵之后點(diǎn)擊Go To Disassemble,也就是進(jìn)入反編譯界面,我們來看看反編譯的代碼
這就是咱們main函數(shù)反編譯后的結(jié)果,那么現(xiàn)在我們記錄一下ebp,esp的值,并且畫出現(xiàn)在的堆棧圖
ESP = 0019FEF4
EBP = 0019FF40
黃色=ebp~esp初始的內(nèi)存
那好,我們繼續(xù)來看代碼
這里是我們自己寫的匯編代碼,編譯器也沒有改動(dòng)過可以說是本色出演,這里內(nèi)存沒有變化,好,那么我們接著來看add函數(shù)這里的調(diào)用
可以看到函數(shù)調(diào)用的時(shí)候首先是將3、1這兩個(gè)值推入棧中,但是又有疑問了“add函數(shù)的調(diào)用是這樣的add(1,3),為啥首先推入棧中的是3而不是1呢?”之所以這樣是因?yàn)闂V惺窍冗M(jìn)后出的,所以參數(shù)進(jìn)入棧中的順序是從右向左的,當(dāng)然這里也可以看到函數(shù)中的參數(shù)是壓入棧中然后取出來而不是通過通用寄存器eax,edx,ebx這些來傳送參數(shù)的,其實(shí)這也好理解,因?yàn)橥ㄓ眉拇嫫髦挥邪藗€(gè),像esp,eip,ebp這樣的寄存器還不能隨便改,能用的也只有剩下的幾個(gè),參數(shù)超過剩下的幾個(gè)咋辦?那就只能用堆棧了。我們繼續(xù)來看F10單步執(zhí)行一下,看看堆棧的變化
我們?cè)倏纯碋BP和ESP
這里可以看到壓入一個(gè)3后棧頂指針減去了4h,至于為啥減去4h呢?是因?yàn)橐粋€(gè)int類型的數(shù)據(jù)寬度是4Byte=32Bit,能存入的最大數(shù)也就是0xFFFFFFFF,16進(jìn)制數(shù)又是2進(jìn)制數(shù)的簡寫形式,一個(gè)二進(jìn)制數(shù)需要4Bit來存儲(chǔ),所以4位二進(jìn)制數(shù)最大的值為1111轉(zhuǎn)換為16進(jìn)制后剛好為F,這樣也方便了開發(fā)者,存儲(chǔ)空間中我們看到的數(shù)據(jù)都是16進(jìn)制數(shù)
可能以上講得有些出入,如有錯(cuò)誤,請(qǐng)幫忙糾正,好了,我們接著來看,接下來push 1進(jìn)去,我們來看看現(xiàn)在的堆棧圖:
繼續(xù)看下面的代碼:
接著是call,call指令在匯編中多用于函數(shù)調(diào)用,call指令做了兩個(gè)操作,
1.Push 00401103(下一行代碼地址) 2.Jmp 0040100A(函數(shù)地址)
這里我們F11一下,遇到call指令后按F11進(jìn)入函數(shù)即可,這樣我們就可以看到函數(shù)體中的指令
這里CALL之后看看堆棧中的變化:
繼續(xù)向下走,F(xiàn)11后跳轉(zhuǎn)到的結(jié)果如下
這里是編譯器決定的,不是所有編譯器call后會(huì)進(jìn)入一個(gè)jmp指令中轉(zhuǎn),再F11一下
Jmp執(zhí)行之后直接進(jìn)入了函數(shù)體,這里將通用寄存器ebp的值存入棧中,之所以存入棧中是因?yàn)槊恳粋€(gè)函數(shù)中都要使用ebp來尋址,所以需要將ebp的原始值存入棧中,隨后將esp棧頂指針的值移入ebp中,sub esp,40h是將棧頂指針加到40h這個(gè)位置,之所以是減40h是因?yàn)闂?臻g是從高到低的,現(xiàn)在我們單步執(zhí)行一下看看棧中的變化
這里40h移動(dòng)的位置=40h/4h=10h=16,我們看看現(xiàn)在堆棧的變化
Sub esp,40h這段代碼我們是為函數(shù)開辟一塊??臻g出來供函數(shù)存取值的,也就是我們常說的緩沖區(qū),通常用來存儲(chǔ)函數(shù)中的局部變量,我們接著往下看
接著向棧中推入了ebx,esi,edi,棧頂指針[esp-Ch],然后lea指令將[ebp-40h]的地址放入edi中,給ecx賦值為10h=16,也就是循環(huán)16次又將0xCCCCCCCCh賦給eax,這也被稱為斷點(diǎn)字符,然后使用rep指令將緩沖區(qū)中的值賦值為0xCCCCCCCCh,現(xiàn)在我們?cè)賮砜纯炊褩V械淖兓?/p>
我們看一下單步執(zhí)行后的esp和ebp的結(jié)果
好勒,咱們接著往下走
這里可以看到首先是將棧中的[ebp+8]=0019FEE4+8=0019FEEC地址中的值移動(dòng)到eax中,然后將eax與[ebp+Ch]=0019FEE4+Ch=0019FEF0地址中的值相加,并且將相加后的值存入eax中,??臻g無任何變化,變化的僅僅是eax,咱們單步執(zhí)行看下
好了,我們接著往下看
首先將edi,esi,ebx中的值取出來,這里可以看到,我們推入和取出的順序剛好相反,先進(jìn)后出的道理,隨后將ebp的值移動(dòng)到esp中,這里也就改變了棧頂指針,然后pop ebp,最后ret,ret的做的操作:
pop eip(這里取出的是返回地址)
咱們單步執(zhí)行一下
我們接著來看代碼
這里esp+8是為了堆棧平衡,恢復(fù)最初的堆棧,我們單步一下
堆棧的變化如下:
這樣就和我們沒進(jìn)入函數(shù)之前的堆棧一樣了,程序到這里就解釋了函數(shù)調(diào)用以及傳參的問題。我們接著往下走
函數(shù)調(diào)用又是一個(gè)call,call的兩個(gè)操作:
1、Push 0040110B(下一行代碼地址)
2、Jmp 00401005(函數(shù)地址)
單步會(huì)遇到j(luò)mp,我們直接單步進(jìn)入函數(shù)體
對(duì)于這里的堆棧就不畫了,主要講解一下這里的全局變量以及“基址”是啥,這里我們的全局變量z是由變量定義的時(shí)候分配指定的內(nèi)存地址,在每一個(gè)函數(shù)中都可以找到,每一個(gè)全局變量都有一個(gè)唯一的內(nèi)存地址,有且只有一個(gè),在游戲外掛中經(jīng)常會(huì)聽到找“基址”,然而這個(gè)“基址”就是全局變量的地址,只要程序被編譯那么就只有這么一個(gè)指定的地址,我們這個(gè)程序中z的地址[00424a30],打開CE
首先我們運(yùn)行一下我們寫好的程序
選擇我們剛才運(yùn)行的程序,點(diǎn)擊加入地址,我們將00424a30這個(gè)內(nèi)存地址加入進(jìn)去
點(diǎn)擊ok,我們看看它的初始值
這里完全沒有自己輸入值,我們改一下值,看看程序的輸出
點(diǎn)擊OK,再看一下改了之后輸出的值
總結(jié):
1、全局變量是編譯后分配的一個(gè)指定內(nèi)存空間,因?yàn)槭枪驳乃匀魏纬绦蚧蛘叱绦蛑械暮瘮?shù)都可以調(diào)用以及修改。
2、局部變量的地址是隨機(jī)的,因?yàn)槊看芜M(jìn)入函數(shù)都會(huì)隨機(jī)分配一段地址給函數(shù),這段分配的地址稱為緩沖區(qū),緩沖區(qū)也是用來存儲(chǔ)局部變量的。
3、“基址”就是全局變量,這是外掛開發(fā)中常用到的一個(gè)詞匯。
4、函數(shù)調(diào)用使用call,call指令做的兩個(gè)操作:
(1)push call指令下一行地址
(2)Jmp 函數(shù)地址(編譯器決定,可能先跳轉(zhuǎn)到中轉(zhuǎn)地址,然后跳轉(zhuǎn)到函數(shù)地址)
5、匯編中的函數(shù)就是指令的集合,唯一不同的是函數(shù)最后都會(huì)用ret返回
6、函數(shù)中的參數(shù)傳遞是使用堆棧來傳遞的。
以上所述是小編給大家介紹的匯編語言中的函數(shù)調(diào)用參數(shù)傳遞及全局與局部變量與“基址”,希望對(duì)大家有所幫助!
相關(guān)文章
os_object_release Crash 排查記錄分析
這篇文章主要為大家介紹了os_object_release Crash 排查記錄分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11匯編語言基礎(chǔ)理解計(jì)算機(jī)底層技術(shù)原理
這篇文章主要為大家介紹了匯編語言基礎(chǔ),理解計(jì)算機(jī)底層原理,想要成為高級(jí)程序員,我們必須要學(xué)會(huì)匯編語言,匯編語言是非常重要的計(jì)算機(jī)底層技術(shù),一般用于底層的編寫2021-11-11計(jì)算機(jī)系統(tǒng)匯編語言和機(jī)器語言深入理解
這篇文章主要為大家介紹了計(jì)算機(jī)系統(tǒng)匯編語言和機(jī)器語言深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09匯編語言80x86系統(tǒng)通用數(shù)據(jù)傳送指令詳解
這篇文章主要為大家介紹了匯編語言80x86系統(tǒng)通用的數(shù)據(jù)傳送指令詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11