如何确定一个没有源代码的 Delphi 程序使用了哪些库?

10

我有一个Windows .exe文件,但它的源代码丢失了。开发人员没有尽责并离开了我们公司。我认为这是一个Delphi/Pascal程序。开发者使用了许多库,但我不确定使用了哪些库。是否有工具可以告诉我用于制作该exe的库?

有没有工具可以帮助查找exe文件中使用的库?


2
@Andreas Rejbrand:他并没有问使用了哪些库,而是是否有工具可以发现使用了哪些库。所以这个问题是可以回答的。不幸的是,据我所知,答案是否定的。 - The_Fox
4
Delphi 可执行文件/库中的 'packageinfo' 资源包含所有链接的单元名称。这可能(或可能不)提示可能使用的库。 - Sertac Akyuz
1
此外,如果它是一个VCL窗体应用程序,使用Spy++或类似工具查看可视控件的类名可能(也可能不)会显示该控件的来源库。 - Sertac Akyuz
3
没错,PACKAGEINFO资源中包含已使用单位的名称。此外,Delphi的打包系统要求单位名称必须是唯一的。因此,我们可以收集宝贵的信息。另外,检查窗体资源可以得到组件类名(同样也是唯一的)。所以,这个问题并不那么无望。最可能使用的工具是DeDe。 - Free Consulting
2
这里的评论表明这个问题并不是无法回答的。虽然追求可能会徒劳无功,但它仍然是一个有效的问题。投票重新开放。 - Rob Kennedy
显示剩余2条评论
4个回答

6
如何获取一些用户建议的信息?您可以使用存储在每个由Delphi生成的exe、dll或bpl中包含的PACKAGEINFO资源。您可以使用GetPackageInfo函数来获取软件包信息表中的数据。请查看此示例代码,以了解如何使用此函数。
program ResPACKAGEINFO;

{$APPTYPE CONSOLE}

uses
  Windows,
  Classes,
  SysUtils;


function GetUnitFlagInfo(Flags: Byte):string;
begin

  { PackageUnitFlags:
    bit      meaning
    -----------------------------------------------------------------------------------------
    0      | main unit
    1      | package unit (dpk source)
    2      | $WEAKPACKAGEUNIT unit
    3      | original containment of $WEAKPACKAGEUNIT (package into which it was compiled)
    4      | implicitly imported
    5..7   | reserved
  }

  Result:='';
  if (Flags and ufMainUnit<>0) then
  Result:='[Main Unit] ';

  if (Flags and ufPackageUnit<>0) then
  Result:=Result+'[Package Unit] ';

  if (Flags and ufWeakUnit<>0) then
  Result:=Result+'[Weak Unit] ';

  if (Flags and ufImplicitUnit<>0) then
  Result:=Result+'[implicitly imported] ';

  if (Flags and ufWeakPackageUnit<>0) then
  Result:=Result+'[$WEAKPACKAGEUNIT unit] ';

  if (Flags and ufOrgWeakUnit<>0) then
  Result:=Result+'[original containment of $WEAKPACKAGEUNIT]';
end;


procedure GetInfoPackageFlags(Flags:Cardinal);
begin

        { Package flags:
          bit     meaning
          -----------------------------------------------------------------------------------------
          0     | 1: never-build                  0: always build
          1     | 1: design-time only             0: not design-time only      on => bit 2 = off
          2     | 1: run-time only                0: not run-time only         on => bit 1 = off
          3     | 1: do not check for dup units   0: perform normal dup unit check
          4..25 | reserved
          26..27| (producer) 0: pre-V4, 1: undefined, 2: c++, 3: Pascal
          28..29| reserved
          30..31| 0: EXE, 1: Package DLL, 2: Library DLL, 3: undefined
        }


        if  (Flags and pfModuleTypeMask = pfExeModule) then
         Writeln('Type Exe')
        else
        if  (Flags and pfModuleTypeMask = pfPackageModule) then
         Writeln('Type Package')
        else
        if  (Flags and pfModuleTypeMask = pfLibraryModule) then
         Writeln('Type Library');

        if  (Flags and pfNeverBuild = 0) then
         Writeln('Build with runtime packages')
        else
         Writeln('Build without runtime packages');

        if  (Flags and pfIgnoreDupUnits = 0) then
         Writeln('perform normal dup unit check')
        else
         Writeln('Ignore Dup Units');

        if  (Flags and pfProducerMask = pfDelphi4Produced) then
         Writeln('Producer Pascal');

        if  (Flags and pfProducerMask = pfV3Produced) then
         Writeln('Producer pre-V4');

        if  (Flags and pfProducerMask = pfProducerUndefined) then
         Writeln('Producer undefined');

        if  (Flags and pfProducerMask = pfBCB4Produced) then
         Writeln('Producer c++');

        if  (Flags and pfConsumerMask = pfConsumerCompat) then
         Writeln('Consumer Compatible')
        else
        if  (Flags and pfConsumerMask = pfConsumerDelphi) then
         Writeln('Consumer Delphi')
        else
        if  (Flags and pfConsumerMask = pfConsumerBCB) then
         Writeln('Consumer BCB');
