2016-01-21 56 views
4

如何从共享对象中找到程序的argcargv?我正在用C编写一个库,它将通过LD_PRELOAD加载。我已经能够找到堆栈两种不同的方式:通过从库中查找argc和argv

  1. rsp直列__asm__电话。
  2. 阅读/proc/<pid>/maps并解析堆栈的条目。

然后我可以创建一个指针,将它指向堆栈段,然后遍历查找数据。问题是我找不出一个有效的方法来确定哪些字节是argc和指向argv字符串的指针。

我知道/proc/<pid>/cmdline也包含参数,每个参数都由0x00分开,但我有兴趣在内存中查找所有内容。

在gdb中,我看到一个DWORDargc后跟一个QWORD这是第一个指针。在地址argc之前的20个字节是一个指向主程序代码段的指针。但是,这不是确定性的方式来识别argcargv

我见过几个职位,但没有工作代码:

+0

似乎有点薄片状的方式来做到这一点,是依赖于编译器如何使用堆栈。只要有人发现编译器/运行时优化,这可能会发生变化。应用程序也可能希望在不同的意义上使用相同的参数,如果您的lib试图解释不是针对它的参数,这可能会导致问题。你能否在“构造函数”调用中直接将这些传递给你的库?是的,我明白你想要做的是避免这种开销。 – ChrisR

+0

什么时候会访问'argc'和'argv'?在LD_PRELOAD阶段可能不可能。 –

+0

程序修改'argv'中的数据也是完全合理的。我不确定在这种情况下堆栈会发生什么。 – paddy

回答

9

This response在你的第二个链接中包含的工作这对我来说工作得很好的源代码(GNU /基于Linux精灵的系统),包括在LD_PRELOAD期间。

该代码非常短;它包括一个功能:

int foo(int argc, char **argv, char **env) { 
    // Do something with argc, argv (and env, if desired) 
} 

,并在.init_array部分的指针,该函数:

__attribute__((section(".init_array"))) static void *foo_constructor = &foo; 

把那到一个共享库,然后LD_PRELOADing共享库肯定触发调用foo时我试了一下,并且明确地调用了argcargv,稍后将传递给main(以及environ的值)。

+0

很好的答案!我从来没有想过在库中以这种方式运行构造函数。没有摆弄编译器或运行时依赖关系。爱它。我每天都在学习。 – ChrisR

0

最可靠的可能是使用/proc/<pid>/cmdline,因为它由内核提供,并且不会因C实现而异(例如,它取决于您使用的处理器)。

问题是,在某些平台上,函数参数(fx main)将在堆栈上传递,但在其他平台上,它可能作为寄存器(x86-64平台上的fx)传递。如果它是通过寄存器发送的,那么如果启用优化main而不是如果它不需要,将它们存储在内存中 - 也就是说,如果您自己没有明确地这样做,它可能不会保留在内存中。

即使参数在堆栈上传递,main的参数所在的确切位置可能因编译器/实现的版本而异。这意味着几乎没有任何可靠的方法从堆栈中检索它们(并且正如有人指出,在执行main时可能会将其修改为命令行解析的一部分)。

即使途中内核传递参数给程序没有太大的帮助,因为他们通过寄存器传输 - 这意味着他们要去哪里存储是完全由CRT的init(这反过来又可能从版本到版本更改)。

简而言之,检索argvargc稍后需要使用CRT的明确支持(微软的CRT确实如此,但GNU并不AFAIK)。

什么你当然做的是抓住GCC的源和修补CRT初始化到实际存储argvargc的地方在那里,你可以稍后进行检索。如果你需要在程序运行的CRT init之前访问它们(fx在动态链接期间),这当然不起作用。