是否可以从附加的 GDB 中找到正在运行的进程的 main 参数?

逆向工程 数据库
2021-06-24 19:50:21

给定一个非常基本的程序,

perl -e'$|=1; print $$; sleep 500;' HELLO WORLD

如何HELLO WORLD使用 GDB查找我想,bt -full但是当我附加并运行时,我得到了

#0  __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7ffe3b266bb0, rem=rem@entry=0x7ffe3b266bb0)
    at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:79
        r = -516
#1  0x00007f99fe824403 in __GI___nanosleep (requested_time=requested_time@entry=0x7ffe3b266bb0, remaining=remaining@entry=0x7ffe3b266bb0) at nanosleep.c:27
        ret = <optimized out>
#2  0x00007f99fe82433a in __sleep (seconds=0) at ../sysdeps/posix/sleep.c:55
        save_errno = 0
        ts = {tv_sec = 474, tv_nsec = 980286586}
#3  0x000055d533c98518 in Perl_pp_sleep ()
No symbol table info available.
#4  0x000055d533c38d06 in Perl_runops_standard ()
No symbol table info available.
#5  0x000055d533baca7c in perl_run ()
No symbol table info available.
#6  0x000055d533b82472 in main ()
No symbol table info available.

我希望能够将参数解析为main.


注意:我不是在寻找/proc/$$/cmdline. 那是可以改变的。我想要实际的论点main

1个回答

如果没有调试符号和那些函数参数 ( , ) 的持久存储地址,您想要的东西不可能以任何通用方式实现只有调试符号会给你访问的通用方法,并从代表帧的符号理论上。来自 x86-64 的示例:argcargvargcargvmain

(gdb) bt
#0  __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7fffffffdd30, rem=rem@entry=0x7fffffffdd30) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:79
#1  0x00007ffff7d25eb7 in __GI___nanosleep (requested_time=requested_time@entry=0x7fffffffdd30, remaining=remaining@entry=0x7fffffffdd30) at nanosleep.c:27
#2  0x00007ffff7d25dee in __sleep (seconds=0) at ../sysdeps/posix/sleep.c:55
#3  0x00005555556b38ec in Perl_pp_sleep ()
#4  0x0000555555653a56 in Perl_runops_standard ()
#5  0x00005555555c78dc in perl_run ()
#6  0x000055555559d432 in main ()
(gdb) f 6
#6  0x000055555559d432 in main ()
(gdb) info frame
Stack level 6, frame at 0x7fffffffdf30:
 rip = 0x55555559d432 in main; saved rip = 0x7ffff7c670b3
 caller of frame at 0x7fffffffdee0
 Arglist at 0x7fffffffded8, args: 
 Locals at 0x7fffffffded8, Previous frame's sp is 0x7fffffffdf30
 Saved registers:
  rbx at 0x7fffffffdf08, rbp at 0x7fffffffdf10, r12 at 0x7fffffffdf18, r13 at 0x7fffffffdf20, rip at 0x7fffffffdf28
(gdb) p (char*)rdi
No symbol "rdi" in current context.
(gdb) p argc
No symbol "argc" in current context.
(gdb) p argv
No symbol "argv" in current context.

正如你所看到的,保留了寄存器几乎不足够引导你的正确位置argc,并argv在内存中。用于参数传递的前几个将是 RDI、RSI、RDX、RCX ......这些在堆栈帧中是易变的。

因此,任何传递给的值都main()不再可从我们确定​​的任何位置获得。

通过了解目标,您可能会发现保存在本地堆栈变量中的指针,但寄存器值将不再存在。可能的位置(如果您喜欢取决于特定的 C 运行时实现)将查看__libc_start_main和朋友。此外,info args(基本上你可以设置的参数set args... 这也是一个长字符串)可能会给你一些东西,但通常不是没有可用的符号。

在切换到第 6 帧(主)并发出后x/16xg $sp,您可以自己从第 6 帧(主)中挖掘您的堆栈……然后您可以尝试查看所有这些地址,例如通过将它们打印为char*withp (char*)0x7fffffffded8和 similar ...

原答案如下。


这个怎么样?:

(gdb) info proc cmdline 
process 27856
cmdline = '/usr/bin/perl -e$|=1; print $$; sleep 500; HELLO WORLD'

应该相当于查询/proc/$$/cmdline...