【问题标题】:How get the address(location) of the VMT table of a EXE generated by delphi如何获取delphi生成的EXE的VMT表的地址(位置)
【发布时间】:2011-08-31 13:48:00
【问题描述】:

我需要枚举用delphi编写的外部应用程序中使用的类 ,所以我需要访问 VMT 表以获取该信息,但我找不到任何有关如何在 exe(由 delphi 生成)文件中找到 VMT(虚拟方法表)的位置(地址)的文档。

【问题讨论】:

  • 迂腐提示:您只是想枚举类名及其方法名?或者您希望能够调用这些方法?
  • @joe, Delphi 2007,但是如果你有办法找到任何其他版本的 delphi 的位置也可以。
  • @Warren 只是暂时列举。 ;)
  • 你怎么知道有这样的东西?每个类都有自己的 VMT。为什么要连续存储它们?
  • 当您说外部应用程序时,您是在尝试读取 EXE 文件还是其他进程的内存以查找其中使用的类?这不是你自己的程序,你不能改变源? (如果是这样……为什么?)

标签: delphi


【解决方案1】:

是的,在某种程度上是可能的!

为了描述它,您需要一种 类浏览器 用于 EXE 文件,类似于 IDE 使用 pascal 单元的方式。

Revendepro的源代码说明了解决方法。

摘自http://www.ggoossen.net/revendepro/findingClasses.html(现在似乎是死链接):


  I := Code - vmtSelfPtr;
  while I < Code + CodeSize do
  begin
    // vmtSelfPtr must point to itself.
    if PPChar(I + vmtSelfPtr)^ = I then
    begin
        if PPChar(I + vmtParent)^ = nil then
        try
          // If no classParent then class can be object
          if (not UsePackages) and (TClass(I).ClassName = 'TObject') then
            // if class if object add it to classes.
            Add(TClass(I))
        except
          on EAccessViolation do
        end
        else
          // className must be in the code section.
          // classParent must be in the code section or the import section (when it is imported).
          if (PPChar(I + vmtClassName)^ <= Code + CodeSize) and
             (PPChar(I + vmtClassName)^ >= Code) and
             (((PPChar(I + vmtParent)^ <= Code + CodeSize) and
               (PPChar(I + vmtParent)^ >= Code)) or
              ((PPChar(I + vmtParent)^ <= ImportStart + ImportSize) and
               (PPChar(I + vmtParent)^ >= ImportStart))) then
          // Add possible class to possible class list.
          PossClasses.Add(I);
    end;
    Inc(I, 4);
  end;
   // Can't be more then 1 TObject.
  if (not TPEFileClass(PEFileClass).UsePackages) and (Count > 1) then
    raise EDecompilerError.Create('There can only be one TObject.');

  // If no classParent then class can be object
  if TClass(I).ClassName = 'TObject' then
    Add(TClass(I)) // if class if object add it to classes.

    // Add Classes to the list which parent is in the list.
  repeat
    Added := False;
    for J := PossClasses.Count -1 downto 0 do
    begin
      // Try to find parent class in classList
      if FindClass(TClass(PossClasses[J]).ClassParent) <> nil then
      begin
        // Class in class list
        Add(PossClasses[J]);
        PossClasses.Delete(J);
        Added := True;
      end;
      // Try to find parent class in a other package.
      for K := 0 to High(PEFiles) do
        if PEFiles[K].Classes.FindClass(TClass(PossClasses[J]).ClassParent) <> nil then
        begin
          // Class in class list
          Add(PossClasses[J]);
          PossClasses.Delete(J);
          Added := True;
          Break;
        end;
    end;
  until not Added;

免责声明:我从未测试过这些代码。

【讨论】:

    【解决方案2】:

    .exe 文件中没有一个 VMT。每个类都有自己的 VMT。 AFAICT,没有可靠的方法来枚举可执行文件中的类。我假设可执行文件只是一个文件。唯一的方法是分析这些数据是如何存储在 .exe 文件中的。

    但即使 .exe 正在运行,并且您可以访问其中一个对象,您也只能找到该对象的类的 VMT(在对象的偏移量 0 处)。这也将使您能够访问该类的基类,但仅此而已。

    【讨论】:

      【解决方案3】:

      请注意,运行时类型信息存在差异,只有 VMT。如果您需要 RTTI 而不是 VMT 的类型信息(如方法和类型的名称);如果可以访问 VMT(您可以通过类类型的 RTTI 通过类型,请参见下文)将包含指向方法的指针列表,并且没有方法 mname、参数信息等。Delphi 不会为每个创建像 IDispatch 这样的信息以及每个类/接口..

      直到 Delphi 2007,您没有所有类型的列表,以后的版本可能相同,但我不确定。如果你有一个地图文件,你可以从中获取一些数据,或者你可以使用一些启发式方法来搜索文件:Delphi 中的类型总是带有指向自身的指针(例如,指向 PTypeInfo 的 PPTypeInfo)。由于 PTypeinfo 也具有特定格式,因此您可以通过扫描可执行文件很容易地检测到这些格式。

      一旦找到 PTypeInfo,您就可以解析后面的数据,生成类型名并获得 TypeData。对于此处的类类型,您可以在正偏移处找到包含 VMT 的类的指针。包含已发布方法/属性的类型将在类型数据之后具有那些。您可以在单元 TypInfo 中找到结构的所有详细信息。

      除了映射文件之外,你永远不会找到所有方法的所有地址;只有具有 RTTI 的方法(例如已发布)具有带名称的地址。只有一组选定的类型有 RTTI(后来 Delphi 有新的 RTTI 信息,但我不知道它们在模块中的构造)。

      祝你好运。

      【讨论】:

        猜你喜欢
        • 2020-12-11
        • 1970-01-01
        • 2012-04-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多