PWN入门之三:寄存器与汇编

PWN入门之三:寄存器与汇编

参考文章:
https://www.cnblogs.com/xuanyuan/p/13850548.html

寄存器

0x00 前言

本篇文章实际上为PWN入门之四:C语言调用栈的前置,旨在介绍x86架构下的击中常见的寄存器,和一些简单的汇编代码。

0x01 什么是寄存器?

简单来说,寄存器就是CPU内部的一些小型储存区域,用来暂时存放一些需要计算的数据以及运算出的结果和一些CPU运行需要的信息,比如下面这些:

  1. 可将其内的数据执行算数和逻辑运算
  2. 储存在其内的地址可以用来指向内存的某个地址,即寻址
  3. 可以用来读写数据到电脑周边的数据

0x02 通用寄存器

通用寄存器,看名字也知道,这也是我们最常见的寄存器,电脑运行程序是,大部分的操作都是在这些寄存器中完成的,但是,虽然名字里面有“通用”,但是并不是真正的通用,这几个寄存器在实际使用中还有一些自己的潜规则。

寄存器(64位/32位) 作用
RAX/EAX 通常用来执行加法,函数调用的返回值一般也放在这里面
RBX/EBX 数据存取
RCX/ECX 通常用来作为计数器,比如for循环
RDX/EDX 读写I/O端口时,edx用来存放端口号
RSP/ESP 栈顶指针,指向栈的顶部
RBP/EBP 栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量
RSI/ESI 字符串操作时,用于存放数据源的地址
RDI/EDI 字符串操作时,用于存放目的地址的,和esi两个经常搭配一起使用,执行字符串的复制等操作
R8~R15(64位独有)

0x03 指令寄存器

RIP/EIP指令寄存器可以说是CPU中最最重要的寄存器了,它指向了下一条要执行的指令所存放的地址,CPU的工作其实就是不断取出它指向的指令,然后执行这条指令,同时指令寄存器继续指向下面一条指令,如此不断重复,这就是CPU工作的基本日常。而在漏洞攻击中,黑客想尽办法费尽心机都想要修改指令寄存器的地址,从而能够执行恶意代码。

汇编

参考资料
pwn.college

《汇编语言第3版》王爽著

从0到1:CTFer成长之路Nu1L战队%20编著

0x00 前言

“汇编”部分,旨在能让读者能在较短时间内掌握几个比较基础的汇编命令,进而可以看的懂大部分的反汇编代码,并不真正意义上的汇编入门教程。如果你想更全面的了解pwn中的汇编,可以去参考资料的pwncollege中完成Computing 101这个道馆。

0x01 MOV

MOV是一种数据传送型指令, 其指令的基本格式是:

1
mov <目标操作数>, <源操作数>
  • 目标操作数:数据要去的地方,可以是寄存器或者内存地址
  • 源操作数:数据来的地方,可以是寄存器或者内存地址一个明确的数值

具体细分,有以下五种用法

立即数到寄存器

1
mov eax, 32

将一个明确的数值放入寄存器。这是初始化寄存器最常用的方法。

寄存器到寄存器

1
mov ebx, eax

将数据从一个寄存器复制到另一个寄存器。

立即数到内存

1
2
mov ebx, 10000
mov [eax], 42

将42这个立即数放入10000这个地址中,这里的[]是解引用的意思。

内存到寄存器

1
mov eax, [10000]

将10000这个地址中储存的数放入eax这个寄存器中

寄存器到内存

1
2
3
mov ebx, 10000
mov eax, 42
mov [ebx], eax

eax这个寄存器中的值,放入ebx储存的地址值下

0x02 LEA

LEA是一条取地址指令,其指令的基本格式是:

1
LEA <目标寄存器>, <内存源操作数>
  • 目标寄存器:必须是一个通用寄存器
  • 内存源操作数:必须是以一个内存寻址模式,比如[eax]之类的

举个例子:

1
lea eax, [esi]

这条代码的与下面这条C语言伪代码的作用是一样的

1
eax = &*(esi)

拆开来说就是,先获取储存在esi寄存器中的地址值,比如说10000,然后再使用[]解引用,找到地址10000下的储存的值。比如说42,然后再计算42这个值所在的地址,即10000

0x03 ADD

ADD是一条算术运算指令,其的使用方式和MOV非常相似

1
add <目标操作数>, <源操作数>

翻译成伪代码就是

1
<目标操作数> += <源操作数>

它的用法细分和MOV一样,这里就不展开赘述了。

