【问题标题】:Delphi decompiling [closed]Delphi反编译[关闭]
【发布时间】:2011-09-02 01:43:26
【问题描述】:

与使用其他编程语言/编译器构建的其他可执行文件相比,为什么反编译 delphi exe 如此简单?

【问题讨论】:

  • 为什么你认为这很容易?
  • 我所知道的所有编译语言都可以使用各种质量的反编译器。主要是质量很差。
  • 知道可视组件类的名称(例如,TMyFormTEdit1 等)并不能帮助您了解应用程序的功能。您声称这使反编译变得更容易是无稽之谈 - 知道 Delphi32 使用名为 TAppBuilder 的窗口类并不意味着您可以编写具有相同功能的新版本的 Delphi IDE。
  • 您链接到的程序会创建一个 .pas 文件,其中包含 assembler code。不是我所说的反编译程序,只是一个反汇编程序。它没有什么特别的。
  • @BlackShadow 如果我没记错的话,DeDe 只是一个了解一点 Delphi 元数据的反汇编程序。将其称为反编译器是一种误导。

标签: delphi reverse-engineering exe decompiling


【解决方案1】:

你的陈述是错误的。 Delphi 并不比其他主流编译器生成的代码更容易反编译。

如果您能够证明反编译 Delphi 可执行文件的结果比其他广泛使用的语言的质量要高得多,那么您的问题就会更有分量。

【讨论】:

  • 我的问题仅涉及已编译的可执行文件(包含汇编代码的 exe,而不是 .net 等 IL)
  • 我的答案是正确的。您在哪里证明 Delphi 可执行文件比 MSVC 可执行文件更成功地反编译?如果您的问题只是指生成本机代码的编译器,那您为什么不这么说呢?
  • 没必要讨厌。 CodeInChaos 很好地描述了推理。基本上,Delphi 程序比其他原生编译器保留了更多的元数据(绝对比 VC/MFC 程序更多),这使得逆向它们更容易。
  • Cosmin 的故事并不相关。他试图在单个 DLL 中反转单个函数,它不涉及任何元数据。真正的 Delphi 应用程序有许多类,其中大部分细节在 RTTI 中可用:名称、大小、继承层次结构、字段名称和 UI 事件的处理程序等。例如,以下是可以从单个表单的可执行文件中恢复的内容:pastie.org/private/bexiwdctu7scsrafqqsw(使用 IDC 脚本完成)。这样,您可以恢复许多类的几乎完整的布局,从而显着加快倒车速度。
  • 倒车时,每一条信息都可能有用,不管是否“绒毛”。即使是孤立的代码函数也必须与程序的其余部分交互,您可能拥有的额外信息会有所帮助。
【解决方案2】:

有一些事情可以帮助反转 delphi 程序:

  • 您将获得完整的表单数据,包括事件处理程序方法的名称
  • 具有published 可见性的所有成员都有用于 RTTI 的元数据
  • 编译器在优化方面做得很差。它不会对整个程序进行优化,并且程序集通常是对原始源代码的直接翻译,只有少量优化。 (至少在我使用的版本中,从那时起可能会有所改进)
  • 所有类,即使是那些关闭 RTTI 编译的类,都有一定程度的元数据可用。特别是可以得到classes 的名称和继承结构。对于您碰巧在调试器中看到的任何类实例,您都可以获取其 VMT 以及其类名。

Delphi 使用描述表单内容的文本文件并按名称连接事件处理程序。这种方法显然需要足够的元数据来反序列化 from 的文本表示并按名称连接事件处理程序。

其他一些 GUI 工具包使用的另一种选择是自动生成代码,用于初始化表单并将事件处理程序与代码挂钩。由于此代码直接使用指向事件处理程序的指针并直接分配给属性/调用设置器,因此不需要任何元数据。这样做的副作用是倒车变得有点困难。

创建一个将 dfm 文件转换为一系列硬编码指令来创建表单的程序应该不会太难。所以像 DeDe 这样的工具不会再那么好用了。但这在实践中并没有给你带来太多好处。

但找出哪个事件处理程序对应于哪个控件/事件仍然相当容易。特别是因为像 FLIRT 这样的东西可以识别大多数库函数。所以你只需要断点你感兴趣的那个,然后进入用户代码。

【讨论】:

  • 是的,这正是我的意思,但我的问题是为什么?为什么我可以在使用其他语言构建的其他 exe 时检索事件句柄的名称(参见 C++)?
  • 这不是语言问题,更多的是您的 GUI 工具包/GUI 设计器的工作方式。但是反转 GUI 部分很少有趣。它只是帮助您更快地找到您感兴趣的代码部分。
  • 在使用包构建的情况下,可能更容易获得 RTL/VCL 入口点的完整列表。
  • 我认为包使用带有损坏名称的 dll 导出导出所有公共函数。但我希望 FLIRT 能很好地发挥作用,这在实践中不会产生太大影响。
【解决方案3】:

战壕中的故事:反编译一个微小的 Delphi DLL

