汇编指令学习之出入栈与现场保护

admin 2026-06-18 07:44:14 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文深入讲解了汇编语言中堆栈操作指令的用法,重点分析了PUSH/POP的字节序反转与ESP指针变化,演示了PUSHAD/POPAD保存通用寄存器及PUSHFD/POPFD保存标志位寄存器的现场保护机制。通过调试实验验证了指令执行效果,揭示了栈内存增长规律,为理解底层程序运行与逆向分析奠定了基础。 综合评分: 86 文章分类: 二进制安全,逆向分析


cover_image

汇编指令学习之出入栈与现场保护

原创

secureyang secureyang

secureyang

2026年6月14日 19:22 陕西

在小说阅读器读本章

去阅读

汇编指令学习之出入栈与现场保护一、nop指令二、push和poppushpop三、pushad和popadpushadpopad四、pushfd和popfd

汇编指令学习之出入栈与现场保护

一、nop指令

其实我们可以看到,其实执行nop指令,是没有任何操作的,也就是说nop指令并不执行任何操作。

二、push和pop

push

push除了能压入之前的那些值,还能压入寄存器、地址值、地址指向的值。比如

push eax 就是把eax中的地址压入栈中。

push 0x0049341D。不过在汇编指令窗口被自动识别成了程序名称

push [0x493413]。[] 中括号其实可以用来提取地址中的值

这段指令会被识别并转换为

push dword ptr ds:[0x493413]

其中dword就表示压入的是4字节,比如 00 00 00 00 这样的就是一个4字节的。

在这里我们压入0x493413的地址的值,我们找到这个地址,然后右键,数据窗口中跟随,如下图:

我们可以看到,数据窗口中的找到的值就是5E,但为什么最后插入的值是 0D89645E呢。

压栈时,从5E开始向后的四个字节会被压入栈中,但是压入后,值的顺序是反的,看这里就是原本的 5E 64 89 0D 压入栈中后,栈内的值就变成了0D89645E。

pop

pop顾名思义就是把栈顶的元素弹出然后赋值给目标,比如 pop eax 就是把栈顶的值弹出然后赋值给eax。下面会给出示例介绍。

三、pushad和popad

针对寄存器的现场保护

pushad

pushad什么意思呢?就是将当前除过EIP之外的八个寄存器的地址的值全都存到栈空间内。也就是所谓的现场保护。

 pushad
 =
 push eax
 push ecx
 push edx
 push ebx
 push esp
 push ebp
 push esi
 push edi

比如我们修改EIP地址要执行的汇编代码为:pushad

我们来执行看一下结果

我们看栈空间里,和上面说的结果是一样的。将八个寄存器的值存储到栈空间内。而且同时可以看出来他是先入栈的在最下面,这就是入栈和出栈的规则。此时如果寄存器中的地址发生了变化,还可以从栈中取数据,来恢复现场。

pop扩展讲解。

同时出栈的话也是一样,需要按照顺序出栈,否则的话很有可能导致程序终止。比如下图:

我修改了ESP为1,想试图通过pop esp 来修改他,结果直接把程序干终止了。别忘了esp是要指向栈顶的。

此时我们重新载入程序并pushad:

修改esi为0,并pop esi,看看结果

可以正常运行,没问题。

重新载入,修改ebp地址为0,并pop ebp,我们来看看结果

可以正常运行,同时把原先EDI的值,即0049341D赋值给了ebp,所以就可以看出来pop就是把栈顶的值弹出来然后赋值给目标。比如这里的pop esp就是把栈顶的值弹出来赋值给esp。而并不是把原先esp的值再返回给esp,这是不一样的。

popad

然后我们把寄存器里的值修改一部分,但记得不要修改ESP,否则程序会被迫中止,然后再执行popad来看看

我们可以看到,寄存器里的地址值已经全部回归,栈空间中EIP对应的栈顶的值也增加了到了0019FF78。

向栈内压入,会占用一定的空间,比如这里压入一个地址值,对应的就是4个字节的值,然后栈顶的地址就会减少4个字节,即OD窗口中向上移动。同理,从栈中弹出值之后,栈顶的地址就会增加4个字节,即OD窗口中向下移动。

如下图所示,我们执行一个 push 0x1 的汇编代码,来观察esp中地址值的变化。

我们可以看到,压栈窗口中出现了一个00000001的值,对应的地址是0019FF74,从上面的0019FF78减少了4个字节。

四、pushfd和popfd

针对标志位的现场保护

如下所示,此时标志位分别为 0 1 0 1 0 0 0 0,此时pushfd,我们可以看到有一个压栈的值,是00000246

此时修改标志位全0,即 0 0 0 0 0 0 0 0,然后执行 popfd,即一切又恢复正常。

全0标志位压栈的结果是多少,看下图

0 0 0 0 0 0 0 0 对应的压栈结果是 00000202

全1的标志位压栈结果是 00000FD7

所以看来不同标志位的值,压栈结果也不同,我们用一张表汇总一下

| 标志位 8 位二进制串 | 最终 16 进制压栈值(32 位) | | — | — | | 0 0 0 0 0 0 0 0 | 00000202 | | 0 1 0 1 0 0 0 0 | 00000246 | | 1 1 1 1 1 1 1 1 | 00000FD7 | | 1 0 0 0 0 0 0 0 | 00000203 | | 0 0 0 0 1 0 0 0 | 00000282 | | 0 0 0 1 0 0 0 0 | 00000242 | | 0 0 0 0 0 1 0 0 | 00000302 | | 0 0 0 0 0 0 1 0 | 00000402 | | 0 0 0 0 0 0 0 1 | 00000602 | | 1 1 0 0 0 0 0 0 | 00000207 |


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:secureyang secureyang secureyang《汇编指令学习之出入栈与现场保护》

评论:0   参与:  0