memset() 在 GDB 中通过 Python API 调用时不起作用

问题描述 投票:0回答:1

我正在尝试将数据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() 使用完整的 memset() 表达式计算字符串。
>>> gdb.parse_and_eval("(void*)memset({},0,4)".format(i))

<gdb.Value object at 0x7fdb9eef58b0>

>>> gdb.execute("x/t $i")

0x76d8550:  00000000000000000000000000000000

关于为什么第一个两个选项不起作用的任何解释?

谢谢

gdb ctypes gdb-python
1个回答
0
投票

根据打印的地址判断,您可能在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

© www.soinside.com 2019 - 2024. All rights reserved.