2010-08-07 11 views
5

बाहरी डीएलएल में उपयोग किए गए कार्यों को आयात करने के लिए EXE फ़ाइलों में उपयोग की जाने वाली आयात पता तालिका के संबंध में एक थंक तालिका क्या है?आयात पता तालिका में थंक तालिका?

क्या यह थंक तालिका सिर्फ एक तालिका है जिसमें अन्य कार्यों में 'थंक्स' है?

+0

एक से शुरुआत कर सकते: तो मैं PEInfo.c के कोड का हिस्सा (कार्यों DumpImports और DumpExports) नीचे शामिल http://sandsprite.com/CodeStuff/Understanding_imports.html – quantumSoup

उत्तर

5

Thunks आयात तालिका (IMAGE_DIRECTORY_ENTRY_IMPORT) और देरी आयात तालिका (IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT) के एक हिस्सा हैं। उन्हें http://msdn.microsoft.com/en-us/library/ms809762.aspx वर्णित किया गया है।

मैं अपना पुराना स्रोत कोड देखूंगा और बाद में एक कामकाजी कोड पोस्ट करूंगा जो इस सारणी को समावेशी बाध्यकारी जानकारी दोनों को डंप करेगा।

UPDATED:

यहाँ एक कोड है जो मैं अपने पुराने कार्यक्रम में से एक में शौकीन है। यह केवल 32-बिट पीई का समर्थन करता है, लेकिन इसे 64-बिट में आसानी से संशोधित किया जा सकता है। जिस तरह से आप देख सकते हैं, कि यह बाध्यकारी जानकारी भी डंप करता है। परीक्षण करने के लिए पीई को बांधें जिसे आप bind.exe के संबंध में डंप करना चाहते हैं (उदाहरण के लिए उपयोग करें, bind.exe -u -v Test.dll)।

कोड में लगभग 1000 लाइनें शामिल हैं, इसलिए मैं इसे यहां पोस्ट नहीं कर सका। मुझे एक त्रुटि संदेश

ओह! आपका संपादन सबमिट नहीं किया जा सका क्योंकि:

  • शरीर 30000 वर्णों तक सीमित है; आपने 55095

इसलिए मैंने इसे यहां रखा: http://www.ok-soft-gmbh.com/ForStackOverflow/PEInfo.c। मुझे आशा है कि कोड आपको लंबे विवरण के रूप में बेहतर तरीके से मदद करेगा।

अद्यतन 2: मुझे लगता है कि मेरा पुराना उत्तर खोज इंजन के लिए अच्छा नहीं है।

void MakeIdent (UINT nOffset) 
{ 
    for (; nOffset; nOffset--) 
     printf (" "); // 4 blanks 
} 

void DumpDword (UINT nOffset, LPCSTR pszPrefix, DWORD dw) 
{ 
    MakeIdent(nOffset); 

    if (dw < 100) 
     printf ("%s: %d\n", pszPrefix, dw); 
    else if (dw%(256*256) == 0) 
     printf ("%s: 0x%X\n", pszPrefix, dw); 
    else 
     printf ("%s: %d (0x%X)\n", pszPrefix, dw, dw); 
} 

