自学汇编碰到许多问题,有的已经解决,有的还没解决,都写在这里。
自己寻找问题的答案时也问过许多人,走过不少弯路,希望这篇文章能为有同样问题的朋友省下许多弯路。
1. push指令是什么意思?
答:压栈(看不懂吧。。呵,往后看。)。相信做过破解的人都会注意到,程序里push指令是最常出现的指令之一,那么这个指令到底是什么意思呢?问了高手们,都说是压栈。我们知道栈只是一种数据结构,那么汇编里的栈和我们数据结构的栈是不是一回事呢?事实上,不是的!汇编里的push是将push后面的数据压入系统栈。所谓系统栈,通常是开辟在内存最低层的连续数据空间,用于什么我就不知道了。但是这块数据空间是具有栈的特性的,也就是所谓的先进后出。所以这块空间叫做系统栈。push压栈操作,就是把数据压到系统栈里。
ps:这个问题的回答是我问了许多人之后的心得。但是我发给我同学看(他们有汇编课,我则是自学的,所以经常请教他),他告诉我,那个系统栈应该是堆栈段,而且不是系统分配的,而是自己装入的。我就有点糊涂了。
回答:
by2楼 mik
对于 push 指令,认为简单就是简单,认为复杂就是复杂
下面看看从低往深的理解:
第1层:就是入栈
第2层:怎样入栈?用C代表就是:esp--; *esp = XXX;
第3层:esp-- 是多少?
答案:一般来说:在实模式下是 esp 减 2,在保护模式下 esp 减 4,在 64 bit 模式下 rsp 减 8。
第4层:为什么实模下减 2,保护模式下减 4,64 bit 模式下减 8 ?
答案:esp(stack pointer)减多少,取决于 SS.B。
SS.B 是什么?SS.B 就是 SS 寄存器内的 B 属性,这个 B 属性就是:data segment default operand size(数据段缺省的操作数大小),SS 寄存器所装载的 segment descriptor 这时表示为 stack segment descriptor,B 属性用来表示:缺省的 stack 的操作数大小。
即:B = 1 时,它的栈操作数是 32 位,B = 0,它的栈操作数是 16 位。
在实模式下,SS.B 一定是 0,表示实模式下栈的操作数是 16,所以,sp 减 2。
在保护模式下,SS.B 总是被置为 1,表示保护模式下操作数是 32 位,所以,esp 减 4。
在 64 bit 模式下,SS.B 是无效的,x64 定义栈操作数强制为 64 位。
第 5 层:可以更改栈操作数大小吗?
答案:可以。
在实模式下,几乎不能更改栈操作数大小,但还是有办法的,这里就不说了。
在保护模式下,若定义的 B = 0 则为16 位,但所有的 OS 都不会这么做。所有 OS 栈的缺省操作数都是 32 位。
但是,可以 32 位的栈上强制压入 16 位的值。这样造成栈边界不对齐。产生性能问题。
在 64 位模式下,不能改变,所有的栈操作数都是 64 位。
第6层:push 压入的数据是多大?
答案:缺省情况下,就是上面所说的栈操作数大小。
但是,在强制情况下,16 位栈可以压入 32 位值,32位栈可以压入16位。64位栈只能固定压入64位值。
第7层:压入后栈指针,指向哪?
答案:就是栈顶,ESP 指向栈顶。
第8层:往哪个栈压栈呢?
答案:就是往当前的栈压入栈。
第9层:什么是当前的栈?
答案:SS:SP、SS:ESP 和 SS:RSP 就是代表当前的栈。
当 SS:ESP 指向内核栈时,当前的栈就是内核栈。当 SS:ESP 指向用户栈时,当前的栈就是用户栈。
第10层:什么时候指向用户栈?什么时候指向内核栈?
答案:当代码转入内核,或者说:代码陷入内核时。SS:ESP 会切换到内核栈。一般的应用层上都使用用户栈。
第11层:能使用DS访问栈吗?
答案:看情况,在平垣的内存模式下,可以使用DS该问栈,也就是,数据段来指引栈段。现在绝大多数OS 都是平垣的内存管理模式下,所以,绝大多数情况下,可以用DS段访问SS 段
-----------------------------------------------------------
上面的11层中,你理解到哪一层呀?
一般的人都是理解到 第 3 层而已。。。
回答二: by3楼 hzfc
SS 堆栈段 esp是堆栈寄存器,始终指向栈顶
Push把值压入堆栈 esp=esp-4 入栈元素存入esp
Pop把值弹出堆栈 把esp中存储值给出栈元素 esp=esp+4
2. 据说伪指令是不进行实际操作的。那么我们可以不写吗?为什么?
答:by4楼 要学汇编
伪指令要写,记得好象看过伪指令是在编译器这一层来支持的,源代码中的伪指令编译时都被编译器实现了.
3. fstsw指令是什么意思?~ 什么是浮点运算?
by 16楼 cmdxhz
FSTSW:
FPU储存狀态暂存器值至AX(这个指令的功用是用来把状态字组取出并存入记忆体变数里,而这个记忆体变数必须是 16 位元的记忆体变数)
FPU 的暂存器可分为五类,堆叠暂存器 (register stack)、状态字组 (status word)、控制字组 (control word)、标籤字组 (tag word)、例外指标 (exception pointer)。虽然看起来很複杂,但是最重要且最常用的是堆叠暂存器。
FPU 共有八个堆叠暂存器,分别是 ST、ST(1)、ST(2)、ST(3)……ST(7),这八个暂存器每一个都是 80 位元,用来存放运算时所需要的资料,这和以前我们所说的堆叠所存的资料不太相同,但是操作方式却是一样的。FPU 许多运算都是先把数值推入堆叠顶端的 ST 暂存器,再对 ST 暂存器作运算
使用
4. 看汇编的书,似乎寄存器就是eax,ebx那些常用的加上flag寄存器。原来后面那些st0,st1...也是寄存器。但是书上都没提到过(我看的80x86汇编语言)。这样很误导我们这样的初学者。能不能详绍一下,cpu里的寄存器数量,功能(我猜每个CPU都是不同的,但是大概介绍下吧^ ^);
我会尽量快地更新这篇文章,整理回答,并提出新的问题。
另外各位有什么问题也可以提出来,我会整理到一楼来的^ ^
希望踊跃拍砖,多多指出不足指出。
万分感谢看贴和回帖的各位朋友。
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。