文章总结: 本文档介绍了PWN入门所需的基础汇编语言知识,详细对比了32位与64位架构下的寄存器及指令集差异。涵盖了数据传送、算术运算、控制转移等核心指令,深入解析了内存空间构建、栈帧管理、函数调用流程及栈对齐机制,为逆向分析与漏洞利用奠定理论基础。 综合评分: 81 文章分类: 二进制安全,CTF,逆向分析
PWN入门笔记-基本汇编语言知识
原创
暗流者
绿洲安全
2026年1月7日 09:00 北京
免责声明
由于传播、利用本公众号绿洲安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号绿洲安全及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢
文章作者:CSDN(暗流者)
参考来源:https://blog.csdn.net/2403_86572967/article/details/149548510
一、寄存器架构
32位(x86):
- 通用寄存器(8个):
EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP - 段寄存器:
CS,DS,ES,FS,GS,SS - 特殊寄存器:
EIP(指令指针),EFLAGS(状态标志)
64位(x86-64):
- 扩展通用寄存器(16个):
RAX,RBX,RCX,RDX,RSI,RDI,RBP,RSP,R8–R15(新增8个64位寄存器) - 保留部分寄存器: 段寄存器(除
FS/GS外)基本弃用 - 特殊寄存器:
RIP(64位指令指针),RFLAGS
二,基础指令
一、数据传送指令
| 指令 | 32位示例 | 64位示例 | 功能说明 |
| — | — | — | — |
| MOV | mov eax, 10 | mov rax, 10 | 数据传送 |
| LEA | lea esi, [ebx+ecx*4] | lea rsi, [rbx+rcx*4] | 地址计算(不访问内存) |
| XCHG | xchg eax, ebx | xchg rax, rbx | 交换数据 |
| MOVZX | movzx eax, byte [mem] | movzx rax, byte [mem] | 零扩展传送 |
| MOVSX | movsx eax, byte [mem] | movsx rax, byte [mem] | 符号扩展传送 |
二、算术运算指令
| 指令 | 通用示例 | 功能说明 |
| — | — | — |
| ADD | add eax, 10 / add rax, 10 | 加法 |
| SUB | sub ebx, ecx / sub rbx, rcx | 减法 |
| INC | inc dword [mem] | 自增(不影响CF标志) |
| DEC | dec esi | 自减(不影响CF标志) |
| MUL | mul ecx | 无符号乘法(EDX:EAX = EAX * ECX) |
| IMUL | imul eax, ebx | 有符号乘法 |
| DIV | div ecx | 无符号除法(EAX = EDX:EAX / ECX) |
三、位操作指令
| 指令 | 通用示例 | 功能说明 |
| — | — | — |
| AND | and eax, 0Fh | 按位与 |
| OR | or ebx, 80h | 按位或 |
| XOR | xor eax, eax | 按位异或(常用清零) |
| NOT | not ecx | 按位取反 |
| SHL | shl edx, 4 | 逻辑左移 |
| SHR | shr eax, 1 | 逻辑右移 |
| SAL | sal ebx, cl | 算术左移(同SHL) |
| SAR | sar ecx, 3 | 算术右移(保留符号位) |
四、控制转移指令
| 指令 | 32位示例 | 64位示例 | 功能说明 |
| — | — | — | — |
| JMP | jmp label | jmp label | 无条件跳转 |
| CALL | call func | call func | 函数调用 |
| RET | ret | ret | 函数返回 |
| JE/JZ | je target | je target | 相等/为零时跳转 |
| JNE/JNZ | jne target | jne target | 不相等/非零时跳转 |
| LOOP | loop label | loop label | ECX/RCX减1,非零跳转 |
五、栈操作指令
| 指令 | 32位示例 | 64位示例 | 功能说明 |
| — | — | — | — |
| PUSH | push eax | push rax | 入栈(ESP/RSP递减) |
| POP | pop ebx | pop rbx | 出栈(ESP/RSP递增) |
| PUSHA | pusha | ✘ 64位移除 | 保存所有通用寄存器 |
| POPA | popa | ✘ 64位移除 | 恢复所有通用寄存器 |
| ENTER | enter 16, 0 | 极少使用 | 创建栈帧 |
| LEAVE | leave | leave | 销毁栈帧 |
六、系统调用指令对比
| 架构 | 指令 | 参数传递方式 |
| — | — | — |
| 32位 | int 0x80 | EAX=调用号, EBX/ECX/EDX/ESI/EDI/EBP=参数 |
| 64位 | syscall | RAX=调用号, RDI/RSI/RDX/R10/R8/R9=参数 |
七、核心数据定义指令
| 指令 | 全称 | 位数 | 功能说明 | 示例 |
| — | — | — | — | — |
| DB | Define Byte | 8位 | 定义字节数据 | num DB 0x55 |
| DW | Define Word | 16位 | 定义字(2字节)数据 | buffer DW 1024 |
| DD | Define Doubleword | 32位 | 定义双字(4字节)数据 | pointer DD 0x8040000 |
| DQ | Define Quadword | 64位 | 定义四字(8字节)数据 | addr64 DQ 0x7FFFFFFFFFFF |
| DT | Define Ten Bytes | 80位 | 定义10字节数据(浮点专用) | float DT 3.1415926535 |
八、64位专属指令
-
RIP相对寻址:
bash复制代码
asm
lea rax, [rip + label] ; 动态计算地址(位置无关代码)
-
SWAPGS:
bash复制代码
asm
swapgs ; 切换内核GS寄存器(系统编程)
-
SYSCALL/SYSRET:
bash复制代码
asm
syscall ; 快速系统调用
sysret ; 快速系统返回
三.构建内存空间
一.寄存器构建
1.如何构建一段栈空间,需要这三个ebp,esp,ss寄存器
| 寄存器 | 全称 | 位数 | 核心功能 | | — | — | — | — | | ESP | Extended Stack Pointer | 32位 | 栈顶指针 ,始终指向当前栈顶位置 | | EBP | Extended Base Pointer | 32位 | 栈帧基址 ,指向当前函数栈帧起点 | | SS | Stack Segment | 16位 | 栈段寄存器 ,定义栈内存的基地址 |
高地址 +—————–+ | 返回地址 | +—————–+ | 保存的RBP | <– RBP (当前帧基址) +—————–+ | 局部变量 | | … | +—————–+ | 额外参数 | +—————–+ 低地址 <– RSP (栈顶)
二、函数调用中的协作流程
1. 函数进入序言 (Prologue):
bash复制代码
asm
; 保存调用者的栈帧基址
push ebp ; ESP自动减4,旧EBP入栈
; 建立新栈帧
mov ebp, esp ; EBP指向当前栈顶(即旧EBP位置)
; 分配局部变量空间
sub esp, 16 ; 分配16字节局部变量区
2. 函数内栈操作:
bash复制代码
asm
; 访问参数(假设32位cdecl调用约定)
mov eax, [ebp+8] ; 第一个参数(返回地址占4字节)
; 访问局部变量
mov [ebp-4], eax ; 存储到第一个局部变量
3. 函数退出尾声 (Epilogue):
bash复制代码
asm
; 恢复栈指针(释放局部变量)
mov esp, ebp ; ESP回到栈帧起点
; 恢复调用者栈帧
pop ebp ; 恢复旧EBP,ESP自动加4
; 返回(清理参数由调用者负责)
ret
三,栈对齐的问题(32位和64位都需要)
栈对齐(Stack Alignment)是x86架构中极易被忽视却至关重要的机制,尤其在64位系统中直接关系到程序稳定性和性能。本文将通过原理分析、实例演示和解决方案全面解析这一核心问题。
- 函数调用前RSP必须16字节对齐
- 调用指令
call会压入8字节返回地址
bash复制代码
asm
; 正确对齐示例
sub rsp, 24 ; 24+8(返回地址)=32 → 16字节对齐
call func
add rsp, 24
4.pop和push指令
pop和push指令用于压栈和出栈
PUSH 执行流程(以 32位 push eax 为例):
- ESP 减 4(栈指针下移)
ESP = ESP - 4 - 将 EAX 值写入 ESP 指向的地址
[ESP] = EAX - 更新 EFLAGS 寄存器(不影响标志位)
plaintext
复制代码
执行前: 执行后:
高地址 高地址
┌─────────┐ ┌─────────┐
│ │ │ EAX值 │ ← ESP
├─────────┤ ├─────────┤
│ │ ← ESP │ │
└─────────┘ └─────────┘
低地址 低地址
POP 执行流程(以 32位 pop ebx 为例):
复制代码
1. 读取 ESP 指向的值
`EBX = [ESP]`
2. ESP 加 4(栈指针上移)
`ESP = ESP + 4`
3. 更新 EFLAGS 寄存器(不影响标志位)
5.ret和call指令
call 指令
-
作用 :
call指令将当前的 IP(指令指针)或 CS:IP(段寄存器和指令指针)压入栈中,然后跳转到指定的函数地址,从而实现子程序的调用。 -
执行流程
bash复制代码
- 1. 将当前的 IP 或 CS 和 IP 压入栈中(相当于 `push IP`)。
2. 跳转到目标地址(相当于 `jmp near ptr 标号`)。
- **示例**:`call 标号`(近转移)相当于执行 `push IP` 和 `jmp near ptr 标号` 。
ret 指令
-
作用 :
ret指令用于从子程序返回到调用点,它通过从栈中弹出返回地址,并将其加载到 IP 寄存器中,从而恢复程序的执行流程。 -
执行流程
bash复制代码
- :
1. 从栈中弹出返回地址(相当于 `pop IP`)。
2. 将返回地址加载到 IP 寄存器中,程序继续执行。
- **示例**:`ret` 指令相当于执行 `pop IP`,并更新 SP 寄存器(栈指针)。
6.leave指令
leave 指令
-
作用 :
leave是汇编语言中用于结束堆栈帧的指令,通常与函数调用的栈帧管理相关。它的主要功能是恢复函数调用前的栈指针(ESP)和帧指针(EBP)的值,从而清理当前函数的栈帧。。
-
执行流程
bash复制代码
- 1. mov esp, ebp ; 将栈指针恢复到帧指针的位置。
2. pop ebp ; 弹出原帧指针,恢复调用者的帧指针。
- **示例**:
func PROC
enter 0, 0 ; 创建堆栈帧,无局部变量
; 函数体代码
leave ; 结束堆栈帧
ret ; 返回调用者
func ENDP。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:绿洲安全 暗流者《PWN入门笔记-基本汇编语言知识》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论