void DumpTimeDateStamp (UINT nOffset, LPCSTR pszTimeDateStampPrefix, DWORD dwTimeDateStamp) 
{ 
    //struct tm tmTime;//= localtime_s ((time_t *)&dwTimeDateStamp); 
    //errno_t err = localtime_s (&tmTime, ((time_t *)&dwTimeDateStamp)); 

    struct tm *ptmTime = _localtime32 ((__time32_t *)&dwTimeDateStamp); 
    SYSTEMTIME stSystemTime; 
    static CHAR szString[128]; 

    stSystemTime.wYear = (WORD)(1900 + ptmTime->tm_year); 
    stSystemTime.wMonth = (WORD)(ptmTime->tm_mon + 1); 
    stSystemTime.wDay = (WORD)ptmTime->tm_mday; 
    stSystemTime.wDayOfWeek = (WORD)(ptmTime->tm_wday + 1); 
    stSystemTime.wHour = (WORD)ptmTime->tm_hour; 
    stSystemTime.wMinute = (WORD)ptmTime->tm_min; 
    stSystemTime.wSecond = (WORD)ptmTime->tm_sec; 
    stSystemTime.wMilliseconds = 0; 

    MakeIdent(nOffset); 
    printf ("%s: 0x%8X (", pszTimeDateStampPrefix, dwTimeDateStamp); 

    if (GetDateFormatA (LOCALE_USER_DEFAULT, 0, &stSystemTime, NULL, 
     szString, sizeof(szString)/sizeof(TCHAR)) != 0) { 
     printf (szString); 
    } 

    if (GetTimeFormatA (LOCALE_USER_DEFAULT, 0, &stSystemTime, NULL, 
         szString, sizeof(szString)/sizeof(TCHAR)) != 0) { 
     if (szString[0] != 0) 
      printf (" "); 
     printf (szString); 
    } 
    printf (")\n"); 
} 

