الوصول إلى معلومات JCL Debug الموجودة في الملف القابل للتنفيذ؟
-
14-11-2019 - |
سؤال
هل هناك طريقة للوصول إلى معلومات تصحيح جيدي (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)، وإدخال عنوان، والحصول على إرجاع
- وظيفة
- طريقة
- ملف
- رقم السطر
من الإزاحة.
على سبيل المثال
[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
تحصل الفئات التابعة على تدفق ناقص عندما تحاول تحويل ما تفترض أنه عنوان افتراضي إلى عنوان إزاحة.
المحلول
إنشاء TJclDebugInfoBinary
الكائن باستخدام HModule
التعامل الذي تحصل عليه من LoadLibrary
.ثم اتصل GetLocationInfo
عليه.هذا كل شئ TJclDebugInfoList
كان من الممكن أن يتم ذلك على أي حال، إلا أنه يحتوي على بعض الطرق المساعدة لتعيين العناوين من مساحة العنوان الحالية إلى الوحدات التي تتوافق معها، بينما عندما تفعل ذلك يدويًا، سيتعين عليك معرفة الوحدة النمطية التي تنتمي إليها العناوين بالفعل.(لكن ملف تفريغ الأعطال أخبرك بالفعل بهذا الجزء، لذلك لا تحتاج إلى مساعدة فئة القائمة.)
ربما سيتعين عليك تدليك العناوين لأن العنوان الأساسي للوحدة في وقت التعطل لن يكون هو نفسه عندما قمت بتحميلها LoadLibrary
.
لا يتم تخزين معلومات تصحيح JCL في أحد الموارد.يتم تخزينه في قسم PE المسمى JCLDEBUG.شاهد استخدامات PeMapImgFindSection32
و PeMapImgFindSectionFromModule
في JclDebug.pas.
نصائح أخرى
لقد صنعت مثل هذه الأداة منذ فترة، ولا أعرف إذا كان بإمكاني العثور عليها مرة أخرى، ولكن على الأقل هذا ممكن :-)
من ناحية أخرى، قمت بإنشاء العديد من الأدوات باستخدام jclDebug.pas، والآن أتذكر:لقد قمت بإجراء بعض التغييرات عليه لجعل تتبع المكدس "غير متصل" ممكنًا.يمكنك إلقاء نظرة على هذه:
عارض مكدس العمليات المباشرة:http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer
قارئ Minidump (باستخدام خريطة القراءة دون الاتصال بالإنترنت أو معلومات jdbg المضمنة من exe):http://code.google.com/p/asmprofiler/source/browse/#svn%2Ftrunk%2FMiniDumpReader
هذا هو الكود الذي يمكن أن يوفر معلومات تصحيح الأخطاء حول عنوان في الوحدة النمطية
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