【问题标题】:Determine source language from a binary?从二进制文件中确定源语言?
【发布时间】:2010-12-14 19:43:58
【问题描述】:

responded 回答了另一个关于使用非 Objective-C 语言为 iPhone 开发的问题,我断言使用 C# 为 iPhone 编写会令 Apple 审稿人犯错。我主要是在谈论所讨论的 ObjC 和 C# 库之间的 UI 元素不同,但评论者提出了一个有趣的观点,让我想到了这个问题:

是否有可能仅从其二进制文件中确定程序的编写语言?如果有这样的方法,它们是什么?

让我们假设问题的目的:

  • 从交互的角度(控制台行为、任何 GUI 外观等)来看,两者是相同的。
  • 该性能并不是语言的可靠指标(没有比较,例如 Java 和 C)。
  • 在您和语言之间没有解释器或其他东西 - 只是原始可执行二进制文件。

如果您与语言无关,则可以加分。

【问题讨论】:

    标签: programming-languages binary disassembly


    【解决方案1】:

    嗯,C最初是转换成ASM的,所以你可以用ASM写所有的C代码。

    【讨论】:

    • 好吧,确实不是所有的 C 编译器都必须以这种方式工作,但是您可以使用 gcc-S 生成 asm 代码,所以我不这么认为值得一票否决。
    • 这是评论,不是答案。但由于这是一个很好的评论,所以投票归零。
    • @Todd Main 非常不同意。我的回答是“不”,因为我提供了一个反例。在一般意义上,答案是“通常你可以告诉”,但从严格意义上说,你只需要一个反例就可以得到答案是不可能的。
    • @alternative 但是说一个反例表明它是不可能的并不完全有帮助,除非问题是“你能总是从二进制文件中检测到源语言吗”。一个更准确的答案是,“通常但并非总是如此,在某些情况下它可能是不可能的”。说它是不可能的,意味着它永远不可能,这是不正确的。抱歉,有时我会卡在单词选择上,我并不是完全不同意程度。如果您找不到来源证据,您可以说它必须是 100% 汇编或作者故意混淆。
    【解决方案2】:

    我希望你可以,如果你反汇编源代码,或者至少你可能知道编译器,因为并非所有编译器都会对printf 使用相同的代码,所以 Objective-C 和 gnu C 在这里应该不同。

    您已排除所有字节码语言,因此此问题将比预期的要少。

    【讨论】:

      【解决方案3】:

      我不是编译器黑客(我希望有朝一日),但我认为您可能能够在二进制文件中找到可以指示生成它的编译器以及使用的一些编译器选项的迹象,例如指定的优化级别。

      但是,严格来说,您要问的是不可能的。可能有人拿着笔和纸坐下来,计算出与他们想要编写的程序相对应的二进制代码,然后在十六进制编辑器中输入这些内容。基本上,他们会在没有汇编工具的情况下进行汇编编程。同样,您可能永远无法确定本机二进制文件是用直接汇编程序编写的,还是用 C 语言和内联汇编编写的。

      对于 JVM 和 .NET 等虚拟机环境,您应该能够通过二进制可执行文件中的字节码识别 VM,我希望。但是,您可能无法分辨源语言是什么,例如 C# 与 Visual Basic,除非有特定的编译器怪癖提示您。

      【讨论】:

      • 在我看来,理论上这是不可能的,而实际上却是。 :)
      • 如果它是 100% 汇编,你可以通过检查二进制文件来判断。理论上,有人可以在 FORTRAN 中编写程序,然后通过 fortran-to-c 应用程序运行它以获得“C”源代码。当它被编译时,可能没有任何痕迹表明原始语言不是“C”。这就引出了一个问题,即究竟什么才是“它所用的语言”。也许这样的问题可以更具体,“你能说出创建这个二进制文件是用什么语言吗?”换句话说,就是被翻译成二进制的语言。
      【解决方案4】:

      首先,在一些二进制文件上运行what 并查看输出。 CVS(和 SVN)标识符分散在整个二进制映像中。其中大部分来自图书馆。

      此外,各种库函数通常都有一个“映射”。这也是一个很大的暗示。

      当库链接到可执行文件中时,通常会在二进制文件中包含一个带有名称和偏移量的映射。这是创建“位置无关代码”的一部分。您不能简单地将各种目标文件“硬链接”在一起。您需要一个地图,并且在将二进制文件加载到内存时必须进行一些查找。

      最后,C、C++(我想是 C#)的启动模块是该编译器的默认库集所独有的。

      【讨论】:

      • 如果你静态链接所有你可以的库怎么办。
      • @James Black:不会改变任何事情。 .o 只是连接到可执行文件中,以及一些关于如何在内存中填充材料的加载器指令。
      【解决方案5】:

      不,字节码与语言无关。不同的编译器甚至可以采用相同的代码源并生成不同的二进制文件。这就是为什么您看不到适用于二进制文件的通用反编译器的原因。

      【讨论】:

        【解决方案6】:

        “strings”命令可用于获取有关所使用语言的一些提示(例如,我只是在我编写的 C 应用程序的剥离二进制文件上运行它,它找到的第一个条目是链接的库可执行文件)。

        【讨论】:

          【解决方案7】:

          简短回答:

          长答案:

          如果您查看二进制文件,您可以找到已链接的库的名称。在 TextPad 中打开 cmd.exe 很容易在十六进制偏移量 0x270 处找到以下内容:msvcrt.dll、KERNEL32.dll、NTDLL.DLL , USER32.dll 等 msvcrt 是微软'C' 运行时支持函数。 KERNEL32、NTDLL 和 USER32.dll 是特定于操作系统的库,它们可以告诉您目标平台或构建目标平台的平台,具体取决于跨平台开发环境将两者分离的程度。

          撇开这些线索不谈,大多数 c/c++ 编译器都必须将函数的名称插入二进制文件中,所有函数(或入口点)的列表都存储在一个表中。 C++ 'mangles' 函数名称以对参数及其类型进行编码以支持重载方法。可以混淆函数名称,但它们仍然存在。函数签名将包括可用于跟踪系统或程序中使用的内部调用的参数的数量和类型。在偏移量 0x4190 处是“SetThreadUILanguage”,可以通过搜索找到很多关于 development environment 的信息。我在偏移量 0x1ED8A 处找到了入口点表。我可以很容易地看到 printf、exit 和 scanf 等名称;以及 __p__fmode、__p__commode 和 __initenv

          x86 处理器的任何可执行文件都有一个数据段,其中包含程序中包含的任何静态文本。回到 cmd.exe(偏移量 0x42C8)是文本“S.o.f.t.w.a.r.e..P.o.l.i.c.i.e.s..M.i.c.r.o.s.o.f.t..W.i.n.d.o.w.s..S.y.s.t.e.m.”。该字符串占用的字符数是通常所需的两倍,因为它是使用双宽字符存储的,可能是为了国际化。错误代码或消息是这里的主要来源。

          在 B1B0 偏移处是“p.u.s.h.d”,后跟 mkdir、rmdir、chdir、md、rd 和 cd;为了便于阅读,我省略了不可打印的字符。这些都是 cmd.exe 的命令参数。

          对于其他程序,我有时能够找到编译程序的路径。

          所以,是的,可以从二进制文件中确定源语言。

          【讨论】:

          • 这一切都依赖于链接库的人。如果这是静态完成的,或者函数或复制/粘贴到源代码中会发生什么?这是一个很棒的提示(我 +1),但它并不总是可靠的。
          • 即使可执行文件是静态链接的,也存在入口点。它们基于定义的函数,无论它们来自哪个对象模块或它们如何链接。在运行时加载的函数在入口点表中没有它们的名称,但必须在数据段中的某个地方提及,因为运行时加载器需要它。在某种程度上,您对复制/粘贴的源代码是正确的。解决这个问题的唯一方法是,如果所有代码都在 main 中,并且没有链接任何库。
          【解决方案8】:

          这些工具怎么样:

          PE Detective

          PEiD

          两者都是 PE 标识符。好的,它们都是用于 windows 的,但我到达这里时就是这样

          【讨论】:

            猜你喜欢
            • 2018-04-28
            • 2021-08-17
            • 2018-11-30
            • 2014-03-01
            • 2015-05-26
            • 2020-12-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多