void DumpImports (UINT nOffset, IMAGE_OPTIONAL_HEADER32 *pOptionalHeader, PBYTE pbyFile, 
        IMAGE_SECTION_HEADER *pSectionHeader, IMAGE_NT_HEADERS32 *pNtHeader) // header of the section, which contains export section 
{ 
    IMAGE_IMPORT_DESCRIPTOR *pImportDescriptor = (IMAGE_IMPORT_DESCRIPTOR *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData + 
     pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress - pSectionHeader->VirtualAddress); 
    DWORD dwBoundImportVA = pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress; 
    IMAGE_BOUND_IMPORT_DESCRIPTOR *pFirstBoundImportDescriptor = NULL, *pBoundImportDescriptor; 

    //DumpDword (nOffset, TEXT("Characteristics"), pImportDescriptor->Characteristics); 
    if (dwBoundImportVA) { 
     UINT i; 
     IMAGE_SECTION_HEADER *pFirstSectionHeader = (IMAGE_SECTION_HEADER *)((PBYTE)pOptionalHeader + //sizeof(IMAGE_OPTIONAL_HEADER32)); 
                       pNtHeader->FileHeader.SizeOfOptionalHeader); 

     for (i=0; i<pNtHeader->FileHeader.NumberOfSections; i++) { 
      if (pFirstSectionHeader[i].VirtualAddress <= dwBoundImportVA && 
       dwBoundImportVA < pFirstSectionHeader[i].VirtualAddress + pFirstSectionHeader[i].Misc.VirtualSize) { 

       pFirstBoundImportDescriptor = (IMAGE_BOUND_IMPORT_DESCRIPTOR *)((PBYTE)pbyFile + pFirstSectionHeader[i].PointerToRawData + 
              dwBoundImportVA - pFirstSectionHeader[i].VirtualAddress); 
       break; 
      } 
     } 
     if (i >= pNtHeader->FileHeader.NumberOfSections) 
      pFirstBoundImportDescriptor = (IMAGE_BOUND_IMPORT_DESCRIPTOR *)((PBYTE)pbyFile + dwBoundImportVA); 
    } 

    for (;pImportDescriptor->Characteristics; pImportDescriptor++) { 
     IMAGE_THUNK_DATA *pOriginalFirstThunk = (IMAGE_THUNK_DATA *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData + 
      pImportDescriptor->OriginalFirstThunk - pSectionHeader->VirtualAddress); 
     IMAGE_THUNK_DATA *pFirstThunk = (IMAGE_THUNK_DATA *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData + 
      pImportDescriptor->FirstThunk - pSectionHeader->VirtualAddress); 
     IMAGE_THUNK_DATA *pOriginalThunk, *pThunk; 

     MakeIdent(nOffset); 
     printf ("%s ", pbyFile + pSectionHeader->PointerToRawData + pImportDescriptor->Name - pSectionHeader->VirtualAddress); 
     //DumpDword (nOffset, TEXT("Ordinal Base"), pExportDirectory->Base); 

     if (pImportDescriptor->TimeDateStamp == 0) { 
      //MakeIdent(nOffset); 
      printf ("(DLL is Not bound)\n"); 
     } 
     else if (pImportDescriptor->TimeDateStamp == -1) { 
      //if bound, and real date\time stamp 
      //         //  in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) 
      //MakeIdent(nOffset); 
      printf ("(DLL bound with New BIND)\n"); 
     } 
     else { 
      //MakeIdent(nOffset); 
      printf ("(DLL bound with Old BIND) "); 
      DumpTimeDateStamp (nOffset, "TimeDateStamp", pImportDescriptor->TimeDateStamp); 
     } 

     MakeIdent(nOffset+1); 
     if (pImportDescriptor->TimeDateStamp) // if bound 
      printf (TEXT("  Ordinal   hint BoundAddrs Name\n")); 
     else 
      printf (TEXT("  Ordinal   hint Name\n")); 

     for (pOriginalThunk=pOriginalFirstThunk, pThunk=pFirstThunk; pOriginalThunk->u1.AddressOfData; pOriginalThunk++, pThunk++) { 
      if (IMAGE_SNAP_BY_ORDINAL32(pOriginalThunk->u1.Ordinal)) { 
       MakeIdent(nOffset+1); 
       // Ordinal 
       if (pImportDescriptor->TimeDateStamp) 
        printf (TEXT("%4u (0x%04X)    0x%08X\n"), 
          pOriginalThunk->u1.Ordinal & ~IMAGE_ORDINAL_FLAG32, 
          pOriginalThunk->u1.Ordinal^IMAGE_ORDINAL_FLAG32, 
          pThunk->u1.AddressOfData); 
       else 
        // pThunk->u1.AddressOfData == pOriginalThunk->u1.Ordinal so don't print it 
        printf (TEXT("%4u (0x%04X)\n"), 
          pOriginalThunk->u1.Ordinal & ~IMAGE_ORDINAL_FLAG32, 
          pOriginalThunk->u1.Ordinal^IMAGE_ORDINAL_FLAG32); 
      } 
      else { 
       IMAGE_IMPORT_BY_NAME *pImportByName = (IMAGE_IMPORT_BY_NAME *) (pOriginalThunk->u1.AddressOfData + 
        (PBYTE)pbyFile + pSectionHeader->PointerToRawData - pSectionHeader->VirtualAddress); 

       MakeIdent(nOffset+1); 
       // Hint - Index into the Export Name Pointer Table. A match is attempted first with this value. 
       // If it fails, a binary search is performed on the DLL’s Export Name Pointer Table. 
       if (pImportDescriptor->TimeDateStamp) // if bound 
        printf (TEXT("%18u (0x%04X) 0x%08X %hs\n"), pImportByName->Hint, pImportByName->Hint, pThunk->u1.AddressOfData, 
         pImportByName->Name); 
       else 
        printf (TEXT("%18u (0x%04X) %hs\n"), pImportByName->Hint, pImportByName->Hint, pImportByName->Name); 
      } 
     } 
    } 

    if (pFirstBoundImportDescriptor) { 
     MakeIdent(nOffset); 
     printf ("PE Header contains the following bound import information:\n"); 

     for (pBoundImportDescriptor=pFirstBoundImportDescriptor; pBoundImportDescriptor->TimeDateStamp; 
      pBoundImportDescriptor = (IMAGE_BOUND_IMPORT_DESCRIPTOR *)((PBYTE)(pBoundImportDescriptor+1) + pBoundImportDescriptor->NumberOfModuleForwarderRefs*sizeof(IMAGE_BOUND_FORWARDER_REF))) { 
      PSTR pszDllName = (PSTR) ((DWORD)pFirstBoundImportDescriptor + pBoundImportDescriptor->OffsetModuleName); 
      IMAGE_BOUND_FORWARDER_REF *pRef = (IMAGE_BOUND_FORWARDER_REF *)(pBoundImportDescriptor+1); 

      MakeIdent(nOffset+1); 
      printf ("Bound to %hs", pszDllName); 
      DumpTimeDateStamp (0, "", pBoundImportDescriptor->TimeDateStamp); 
      if (pBoundImportDescriptor->NumberOfModuleForwarderRefs) { 
       UINT i; 

       for (i=0;i<pBoundImportDescriptor->NumberOfModuleForwarderRefs;i++) { 
        PSTR pszDllName = (PSTR) ((DWORD)pFirstBoundImportDescriptor + pRef->OffsetModuleName); 

        MakeIdent(nOffset+2); 
        printf ("Contained forwarders bound to %hs", pszDllName); 
        DumpTimeDateStamp (0, "", pRef->TimeDateStamp); 
       } 
      } 
     } 
    } 
} 

