You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

尝试用scasb读取程序自身代码遇段错误,咨询该操作是否可行?

用SCASB读取自身.text段的可行性与问题修复

首先可以明确:使用SCASB指令访问程序自身的.text段是完全可行的,你的段错误来自几个关键的寄存器配置和指令使用误区,下面逐一拆解并给出修复方案:

核心问题分析

1. SCASB的本质是扫描比较,不是直接读取

SCASB指令的作用是将AL寄存器中的值与ES:EDI(32位)/RDI(64位)指向的字节做比较,然后根据DF标志位自动增减地址寄存器。你当前的代码既没有设置AL的目标值,也没有利用它的扫描逻辑——这不是“读取”操作的正确用法,如果只是想读取字节,用movb (%rdi), %al更直接;但如果要利用SCASB做扫描(比如找某个特定字节),必须先把目标字节存入AL。

2. 32位模式下段寄存器配置错误

在32位保护模式下,ES寄存器不能直接设为0(空选择子会触发段错误)。你需要让ES指向与CS相同的段选择子,因为CS对应的代码段默认是可读可执行的(只要链接脚本没特殊限制)。通过mov %cs, %ax; mov %ax, %es可以让ES和CS同段,从而合法访问.text段的地址。

3. 64位模式下的隐性问题

64位平坦内存模型不需要段寄存器干预,但你的代码存在两个小问题:

  • 没有初始化AL的值(虽然这不会直接导致段错误,但会让SCASB的比较结果无意义)
  • 程序返回时没有设置返回值(不过这不是段错误的根源,只是不规范)

修复后的示例代码

64位版本(编译命令:gcc -m64 -nostdlib yourcode.s -o test)

.section .text
.globl main
main:
    mov $0x03, %al          ; 设置要扫描的目标字节(比如找0x03)
    leaq str(%rip), %rdi    ; 用RIP相对寻址加载str的地址(64位推荐写法)
    scasb                   ; 比较AL与(RDI),然后RDI自动+1(DF默认是0)
    ; 此时如果ZF=1,说明找到目标字节,RDI指向str+1的位置
    xor %eax, %eax          ; 设置返回值0
    ret
str:
    .byte 0x01,0x02,0x03,0x04,0x05

32位版本(编译命令:gcc -m32 -nostdlib yourcode.s -o test)

.section .text
.globl main
main:
    mov %cs, %ax            ; 将CS段选择子加载到AX
    mov %ax, %es            ; 设置ES与CS同段,允许访问.text段
    mov $0x03, %al          ; 设置目标扫描字节
    mov $str, %edi          ; 加载str的地址到EDI
    scasb                   ; 比较AL与ES:EDI,EDI自动+1
    xor %eax, %eax          ; 返回0
    ret
str:
    .byte 0x01,0x02,0x03,0x04,0x05

额外注意事项

  • 确保你的.text段具有读权限:绝大多数编译链接工具默认会给.text段添加可读权限(因为要支持字符串常量、只读数据等),如果你的链接脚本做了特殊限制,需要修改配置添加READONLY属性。
  • DF标志的影响:如果之前的代码修改过DF标志(比如用std指令设置为1),SCASB会让地址寄存器递减,记得用cld指令恢复默认的DF=0(地址递增)。

内容的提问来源于stack exchange,提问作者qwr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:10:48