访问可执行文件中包含的JCL调试信息?

时间:2011-05-16 15:31:59

标签: delphi delphi-5 jedi-code-library

有没有办法访问可执行文件中包含的 Jedi调试信息(JDBG)?

Microsoft调试工具指出我的二进制文件中的堆栈链,我想知道这些偏移对应的方法/过程/函数:

user32.dll!SendMessageA+0x4c
StackOverflow.exe+0x179263
StackOverflow.exe+0x2315b5
StackOverflow.exe+0x1fc82
StackOverflow.exe+0x50388
StackOverflow.exe+0x541fe
user32.dll!gapfnScSendMessage+0x332

显然我正在呼叫SendMessage,但我不知道从哪里来。可执行文件是使用嵌入在可执行文件中的Jcl Debug信息构建的;但我无法弄清楚如何阅读它。

查看JclDebug.pas中的一些函数和类,一切似乎都是为了获取当前进程内部的调试信息,例如:

function GetLocationInfo(const Addr: Pointer; var Info: TJclLocationInfo): Boolean;

在我当前进程的地址空间中获取一个地址。它是HMODULE地址所在的数字,例如:

  • Stackoverflow.exe
  • GDI32.DLL
  • USER32.dll中
  • KERNELBASE.dll
  • dwmapi.dll文件
  • 了UxTheme.dll

我想我可以使用LoadLibrary(返回HMODULE)来手动加载模块,然后将其提供给一些挖掘模块图像以获取调试信息的类:

module := LoadLibrary('C:\Users\Ian\Desktop\StackOverflow.exe');

TJclDebugInfoList = class(TObjectList)
private
   function GetItemFromModule(const Module: HMODULE): TJclDebugInfoSource;
   ...
protected
   function CreateDebugInfo(const Module: HMODULE): TJclDebugInfoSource;
   ...
end;

除了它受到保护。

我正在尝试(希望)我可以写一个工具,我选择二进制(* .exe),输入一个地址,然后返回

  • 功能
  • 方法
  • 文件
  • 行号

的偏移量。

e.g。

[002315B5] FMain.TfrmMain.lvQuestions (Line 158, "FMain.pas" + 1) + $11

可能的?


编辑:我的第一个粗略准备方法是提取压缩的map文件,以便我可以查看它。但它没有保存为资源():

enter image description here

虽然一般工具会更有用:

enter image description here


更新

我尝试使用TJclDebugInfoList;我意识到数组属性ItemFromModule将访问受保护的方法:

function GetModuleLocationInfo(filename: string; Addr: Pointer): TJclLocationInfo;
var
   module: HMODULE;
   infoList: TJclDebugInfoList;
   infoSource: TJclDebugInfoSource;

   Address: Pointer;
   locationInfo: TJclLocationInfo;
   AddressOffset: Integer;
begin
   module := LoadLibrary(filename);
   if module = 0 then
      RaiseLastWin32Error;
   try
      infoList := TJclDebugInfoList.Create;
      try
         infoSource := infoList.ItemFromModule[module];
         if source = nil then
            raise Exception.Create('Could not find debug info source for module '+IntToStr(module));
         if not source.GetLocationInfo(Addr, {var}locationInfo) then
            raise Exception.Create('Could not get location info for address $'+IntToHex(Integer(Address), 8));

         Result := locationInfo;
      finally
         infoList.Free;
      end;
   finally
      FreeLibrary(module);
   end;
end;

除了其中一个TJclDebugInfoSource后代类中的代码在尝试将其假定的虚拟地址转换为偏移地址时获得下溢。

3 个答案:

答案 0 :(得分:2)

使用TJclDebugInfoBinary获得的HModule句柄创建LoadLibrary对象。然后在其上调用GetLocationInfo。无论如何,这都是TJclDebugInfoList所做的,除了它有一些辅助方法将地址从当前地址空间映射到它们对应的模块,而当你手动执行时,你必须已经知道哪个模块地址属于。 (但崩溃转储已经告诉你那个部分,所以你不需要列表类的帮助。)

您可能需要按摩地址,因为崩溃时模块的基地址与您使用LoadLibrary加载时的基地址不同。

JCL调试信息未存储在资源中。它存储在名为JCLDEBUG的PE部分中。请参阅 JclDebug.pas PeMapImgFindSection32PeMapImgFindSectionFromModule的用法。

答案 1 :(得分:1)

我不久前制作了这样一个工具,不知道我是否能再找回来,但至少有可能: - )

另一方面,我使用jclDebug.pas制作了几个工具,现在我记得:我对它进行了一些更改,以使“离线”堆栈跟踪成为可能。 你可以看看这些:

Live Process Stack Viewer: http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer

Minidump阅读器(使用脱机阅读.map或来自exe的嵌入式jdbg信息): http://code.google.com/p/asmprofiler/source/browse/#svn%2Ftrunk%2FMiniDumpReader

答案 2 :(得分:1)

这里的代码可以提供有关模块中地址的调试信息

function GetModuleLocationInfo(filename: string; AddressOffset: Pointer; AssumeOffsetIsRelativeToStartOfCodeSection: Boolean=False): TJclLocationInfo;
var
    module: HMODULE;
    infoList: TJclDebugInfoList;
    infoSource: TJclDebugInfoSource;

    Address: Pointer;
    locationInfo: TJclLocationInfo;
begin
    //Code is public domain. No attribution required.
    module := LoadLibrary(PChar(filename));
    if module = 0 then
        RaiseLastWin32Error;
    try
        infoList := TJclDebugInfoList.Create;
        try
            infoSource := infoList.ItemFromModule[module];
            if infoSource = nil then
                raise Exception.Create('Could not find debug info source for module '+IntToStr(module));

            DWORD(Address) := DWORD(AddressOffset) + DWORD(module) + DWORD(ModuleCodeOffset);
            if not infoSource.GetLocationInfo(Address, {var}locationInfo) then
                raise Exception.Create('Could not get location info for address $'+IntToHex(Integer(Address), 8));

            Result := locationInfo;
        finally
            infoList.Free;
        end;
    finally
        FreeLibrary(module);
    end;
end;

一个实际的例子,来自Process Explorer的偏移量:

enter image description here

GetModuleLocationInfo('C:\Program Files (x86)\Avatar\HelpDesk.exe', 0xdcb17);

返回:

TJclLocationInfo
   Address: $266CB17
   UnitName: 'BalloonHint'
   ProcedureName: 'TBalloonHint.SetVisible'
   OffsetFromProcName: 83
   LineNumber: 281
   OffsetFromLineNumber: 0
   SourceName: 'BalloonHint.pas'
   DebugInfo: $1F25C74

或者采用JclDebug的风格:

  

[0266CB17] BalloonHint.TBalloonHint.SetVisible(第281行,“BalloonHint.pas”)+ $ 0