c语言 - 即使设置了优化标志 (-O2),GCC 也无法启用D_FORTIFY_SOURCE



我最近读到了D_FORTIFY_SOURCE及其对易受攻击函数所做的更改。我希望把它弄得一团糟,因此做了一个小的二进制测试。

测试二进制文件的源代码是:

#include <stdio.h>
#include <stdlib.h>
//No ASLR/PIE
//Enable FORTIFY
//
//
//
void shell()
{
system("sh");
}

int flag = 0;

int main(int argc, char * argv[])
{
char buf [256];
fgets(buf, sizeof(buf), stdin);
printf(buf);
if(flag)
{
shell();
}
}

这并不是为了做任何事情,只是为了尝试对printf的保护。

然而,当我编译这个程序时,它似乎并没有"强化">

确切的gcc命令是:

gcc fsFORTIFIED.c -o fsFORTIFIED -m32 -no-pie -D_FORITFY_SOURCE=2 -O2

我确保设置了优化标志,但保留了标准的printf函数。GDB给出了主组件:

0x080491c6 <+0>: lea    ecx,[esp+0x4]
0x080491ca <+4>: and    esp,0xfffffff0
0x080491cd <+7>: push   DWORD PTR [ecx-0x4]
0x080491d0 <+10>:    push   ebp
0x080491d1 <+11>:    mov    ebp,esp
0x080491d3 <+13>:    push   esi
0x080491d4 <+14>:    push   ebx
0x080491d5 <+15>:    push   ecx
0x080491d6 <+16>:    sub    esp,0x120
0x080491dc <+22>:    call   0x80490e0 <__x86.get_pc_thunk.bx>
0x080491e1 <+27>:    add    ebx,0x2e1f
0x080491e7 <+33>:    mov    eax,gs:0x14
0x080491ed <+39>:    mov    DWORD PTR [ebp-0x1c],eax
0x080491f0 <+42>:    xor    eax,eax
0x080491f2 <+44>:    mov    eax,DWORD PTR [ebx-0x8]
0x080491f8 <+50>:    push   DWORD PTR [eax]
0x080491fa <+52>:    push   0x100
0x080491ff <+57>:    lea    esi,[ebp-0x11c]
0x08049205 <+63>:    push   esi
0x08049206 <+64>:    call   0x8049050 <fgets@plt>
0x0804920b <+69>:    mov    DWORD PTR [esp],esi
0x0804920e <+72>:    call   0x8049040 <printf@plt>
0x08049213 <+77>:    add    esp,0x10
0x08049216 <+80>:    cmp    DWORD PTR [ebx+0x2c],0x0
0x0804921d <+87>:    jne    0x804923b <main+117>
0x0804921f <+89>:    mov    eax,DWORD PTR [ebp-0x1c]
0x08049222 <+92>:    sub    eax,DWORD PTR gs:0x14
0x08049229 <+99>:    jne    0x8049242 <main+124>
0x0804922b <+101>:   mov    eax,0x0
0x08049230 <+106>:   lea    esp,[ebp-0xc]
0x08049233 <+109>:   pop    ecx
0x08049234 <+110>:   pop    ebx
0x08049235 <+111>:   pop    esi
0x08049236 <+112>:   pop    ebp
0x08049237 <+113>:   lea    esp,[ecx-0x4]
0x0804923a <+116>:   ret    
0x0804923b <+117>:   call   0x80491a6 <shell>
0x08049240 <+122>:   jmp    0x804921f <main+89>
0x08049242 <+124>:   call   0x80492d0 <__stack_chk_fail_local>

在这里,我本来想打电话给printf_chk@plt,但事实上printf@plt.为了确保安全,我运行了程序,并给它输入%3$x,它运行得很好,而不是停止。

我的问题是,为什么GCC没有正确地实现D_FORITFY_SOURCE,即使在设置了优化标志之后?

感谢的帮助

确保-D_FORTIFY_SOURCE=2拼写正确
(在这种情况下,不是:-D_FORITFY_SOURCE=2是问题所在。(

与普通选项不同的是,GCC不能为您捕获拼写错误。

-Dfoo=bar只是定义了一个预处理器宏(GCC手册(,与文件顶部的#D_FORTIFY_SOURCE 2完全相同。(-D是所有编译器都接受的标准编译器选项,而不仅仅是GCC。(只有少数特殊的宏名称会影响stdio.h等标头。

对于-fstack-protector-strong-march=skylake-fno-math-errno等选项,GCC只接受其识别的有效选项。当然,-Dfoo=bar对任何foo都有效,它只是不起任何作用,因为它不是glibc标头在#ifdefs中使用的宏。

-D拼写正确;选项的其余部分正是正在定义的内容。


在ISO C中,以_1开头的全局作用域名称保留供实现使用,这就是为什么允许定义_FORTIFY_SOURCE是特殊的。但海湾合作委员会本身并不拒绝这样的名字。为了让GCC做到这一点,它必须知道glibc、MUSL和";C实现";碰巧使用,这会让处理这些头文件变得很痛苦。

脚注1:保留名称规则没有那么宽泛,我正在简化。

最新更新