您可以使用 python 代码来定位核心文件中的各种内容。structer包包含一个模块,其类为此提供方法。会话的以下输出包含如何使用该代码的示例。elf
Elf
gdb
该会话的第一个摘录显示gdb
打开由 生成的核心文件gcore
,并为后续搜索提供一些数据。
18:33:00 $ gdb -q /home/efuller/gnu/bin/gdb core.17856
Reading symbols from /home/efuller/gnu/bin/gdb...done.
[New LWP 17856]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `/home/efuller/gnu/bin/gdb /home/efuller/gnu/bin/gdb'.
Program terminated with signal SIGINT, Interrupt.
#0 0x00007ffff62c5660 in __poll_nocancel () at ../sysdeps/unix/syscall-template.S:84
84 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) backtrace
#0 0x00007ffff62c5660 in __poll_nocancel () at ../sysdeps/unix/syscall-template.S:84
#1 0x00005555557f7ea6 in gdb_wait_for_event (block=1) at event-loop.c:772
#2 0x00005555557f7185 in gdb_do_one_event () at event-loop.c:347
#3 0x00005555557f71bd in start_event_loop () at event-loop.c:371
#4 0x00005555557f003a in captured_command_loop (data=0x0) at main.c:324
#5 0x00005555557eb2e9 in catch_errors (func=0x5555557efff8 <captured_command_loop(void*)>, func_args=0x0, errstring=0x555555b4f733 "", mask=RETURN_MASK_ALL) at exceptions.c:236
#6 0x00005555557f16e2 in captured_main (data=0x7fffffffea10) at main.c:1149
#7 0x00005555557f170b in gdb_main (args=0x7fffffffea10) at main.c:1159
#8 0x00005555555f2daa in main (argc=2, argv=0x7fffffffeb18) at gdb.c:32
(gdb) frame 6
#6 0x00005555557f16e2 in captured_main (data=0x7fffffffea10) at main.c:1149
1149 catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL);
(gdb) info locals
context = 0x7fffffffea10
argc = 2
argv = 0x7fffffffeb18
quiet = 0
set_args = 0
inhibit_home_gdbinit = 0
symarg = 0x7fffffffed8e "/home/efuller/gnu/bin/gdb"
execarg = 0x7fffffffed8e "/home/efuller/gnu/bin/gdb"
pidarg = 0x0
corearg = 0x0
pid_or_core_arg = 0x0
cdarg = 0x0
ttyarg = 0x0
print_help = 0
print_version = 0
print_configuration = 0
cmdarg_vec = 0x0
cmdarg_p = 0x0
dirarg = 0x555555fdeb80
dirsize = 1
ndir = 0
system_gdbinit = 0x0
home_gdbinit = 0x555556174960 "/home/efuller/.gdbinit"
local_gdbinit = 0x0
i = 0
save_auto_load = 1
objfile = 0x0
pre_stat_chain = 0x555555b2c000 <sentinel_cleanup>
(gdb)
下一个摘录显示了gdb
导入 python 代码,并根据局部变量的值执行两次搜索。第一次搜索显示了该值出现的多个地址(symarg
和的值execarg
在其中)。该findbytes
方法需要一个bytes
对象,而不是一个str
对象。第二次搜索只显示一个地址,其中包含第一次搜索的第一个匹配的地址,该地址恰好在符号表中有一个名称。
(gdb) pi
>>> from structer import memmap, elf
>>> core = elf.Elf(memmap('core.17856'))
>>> from pprint import pprint
>>>
(gdb) python pprint(tuple(hex(a) for a in core.findbytes(b"/home/efuller/gnu/bin/gdb")))
('0x555555fdef30',
'0x55555606fce0',
'0x55555614ff72',
'0x5555562496a0',
'0x55555624b915',
'0x55555625f250',
'0x5555562c6c4b',
'0x55555689f2b5',
'0x7ffff5f2d490',
'0x7fffffffed74',
'0x7fffffffed8e',
'0x7fffffffedf0',
'0x7fffffffefde')
(gdb) python pprint(tuple(hex(a) for a in core.findwords(0x555555fdef30)))
('0x555555faea38',)
(gdb) x/a 0x555555faea38
0x555555faea38 <_ZL16gdb_program_name>: 0x555555fdef30
(gdb)
下一个摘录显示了搜索的其他变体。搜索dirname
第一个搜索模式会出现多个命中,其中包括来自第一次搜索的所有命中。随后的搜索通过需要一个空终止符来过滤掉常见的匹配项,之后的搜索过滤掉不以空终止符开头的匹配项。最后两次搜索报告了相同的结果,尽管地址相差一个,因为搜索需要在该前导空点处有前导空点。
(gdb) python pprint(tuple(hex(a) for a in core.findbytes(b"/home/efuller/gnu/bin")))
('0x555555b4f701',
'0x555555bd33f0',
'0x555555fdef30',
'0x55555606fce0',
'0x55555614ff72',
'0x5555562496a0',
'0x55555624b915',
'0x55555625f250',
'0x5555562c6c4b',
'0x55555689f2b5',
'0x7ffff5f2d490',
'0x7fffffffed74',
'0x7fffffffed8e',
'0x7fffffffedf0',
'0x7fffffffefde')
(gdb) python pprint(tuple(hex(a) for a in core.findbytes(b"/home/efuller/gnu/bin\x00")))
('0x555555b4f701', '0x555555bd33f0')
(gdb) python pprint(tuple(hex(a) for a in core.findbytes(b"\x00/home/efuller/gnu/bin\x00")))
('0x555555b4f700', '0x555555bd33ef')
(gdb)
最后的摘录将第一次搜索的命中分为两种情况,一种是具有前导空值的情况,一种是没有前导空值的情况。后者使用最通用的搜索类型(两者都findbytes
依赖的搜索findwords
),因此它可以包含搜索模式固定部分之前的非空字符。
(gdb) python pprint(tuple(hex(a) for a in core.findbytes(b"\x00/home/efuller/gnu/bin/gdb")))
('0x555555fdef2f',
'0x55555606fcdf',
'0x55555624969f',
'0x55555625f24f',
'0x7fffffffed73',
'0x7fffffffed8d',
'0x7fffffffefdd')
(gdb) python import re
(gdb) python pprint(tuple(hex(a) for a in core.find(re.compile(rb"\x00[^\x00]+/home/efuller/gnu/bin/gdb"))))
('0x55555614ff6f',
'0x55555624b8ff',
'0x5555562c6c37',
'0x55555689f297',
'0x7ffff5f2d487',
'0x7fffffffeded')
(gdb) x/s 0x55555614ff6f + 1
0x55555614ff70: "_=/home/efuller/gnu/bin/gdb"
(gdb)
最后+ 1
一个命令中的 跳过该搜索命中中的前导 null,尽管它也可以合并到搜索代码中,如下所示。
(gdb) python pprint(tuple(hex(a+1) for a in core.find(re.compile(rb"\x00[^\x00]+/home/efuller/gnu/bin/gdb"))))
('0x55555614ff70',
'0x55555624b900',
'0x5555562c6c38',
'0x55555689f298',
'0x7ffff5f2d488',
'0x7fffffffedee')
(gdb)
结构gdb
代码不需要; 它可以在 gdb 之外的 python 解释器中运行。它与 python2 不兼容,因此在其中运行它gdb
需要gdb
与 python3.5 链接的二进制文件。
在核心文件中搜索模式可以报告结构代码中的搜索方法未报告的结果。有两个原因。structer代码只搜索加载段,所以它不会找到注释段的内容,其中包含与内核中的虚拟地址不对应的各种东西。如果两个相邻段有间隙(段之间的未映射区域),则结构代码找不到跨越多个加载段的结果。该代码组合了在虚拟地址空间中连续的相邻段,因此搜索结果不必局限于单个段。