gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 03:39:53 24 4
gpt4 key购买 nike

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

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

如果运行gdb,则可以看到回溯,并且可以导航到main()框架。一旦到达那里,是否有一种方法可以在不知道其确切地址的情况下恢复argv?

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

我满怀希望的原因之一是核心转储似乎显示了一部分argv。

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

最佳答案

x86_64上,参数在%rdi%rsi等寄存器(calling convention)中传递。

因此,当您进入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

不幸的是,当您切换帧时,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

因此,您将不得不多做一些工作...

您可以做的是在 process startup上使用有关如何建立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.

因此,现在我们期望原始的 %rsp$rsp+8(一个POP,两个PUSH),但是由于在 $rsp+16指令上进行了对齐,因此它可能位于 0x0000000000400449
让我们看看那里有什么...
(gdb) x/8gx $rsp+8
0x7fffbe5d5e98: 0x000000000000001c 0x0000000000000004
0x7fffbe5d5ea8: 0x00007fffbe5d6eb8 0x00007fffbe5d6ec0
0x7fffbe5d5eb8: 0x00007fffbe5d6ec4 0x00007fffbe5d6ec8
0x7fffbe5d5ec8: 0x0000000000000000 0x00007fffbe5d6ecf

看起来很有希望: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"

确实,这就是我调用二进制文件的方式。作为最终的健全性检查, 0x00007fffbe5d6ecf看起来像是装修的一部分吗?
(gdb) x/s 0x00007fffbe5d6f3f
0x7fffbe5d6f3f: "SSH_AGENT_PID=2874"

是的,那是环境的开始(或结束)。

所以你有它。

最后说明:如果GDB没有打印太多 <optimized out>,我们可以从第5帧中恢复 argcargv。 GDB和GCC方面都有工作,以使GDB打印的“优化输出”少得多。

另外,在加载核心时,我的GDB会打印:
Core was generated by `./a.out foo bar bazzzz'.

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

关于gdb - 我有一个不是用调试符号构建的可执行文件的核心转储。我可以恢复argv内容吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9049297/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com