到底日更变成拖更变成月更了,水一篇吧,实在太忙了,或者你们想看的话我更新高等数学也行

借鉴来源:


# ASM 源码:

section .data
    msg db "Welcome_to_CTFshow_PWN", 0

section .text
    global _start

_start:

; 立即寻址方式
    mov eax, 11         ; 将11赋值给eax
    add eax, 114504     ; eax加上114504
    sub eax, 1          ; eax减去1

; 寄存器寻址方式
    mov ebx, 0x36d      ; 将0x36d赋值给ebx
    mov edx, ebx        ; 将ebx的值赋值给edx

; 直接寻址方式
    mov ecx, msg      ; 将msg的地址赋值给ecx

; 寄存器间接寻址方式
    mov esi, msg        ; 将msg的地址赋值给esi
    mov eax, [esi]      ; 将esi所指向的地址的值赋值给eax

; 寄存器相对寻址方式
    mov ecx, msg        ; 将msg的地址赋值给ecx
    add ecx, 4          ; 将ecx加上4
    mov eax, [ecx]      ; 将ecx所指向的地址的值赋值给eax

; 基址变址寻址方式
    mov ecx, msg        ; 将msg的地址赋值给ecx
    mov edx, 2          ; 将2赋值给edx
    mov eax, [ecx + edx*2]  ; 将ecx+edx*2所指向的地址的值赋值给eax

; 相对基址变址寻址方式
    mov ecx, msg        ; 将msg的地址赋值给ecx
    mov edx, 1          ; 将1赋值给edx
    add ecx, 8          ; 将ecx加上8
    mov eax, [ecx + edx*2 - 6]  ; 将ecx+edx*2-6所指向的地址的值赋值给eax

; 输出字符串
    mov eax, 4          ; 系统调用号4代表输出字符串
    mov ebx, 1          ; 文件描述符1代表标准输出
    mov ecx, msg        ; 要输出的字符串的地址
    mov edx, 22         ; 要输出的字符串的长度
    int 0x80            ; 调用系统调用

; 退出程序
    mov eax, 1          ; 系统调用号1代表退出程序
    xor ebx, ebx        ; 返回值为0
    int 0x80            ; 调用系统调用

# 详解:

# 1. .data 段

section .data
    msg db "Welcome_to_CTFshow_PWN", 0

解释:

  • .data:用来存放程序中的已初始化数据,这些数据在程序运行时会被加载到内存中。
  • msg db :声明一个字符串 "Welcome_to_CTFshow_PWN" ,以字节( db = Define Byte)存储,并以 0 结尾,表示字符串结束符(类似 C 语言的 \0 )。
  • 地址msg 是一个标签,代表该字符串的内存地址,供后续使用。

# 2. .text 段

section .text
global _start

_start:

解释:

  • .text:存放程序的代码(指令)。
  • _start :程序的入口,系统从这里开始执行程序(对应 Linux 的 ELF 文件格式的起点)。

# 3. 立即寻址方式

mov eax, 11         ; 将11赋值给eax
add eax, 114504     ; eax加上114504
sub eax, 1          ; eax减去1

解释:

  • 立即寻址方式:操作数是一个立即数,直接嵌入在指令中。例如 11114504

  • 过程

    1. mov eax, 11 :将立即数 11 加载到寄存器 eax 中。
    2. add eax, 114504 :将立即数 114504 加到 eax 的当前值上。
    3. sub eax, 1 :将 eax 的值减去立即数 1
  • 硬件实现:立即数直接写入指令的操作数字段,CPU 解码指令后直接将值加载到指定寄存器中。


# 4. 寄存器寻址方式

mov ebx, 0x36d      ; 将0x36d赋值给ebx
mov edx, ebx        ; 将ebx的值赋值给edx

解释:

  • 寄存器寻址方式:操作数在寄存器中,CPU 直接对寄存器进行操作。

  • 过程

    1. mov ebx, 0x36d :将立即数 0x36d 加载到寄存器 ebx
    2. mov edx, ebx :将寄存器 ebx 的值复制到寄存器 edx
  • 硬件实现:寄存器之间的数据传递不需要访问内存,速度非常快。


# 5. 直接寻址方式

mov ecx, msg      ; 将msg的地址赋值给ecx

解释:

  • 直接寻址方式:操作数的地址直接给出,即指令中明确指出操作数所在的内存地址。

  • 过程

    • mov ecx, msg :将标签 msg 所指向的内存地址加载到寄存器 ecx
  • 硬件实现:CPU 将指令中的地址字段直接解析为内存地址,然后取出对应地址的内容。


# 6. 寄存器间接寻址方式

mov esi, msg        ; 将msg的地址赋值给esi
mov eax, [esi]      ; 将esi所指向的地址的值赋值给eax

