使用汇编语言和 Delphi 映射文件获取函数的地址

Get the address of a function using assembly language and Delphi map file

我试图在 "Detailed" 映射文件中查找单元名称和函数名称,该映射文件是通过在 Delphi 中构建项目生成的 5. 我找到了一些代码网上声称可以这样做,但我做不到。

代码要求:

目标: 函数:'Log' 应该是 return 调用过程的地址。一旦确定了地址,就可以在映射文件中查找单元和函数名称以及行号。

用途: 岂不是很好......如果一个函数的名称可以通过从程序中的任何地方调用 'Log' 来获得。

现实: 我真的很想了解 'Log' 函数中发生的事情,以及它为什么或为什么不工作,其次是 returning 单元和函数名称的另一种方式作为调用过程的行号。

问题: 我从 TForm1.Button1Click > TForm1.Log > TForm1.LogAddress > TForm1.ShowInfo 获得的地址与我正在寻找的地图文件中的相应项目不一致,即 M=Unit1, TForm1.Button1Click等...

网站: http://www.haydenr.com/delphi/articles/article002.htm , http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_22596248.html 最后一个网站可能无法从 link 访问 -- 我将 Google 搜索字符串放在 'Log' 函数中。

Delphi代码:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
     Button1: TButton;
     Label1: TLabel;
     Edit1: TEdit;
     procedure Button1Click(Sender: TObject);
     Procedure Log;
     Procedure ShowInfo(hexAddress : Integer);
     Procedure LogAddress(ptr: pointer);
  private
     { Private declarations }
  public
     { Public declarations }
  end;

var
  Form1: TForm1;

Implementation

{$R *.DFM}

    Procedure TForm1.Log;
    // Google Search: capturing a procedure or function's name for logging purposes
    // http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_22596248.html
    Begin
        ASM
             pop EAX
            push EAX
            Call LogAddress
        End;//ASM
    End;

    Procedure TForm1.ShowInfo(hexAddress: Integer);
    // http://www.haydenr.com/delphi/articles/article002.htm
    Var
        iMapFileAddress : Integer;
        sMapFileAddress : String;
        ImageBase        : Integer;
        SubOffset        : Integer;
        Offset           : Integer;
    Begin
        ImageBase := [=11=]400000; // Project > Options... > Linker Tab > Memory sizes group box > Image Base
        SubOffset := 00;
        Offset    := ImageBase + SubOffset;

        iMapFileAddress := hexAddress - Offset;
        sMapFileAddress := IntToHex(iMapFileAddress,8);
        Edit1.Text := sMapFileAddress; //This is the value I get: sMapFileAddress = 00542214
        {
         Here are some excerpts from: Project1.map
         |Detailed map of segments
         | 0001:00040498 000002D4 C=CODE     S=.text    G=(none)   M=Unit1    ACBP=A9
         | 0001:0004076C 000001A5 C=CODE     S=.text    G=(none)   M=Project1 ACBP=A9
         |   :
         |   :
         |   :
         |  Address         Publics by Name
         |
         | 0001:0004071C       TForm1.Button1Click
         | 0001:00040668       TForm1.Log
         | 0001:00040700       TForm1.LogAddress
         | 0001:0004067C       TForm1.ShowInfo
        }
    End;

    procedure TForm1.LogAddress(ptr: pointer);
    begin
      ShowInfo(Integer(ptr));
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
        Log;
    end;

end.

您没有正确调用 LogAddress。作为TForm1的方法,它实际上是一个双参数函数。这两个参数依次是 Selfptr,这意味着寄存器 EAX 是 Self 而 EDX 是 ptr。但是,您在 EAX 中传递了地址参数,而您对 EDX 没有做任何事情。这意味着您正在查找谁知道什么的名称,这可能不是您程序中任何代码段的地址。最重要的是,Self 值不再有效,因此对成员变量(例如 Edit1)的任何引用都将不起作用;你会遇到访问冲突或某种形式的内存损坏。

Log 方法更改为:

procedure TForm1.Log;
asm
  // fetch return address from top of stack
  mov edx, [esp+4]
  call LogAddress
end;