end;

procedure PackageInfoCallback(const Name: string; NameType: TNameType; Flags: Byte; Param: Pointer);
begin
    case NameType of
      ntContainsUnit   :  Writeln(Format('Contains %s  %s',[Name+#13#10,GetUnitFlagInfo(Flags)]));
      ntRequiresPackage:  Writeln(Format('Requires %s  %s',[Name+#13#10,GetUnitFlagInfo(Flags)]));
    end;
end;


procedure GetPackageResInfo(const FileName:string);
const
 ResPACKAGEINFO='PACKAGEINFO';
var
  FModule    : Cardinal;
  Flags      : Integer;
begin
  FModule := LoadLibraryEx(PChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE);
  try
    SysUtils.GetPackageInfo(FModule, nil, Flags, PackageInfoCallback);
    GetInfoPackageFlags(Flags);
    Writeln(GetPackageDescription(PChar(FileName)));
  finally
    FreeLibrary(FModule);
  end;
end;

begin
  try
     GetPackageResInfo('yourApp.exe');
     Readln;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

6

一款列出 Delphi 二进制文件中所使用单元的应用程序(类似于 RRUZ 的演示)是 XN 资源编辑器。据我所知,最新版本在 这里。以下示例屏幕截图(幸运地 :)))指向一个特定的第三方库:

XN 资源编辑器

如评论中“Worm Regards”所建议的,该应用程序还显示“dfm”内容,因此可以看到所使用组件的类名。但为此,我建议使用DFM Editor,因为该应用程序以树形结构显示所使用的组件,就像Delphi IDE中的“结构面板”:

DFM Editor

XN或任何其他资源编辑器都可以用于将dfm资源导出到文件中,以便使用DFM Editor进行检查。


5
你提到你“认为”它是用Delphi编写的。如果你不确定,那么你可以使用这个小工具。它只是一个命令行工具-使用方法是“IsDelphi.exe”。
如果确实是用Delphi编写的,那么交互式Delphi重构器可以做出惊人的事情。以下是使用它的逐步说明:
  1. 点击那个链接

  2. 下载三个文件:

    a)exe文件

    b)support dll文件

    c)用于您前同事使用的Delphi版本的“字典”

  3. 提取所有三个文件

    (如果没有rar文件提取器,请使用 7-zip)

  4. 打开IDK.exe
  5. 选择“文件”->“加载”->“自动检测版本”
  6. 在对话框中选择您的EXE文件
  7. 开始浏览Code Viewer和Class Viewer。

最后,您可以在此页面找到一些更通用的指导方针以及其他工具的链接。

祝好运!


1
不,几乎不可能对 Delphi 应用程序进行逆向工程。如果你这样做了,你只会得到一堆汇编代码。几乎不可能重构调用哪些 VCL 函数,更不用说使用了哪些库。
除非这个程序包含一些非常独特和无法复制的逻辑,否则最好从头开始重新编写。

为什么不能将其投票否决?该问题询问如何获取所使用的库。您的回答涉及反向工程,这是一项完全不同的任务。即便如此,您也没有实际提到任何可以完成该任务的工具或技术;您只是说它几乎是不可能的,但实际上并非如此。这不是一个有用的答案。 - Rob Kennedy
好吧,但至少请说明情况,而不是匿名投票反对。我谈论逆向工程,因为检查所使用的库只能通过检查代码和(不太可靠的)应用程序中的资源来实现。但既然您似乎比我更了解,请告诉我们哪些工具可以用来检查使用了哪些库。 - GolezTrol
1
@Rob 我认为Golez并不是反对你的投票,他只是希望有一些意见可以附加在其中。我总是很感激别人告诉我我的错误,但很遗憾这种情况比应该发生的更多! - David Heffernan
1
当然了。我宁愿是正确的,但如果我错了,我想知道为什么。 :) - GolezTrol
请注意,原问题提到了库,但有些答案似乎将其解读为设计时组件。如果您不采取这一步骤,像这样的答案会更合理。 - Marco van de Voort

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接