为时已晚,但我仍然提供我的答案。
所以让我们来区分一下
main()
{
char *a="blabla";
a[3]='x';
}
还有这个,你的。
main()
{
char a[7] = "blabla"
a[3]='x';
}
所以他们之间有很大的不同。
在第一种情况下,对象a 是一个指针,其值指向blabla 字符串的开头。
转储汇编代码,我们看到:
4004aa: 48 c7 45 f8 54 05 40 movq $0x400554,-0x8(%rbp)
4004b1: 00
4004b2: 48 8b 45 f8 mov -0x8(%rbp),%rax
4004b6: 48 83 c0 03 add $0x3,%rax
4004ba: c6 00 78 movb $0x78,(%rax)
因此,它尝试将指针设置为指向地址0x400554。
Objdumpo 报告此地址在 .rodata 段中。
段.rodata的反汇编:
0000000000400550 <_IO_stdin_used>:
400550: 01 00 add %eax,(%rax)
400552: 02 00 add (%rax),%al
400554: 62 (bad)
400555: 6c insb (%dx),%es:(%rdi)
400556: 61 (bad)
400557: 62 .byte 0x62
400558: 6c insb (%dx),%es:(%rdi)
400559: 61 (bad)
因此,编译器在该地址的 .rodata 中安装了字符串 blabla,然后尝试修改 .rodata 段,以分段错误结束。
readelf 报告在 .rodata 上没有 W 访问权限:
[13] .rodata PROGBITS 0000000000400550 00000550
000000000000000b 0000000000000000 A 0 0 4
另一方面,您尝试执行的操作(第二个程序)被编译为:
00000000004004a6 <main>:
4004a6: 55 push %rbp
4004a7: 48 89 e5 mov %rsp,%rbp
4004aa: c7 45 f0 62 6c 61 62 movl $0x62616c62,-0x10(%rbp)
4004b1: 66 c7 45 f4 6c 61 movw $0x616c,-0xc(%rbp)
4004b7: c6 45 f6 00 movb $0x0,-0xa(%rbp)
4004bb: c6 45 f3 78 movb $0x78,-0xd(%rbp)
在这种情况下,数组对象a在堆栈帧上分配了7个字节,从偏移量%RBP-0xA开始直到%RBP-0x10。
当它尝试执行 a[3]='x' 时,它将修改位于 %RBP-0xD 的堆栈。栈有write权限,一切正常。
更多信息我建议你阅读https://en.wikipedia.org/wiki/Identity_and_change