前言
轉載請聲明作者!

對於二進制安全 棧結構是最基本要了解的東西
關於棧 這里用匯編語言來 “調戲” 棧 玩玩。
希望通過這篇文章能夠初步認識棧的原理及其工作機理
這里用三本書來形象概括
《窮,不搞黑產》、《富,不搞PC》、《黑客從入門到入獄》

當我們存數據的時候 先把《窮,不搞黑產》壓入棧

再把《富,不搞PC》、《黑客從入門到入獄》依次壓入

從上述圖中可以大概理解了棧的數據存儲和讀取的原理
就是先進的數據只能最后出來,而后進的數據卻是最先出來
棧的這個規則叫做:先進后出(Last In First Out)。
利用匯編代碼了解棧
從上述可以知道棧的存儲和取出原理
這里我再用匯編代碼深入講解
mov ax,1000 mov ss,ax mov sp,0010 mov ax,15 mov bx,17 mov cx,8 push ax push bx push cx pop ax pop bx pop cx
給出匯編代碼 ,下面我們將用到DeBug工具來調試分析
首先用-a命令寫入我們的匯編代碼

稍微講解下匯編指令
mov是傳值 例:mov ax,1000 就是把1000傳給ax寄存器中
push是壓棧 例:push ax將當前寄存器內的值壓入棧中
pop是出棧 例:pop ax將棧中的數據彈出賦值給ax寄存器
現在已經寫完了匯編代碼 那么我們就按t單步執行下去
並注意觀察每一步走完后寄存器內的值
調試:
mov ax,1000

這時候ax寄存器已經被賦值為1000了
mov ss,ax

將ax的值賦值給ss寄存器
關於SS:SP在后面會講
這里賦值我就不繼續了 直接走到push ax那

前面的mov賦值完后 相應的寄存器值都如下AX=0015 BX=0017 AX=0008
接着執行完push

可以看到0015 0017 0008已經依次壓入棧中了
因為我們的寄存器里存儲的是16位的數值,例如AX分為AH和AL
其中AH是高8位 AH是低8位
比如AX寄存器里的值存儲着0123H
那么AH=01H AL=23H
然后在內存中 又是以一個字單元寫入的
簡單的說 要占用兩個單元空間 這樣的單元被稱為一個字單元
所以 高8位被存放在下面 而低位被存放在上面

所以push ax(ax的值這時候等於0015)

然后棧頂指針依次-2
最后變成這樣

再出棧
由於這里出棧是
pop ax
pop bx
pop cx
所以最先吧0008的彈出給了ax
0017給bx 0015給了cx

debug中跟蹤查看

此時AX、BX、CX寄存器中的值就與之前相反了~~
后續:
棧在哪里?
知己知彼,方能百戰不殆。
那么,現在已經知道棧的存儲和讀取原理了,可是,棧 在哪呢???
也許大部分人都聽到過寄存器、內存
可是、、、棧???
其實棧就是內存中分配的一段空間
這段空間我們可以用來當棧使用
如下圖就是在內存10000H~1000FH處分配了16個單元的棧空間

但由於是在內存中,系統不會認為他是棧。(並不會把他當做棧使用)
這時候就需要用到我們的寄存器SS:SP了
當寄存器SS:SP所指向的地址就會被當做棧使用
SS:SP尋址原理
SS:SP要尋到我們在內存空間里定義的一塊棧空間
問題是 怎么尋址的呢?
8086CPU中提供兩個16位的地址,一個稱為段地址,用來指向一個段空間(最大空間為64KB)
另一個就是偏移地址了
所以物理地址=段地址x16+偏移地址 (相關問題請留言評論)
通常我們用1000:0001來表示段地址和偏移地址
其中1000是段地址
:是分割符
0001是偏移地址
也許很多人對這個段地址x16怎么算不知道
其實乘16就相當於左移一位
最后找到1000:0001的位置為

然后在內存地址中指向了10001H處
SS:SP是棧頂指針
因為內存中的高位在下面
所以
每次push sp-2
每次pop sp+2
未完待續~
