为何在GDB中通过Python API调用memset的两种方式无效?
GDB中memset调用失效问题排查
我在GDB会话中尝试对指定地址的数据执行memset操作:先分配内存并将其设为-1(二进制全1),试图用0覆盖该内存。
初始操作步骤及结果
(gdb) set $i = (int*)malloc(sizeof(int)) (gdb) set *$i = -1 (gdb) x/t $i 0x76d8550: 11111111111111111111111111111111
两种无效的memset调用方式
1. 通过GDB Python API调用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
2. 调用ctypes的memset
操作代码及结果:
>>> 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
问题
为何前两种调用memset的方式无法生效?
原因分析
1. GDB Python API直接调用函数指针的问题
当你把memset转为gdb.Value的函数指针并在Python中调用时,这个调用是在GDB的进程空间里执行的,而非被调试的目标进程空间。你传入的地址0x76d8550是目标进程的内存地址,但GDB自身的进程里这个地址要么无效,要么指向完全无关的内存,所以memset操作根本没碰目标进程的内存,自然看不到变化。
GDB的Python API里直接调用函数指针,本质是让GDB自身去执行这个函数,而不是让被调试程序执行。
2. ctypes.memset的问题
ctypes是Python标准库,它调用的memset是Python进程(也就是GDB进程,因为你是在GDB的pi命令里运行Python)的libc中的memset,同样是在GDB进程空间内操作。你传入的目标进程地址0x76d8550对GDB进程来说没有意义,操作的不是目标进程的内存,所以目标进程里的数据不会被修改。
3. 为什么gdb.parse_and_eval有效?
gdb.parse_and_eval会把表达式发送给GDB的表达式解析器,GDB会在被调试的目标进程上下文里执行这个memset调用——相当于让被调试程序暂停时执行了memset,直接操作目标进程的内存空间,所以能成功修改数据。
内容的提问来源于stack exchange,提问作者cheater
相关产品推荐
相关产品推荐

