का उपयोग करते हुए जानकारी प्रपत्र CONTEXT
आप समारोह अनुभाग ढूंढें और पीई छवि में ऑफसेट कर सकते हैं। उदाहरण के लिए, आप लिंकर द्वारा जेनरेट की गई .map फ़ाइल से फ़ंक्शन नाम प्राप्त करने के लिए इस जानकारी का उपयोग कर सकते हैं।
CONTEXT
संरचना प्राप्त करें। आप कार्यक्रम काउंटर सदस्य में रुचि रखते हैं। चूंकि CONTEXT
मंच पर निर्भर है, आप अपने आप के लिए यह पता लगाने के लिए है। जब आप प्रारंभ करते हैं, तो आप इसे पहले ही करते हैं, उदाहरण के लिए x64 विंडोज के लिए STACKFRAME64.AddrPC.Offset = CONTEXT.Rip
। अब हम स्टैक पैदल शुरू करते हैं और STACKFRAME64.AddrPC.Offset
का उपयोग करते हैं, जो हमारे शुरुआती बिंदु के रूप में StaclkWalk64
से भरा हुआ है।
आवंटन आधार पते का उपयोग करके आपको इसे रिलेटिव वर्चुअल एड्रेस (आरवीए) में अनुवाद करने की आवश्यकता है: RVA = STACKFRAME64.AddrPC.Offset - AllocationBase
। आप VirtualQuery
का उपयोग कर AllocationBase
मिल सकती है।
एक बार आपके पास यह हो जाने के बाद, आपको अनुभाग आरएफए गिरने और धाराऑफसेट प्राप्त करने के लिए सेक्शन प्रारंभ पता घटाए जाने की आवश्यकता है: SectionOffset = RVA - SectionBase = STACKFRAME64.AddrPC.Offset - AllocationBase - SectionBase
। ऐसा करने के लिए आपको पीई छवि हेडर संरचना (IMAGE_DOS_HEADER, IMAGE_NT_HEADER, IMAGE_SECTION_HEADER) तक पहुंचने की आवश्यकता है ताकि पीई और उनके प्रारंभ/अंत पते में अनुभागों की संख्या प्राप्त हो सके। यह बहुत सरल है।
यह है कि। अब आपके पास पीई छवि में सेक्शन नंबर और ऑफ़सेट है। फंक्शन ऑफसेट .map फ़ाइल में सेक्शनऑफसेट से कम उच्चतम ऑफ़सेट है।
यदि आप चाहें तो मैं बाद में कोड पोस्ट कर सकता हूं।
संपादित करें: कोड मुद्रित करने के लिए function address
(हम 64 सामान्य सीपीयू मान):
#include <iostream>
#include <windows.h>
#include <dbghelp.h>
void GenerateReport(void)
{
::CONTEXT lContext;
::ZeroMemory(&lContext, sizeof(::CONTEXT));
::RtlCaptureContext(&lContext);
::STACKFRAME64 lFrameStack;
::ZeroMemory(&lFrameStack, sizeof(::STACKFRAME64));
lFrameStack.AddrPC.Offset = lContext.Rip;
lFrameStack.AddrFrame.Offset = lContext.Rbp;
lFrameStack.AddrStack.Offset = lContext.Rsp;
lFrameStack.AddrPC.Mode = lFrameStack.AddrFrame.Mode = lFrameStack.AddrStack.Mode = AddrModeFlat;
::DWORD lTypeMachine = IMAGE_FILE_MACHINE_AMD64;
for(auto i = ::DWORD(); i < 32; i++)
{
if(!::StackWalk64(lTypeMachine, ::GetCurrentProcess(), ::GetCurrentThread(), &lFrameStack, lTypeMachine == IMAGE_FILE_MACHINE_I386 ? 0 : &lContext,
nullptr, &::SymFunctionTableAccess64, &::SymGetModuleBase64, nullptr))
{
break;
}
if(lFrameStack.AddrPC.Offset != 0)
{
::MEMORY_BASIC_INFORMATION lInfoMemory;
::VirtualQuery((::PVOID)lFrameStack.AddrPC.Offset, &lInfoMemory, sizeof(lInfoMemory));
::DWORD64 lBaseAllocation = reinterpret_cast<::DWORD64>(lInfoMemory.AllocationBase);
::TCHAR lNameModule[ 1024 ];
::GetModuleFileName(reinterpret_cast<::HMODULE>(lBaseAllocation), lNameModule, 1024);
PIMAGE_DOS_HEADER lHeaderDOS = reinterpret_cast<PIMAGE_DOS_HEADER>(lBaseAllocation);
PIMAGE_NT_HEADERS lHeaderNT = reinterpret_cast<PIMAGE_NT_HEADERS>(lBaseAllocation + lHeaderDOS->e_lfanew);
PIMAGE_SECTION_HEADER lHeaderSection = IMAGE_FIRST_SECTION(lHeaderNT);
::DWORD64 lRVA = lFrameStack.AddrPC.Offset - lBaseAllocation;
::DWORD64 lNumberSection = ::DWORD64();
::DWORD64 lOffsetSection = ::DWORD64();
for(auto lCnt = ::DWORD64(); lCnt < lHeaderNT->FileHeader.NumberOfSections; lCnt++, lHeaderSection++)
{
::DWORD64 lSectionBase = lHeaderSection->VirtualAddress;
::DWORD64 lSectionEnd = lSectionBase + max(lHeaderSection->SizeOfRawData, lHeaderSection->Misc.VirtualSize);
if((lRVA >= lSectionBase) && (lRVA <= lSectionEnd))
{
lNumberSection = lCnt + 1;
lOffsetSection = lRVA - lSectionBase;
break;
}
}
std::cout << lNameModule << " : 000" << lNumberSection << " : " << reinterpret_cast< void * >(lOffsetSection) << std::endl;
}
else
{
break;
}
}
}
void Run(void);
void Run(void)
{
GenerateReport();
std::cout << "------------------" << std::endl;
}
int main(void)
{
::SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
::SymInitialize(::GetCurrentProcess(), 0, 1);
try
{
Run();
}
catch(...)
{
}
::SymCleanup(::GetCurrentProcess());
return (0);
}
सूचना, हमारे कॉल स्टैक (अंदर बाहर) है GenerateReport()->Run()->main()
। कार्यक्रम निर्गम (मेरी मशीन पर, पथ निरपेक्ष है):
D:\Work\C++\Source\Application\Prototype.Console\Prototype.Console.exe : 0001 : 0000000000002F8D
D:\Work\C++\Source\Application\Prototype.Console\Prototype.Console.exe : 0001 : 00000000000031EB
D:\Work\C++\Source\Application\Prototype.Console\Prototype.Console.exe : 0001 : 0000000000003253
D:\Work\C++\Source\Application\Prototype.Console\Prototype.Console.exe : 0001 : 0000000000007947
C:\Windows\system32\kernel32.dll : 0001 : 000000000001552D
C:\Windows\SYSTEM32\ntdll.dll : 0001 : 000000000002B521
------------------
अब, पते के मामले में कॉल स्टैक (अंदर बाहर) 00002F8D->000031EB->00003253->00007947->0001552D->0002B521
है। मुकाबले के पहले तीन .map
फ़ाइल सामग्री के लिए ऑफसेट:
...
0001:00002f40 [email protected]@YAXXZ 0000000140003f40 f FMain.obj
0001:000031e0 [email protected]@YAXXZ 00000001400041e0 f FMain.obj
0001:00003220 main 0000000140004220 f FMain.obj
...
जहां 00002f40
निकटतम छोटे 00002F8D
को ऑफसेट और इतने पर है। पिछले तीन पतों सीआरटी/ओएस कार्यों कि फोन main
(_tmainCRTstartup
आदि) का उल्लेख है - हम उन्हें अनदेखा करना चाहिए ...
तो, हम देख सकते हैं कि हम .map
फ़ाइल की मदद से स्टैक ट्रेस ठीक करने के लिए सक्षम हैं।फेंकने वाले अपवाद के लिए स्टैक ट्रेस उत्पन्न करने के लिए, आपको केवल GenerateReport()
कोड अपवाद कन्स्ट्रक्टर में रखना है (वास्तव में, यह GenerateReport()
मेरे कस्टम अपवाद वर्ग कन्स्ट्रक्टर कोड (इसके कुछ भाग) से लिया गया था)।
मेरा कार्यान्वयन देखें: http://www.dima.to/blog/?p=13 – Alexandru
ब्लॉग में आपकी टिप्पणियों के अनुसार आपके कार्यान्वयन के लिए पीडीबी-एस की आवश्यकता है। –