我自己也经历过 Delphi 反编译会话。这是那些听起来很假的“我丢失了我的资源”的事情之一,我确实丢失了一个 tiny Firebird UDF 库的资源。现在我没有做得更好,我没有直接反编译,因为库太小了,而且我知道重写会快得多。

此 DLL 导出的函数如下所示:

function udf_do_some_math(Number1, Number2:Currency): Currency;

在完成理智的事情并重写函数并进行一些回归测试之后,我发现了一些模糊的极端情况,其中新函数的结果与旧函数的结果不同!问题是,new 函数的结果是正确的,旧的 DLL 包含一个 BUG,我不得不重现这个 BUG - 这个函数的一致性比准确性更重要.

再次,做了理智的事情并试图“猜测”BUG。我知道这是一个四舍五入的问题,但根本无法弄清楚它是什么。最后我决定给我尝试的反编译器。毕竟这是一个小库,入口很简单,我真的不需要重新编译代码,也不需要 100% 反编译:我只需要找出旧的 BUG 就可以重现它!

反编译失败!我尝试了很多不同的反编译器,包括几个“商业”反编译器。大多数产生了表面上看起来不错的数据,但不足以找出旧的错误。最有希望的一个,具有 VCL 和 RTL 特定版本知识的那个给出了最严重的失败:当然,它找出了 RTL 调用,给了它们名称,但未能找到导出的函数!我感兴趣的一个函数没有显示在入口点列表中,它应该是直截了当的,因为它是一个导出函数。

这个反编译尝试应该很容易,因为:

  • 代码相当简单,并不多。
  • 这是一个带有导出函数的 DLL,没有您期望的事件驱动 exe 的复杂性。
  • 我对可重新编译的代码不感兴趣,我只是想找到一个旧错误以便重现它。
  • 我没有要求 Pascal 代码,汇编程序就足够了。
  • 我确切地知道代码在做什么以及它是如何做的。这不是神秘的第 3 方代码。

我的解决方案

在反编译器失败后,我转向了我自己值得信赖的 Delphi IDE 进行调试。我写了一个小的 Delphi 程序,它直接 导入 DLL 中的函数,创建了一个假的 Firbird 内存管理器 DLL,这样我的 DLL 就可以加载,用我知道会产生不好结果的参数调用我的旧函数,步进使用调试器进入代码并密切关注 FPU 寄存器。经过几次失败的尝试后,我终于注意到从 FPU 堆栈中弹出了一个值作为整数,它不应该是整数,所以我有我的 BUG:我错误地定义了一个整数局部变量,我应该有使用的货币。有了这些知识,我就能够重现这个错误。

【讨论】:

  • 很高兴知道您使用的反编译器的目标 Delphi 版本是否与实际编译 DLL 的版本匹配。
  • @Marco,完美匹配:DLL 是用 Delphi 7 构建的。
【解决方案4】:

在 Delphi 中唯一更容易的是检索 VCL。 使用 DeDe 等反编译器后,您将获得应用程序用户界面,但没有任何逻辑。 因此,如果您只想检索表单和按钮 - Delphi 比其他编译器更容易,但如果您想知道单击按钮后发生了什么,您需要使用 ollydbg 或其他(调试器/反汇编器)作为其他创建可执行文件的语言。

【讨论】:

    【解决方案5】:

    有利有弊。我不确定你指的是哪个角度更容易。 1 形式的简单应用程序与具有多种形式和大量类和函数的非常深入的应用程序之间也存在巨大差异。这就像记事本与 Office 2013(假设它们是用 delphi 编码的,只是比较复杂性而不是语言的一个例子)。

    在一个小型应用程序中,拥有 Delphi 应用程序“通常”包含的额外信息可以轻松完成。但是,在大型应用程序中,它可能“有帮助”,但您有上百万个调用需要挖掘。它们可能会帮助您靠近附近,但是在呼叫内部呼叫内部呼叫,然后用作跳转的多次返回......让您头晕目眩。然后,如果应用程序“被”打包或保护,有些事情仍然可能是乱码。虽然它可以在编程方面发挥作用,但阅读它可能要困难得多。前几天我在里面,所有的字符串都被加密了,所以“引用的文本字符串”没有帮助,而且加密不是简单的 md5 或 base64,而是一些自定义算法。也许是带盐的 MD5,然后进行 base64 编码?我永远无法找到字符串的确切方法。我知道其中一些应该是什么,但无法重现该方法,即使它看起来像是 base64,它是字符串的 base64 已经加密了某种方式......我不依赖文本字符串,但是在一个大型应用程序中,每一点都有帮助。

    当然,我对这个问题的解释是查看 OllyDbg 中的一个 Delphi exe。我可能不知道你们对这个话题的看法,但我觉得关于 Olly 和倒车,我是正确的(如果那是你在说的话)哈哈。

    【讨论】:

      猜你喜欢
      • 2010-09-25
      • 2019-12-17
      • 2017-06-12
      • 2012-06-14
      • 1970-01-01
      • 1970-01-01
      • 2012-01-01
      • 2012-03-08
      • 2014-06-26
      相关资源
      最近更新 更多