当调试器可以手动写入同一内存时,为什么在尝试执行写入内存的指令时会出现分段错误?
Why do I get a segmentation fault when attempting to execute an instruction writing to memory when the debugger can manually write to the same memory?
这是针对 x86-64 的,是一些堆栈溢出漏洞利用的一部分。
gdb 输出:
=> 0x000055555555e996: 48 89 18 mov QWORD PTR [rax],rbx
将rbx移动到rax存放的内存地址,简单。由于它在这条指令处出现段错误,让我们看一下。
rax 是什么?
(gdb) i r rax
rax 0x7ffff79f4c80 140737347800192
这段记忆有效吗?
(gdb) x/16b $rax
0x7ffff79f4c80 <_itoa_upper_digits>: 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37
0x7ffff79f4c88 <_itoa_upper_digits+8>: 0x38 0x39 0x41 0x42 0x43 0x44 0x45 0x46
好吧,至少我能读书。我可以写吗?
(gdb) set $rbx = 0x4141414141414141
(gdb) set {unsigned long} $rax = $rbx
(gdb) x/16b $rax
0x7ffff79f4c80 <_itoa_upper_digits>: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffff79f4c88 <_itoa_upper_digits+8>: 0x38 0x39 0x41 0x42 0x43 0x44 0x45 0x46
似乎工作正常,并且此设置操作确实似乎确实写入了内存,尝试对已知的无效地址执行相同操作将导致错误。所以看来我可以写入和读取这个内存。
那我们试试执行这条指令吧。还是一样的:
(gdb) x/i $pc
=> 0x55555555e996: mov QWORD PTR [rax],rbx
(gdb) si
Program received signal SIGSEGV, Segmentation fault.
(a=<error reading variable: Cannot access memory at address 0x376141366141355d>)
at test.c:371
371 asm volatile("mov %rbx,(%rax);"
=> 0x000055555555e996: 48 89 18 mov QWORD PTR [rax],rbx
0x000055555555e999: c3 ret
为什么我刚刚验证我可以在那里写就失败了?
Why does it fail when I've just verified I can write there?
程序不能写在那里,只有GDB可以。
您尝试写入的地址位于 .text
部分,该部分通常 mmap
带有 PROT_READ|PROT_EXEC
并且 没有 PROT_WRITE
.
但是,允许 GDB(或正在 ptrace
ing 的任何进程)写入此类映射。这是 GDB 能够插入断点所必需的(这通常需要重新编写程序指令)。
这是针对 x86-64 的,是一些堆栈溢出漏洞利用的一部分。
gdb 输出:
=> 0x000055555555e996: 48 89 18 mov QWORD PTR [rax],rbx
将rbx移动到rax存放的内存地址,简单。由于它在这条指令处出现段错误,让我们看一下。
rax 是什么?
(gdb) i r rax
rax 0x7ffff79f4c80 140737347800192
这段记忆有效吗?
(gdb) x/16b $rax
0x7ffff79f4c80 <_itoa_upper_digits>: 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37
0x7ffff79f4c88 <_itoa_upper_digits+8>: 0x38 0x39 0x41 0x42 0x43 0x44 0x45 0x46
好吧,至少我能读书。我可以写吗?
(gdb) set $rbx = 0x4141414141414141
(gdb) set {unsigned long} $rax = $rbx
(gdb) x/16b $rax
0x7ffff79f4c80 <_itoa_upper_digits>: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x7ffff79f4c88 <_itoa_upper_digits+8>: 0x38 0x39 0x41 0x42 0x43 0x44 0x45 0x46
似乎工作正常,并且此设置操作确实似乎确实写入了内存,尝试对已知的无效地址执行相同操作将导致错误。所以看来我可以写入和读取这个内存。
那我们试试执行这条指令吧。还是一样的:
(gdb) x/i $pc
=> 0x55555555e996: mov QWORD PTR [rax],rbx
(gdb) si
Program received signal SIGSEGV, Segmentation fault.
(a=<error reading variable: Cannot access memory at address 0x376141366141355d>)
at test.c:371
371 asm volatile("mov %rbx,(%rax);"
=> 0x000055555555e996: 48 89 18 mov QWORD PTR [rax],rbx
0x000055555555e999: c3 ret
为什么我刚刚验证我可以在那里写就失败了?
Why does it fail when I've just verified I can write there?
程序不能写在那里,只有GDB可以。
您尝试写入的地址位于 .text
部分,该部分通常 mmap
带有 PROT_READ|PROT_EXEC
并且 没有 PROT_WRITE
.
但是,允许 GDB(或正在 ptrace
ing 的任何进程)写入此类映射。这是 GDB 能够插入断点所必需的(这通常需要重新编写程序指令)。