linux - 当调试器可以手动写入同一内存时,为什么在尝试执行写入内存的指令时会出现分段错误?
问题描述
这是针对 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
为什么当我刚刚验证我可以在那里写信时它会失败?
解决方案
为什么当我刚刚验证我可以在那里写信时它会失败?
程序不能在那里写,只有GDB可以。
您尝试写入的地址位于该.text
部分中,该部分通常mmap
带有PROT_READ|PROT_EXEC
和不 PROT_WRITE
带有.
但是,允许 GDB(或任何正在ptrace
处理这个的进程)写入此类映射。这是 GDB 能够插入断点所必需的(这通常需要重写程序指令)。
推荐阅读
- c# - 将文件上传到 FTP C# - StatusCode 150
- python - 如何使用 python 将包含大量数据的字典写入 csv 文件?
- amazon-web-services - AWS Lambda 使用在其他注册商处注册的域
- c++ - 由.app执行时QFile不起作用 - Macosx
- typescript - 使用必需和部分类型
- assembly - MIPS 如何计算大于 1.111 x2^1023 的数字?
- reactjs - Office UI Fabric TextField 焦点/光标问题
- oracle - SQL 块中的语句引发完整性约束,但不是作为单个语句
- dax - 如何在 DAX 中添加度量?
- persian - 将 processmaker cartable 中的日期更改为波斯语 (jalali) 日期视图