void DumpExports (UINT nOffset, IMAGE_OPTIONAL_HEADER32 *pOptionalHeader, PBYTE pbyFile, 
        IMAGE_SECTION_HEADER *pSectionHeader) // header of the section, which contains export section 
{ 
    UINT i; 
    UINT iNames; 
    PDWORD pdwAddressOfFunctions; 
    PWORD pwOrdinals; 
    PDWORD pdwNameRVA; 
    IMAGE_EXPORT_DIRECTORY *pExportDirectory = (IMAGE_EXPORT_DIRECTORY *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData + 
     pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress - pSectionHeader->VirtualAddress); 
    DWORD dwVAExportStart = pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; 
    DWORD dwVAExportEnd = pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + 
          pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; 

    DumpDword (nOffset, TEXT("Characteristics"), pExportDirectory->Characteristics); 
    DumpTimeDateStamp (nOffset, "TimeDateStamp", pExportDirectory->TimeDateStamp); 

    MakeIdent(nOffset); 
    printf ("DllName: %s\n", pbyFile + pSectionHeader->PointerToRawData + pExportDirectory->Name - pSectionHeader->VirtualAddress); 
    DumpDword (nOffset, TEXT("Ordinal Base"), pExportDirectory->Base); 

    MakeIdent(nOffset); 
    printf (TEXT("Version: %d.%d\n"), pExportDirectory->MajorVersion, pExportDirectory->MinorVersion); 

    DumpDword (nOffset, TEXT("Number of exported functions"), pExportDirectory->NumberOfFunctions); 
    DumpDword (nOffset, TEXT("Number of functions exported by name"), pExportDirectory->NumberOfNames); 

    MakeIdent(nOffset+1); 
    printf (TEXT("Ordn hint RVA  Name\n")); 

    pdwAddressOfFunctions = (PDWORD)(pbyFile + pSectionHeader->PointerToRawData + pExportDirectory->AddressOfFunctions - pSectionHeader->VirtualAddress); 
    pwOrdinals = (PWORD)(pbyFile + pSectionHeader->PointerToRawData + pExportDirectory->AddressOfNameOrdinals - pSectionHeader->VirtualAddress); 
    pdwNameRVA = (PDWORD)(pbyFile + pSectionHeader->PointerToRawData + pExportDirectory->AddressOfNames - pSectionHeader->VirtualAddress); 

    for (iNames = 0; iNames < pExportDirectory->NumberOfNames; iNames++) { 
     MakeIdent(nOffset+1); 

     // AddressOfFunctions MUST be ouf of Export Directory. If it is not so, it is a Forwarding entry 
     if (pdwAddressOfFunctions[pwOrdinals[iNames]] < dwVAExportStart || 
      pdwAddressOfFunctions[pwOrdinals[iNames]] > dwVAExportEnd) 
      // AddressOfFunctions is normaly in .text section and export table in .edata or .rdata section, so 
      // AddressOfFunctions must be not in Export Directory 
      printf("%4u %4u %08X %s\n", 
        pwOrdinals[iNames] + pExportDirectory->Base, iNames, pdwAddressOfFunctions[pwOrdinals[iNames]], 
        (pbyFile + pSectionHeader->PointerToRawData + pdwNameRVA[iNames] - pSectionHeader->VirtualAddress)); 
     else 
      printf("%4u %4u   %s (forwarded to %s)\n", 
        pwOrdinals[iNames] + pExportDirectory->Base, iNames, 
        (pbyFile + pSectionHeader->PointerToRawData + pdwNameRVA[iNames] - pSectionHeader->VirtualAddress), 
        (PSTR)(pbyFile + pSectionHeader->PointerToRawData + pdwAddressOfFunctions[pwOrdinals[iNames]] - pSectionHeader->VirtualAddress)); 
    } 

    // print functions exported by ordinal 
    for (i = 0; i < pExportDirectory->NumberOfFunctions; i++) { 
     if (pdwAddressOfFunctions[i] != 0) { 
      // if EXPORTS in DEF-file look like 
      // 
      // EXPORTS 
      // Message1 @100 
      // Message2 @200 
      // Message3 @300 
      // Message4 @400 
      // Message5 @500 
      // it will be added in export section 401 (500-100+1) entries. 5 from there with not 0 address and the rest 
      // empty entries with 0 
      // we will dump only not empty entries 

      UINT iNames; 
      WORD wOrdinal = (WORD)(i + pExportDirectory->Base); 

      // try to find (i + pExportDirectory->Base) ordinal in the list of pwOrdinals 
      for (iNames = 0; iNames<pExportDirectory->NumberOfNames; iNames++) { 
       if (pdwAddressOfFunctions[pwOrdinals[iNames]] == pdwAddressOfFunctions[i]) 
        break; 
      } 

      if (iNames >= pExportDirectory->NumberOfNames) { 
       // if not found as exported by name, print it here 
       MakeIdent(nOffset+1); 
       if (pdwAddressOfFunctions[i] < pSectionHeader->VirtualAddress || 
        pdwAddressOfFunctions[i] > pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize) 
        printf("%4u  %08X [NONAME]\n", wOrdinal, pdwAddressOfFunctions[i]); 
       else 
        printf("%4u    [NONAME] (forwarded to %s)\n", 
          wOrdinal, (PSTR)(pbyFile + pSectionHeader->PointerToRawData + pdwAddressOfFunctions[i] - pSectionHeader->VirtualAddress)); 
      } 
     } 
    } 
} 
+0

