从库

时间:2016-01-21 05:14:55

标签: c++ c linux pointers argv

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

  1. 通过内联rsp来电阅读__asm__
  2. 阅读/proc/<pid>/maps并解析堆栈条目。
  3. 然后我可以创建一个指针,将其指向堆栈段,然后迭代查找数据。问题是我无法找到一种有效的方法来确定哪些字节是argc以及指向argv字符串的指针。

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

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

    我看过一些帖子但没有工作代码:

3 个答案:

答案 0 :(得分:13)

第二个链接中的

This response包含工作源代码,对我来说很好(基于Gnu / Linux elf的系统),包括在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的值)。

答案 1 :(得分:0)

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

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

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

即使内核将参数传递给程序也没有多大帮助,因为它们通过寄存器传递 - 这意味着它们将被存储的位置完全取决于CRT init(反过来可能会改变)从版本到版本。)

简而言之,稍后检索argvargc需要您使用的CRT的明确支持(Microsoft的CRT会这样做,但GNU不会使用AFAIK)。

当然要做的就是获取GCC的来源并修补CRT init,以便将argvargc实际存储在稍后可以检索它们的地方。如果您需要在运行程序的CRT init之前访问它们(在动态链接期间为fx),那当然不会起作用。

答案 2 :(得分:0)

这是个坏主意,但我还没有天真地说你没有正当的理由。

如果您只知道堆栈的位置,就没有找到argc / argv的好方法。幸运的是,envp就在堆栈中argv之后,我所知道的每个libc都将envp放在了__environ全局中。因此,通过从__environ返回,您可以找到argc和argv。这是一些用Rust编写的示例代码,应该很容易移植到C ++:

extern "C" {
    pub static __environ: *const *const c_char;
}

fn raw_args() -> (c_int, *const *const c_char) {
    let mut walk_environ = unsafe { __environ as *const usize };
    walk_environ = walk_environ.wrapping_offset(-1);
    let mut i = 0;

    loop {
        let argc_ptr = walk_environ.wrapping_offset(-1) as *const c_int;
        let argc = unsafe { *argc_ptr };
        if argc == i {
            break (argc, walk_environ as *const *const c_char);
        }
        walk_environ = walk_environ.wrapping_offset(-1);
        i += 1;
    }
}