我正在尝试将数据memset到gdb会话中的某个地址。
假设它最初填充有 1,我试图用 0 覆盖它。
(gdb) set $i = (int*)malloc(sizeof(int))
(gdb) set *$i = -1
(gdb) x/t $i
0x76d8550: 11111111111111111111111111111111
当我:
时,数据根本没有被修改从 memset 函数指针中创建一个 gdb.Value 并使用正确的地址在 Python 中调用它;
运行 ctypes 的 memset(),向其传递正确的地址。
(gdb) pi memset = gdb.parse_and_eval("(void*(*)(void*,int,size_t))memset").dereference()
(gdb) pi str(memset)
'{void *(void *, int, size_t)} 0x7fffe992e760 <memset>'
(gdb) pi
>>> i = 0x76d8550
>>> memset(i,0,4)
<gdb.Value object at 0x7fdc5c0fbef0>
>>> gdb.execute("x/t $i")
0x76d8550: 11111111111111111111111111111111
>>> import ctypes
>>> ctypes.memset(i,0,4)
124618064
>>> gdb.execute("x/t $i")
0x76d8550: 11111111111111111111111111111111
数据按预期修改,当我:
>>> gdb.parse_and_eval("(void*)memset({},0,4)".format(i))
<gdb.Value object at 0x7fdb9eef58b0>
>>> gdb.execute("x/t $i")
0x76d8550: 00000000000000000000000000000000
关于为什么第一个两个选项不起作用的任何解释?
谢谢
根据打印的地址判断,您可能在Linux/x86_64上运行,并且可能使用GLIBC作为标准
C
库。如果是这样的话...
...
memset
很复杂。
首先,
memset
有两种单独的实现——最小的实现在ld-linux.so
中,而全功能的实现在libc.so.6
中。
其次,
libc.so.6
中的完整实现是一个GNU IFUNC,这意味着它本身不写入内存,它只是返回应该在给定的情况下写入内存的函数的地址处理器。
最后,正如 sbssa 评论的那样,ctype.memset()
不可能工作,因为那是 GDB 本身内的
memset
,而不是下级(正在调试)进程中的 memset
。通过调用 ctypes.memset(i,0,4)
,您正在破坏 GDB 中的随机位置。这可能会导致任何结果,从“无效”(如果损坏的地址未使用但有效)到表达式立即崩溃(要损坏的地址无效)到稍后 GDB 中的随机崩溃(如果损坏的地址实际上是用来做某事的)。
将所有这些放在一起:#include <string.h>
int jj = -1;
int main()
{
memset(&jj, 0, sizeof(jj)); return 0;
return 0;
}
使用
gcc -g x.c
编译,并在 Fedora 38 上的 GDB 下运行
x86_64
:gdb -q ./a.out
Reading symbols from ./a.out...
(gdb) start
Temporary breakpoint 1 at 0x40112a: file x.c, line 6.
Starting program: /tmp/a.out
Temporary breakpoint 1, main () at x.c:6
6 memset(&jj, 0, sizeof(jj)); return 0;
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.37-10.fc38.x86_64
(gdb) p &memset
$1 = (void (*)(void)) 0x7ffff7fec530 <memset>
(gdb) pi memset = gdb.parse_and_eval("(void*(*)(void*,int,size_t))memset").dereference()
(gdb) pi print(str(memset))
{void *(void *, int, size_t)} 0x7ffff7fec530 <memset>
(gdb) info sym 0x7ffff7fec530
memset in section .text of /lib64/ld-linux-x86-64.so.2
在这里你可以看到 GDB 得到了错误
memset
(最小实现)。它仍然可以工作,但不是最理想的,并且可能有其他限制——它从来没有打算在
ld-linux
本身之外使用。例如,可以假设缓冲区是 8 字节对齐的,或者大小至少为 8 字节等。那memset
中调用的real
main
呢?(gdb) b memset
Breakpoint 2 at 0x7ffff7e7cf60 (2 locations)
(gdb) c
Continuing.
Breakpoint 2.1, 0x00007ffff7e7cf60 in memset_ifunc () from /lib64/libc.so.6
(gdb) bt
#0 0x00007ffff7e7cf60 in memset_ifunc () from /lib64/libc.so.6
#1 0x00007ffff7fdac42 in elf_ifunc_invoke (addr=<optimized out>) at ../sysdeps/x86_64/dl-irel.h:32
#2 _dl_fixup (l=0x7ffff7ffe2d0, reloc_arg=<optimized out>) at dl-runtime.c:125
#3 0x00007ffff7fdcf3e in _dl_runtime_resolve_xsavec () at ../sysdeps/x86_64/dl-trampoline.h:130
#4 0x000000000040113e in main () at x.c:6
请注意,这是我所说的 IFUNC`。
(gdb) fin
Run till exit from #0 0x00007ffff7e7cf60 in memset_ifunc () from /lib64/libc.so.6
0x00007ffff7fdac42 in _dl_fixup (l=0x7ffff7ffe2d0, reloc_arg=<optimized out>) at dl-runtime.c:125
125 dl-runtime.c: No such file or directory.
(gdb) p/x $rax
$2 = 0x7ffff7f37950
(gdb) info sym 0x7ffff7f37950
__memset_avx2_unaligned in section .text of /lib64/libc.so.6
__memset_avx2_unaligned
是
实际
memset
实现。请注意,即使我们已经从“memset”返回,jj
的值仍然是
-1
:(gdb) x/t &jj
0x40400c <jj>: 11111111111111111111111111111111
(gdb) watch -l jj
Hardware watchpoint 3: -location jj
(gdb) c
Continuing.
Hardware watchpoint 3: -location jj
Old value = -1
New value = 0
0x00007ffff7f37ae4 in __memset_avx2_unaligned_erms () from /lib64/libc.so.6
附注为什么值改变的是
__memset_avx2_unaligned_erms()
而不是
__memset_avx2_unaligned()
?因为后者对后者使用了“尾调用”:
(gdb) disas __memset_avx2_unaligned
Dump of assembler code for function __memset_avx2_unaligned:
0x00007ffff7f37950 <+0>: endbr64
0x00007ffff7f37954 <+4>: vmovd %esi,%xmm0
0x00007ffff7f37958 <+8>: mov %rdi,%rax
0x00007ffff7f3795b <+11>: cmp $0x20,%rdx
0x00007ffff7f3795f <+15>: jb 0x7ffff7f37aa0 <__memset_avx2_unaligned_erms+224>
0x00007ffff7f37965 <+21>: vpbroadcastb %xmm0,%ymm0
0x00007ffff7f3796a <+26>: cmp $0x40,%rdx
0x00007ffff7f3796e <+30>: ja 0x7ffff7f37a09 <__memset_avx2_unaligned_erms+73>
0x00007ffff7f37974 <+36>: vmovdqu %ymm0,-0x20(%rdi,%rdx,1)
0x00007ffff7f3797a <+42>: vmovdqu %ymm0,(%rdi)
0x00007ffff7f3797e <+46>: vzeroupper
0x00007ffff7f37981 <+49>: ret