0x04 SUB

SUB是一条算术运算指令,其的使用方式与ADD一样,和MOV非常相似

1
SUB <目标操作数>, <源操作数>

翻译成伪代码就是

1
<目标操作数> -= <源操作数>

它的用法细分和MOV一样,这里就不展开赘述了。

0x05 AND

AND是一条逻辑运算指令,意思是“与”,其基本格式是:

1
AND <目标操作数>, <源操作数>

不理解的可以去了解一下逻辑运算,“与”就是“逻辑乘”,遇0则0,只有两个对应的位都为 1 时,结果的该位才为 1。

它有如下四种用法:

  1. 寄存器 AND 寄存器 -> 寄存器
  2. 寄存器 AND 立即数 -> 寄存器
  3. 内存 AND 立即数 -> 内存
  4. 寄存器 AND 内存 -> 寄存器

0x06 XOR

XOR是一条逻辑运算指令,意思是异或,它的核心功能是:对两个操作数进行按位“异或”运算,并将结果存放到目标操作数中。基本格式是:

1
XOR <目标操作数>, <源操作数>

逻辑“异或”的规则是:两个对应的位不同时,结果的该位为 1;相同时,结果的该位为 0。

它有如下四种用法:

  1. 寄存器 XOR 寄存器 -> 寄存器
  2. 寄存器 XOR 立即数 -> 寄存器
  3. 内存 XOR 立即数 -> 内存
  4. 寄存器 XOR 内存 -> 寄存器

0x07 CALL

CALL是一条函数调用指令,具体在执行CALL的时候,CPU都干了什么,这部分会在下一部分PWN入门之四:C语言调用栈中详细讲解,

CALL指令的目标地址可以通过多种方式指定:

寻址方式 示例 解释
直接调用 (Direct Call) CALL myFunction 目标地址是明确的符号(标签)或固定的内存地址。汇编器/链接器会计算其实际地址。
寄存器间接调用 (Register Indirect Call) CALL EAX 目标地址存储在寄存器 EAX中。程序运行时动态决定跳转到哪里。常用于函数指针调用、虚函数表跳转等。
内存间接调用 (Memory Indirect Call) CALL DWORD PTR [EBX] 目标地址存储在内存中 EBX指向的位置(双字)。同样用于动态调用。
远调用 (Far Call) (16位/特殊场景) CALL 1000h:2000h 同时改变代码段寄存器 CS和指令指针 IP/ EIP。用于跨段调用(如不同特权级、不同代码段)。现代操作系统(保护模式)较少直接使用。

0x08 RET

RET是一条函数返回指令,它的核心功能是:从子程序(函数或过程)返回到调用者。它利用栈上保存的信息,恢复程序的执行流程。

它的基本格式可以是:

  • RET(近返回)
  • RET n(带立即数操作数的返回,n`通常是偶数,表示字节数)

具体RET都干了什么,这部分会在下一部分PWN入门之四:C语言调用栈中详细讲解

0x09 CMP

CMP是一条比较指令,它的核心功能是:比较两个操作数,并根据比较结果设置处理器的状态标志位 (FLAGS)。它是实现条件分支(如 if语句、循环)的基石。

它的基本格式是:

1
CMP <操作数1>, <操作数2>

其执行的操作可以理解为:

1
<操作数1> - <操作数2>

这个指令会影响的标志位很多,但是我们只需要记忆一个,ZF零标志位:如果结果为 0,则置 1;否则清 0。操作数1 == 操作数2时 ZF=1。

0x10 JMP

JMP是一条无条件跳转指令,它的功能简单而强大:立即、无条件地改变程序的执行流程,跳转到指定的目标地址继续执行。它是实现循环、分支、函数调用等所有非顺序执行逻辑的基础。

它的基本格式是:

1
JMP <目标地址>

执行 JMP指令时,CPU 会做一件事:

  • 将程序计数器 EIP/ RIP(Instruction Pointer) 的值设置为 <目标地址>
  • 程序的下一条指令将从 <目标地址>处开始执行。

0x11 PUSH & POP

PUSHPOP都是栈操作指令,PUSH是压栈,POP是弹栈,这两个指令在这篇文章中不做重点介绍,我将会在下一篇文章中详细介绍这两个汇编指令


PWN入门之三:寄存器与汇编
https://www.xuanyuan-blog.top/PWN/入门/PWN入门之三:寄存器与汇编/
作者
玄渊
发布于
2025年8月8日
许可协议