我获得了一个 ELF 核心转储,它是由对专有服务器进行模糊测试引起的。由于我无法再访问托管此服务器的机器,并且该服务器是一组紧密耦合的二进制文件的一部分,很难模拟,因此我不能太依赖于在更好的条件下动态重现崩溃。
对于每个线程,核心转储没有太多调试信息,主要是有关崩溃时寄存器状态的基本信息:
Displaying notes found at file offset 0x000034a0 with length 0x000045b8:
Owner Data size Description
CORE 0x00000150 NT_PRSTATUS (prstatus structure)
CORE 0x00000088 NT_PRPSINFO (prpsinfo structure)
CORE 0x00000130 NT_AUXV (auxiliary vector)
CORE 0x00000200 NT_FPREGSET (floating point registers)
CORE 0x00000150 NT_PRSTATUS (prstatus structure)
CORE 0x00000200 NT_FPREGSET (floating point registers)
CORE 0x00000150 NT_PRSTATUS (prstatus structure)
(...)
CORE 0x00000150 NT_PRSTATUS (prstatus structure)
CORE 0x00000200 NT_FPREGSET (floating point registers)
当我将核心转储加载到 gdb 中时,我只能看到每个线程的回溯,大多数都不有趣,因为它们只包含位于我无法获取的共享对象内存中的地址的提及:
(gdb) thread 3
[Switching to thread 3 (LWP 9593)]
#0 0x00007fa5eb282489 in ?? ()
(gdb) bt
#0 0x00007fa5eb282489 in ?? ()
#1 0x0000000000000000 in ?? ()
(gdb) x/i 0x00007fa225bce99d
=> 0x7fa5eb282489: Cannot access memory at address 0x7fa5eb282489
然而,其中一个线程稍微有趣一些,因为它包含一个包含在二进制文件中的地址。然而,这个地址被证明位于信号处理程序的中间,而不是最新调用的函数,因为在崩溃时二进制文件已经在库中再次跳转。
回溯的其余部分看起来并不有趣 - 除了一些看起来像是从初始化内存中提取的地址(0x3030303000000009 - 0x30 是 ASCII“0”,这是在某处记录的原因吗?)。
(gdb) thread 1
[Switching to thread 1 (LWP 9593)]
#0 0x00007fa324ee2617 in ?? ()
(gdb) bt
#0 0x00007fa324ee2617 in ?? ()
#1 0x000000000073c0a9 in sigrecv ()
#2 0x3030303000000009 in ?? ()
#3 0x0000246830303030 in ?? ()
#4 0x0000000000000000 in ?? ()
(gdb) frame 1
#1 0x000000000073c0a9 in sigrecv ()
(gdb) info frame
Stack level 1, frame at 0x7fa1cf1d3828:
rip = 0x73c0a9 in sigrecv; saved rip = 0x3030303000000009
called by frame at 0x7fa1cf1d3830, caller of frame at 0x7fa1cf1d3820
Arglist at 0x7fa1cf1d3818, args:
Locals at 0x7fa1cf1d3818, Previous frame's sp is 0x7fa1cf1d3828
Saved registers:
rip at 0x7fa1cf1d3820
当使用 IDA 跳转到信号处理程序的轮廓点时,我调用看到它是一个大函数的一部分,并且位于调用kill(gettid(), SIGQUIT). 核心转储的元数据确实表示 SIGQUIT,尽管我猜这个 SIGQUIT 是在实际崩溃后触发的,然后才是 SIGSEGV。
我想过编写一个脚本来扫描核心转储以查找 siginfo_t 或 ucontext_t 的存在,但我认为如果不是不可能的话,这可能会很痛苦,因为这些结构似乎没有非常独特的标记。
那么,我该怎么做才能进一步排除崩溃的根源?