有没有办法访问可执行文件中包含的 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
地址所在的数字,例如:
我想我可以使用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
文件,以便我可以查看它。但它没有保存为资源(?):
虽然一般工具会更有用:
更新:
我尝试使用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
后代类中的代码在尝试将其假定的虚拟地址转换为偏移地址时获得下溢。
答案 0 :(得分:2)
使用TJclDebugInfoBinary
获得的HModule
句柄创建LoadLibrary
对象。然后在其上调用GetLocationInfo
。无论如何,这都是TJclDebugInfoList
所做的,除了它有一些辅助方法将地址从当前地址空间映射到它们对应的模块,而当你手动执行时,你必须已经知道哪个模块地址属于。 (但崩溃转储已经告诉你那个部分,所以你不需要列表类的帮助。)
您可能需要按摩地址,因为崩溃时模块的基地址与您使用LoadLibrary
加载时的基地址不同。
JCL调试信息未存储在资源中。它存储在名为JCLDEBUG的PE部分中。请参阅 JclDebug.pas 中PeMapImgFindSection32
和PeMapImgFindSectionFromModule
的用法。
答案 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的偏移量:
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