Delphi反编译

Bla*_*dow 3 delphi decompiling exe reverse-engineering

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

Dav*_*nan 18

你的陈述是错误的.与其他主流编译器生成的代码相比,Delphi的反编译特别容易.

如果您能够证明反编译Delphi可执行文件的结果质量远高于其他广泛使用的语言,那么您的问题将会更加重要.

  • 我的回答是.您的证据表明Delphi可执行文件比MSVC更成功地反编译?如果您的问题仅仅是为了引用发出本机代码的编译器,为什么不这样说呢? (3认同)
  • 不必讨厌。CodeInChaos很好地描述了推理。基本上,与其他本机编译器相比,Delphi程序保留了更多的元数据(肯定比VC / MFC程序更多),这使得它们的反转更加容易。 (2认同)

Cod*_*aos 17

有一些东西可以帮助逆转delphi程序:

  • 您将获得完整的表单数据,包括事件处理程序方法的名称
  • 具有published可见性的所有成员都具有与RTTI一起使用
  • 编译器在优化方面非常糟糕.它没有完整的程序优化,并且汇编通常是原始源的直接转换,只需要很少的优化.(至少在我使用的版本中,从那以后可能有所改进)
  • 所有类,甚至那些使用RTTI编译的类都有一定级别的元数据可用.特别是它可以获得名称和继承结构classes.对于您在调试器中碰巧看到的任何类的实例,您可以获得其VMT,从而获得其类名.

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

一些其他GUI工具包使用的替代方法是自动生成代码,该代码初始化表单并使用代码连接事件处理程序.由于此代码直接使用指向事件处理程序的指针并直接分配给属性/调用setter,因此它不需要任何元数据.这有副作用,倒转变得有点困难.

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

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


Cos*_*und 15

来自战壕的故事:反编译一个小的Delphi DLL

我自己经历过Delphi反编译会话.这是一个假的"我丢失了我的来源"的东西,我确实失去了一个 Firebird UDF库的来源.现在我没有做得更好,我没有直接进入反编译,因为库很小,我知道重写会更快.

这个DLL导出一个如下所示的函数:

function udf_do_some_math(Number1, Number2:Currency): Currency;
Run Code Online (Sandbox Code Playgroud)

在做了理智的事情并重写函数并做了一些回归测试后,我发现了一些模糊的角落情况,其中新函数的结果与旧函数的结果不同!麻烦的是,函数的结果是正确的结果,旧的DLL包含一个BUG,我不得不重现BUG - 这个函数的一致性比准确性更重要.

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

反编译失败了!我尝试了很多不同的反编译器,包括一些"商业"反编译器.大多数表面看起来都是好的数据,但还不足以找出旧的bug.最有希望的一个,具有版本特定的VCL和RTL知识的那个给出了最糟糕的失败:当然,它找出了RTL调用,给了它们名字,但未能找到导出的函数!我感兴趣的一个函数没有显示在入口点列表中,它应该是直接的,因为它是一个导出的函数.

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

  • 代码非常简单,而且不是很多.
  • 它是一个带有导出函数的DLL,没有你期望从事件驱动的exe复杂.
  • 我对重新编译的代码不感兴趣,我只想找到一个旧的bug,以便我可以重现它.
  • 我没有要求Pascal代码,汇编程序已经足够好了.
  • 我确切地知道代码在做什么以及它是如何做的.这不是神秘的第三方代码.

我的解决方案

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

  • 好消息,+1好听的故事 (5认同)

Jar*_*cki 5

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