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

如何在不使用数据段的情况下通过Keystone汇编引擎实现打印Hello World

问题根因

Keystone 仅负责汇编原生CPU指令,不支持 NASM 的 section、global、equ 这类汇编器伪指令,也不会自动处理段地址、跨段标号地址计算,因此你传入带段声明、数据段定义的完整NASM代码会报错。

无独立数据段的字符串实现方案

不需要单独定义.data段,可直接把字符串嵌入代码段,用跳转指令跳过字符串内容避免CPU把字符串解析为指令执行,这里提供两种常用实现方式:


方案1:代码段内嵌字符串(写法简单,推荐)

Keystone 支持用db直接定义字节数据,我们把字符串放在代码段的跳转空白区即可,不需要单独声明数据段。
注意你示例中用的int 0x80是32位Linux系统调用方式,初始化Keystone时需要指定KS_MODE_32,如果需要64位版本可以替换为对应syscall逻辑。
可直接运行的完整代码如下:

from keystone import *

# 初始化32位x86模式,匹配int 0x80系统调用规范
ks = Ks(KS_ARCH_X86, KS_MODE_32)

CODE = b'''
_start:
    jmp short call_point       ; 跳转到执行逻辑,跳过字符串数据区

string:
    db "Hello, world!", 0xa    ; 字符串直接嵌在代码段中

call_point:
    call string                ; 调用string标签会自动把字符串地址压入栈
    ; 调用sys_write输出字符串
    mov edx, 13                ; 固定写死字符串长度:"Hello, world!\n"共13字节
    pop ecx                    ; 栈顶就是字符串地址,直接弹出到ecx寄存器
    mov ebx, 1                 ; stdout文件描述符
    mov eax, 4                 ; 32位Linux sys_write系统调用号
    int 0x80

    ; 调用sys_exit退出程序
    mov ebx, 0                 ; 退出状态码0
    mov eax, 1                 ; 32位Linux sys_exit系统调用号
    int 0x80
'''

# 执行汇编
encoding, ins_count = ks.asm(CODE)
print(f"汇编成功,共生成{ins_count}条指令,机器码总长度{len(encoding)}字节")

方案2:完全不用db伪指令,直接压栈构造字符串

如果需要完全避免数据定义伪指令,可以把字符串拆成小端序的立即数直接压入栈,用栈指针esp作为字符串首地址:

; 仅用原生指令构造字符串
xor eax, eax
push 0x0a21646c   ; 对应小端序的 "ld!\n"
push 0x726f7720   ; 对应小端序的 " wor"
push 0x6f6c6c65   ; 对应小端序的 "ello"
push 0x48         ; 对应小端序的 "H"
mov ecx, esp      ; esp当前指向字符串首地址
; 后续sys_write、sys_exit逻辑和方案1一致

这种写法完全由CPU原生指令构成,Keystone可以直接汇编,适合无法内嵌数据的特殊场景。

内容的提问来源于stack exchange,提问作者J.Todd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 06:24:03