CTF无0x00限制下能否强制GAS生成2字节相对JMP指令?
如何强制GAS生成2字节的JMP rel16指令?
绝对可以搞定这个问题!GAS在32位汇编模式下默认会生成4字节的JMP rel32指令(哪怕偏移量在16位范围内),这就导致高位出现0x00字节,正好踩中CTF shellcode的禁忌。不过我们有两种可靠的方法强制它输出2字节的JMP rel16:
方法1:使用jmpw显式指定16位跳转宽度
GAS支持通过jmpw指令(后缀w代表word,即16位)直接生成2字节的相对跳转。这个指令会明确告诉汇编器生成0xE9 opcode + 16位偏移的组合,不会出现冗余的高位0字节。
示例代码:
shellcode: ; 这里放你的主体shellcode代码 jmpw sc_data ; 生成2字节的JMP rel16,无0x00字节 ; 填充至0x514字节,用nop(0x90)填充避免干扰 times 0x514 - ($ - shellcode) db 0x90 ; 覆盖全局符号的常量 dd 0xdeadbeef sc_data: ; 你的数据段,比如字符串等 db '/bin/sh', 0
方法2:手动编码指令字节(更直接可控)
如果jmpw在某些场景下不生效(比如特定版本的GAS),可以直接手动构造指令的机器码,完全掌控每一个字节:
shellcode: ; 手动构造JMP rel16:opcode是0xE9,后跟16位相对偏移 .byte 0xE9 ; 计算偏移:目标地址 - (当前地址 + 2),因为JMP指令占2字节,偏移是相对于下一条指令的 .word sc_data - ($ + 2) ; 填充到0x514字节 times 0x514 - ($ - shellcode) db 0x90 ; 全局符号覆盖常量 dd 0xcafebabe sc_data: db '/bin/sh', 0
关键说明
- GAS默认生成
JMP rel32的原因是在32位模式下,它优先使用32位偏移以兼容更大的地址空间,哪怕偏移量很小。显式指定16位宽度就能绕过这个默认行为。 - 测试时可以用
objdump -d查看生成的机器码,确认JMP指令是2字节且没有0x00字节:objdump -d -m i386 your_shellcode.o - 汇编时记得指定32位模式,比如用
as -32 -o shellcode.o shellcode.s,避免64位模式下的指令差异。
内容的提问来源于stack exchange,提问作者sherrellbc
相关产品推荐
相关产品推荐