请记住,您在 ptr 参数中传递的地址是 Log 调用的 return 地址 。实际上,这通常是 之后用于进入 Log 方法的 CALL 指令的地址。因此,您不应期望在映射文件的函数列表中找到该确切地址。相反,您需要查找地址最接近但不超过您拥有的地址的函数。此外,如果您将该地址转换为行号,则它可能是实际调用站点之后的行。

the JCL 中的 JclDebug 单元已经具有可以为您执行此操作的函数。您可以使用 ProcByLevel 函数获取呼叫者的姓名,并使用 LiveByLevel 获取行号。

根据 Rob Kennedy 的建议进行代码替换并调整“esp 偏移量”后,工作代码如下...

为了制作“地图文件”;在 Delphi IDE 中执行以下步骤:

  1. 项目 > 选项... > 编译器选项卡 > 代码生成窗格: 优化 = FALSE

  2. 项目选项 Window > 链接器选项卡 > 映射文件窗格:Select“详细”

  3. 项目 > 构建所有项目

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls;
    
    type
      TForm1 = class(TForm)
         Button1 : TButton;
         Label1  : TLabel;
         Edit1   : TEdit;
         procedure Button1Click(Sender: TObject);
         Procedure Log;
         Procedure ShowInfo(hexAddress : Integer);
         Procedure LogAddress(ptr: pointer);
      private
         { Private declarations }
      public
         { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    Implementation
    
    {$R *.DFM}
    
        Procedure TForm1.Log;
        // Google Search: capturing a procedure or function's name for logging purposes
        // http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_22596248.html
        Begin
            ASM
                // fetch return address from top of stack
                 mov edx,[esp+8]
                call LogAddress
            End;//ASM
        End;
    
        Procedure TForm1.ShowInfo(hexAddress: Integer);
        // http://www.haydenr.com/delphi/articles/article002.htm
        Var
            iMapFileAddress : Integer;
            sMapFileAddress : String;
            ImageBase       : Integer;
            SubOffset       : Integer;
            Offset          : Integer;
        Begin
            ImageBase := [=10=]400000; // Project > Options... > Linker Tab > Memory sizes group box > Image Base
            SubOffset := 00;
            Offset    := ImageBase + SubOffset;
    
            iMapFileAddress := hexAddress - Offset;
            sMapFileAddress := IntToHex(iMapFileAddress,8);
            Edit1.Text := sMapFileAddress; //This is the value I get: sMapFileAddress = 00040730
            {
             |Here are some excerpts from: Project1.map
             |*******************************************************************************************************************
             |Detailed map of segments
             | 0001:00040498 000002D4 C=CODE     S=.text    G=(none)   M=Unit1    ACBP=A9
             | 0001:0004076C 000001A5 C=CODE     S=.text    G=(none)   M=Project1 ACBP=A9
             |   :
             |   :
             |   V
             |  Address         Publics by Name
             |
             | 0001:0004071C       TForm1.Button1Click
             | 0001:00040668       TForm1.Log
             | 0001:00040700       TForm1.LogAddress
             | 0001:0004067C       TForm1.ShowInfo
             |   :
             |   :
             |   V
             |Line numbers for Unit1(Unit1.pas) segment .text
             |
             |    82 0001:00040728    83 0001:00040730    85 0001:00040764    85 0001:0004076B
             |*******************************************************************************************************************
             |
             |     Returned Hex (H) = 00040730
             | Returned Integer (I) = 263984
             |-------------------------------------------------------------------------------------------------------------------
             |Address Of                Min Hex     Max Hex     Min Integer    Max Integer  |                Evaluation
             |------------------------------------------------------------------------------|------------------------------------
             |Unit1                     00040498    000406E5    263320         263909       | Hmin < H < Hmax   AND   Imin < I < Imax
             |Function/Procedure                    0004071C                   263964       |        H < Hmax   AND          I < Imax
             |Line Number                           00040730                   263984       |        H = Hmax   AND          I = Imax
             |-------------------------------------------------------------------------------------------------------------------
             |
             |NOTE: The actual line number where 'Log' is called is: Returned Line Number - 1 (83 - 1 = 82)
            }
        End;
    
        procedure TForm1.LogAddress(ptr: pointer);
        begin
          ShowInfo(Integer(ptr));
        end;
    
        procedure TForm1.Button1Click(Sender: TObject);
        begin
            Log;
        end;
    
    end.