*我使用的是 Ubuntu x86_64 系统,gcc 11.4.0
我在文件 test.c 中有这个 C 程序:
int fx( int a, int* b ){
*b = 12;
return a;
}
int main(){
int a = 20;
int b = fx(10,&a);
b+= 5;
}
我用“gcc test.c -o test”编译这个文件。然后我用“objdump -dw -M suffix test”检查它,我得到:
0000000000001149 <fx>:
1149: f3 0f 1e fa endbr64
114d: 55 pushq %rbp
114e: 48 89 e5 movq %rsp,%rbp
1151: 89 7d fc movl %edi,-0x4(%rbp)
1154: 48 89 75 f0 movq %rsi,-0x10(%rbp)
1158: 48 8b 45 f0 movq -0x10(%rbp),%rax
115c: c7 00 0c 00 00 00 movl $0xc,(%rax)
1162: 8b 45 fc movl -0x4(%rbp),%eax
1165: 5d popq %rbp
1166: c3 retq
0000000000001167 <main>:
1167: f3 0f 1e fa endbr64
116b: 55 pushq %rbp
116c: 48 89 e5 movq %rsp,%rbp
116f: 48 83 ec 10 subq $0x10,%rsp
1173: 64 48 8b 04 25 28 00 00 00 movq %fs:0x28,%rax
117c: 48 89 45 f8 movq %rax,-0x8(%rbp)
1180: 31 c0 xorl %eax,%eax
1182: c7 45 f0 14 00 00 00 movl $0x14,-0x10(%rbp)
1189: 48 8d 45 f0 leaq -0x10(%rbp),%rax
118d: 48 89 c6 movq %rax,%rsi
1190: bf 0a 00 00 00 movl $0xa,%edi
1195: e8 af ff ff ff callq 1149 <fx>
119a: 89 45 f4 movl %eax,-0xc(%rbp)
119d: 83 45 f4 05 addl $0x5,-0xc(%rbp)
11a1: b8 00 00 00 00 movl $0x0,%eax
11a6: 48 8b 55 f8 movq -0x8(%rbp),%rdx
11aa: 64 48 2b 14 25 28 00 00 00 subq %fs:0x28,%rdx
11b3: 74 05 je 11ba <main+0x53>
11b5: e8 96 fe ff ff callq 1050 <__stack_chk_fail@plt>
11ba: c9 leaveq
11bb: c3 retq
看起来编译器默认使用堆栈保护器,您可以通过查看主要指令来判断。
我的问题:
用“gcc test.c -fno-stack-protector -o test”编译我的C程序可以吗?
-fno-stack-protector 只是一个安全选项,使我们容易受到某些堆栈攻击,还是我们在编译时使用此选项时应该小心,因为它可能会破坏某些内容或产生某种错误/不兼容?
为什么我的 gcc 编译器默认没有打开它,而在其他系统(macOS x86_64 clang)中我注意到它是打开的?
在哪些情况下使用它是有意义的,而在哪些情况下我们绝对应该避免使用它?
用“gcc test.c -fno-stack-protector -o test”编译我的C程序可以吗?
我认为这样做没有任何问题。为了约定,最好将选项放在操作数之前,如下所示:
gcc -fno-stack-protector -o test test.c
-fno-stack-protector 只是一个安全选项,使我们容易受到某些堆栈攻击,还是我们在编译时使用此选项时应该小心,因为它可能会破坏某些内容或产生某种错误/不兼容?
选项
-fstack-protector=...
可以针对堆栈粉碎攻击进行额外的强化。如果您使用 -fno-stack-protector
禁用它,您的代码将不会从这种强化中受益,并且如果它已经存在可利用的缺陷,则可能更容易被利用。您可以根据需要混合和匹配使用或不使用堆栈保护器编译的目标文件,使用堆栈保护器不会导致不兼容。但是,只有在使用堆栈保护器编译的翻译单元中定义的函数才能从这种强化中受益。
为什么我的 gcc 编译器默认没有打开它,而在其他系统(macOS x86_64 clang)中我注意到它是打开的?
Canonical 决定默认启用此选项,以使针对堆栈崩溃的强化成为“选择退出”,而不是像 macOS 上那样“选择加入”。这提高了整体安全性。
在哪些情况下使用它是有意义的,而在哪些情况下我们绝对应该避免使用它?
打开堆栈保护器进行编译通常很有用,特别是如果您的代码使用不受信任的输入或来自网络或外部存储介质的输入运行。然而,有一个较小的性能成本。如果这很重要,您可能需要关闭堆栈保护器。请注意,如果您的应用程序存在此类缺陷,则可能更容易受到堆栈粉碎攻击的利用。