访问另一个代码中的变量

时间:2015-03-28 13:00:13

标签: c variables scope

有没有办法从另一个代码访问一个代码中初始化的变量。例如。我的code1.c如下,

# include <stdio.h>
int main()
{
    int a=4;
    sleep(99);
    printf("%d\n", a);
    return 0;
}

现在,有没有办法可以从另一个C代码(code2.c)中访问a的值?我假设,我掌握了我想要访问的变量的所有知识,但我没有任何关于其在RAM中的地址的信息。那么,有什么办法吗?

我知道extern,我在这里要求的是一种后门。比如,基于某些属性在RAM中搜索变量。

3 个答案:

答案 0 :(得分:1)

你的例子有一个警告,留出可能使变量消失的可能优化:变量a仅在函数执行时才存在且尚未完成。

好吧,假设函数是main(),它至少对于标准C程序来说应该不是问题,所以如果你有这样的程序:

# include <stdio.h>
int main()
{
    int a=4;
    printf("%d\n", a);
    return 0;
}

有可能这段代码会调用一些函数。如果其中一个需要访问a来读取和写入它,只需将指针作为参数传递给a

# include <stdio.h>
int main()
{
    int a=4;
    somefunction(&a);
    printf("%d\n", a);
    return 0;
}

void somefunction (int *n)
{
    /* Whatever you do with *n you are actually
       doing it with a */
    *n++; /* actually increments a */
}

但是如果需要访问a的函数在函数调用堆栈中很深,那么所有父函数都需要将指针传递给a,即使它们不使用它,也会增加混乱并降低了代码的可读性。

通常的解决方案是将a声明为全局,使代码中的每个函数都可以访问它。如果要避免这种情况,则可以使a仅对需要访问它的函数可见。为此,您需要拥有一个包含所有需要使用a的函数的源代码文件。然后,将a声明为静态全局变量。因此,只有在同一源文件中编写的函数才能知道a,并且不需要指针。如果函数非常嵌套在函数调用堆栈中,则无关紧要。中间函数不需要传递任何其他信息来使嵌套函数了解a

因此,code1.c main()a以及需要访问的所有功能/* code1.c */ # include <stdio.h> static int a; void somefunction (void); int main() { a=4; somefunction(); printf("%d\n", a); return 0; } void somefunction (void) { a++; } /* end of code1.c */

year

关于尝试找出RAM中存储的特定变量的位置: 的种类。您可以跨越函数堆栈帧到main()堆栈帧,并且这些堆栈帧内部是每个函数的局部变量,但RAM中没有关于哪个变量位于什么位置的完整信息,以及编译器可以选择将它放在堆栈帧内的任何地方(或者甚至在寄存器中,因此在RAM中没有它的痕迹,除了从/向一般寄存器推送和弹出,这将更难以遵循)。

因此,除非该变量具有非平凡值,否则它是其堆栈帧中唯一的局部变量,已禁用编译器优化,您的代码知道正在使用的体系结构和调用约定,并且该变量被声明为volatile停止存储在CPU寄存器中,我认为没有安全和/或可移植的方法来查找它。

OTOH,如果您的程序已使用-g标志编译,您可能能够从程序中读取调试信息,并找出变量所在的堆栈框架中的位置,并抓取它以查找它。

答案 1 :(得分:0)

code1.c:

#include <stdio.h>

void doSomething(); // so that we can use the function from code2.c

int a = 4; // global variable accessible in all functions defined after this point

int main()
{
    printf("main says %d\n", a);
    doSomething();
    printf("main says %d\n", a);
    return 0;
}

code2.c

#include <stdio.h>

extern int a; // gain access to variable from code1.c

void doSomething()
{
    a = 3;
    printf("doSomething says %d\n", a);
}

输出:

main says 4
doSomething says 3
main says 3

您可以在必须使用extern int a;(本例中为code2.c)的每个文件中使用a,但声明它的文件除外extern(code1)在这种情况下.c)。要使这种方法起作用,您必须全局声明a变量(不在函数内)。

答案 2 :(得分:0)

一种方法是使单独的可执行文件具有与所讨论的程序相同的堆栈布局(因为变量放在堆栈上,我们需要变量的相对地址),因此使用相同或类似的编译它编译器版本和选项,尽可能多 在Linux上,我们可以使用ptrace(PTRACE_PEEKDATA, pid, …)读取正在运行的代码的数据。由于在当前的Linux系统上,堆栈的起始地址各不相同,我们必须考虑到这一点;幸运的是,这个地址可以从/proc/…/stat的第28个字段获得 以下程序(使用cc Debian 4.4.5-8编译,Linux 2.6.32上没有代码生成器选项)可以正常工作;必须将正在运行的程序的pid指定为程序参数。

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>

void *startstack(char *pid)
{   // The address of the start (i. e. bottom) of the stack.
    char str[FILENAME_MAX];
    FILE *fp = fopen(strcat(strcat(strcpy(str, "/proc/"), pid), "/stat"), "r");
    if (!fp) perror(str), exit(1);
    if (!fgets(str, sizeof str, fp)) exit(1);
    fclose(fp);
    unsigned long address;
    int i = 28; char *s = str; while (--i) s += strcspn(s, " ") + 1;
    sscanf(s, "%lu", &address);
    return (void *)address;
}

static int access(void *a, char *pidstr)
{
    if (!pidstr) return 1;
    int pid = atoi(pidstr);
    if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) return perror("PTRACE_ATTACH"), 1;
    int status;
    // wait for program being signaled as stopped
    if (wait(&status) < 0) return perror("wait"), 1;
    // relocate variable address to stack of program in question
    a = a-startstack("self")+startstack(pidstr);
    int val;
    if (errno = 0, val = ptrace(PTRACE_PEEKDATA, pid, a, 0), errno)
        return perror("PTRACE_PEEKDATA"), 1;
    printf("%d\n", val);
    return 0;
}

int main(int argc, char *argv[])
{
    int a;
    return access(&a, argv[1]);
}

另一个更苛刻的方法是mcleod_ideafix在他的答案结束时指出实现大量调试器并使用调试信息(提供它的存在)来定位变量。