前言
转载请声明作者!
对于二进制安全 栈结构是最基本要了解的东西
关于栈 这里用汇编语言来 “调戏” 栈 玩玩。
希望通过这篇文章能够初步认识栈的原理及其工作机理
这里用三本书来形象概括
《穷,不搞黑产》、《富,不搞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
未完待续~