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

C语言局部字符数组初始化存储差异及栈初始化优化方法问询

关于PIC Shellcode中字符数组初始化的问题解答

1. 为何两种局部数组初始化方式的存储位置截然不同?

这本质是编译器对字符串字面量的处理逻辑差异,结合PIC(位置无关代码)的编译特性导致的:

  • 当使用char winexec[] = "WinExec";时,字符串字面量"WinExec"会被编译器存入程序的只读数据段(.rodata)。函数执行时,生成的代码会从这个全局数据段拷贝字节到栈上的数组。但在shellcode注入场景中,原进程的只读数据段地址在目标进程中完全无效,一旦代码尝试访问这个不存在的地址,就会执行失败。
  • 而char winexec[] = { 'W','i','n','E','x','e','c','\0' };的初始化方式,编译器会直接生成栈帧内的字节赋值指令,把每个字符逐个写入栈上的数组空间。整个字符串完全存储在当前函数的局部栈段中,不依赖任何全局数据段,因此注入到目标进程后能正常访问。

2. 有没有更简洁的栈上初始化C字符数组的方法?

针对PIC shellcode场景,推荐以下几种简洁方案:

  • 小端数值赋值法:将字符串转换为对应小端序的整数,直接通过指针赋值,代码最简洁且无全局依赖:
    #include <stdint.h>
    char winexec[8];
    *(uint64_t*)winexec = 0x636578654E6E6957; // 对应"WinExec"的小端字节序列
    
  • 复合字面量+memcpy:利用C的复合字面量特性,让编译器在栈上生成临时字符串,再拷贝到目标数组(需确保编译时启用PIC选项,避免字面量进入全局段):
    #include <string.h>
    char winexec[8];
    memcpy(winexec, (char[]){"WinExec"}, sizeof(winexec));
    
  • 编译期宏拆解字符串:自定义宏将字符串字面量拆解为字符列表,兼顾可读性和栈初始化特性:
    #define STR_STACK_INIT(s) { s[0], s[1], s[2], s[3], s[4], s[5], s[6], '\0' }
    char winexec[] = STR_STACK_INIT("WinExec");
    
  • 内联汇编栈构造:直接通过汇编指令将字符压栈(注意小端序),适合纯shellcode场景:
    char *winexec;
    __asm__ (
        "push 0x00636578\n"
        "push 0x654E6E69\n"
        "push 0x57\n"
        "mov %0, rsp\n"
        : "=r"(winexec)
        :
        : "rsp"
    );
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:50:30