怎么用 gdb find 命令搜索内存 ?
本文,我们讲讲 GDB 命令 find
。
当调试程序时,你可能需要查找程序内存中的特定字节序列。或者,你想查找特定目标的所有地址。内存中每 8 个字节一个字节序列,表示你想确定的地址。
提醒一下,find
命令会返回所有匹配的地址;因此我们必须接受可能存在的错误结果。
没什么-我觉得。
find
命令提供了另一种审查程序的方式。
我们看看怎么用。
Hello, world!
首先,写个简单的程序,用作示例。
打开你喜欢的编辑器(例如,emacs 或 vi)并输入下面的代码。
#include <stdio.h>
int
main(void)
{
printf(“Hello, world!\n”);
printf(“That is all, goodbye.\n”);
Return 0;
}
保存文件名为 hello.c
编译。
$ gcc -g3 hello.c
加载。
$ gdb a.out
启动。
(gdb) start
就绪。
现在我们看看 GDB 的 find 命令。
find 命令
find 语法如下所示:
find [/SIZE-CHAR] [/MAX-COUNT] START-ADDRESS, END-ADDRESS, EXPR1 [, EXPR2, ...]
或者
find [/SIZE-CHAR] [/MAX-COUNT] START-ADDRESS, +LENGTH, EXPR1 [, EXPR2, ...]
你可以通过指定 EXPR1
、 EXRP2
… 搜索程序的内存空间。
搜索从 START-ADDRESS
开始的 +LENGTH
字节或到 END-ADDRESS
结束 。
下文中,我会讲如何获取程序的内存布局,来决定搜索的开始和结束地址。
[ /SIZE-CHAR]
和 [/MAX-COUNT]
是可选项。
[ /SIZE-CHAR]
指定每个搜索目标的大小。
b
字节
h
半字(2 字节)
w
字(4 字节)
g 双字(8 字节)
所有的搜索目标使用程序的编程语言去解释。例如,hello.c 的语言是 C/C++; 所以当我们查找 “Hello,world!” 时,它会包含字符串结束标志 ‘\0’。
如果不指定 [/SIZE-CHAR]
,这个值会从源程序语言中获取。当你想查找的序列是复杂类型时这个参数就派上用场了。
[/MAX-COUNT]
设置了最大返回值数量。默认打印所有结果。
你可以将字符串作为查找对象。确保用 “”
括住。字符串会逐字节的复制到查找模式中,不管目标的字节序和指定的大小。
返回值是每个匹配的地址和匹配到的数量。
查找内存
如果想查找程序的内存空间,你得知道进程的内存布局,用来决定起始地址,结束地址。
怎么告诉 GDB 查找范围呢?
可以像下面这样使用 info proc
命令获取进程的有用信息
(gdb) info proc mappings
此命令会显示进程的所有内存布局;我们的 hello.c 程序,可以访问的所有虚拟地址范围。
按理说,“Hello,world!” 字符一定在 0x555555554000
到 0x555555559000
这个范围内。但是,有一点很重要,0x555555559000
不是结束地址。它是没有被映射的第一个字节!在查找命令中使用这个地址会报错,因为它超出了内存映射的范围。我会在视频中展示。所以,需要后退一个字节,到 0x555555558fff
。
现在,输入下面的命令。
(gdb) find 0x555555554000 to 0x555555558fff, “Hello, world!”
示例的结果表明内存中有两个实例。
验证一下:
(gdb) print (char*) 0x555555556004
不出所料,真是 “Hello, world!”。
小提示
除了确保在映射内存范围内查找,还有其他需要注意的点。
如果要搜索字符串,你必须匹配完整的字符串,例如,我的视频中,忘记输入感叹号,就没返回结果,因为没命中了 \0
。
find
命令查找的是 hello,world\0
。
你可以用别的方法搜索,比如,字符序列。
(gdb) find 0x555555554000 to 0x555555558fff, ‘H’, ‘e’, ‘l’, ‘l’, ‘o’
注意用的是单引号 (')
。
到这里就结束了!
find help
命令提供了更多的查找选项和参数。花点时间去用用。我相信,你会觉得,在调试程序时,GDB 命令 find
提供了一种有用的审查方式。