我有一个可执行文件的核心转储,它不是用调试符号构建的.我可以恢复argv内容吗?

mis*_*bee 9 gdb coredump

我有一个可执行文件的核心转储,它不是用调试符号构建的.

我可以恢复argv内容以查看命令行是什么吗?

如果我运行gdb,我可以看到一个回溯,我可以导航到main()框架.在那里,有没有办法恢复argv,而不知道它的确切地址?

我在运行CEntOS Linux发行版/内核的x86_x64(Intel Xeon CPU)上,

我希望的一个原因是核心转储似乎显示部分argv.

(该程序是postgres,当我加载核心文件时,gdb打印一条消息,其中包含postgres db-user名称,客户端OP地址和查询的前10个字符))

Emp*_*ian 12

x86_64参数在传递%rdi,%rsi等寄存器(调用约定).

因此,当您进入main框架时,您应该能够:

(gdb) p $rdi           # == argc
(gdb) p (char**) $rsi  # == argv

(gdb) set $argv = (char**)$rsi
(gdb) set $i = 0
(gdb) while $argv[$i]
> print $argv[$i++]
> end
Run Code Online (Sandbox Code Playgroud)

不幸的是,GDB不会恢复正常$rdi,并$rsi当您切换帧.所以这个例子不起作用:

cat t.c

#include <stdlib.h>

int bar() { abort(); }
int foo() { return bar(); }
int main()
{
  foo();
  return 0;
}

gcc t.c && ./a.out
Aborted (core dumped)

gdb -q ./a.out core
Core was generated by `./a.out'.
Program terminated with signal 6, Aborted.
#0  0x00007fdc8284aa75 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
64  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
    in ../nptl/sysdeps/unix/sysv/linux/raise.c
(gdb) bt
#0  0x00007fdc8284aa75 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x00007fdc8284e5c0 in *__GI_abort () at abort.c:92
#2  0x000000000040052d in bar ()
#3  0x000000000040053b in foo ()
#4  0x000000000040054b in main ()
(gdb) fr 4
#4  0x000000000040054b in main ()
(gdb) p $rdi
$1 = 5524    ### clearly not the right value
Run Code Online (Sandbox Code Playgroud)

所以你必须再做一些......

可以做的是使用在进程启动时如何设置Linux堆栈的知识,以及GDB 恢复堆栈指针的事实:

(gdb) set backtrace past-main
(gdb) bt
#0  0x00007ffff7a8da75 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x00007ffff7a915c0 in *__GI_abort () at abort.c:92
#2  0x000000000040052d in bar ()
#3  0x000000000040053b in foo ()
#4  0x0000000000400556 in main ()
#5  0x00007ffff7a78c4d in __libc_start_main (main=<optimized out>, argc=<optimized out>, ubp_av=<optimized out>, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdad8) at libc-start.c:226
#6  0x0000000000400469 in _start ()

(gdb) frame 6
(gdb) disas
Dump of assembler code for function _start:
   0x0000000000400440 <+0>: xor    %ebp,%ebp
   0x0000000000400442 <+2>: mov    %rdx,%r9
   0x0000000000400445 <+5>: pop    %rsi
   0x0000000000400446 <+6>: mov    %rsp,%rdx
   0x0000000000400449 <+9>: and    $0xfffffffffffffff0,%rsp
   0x000000000040044d <+13>:    push   %rax
   0x000000000040044e <+14>:    push   %rsp
   0x000000000040044f <+15>:    mov    $0x400560,%r8
   0x0000000000400456 <+22>:    mov    $0x400570,%rcx
   0x000000000040045d <+29>:    mov    $0x40053d,%rdi
   0x0000000000400464 <+36>:    callq  0x400428 <__libc_start_main@plt>
=> 0x0000000000400469 <+41>:    hlt    
   0x000000000040046a <+42>:    nop
   0x000000000040046b <+43>:    nop
End of assembler dump.
Run Code Online (Sandbox Code Playgroud)

所以,现在我们希望原来%rsp$rsp+8(一个POP,二推),但它可能是在$rsp+16由于对准这是在做指示0x0000000000400449

让我们看看有什么......

(gdb) x/8gx $rsp+8
0x7fffbe5d5e98: 0x000000000000001c  0x0000000000000004
0x7fffbe5d5ea8: 0x00007fffbe5d6eb8  0x00007fffbe5d6ec0
0x7fffbe5d5eb8: 0x00007fffbe5d6ec4  0x00007fffbe5d6ec8
0x7fffbe5d5ec8: 0x0000000000000000  0x00007fffbe5d6ecf
Run Code Online (Sandbox Code Playgroud)

这看起来很有希望:4(疑似argc),然后是4个非NULL指针,后跟NULL.

让我们来看看是否平息:

(gdb) x/s 0x00007fffbe5d6eb8
0x7fffbe5d6eb8:  "./a.out"
(gdb) x/s 0x00007fffbe5d6ec0
0x7fffbe5d6ec0:  "foo"
(gdb) x/s 0x00007fffbe5d6ec4
0x7fffbe5d6ec4:  "bar"
(gdb) x/s 0x00007fffbe5d6ec8
0x7fffbe5d6ec8:  "bazzzz"
Run Code Online (Sandbox Code Playgroud)

实际上,这就是我调用二进制文件的方式.作为最后的理智检查,0x00007fffbe5d6ecf看起来像环境的一部分?

(gdb) x/s 0x00007fffbe5d6f3f
0x7fffbe5d6f3f:  "SSH_AGENT_PID=2874"
Run Code Online (Sandbox Code Playgroud)

是的,这是环境的开始(或结束).

所以你有它.

最后说明:如果GDB没有打印<optimized out>这么多,我们可以收回argc,并argv从帧#5.GDB和GCC方面都有工作要使GDB打印更少"优化"......

此外,在加载核心时,我的GDB打印:

Core was generated by `./a.out foo bar bazzzz'.
Run Code Online (Sandbox Code Playgroud)

否定了整个练习的必要性.但是,这仅适用于短命令行,而上述解决方案适用于任何命令行.