2010-08-07 30 views
5

Bảng thunk liên quan đến bảng địa chỉ nhập được sử dụng trong các tệp EXE để nhập các hàm được sử dụng trong các tệp DLL bên ngoài là gì?Bảng nội dung trong bảng địa chỉ nhập?

Bảng thunk này chỉ là một bảng có chứa 'Thunks' với các chức năng khác?

+0

Một nơi tốt để bắt đầu: http://sandsprite.com/CodeStuff/Understanding_imports.html – quantumSoup

Trả lời

5

thunks là một phần của bảng nhập (IMAGE_DIRECTORY_ENTRY_IMPORT) và Delay Biểu thuế nhập khẩu (IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT). Chúng được mô tả http://msdn.microsoft.com/en-us/library/ms809762.aspx.

Tôi sẽ xem mã nguồn cũ của mình và sẽ đăng sau một mã làm việc để kết xuất cả hai bảng này bao gồm thông tin ràng buộc.

CẬP NHẬT:

Dưới đây là một mã mà tôi thích ở một trong những chương trình cũ của tôi. Nó chỉ hỗ trợ PE 32 bit, nhưng có thể dễ dàng sửa đổi thành 64-bit. Bằng cách này bạn có thể thấy, nó đổ cũng ràng buộc thông tin.Để kiểm tra này ràng buộc PE mà bạn muốn đổ với sự ràng buộc của bind.exe (sử dụng ví dụ, bind.exe -u -v Test.dll).

Mã này bao gồm từ khoảng 1000 dòng, vì vậy tôi không thể đăng ở đây. Tôi nhận được thông báo lỗi

Rất tiếc! Không thể gửi chỉnh sửa của bạn vì:

  • nội dung được giới hạn trong 30000 ký tự; bạn đã nhập 55095

Vì vậy, tôi đặt tại đây: http://www.ok-soft-gmbh.com/ForStackOverflow/PEInfo.c. Tôi hy vọng mã sẽ giúp bạn tốt hơn như một mô tả dài.

CẬP NHẬT 2: Tôi thấy câu trả lời cũ của tôi không tốt cho công cụ tìm kiếm. Vì vậy, tôi bao gồm các phần của mã của PEInfo.c (các chức năng DumpImportsDumpExports) dưới đây:

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

Xin chào Tiến sĩ Kiriljuk; ấn tượng đấy! Tôi thực sự thích thử chương trình của bạn, cũng như vượt qua đầu ra của nó. Nó khá sáng. Tôi đã tìm cách phát hiện các DLL mà một DLL hoặc EXE đã được tạo ra, được lưu trữ trong IAT tĩnh của nó; không có gì nhiều hơn tên của họ. Tôi đã nhận thấy rằng với một số EXE tôi đã đi qua trong nguyên, tôi có thể phát hiện tên DLL đôi khi, nhưng tôi không chắc chắn như vậy này là đầy đủ bằng chứng. Bạn có nghĩ rằng bằng cách sử dụng một regex cho tên DLL sẽ là một cách an toàn, câm để đi qua các tập nhỏ nhị phân biên soạn, hoặc tôi nên chơi nó gần hơn với quy ước? –

+1

@kayleeFrye_onDeck: Tôi xa chủ đề năm ngoái. Tôi nghĩ rằng không có quy tắc 100% nào để phát hiện xem PE là một EXE hay DLL. Tuy nhiên các tệp DLL thường có cờ 'IMAGE_FILE_DLL' trong' IMAGE_FILE_HEADER' và các tệp DLL có phần xuất không trống. – Oleg

+0

Cảm ơn bạn, Tiến sĩ Kiriljuk. Tôi có cảm giác đây sẽ là một chuyến đi đầu tiên thú vị vào Windows Internals, hah! –

Các vấn đề liên quan