हैलो डॉ Kiriljuk; यह प्रभावशाली है! मुझे वास्तव में आपके प्रोग्राम की कोशिश करने के साथ-साथ इसके आउटपुट को घुमाने में भी पसंद आया। यह बहुत रोशनी है। मैं डीएलएल का पता लगाने के तरीकों की तलाश कर रहा हूं कि एक डीएलएल या EXE इसके स्थिर आईएटी में संग्रहीत किया गया है; उनके नाम से ज्यादा कुछ नहीं। मैंने देखा है कि मैंने कुछ EXEs को कच्चे में घुमाया है, मैं कभी-कभी डीएलएल नामों को देख सकता हूं, लेकिन मुझे इतना यकीन नहीं है कि यह पूर्ण-प्रमाण है। क्या आपको लगता है कि डीएलएल नामों के लिए रेगेक्स का उपयोग छोटे संकलित बाइनरी को पार करने के लिए एक सुरक्षित, बेवकूफ तरीका होगा, या क्या मुझे इसे सम्मेलन के करीब खेलना चाहिए? –

+1

@kayleeFrye_onDeck: मैं पिछले वर्षों से विषय से दूर हूं। मुझे लगता है कि पीई एक EXE या DLL है या नहीं, यह पता लगाने के लिए कोई 100% नियम नहीं है। फिर भी डीएलएल के पास 'IMAGE_FILE_HEADER' में 'IMAGE_FILE_DLL' ध्वज है और डीएलएल के पास खाली खाली अनुभाग नहीं है। – Oleg

+0

धन्यवाद, डॉ किरिलजुक। मुझे लगता है कि यह विंडोज़ आंतरिक में एक दिलचस्प पहली यात्रा होगी, हां! –

संबंधित मुद्दे