解释:

  • 寄存器间接寻址方式:寄存器中存储的是操作数的内存地址,操作数存储在该地址中。

  • 过程

    1. mov esi, msg :将 msg 的地址加载到寄存器 esi
    2. mov eax, [esi] :从 esi 指向的内存地址中读取数据,并存储到寄存器 eax
  • 硬件实现

    • CPU 读取寄存器 esi 的值(作为内存地址)。
    • 然后去内存中访问该地址,取出存储的值加载到寄存器 eax

# 7. 寄存器相对寻址方式

mov ecx, msg        ; 将msg的地址赋值给ecx
add ecx, 4          ; 将ecx加上4
mov eax, [ecx]      ; 将ecx所指向的地址的值赋值给eax

解释:

  • 寄存器相对寻址方式:寄存器中存储基地址,操作数的地址是基地址加上一个偏移量。

  • 过程

    1. mov ecx, msg :将 msg 的地址加载到寄存器 ecx
    2. add ecx, 4 :将 ecx 加上偏移量 4
    3. mov eax, [ecx] :从 ecx 指向的地址读取数据到寄存器 eax
  • 硬件实现

    • 计算内存地址: ecx + 4
    • 访问该地址并读取数据。

# 8. 基址变址寻址方式

mov ecx, msg        ; 将msg的地址赋值给ecx
mov edx, 2          ; 将2赋值给edx
mov eax, [ecx + edx*2]  ; 将ecx+edx*2所指向的地址的值赋值给eax

解释:

  • 基址变址寻址方式:地址是基地址加上索引值( edx ),并根据一个比例因子(如 *2 )计算得到。

  • 过程

    1. mov ecx, msg :加载基地址到寄存器 ecx
    2. mov edx, 2 :加载索引值 2 到寄存器 edx
    3. mov eax, [ecx + edx*2] :计算地址为 ecx + edx*2 ,然后读取该地址的数据到 eax
  • 硬件实现

    • 地址计算: ecx + edx*2
    • 访问该内存地址并读取数据。

# 9. 相对基址变址寻址方式

mov ecx, msg        ; 将msg的地址赋值给ecx
mov edx, 1          ; 将1赋值给edx
add ecx, 8          ; 将ecx加上8
mov eax, [ecx + edx*2 - 6]  ; 将ecx+edx*2-6所指向的地址的值赋值给eax

解释:

  • 相对基址变址寻址方式:地址是基地址加索引值乘比例因子再加偏移量。

  • 过程

    1. mov ecx, msg :加载基地址到 ecx
    2. mov edx, 1 :加载索引值 1edx
    3. add ecx, 8 :将偏移量 8 加到 ecx
    4. mov eax, [ecx + edx*2 - 6] :计算地址为 ecx + edx*2 - 6 ,然后读取数据到 eax
  • 硬件实现

    • 地址计算: ecx + edx*2 - 6
    • 访问该地址并读取数据。

# 10. 系统调用(输出字符串)

mov eax, 4          ; 系统调用号4代表输出字符串
mov ebx, 1          ; 文件描述符1代表标准输出
mov ecx, msg        ; 要输出的字符串的地址
mov edx, 22         ; 要输出的字符串的长度
int 0x80            ; 调用系统调用

解释:

  • 过程

    1. mov eax, 4 :设置系统调用号为 4sys_write )。
    2. mov ebx, 1 :文件描述符为 1 (标准输出)。
    3. mov ecx, msg :输出字符串的地址。
    4. mov edx, 22 :字符串的长度。
    5. int 0x80 :触发软中断,调用 Linux 内核的系统调用。
  • 硬件实现

    • 将参数放入寄存器( eax , ebx , ecx , edx )。
    • 调用 int 0x80 ,切换到内核模式执行 sys_write

# 11. 退出程序

mov eax, 1          ; 系统调用号1代表退出程序
xor ebx, ebx        ; 返回值为0
int 0x80            ; 调用系统调用

解释:

  • 过程

    1. mov eax, 1 :设置系统调用号为 1sys_exit )。
    2. xor ebx, ebx :返回值为 0
    3. int 0x80 :触发软中断,调用内核终止程序。

# 总结

  • 寻址方式

    1. 立即寻址:直接在指令中给出操作数。
    2. 寄存器寻址:操作数在寄存器中。
    3. 直接寻址:操作数的地址直接给出。
    4. 间接寻址:通过寄存器指向的地址访问数据。
    5. 相对寻址:基址 + 偏移量。
    6. 基址变址寻址:基址 + 索引 * 比例因子。
    7. 相对基址变址寻址:基址 + 索引 * 比例因子 + 偏移量。
  • 系统调用

    • 使用 int 0x80 切换到内核模式执行特定操作。

    这个 int 0x80 有点小关键的,有时候打 shellcode 会用