移除Shellcode空字节:mov rsi指令空字节清除难题求助
解决Shellcode中mov rsi指令空字节问题的干净方案
我完全懂你遇到的这个头疼问题——写无空字节的绑定Shellcode时,mov rsi, 0/1/2这类指令会因为x86_64的mov r64, imm32编码规则带进来空字节(指令会被编码成48 c7 c6 xx 00 00 00,后面三个00就是搞破坏的空字节),常规替换要么失效,要么得用一堆繁琐的变通手段。下面给你两种干净、可靠的解决思路:
方案1:循环递推(最简洁高效)
利用寄存器清零+自增的方式,一次性完成三次dup2调用,全程无空字节,代码还特别紧凑:
; 假设你的socket文件描述符已经存在于rbx寄存器中 xor rsi, rsi ; 安全清零rsi,无空字节,此时rsi=0(对应stdin) dup2_loop: mov rdi, rbx ; 将socket fd传入rdi(dup2的第一个参数) mov rax, 0x21 ; x86_64 Linux下dup2的系统调用号 syscall inc rsi ; rsi自增,依次变为1(stdout)、2(stderr) cmp rsi, 0x3 ; 判断是否完成三次调用(0、1、2) jne dup2_loop ; 未完成则继续循环
这个方案的核心是:用xor rsi, rsi无空字节清零,再通过inc rsi递推目标值,完全避开了直接写入立即数的操作,自然不会产生空字节。同时循环结构还减少了代码冗余。
方案2:直接寄存器递推(逻辑更直观)
如果你不想用循环,也可以用逐次递推的方式,同样不会引入空字节:
; 同样假设socket fd存储在rbx中 ; 处理stdin(rsi=0) xor rsi, rsi mov rdi, rbx mov rax, 0x21 syscall ; 处理stdout(rsi=1) inc rsi mov rdi, rbx mov rax, 0x21 syscall ; 处理stderr(rsi=2) inc rsi mov rdi, rbx mov rax, 0x21 syscall
这种方式虽然代码稍长一点,但逻辑直接明了,适合对循环结构有顾虑的场景。
为什么你的常规方法会失效?
你之前尝试的常规方法大概率是把mov rsi, imm换成mov sil, imm(只修改rsi的低8位),但这样会导致rsi的高56位保留垃圾值——Linux的dup2系统调用会把rsi当作完整的64位整数处理,高56位的垃圾值可能被识别为无效文件描述符,最终导致调用失败。而上面的两种方案都会保证整个rsi寄存器是干净的目标值(0、1、2),同时彻底避开空字节问题。
内容的提问来源于stack exchange,提问作者Wealot
相关产品推荐
相关产品推荐

