繁体   English   中英

为什么初始化 C 本地字符 arrays 在内部将字符串存储在不同的堆栈/数据段中?

[英]Why does initializing C local character arrays internally store the strings in different stack/data segments?

在处理一些与位置无关的C 注入 shellcode 时,字符串最初是使用此数组初始化编码的

char winexec[] = "WinExec";

然而,这导致 shellcode 失败,因为字符串WinExec存储在注入器的数据段中,但被注入者无权访问该数据。

要修复,数组初始化更改为

char winexec[] = { 'W','i','n','E','x','e','c','\0' };

这非常有效,因为该字符串存储在注入者本地堆栈段中。

例如https://godbolt.org/z/v8cqn5E56

#include <stdio.h>

int main()
{
    /* String stored in the stack segment */
    char winexecStack[] = { 'W','i','n','E','x','e','c','\0' };

    /* String stored in the data segment */
    char winexecData[] = "WinExec";
    
    printf("Stack Segment: %s\n", winexecStack);
    printf("Data Segment:  %s\n", winexecData);     
    
    return 0;
}

问题

为什么 C 有多种方式初始化本地 arrays 外部看起来一样,但内部字符串存储却大不相同?

是否存在更整洁的方法来初始化堆栈上的 C 字符数组? 也许像

char winexecStack[8];
winexecStack[0] = 'W';
winexecStack[1] = 'i';
winexecStack[2] = 'n';
winexecStack[3] = 'E';
winexecStack[4] = 'x';
winexecStack[5] = 'e';
winexecStack[6] = 'c';
winexecStack[7] = '\0';

或转换字符串,例如Hello, World! 数组中的小端值

unsigned long long hello[] = { 0x57202C6F6C6C6548,0x00000021646C726F };
printf("Stack Segment: %s\n", (char*)&hello);

也许对于 <= 8 字节的字符串,它们可以表示为数值,存储在堆栈中但被视为 char* 例如“WinExec”

unsigned long long winexec = 0x00636578456e6957;
printf("Stack Segment: %s\n", (char*)&winexec);

为什么 C 有多种方式初始化本地 arrays 外部看起来一样,但内部字符串存储却大不相同?

它没有。 您观察到初始化程序的源数据在这两种情况下以不同方式存储是您的 C 实现的 function。 C 语言本身不需要它。 更一般地说,C 关于存储的内容有很多说法,但关于如何存储的说法较少,而关于存储位置的说法几乎没有。

是否存在更整洁的方法来初始化堆栈上的 C 字符数组?

有效的字符数组初始值设定项采用您显示的两个 forms 之一。

另请注意,“在堆栈上”不是 C概念(请参阅“几乎无话可说”)。

使用/O2打开优化会使差异消失。 这表明,在没有优化的情况下,编译器会按字面意义实现 C,将由字符串文字引起的数组放入数据段(用于 static 存储),同时将单个字符初始值设定项视为小常量。 启用优化后,编译器会执行更深入的语义分析并优化生成的代码,实际上问题中提出的常量 0x00636578456e6957 会出现在生成的程序集中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM