2

我是一名 java 程序员,但我在 C 语言中几乎没有什么事情要做。所以,我从一个简单的例子开始,如下所示。如果我已经编译它并生成一个可执行文件(hello),我可以在没有原始文件(hello.c)的任何unix平台上运行可执行文件(hello)吗?还有有没有办法从可执行文件中读取数据,将可执行文件反编译为原始文件(hello.c)?

[oracle@oracleapps test]$ cat hello.c
#include <stdio.h>
int main(){
int i,data =0;
for(i=1;i<=64;i+=1){
data = i*2;
printf("data=%d\n",data);
}
return 0;
}

编译

gcc -Wall -W -Werror hello.c -o hello
4

6 回答 6

2

您可以在与您为其编译可执行文件的平台兼容 ABI 的平台上运行生成的可执行文件。ABI 兼容性基本上意味着在两个(可能不同的)操作系统上使用相同的物理处理器架构和操作系统接口(加上调用约定)。例如,您可以在 FreeBSD 系统(具有相同的处理器类型)上运行为 Linux 编译的二进制文件,因为 FreeBSD 包含 Linux ABI 兼容性。但是,可能无法在所有其他类型的 Unices 上运行二进制文件,除非进行了一些骇客操作。例如,你不能在 Linux 上运行 Mac OS X 应用程序,但是这个人有一个解决方案,可以在 Linux 上使用一些 OS X 命令行工具(包括 GCC 编译器本身)。

逆向工程:确实有反编译器旨在从机器代码生成 C 代码,但它们(还)不是很强大。原因是它们天生就很难写。必须识别机器代码模式,即使那样你也无法收集所有原始信息。例如,循环类型、注释和非静态局部变量名称以及大多数类型在编译过程中都消失了。例如,如果您有这样的 C 源文件:

int main(int argc, char **argv)
{
    int i;
    for (i = 0; i < 10; i++)
    {
        printf("I is: %d\n", i); /* Write the value of I */
    }

    return 0;
}

C 反编译器可能能够重建以下代码:

int main(int _var1, void *_var2)
{
    int _var3 = 0;
    while (_var3 < 10)
    {
        printf("I is: %d\n", _var3);
        _var3 = _var3 + 1;
    }

    return 0;
}

但这将是一个相当先进的反编译器,例如这个。

于 2012-08-12T17:26:57.923 回答
1

不......每个平台可能有不同的可执行格式要求,不同的硬件架构,由链接器确定的不同的可执行内存布局等。编译的可执行文件是其当前编译平台的“本机”,而不是其他平台。不过,您可以在当前机器上交叉编译另一个架构。

例如,即使它们可能有很多相似之处,在 Linux x86 上编译的可执行文件并不能保证在 BSD 下运行,这取决于它的风格(即,您可能可以在 FreeBSD 下运行它,但通常不是 OSX 的达尔文版本的 BSD,甚至认为两者机器可能具有相同的底层硬件架构)。您也无法在运行 IRIX 的 SGI MIPS 机器上编译某些东西并在运行 Solaris 的 Sun SPARC 上运行它。

于 2012-08-12T17:18:34.367 回答
1

您不能在任何平台上运行可执行文件。

您可以在没有 .c 文件的其他机器(或这台机器)上运行可执行文件。如果它是在相同硬件上运行的相同操作系统/发行版。

您可以使用反编译器到反汇编程序来读取文件并将其视为汇编或 C-它们看起来与原始 c 文件不太一样。

于 2012-08-12T17:19:41.437 回答
1

编译后的文件是纯机器代码(加上一些元数据),因此它是自给自足的,因为它不需要存在源文件。不足之处?机器代码是操作系统和平台特定的。对于平台,我们通常只是粗略地指 CPU 的指令集,即“x86”或“PowerPC”,但使用某些编译器标志编译的某些代码可能需要特定的指令集扩展。操作系统依赖性不仅是由于可执行文件的不同格式(例如,ELF 与 PE 相对)造成的,而且还由使用特定于操作系统的服务或以特定于操作系统的方式使用的通用操作系统服务(例如系统调用)引起的。除此之外,几乎所有重要的代码都依赖于一些库(至少是 C 运行时库),所以你可能不会 如果没有兼容版本的正确库,就无法运行可执行文件。因此,您的可执行文件可能不会在 10 年前的专有 UNIX 上运行,并且可能无法在不同的 Linux 发行版上运行(尽管您的程序很有可能会运行,因为它可能只依赖于glibc.

虽然机器代码可以很容易地反汇编,但结果是非常低级的,对许多人来说毫无用处。尽管有尝试,但反编译为 C 几乎总是要困难得多。算法可以恢复,只是因为它们必须以某种方式在机器代码中编码。假设您没有为调试而编译,它永远不会恢复注释、格式、变量名等,因此即使是“完美”的反编译器也会产生与您输入的不同的 C 文件。

于 2012-08-12T17:22:30.717 回答
0

对于 C 程序,程序与编译它的环境相关联(通常与编译它的平台相同,除非您进行交叉编译)。您可以将为一个版本的 Linux(和特定的硬件架构)构建的东西复制到另一台运行相同版本 Linux 的具有相同架构的机器上,您会没事的。您通常可以在相关版本的 Linux 上运行它。但是您不会让 x86/64 代码在 IA32 机器、PPC 机器或 SPARC 机器上运行。如果基本的 O/S 足够相似,您可能会在 x86/64 机器上运行 IA32 代码。你可能会也可能不会为 Debian 编译一些东西以在 RedHat 下运行,反之亦然;这取决于您的程序使用哪些库。

Java 通过编译一个与平台无关的字节码程序和一个平台特定的 JVM (JRE) 在每个平台上运行它来避免这种情况。这种 WORM(一次写入,多次运行)行为是 Java 的一个关键卖点。

于 2012-08-12T17:21:03.790 回答
0

是的,你可以在任何 unixqemu上运行它。这与 java 程序非常相似,您可以在 jvm 运行的任何 unix 上运行它...

于 2012-08-12T17:42:04.143 回答