2010-08-07 10 views
5

Che cos'è una tabella thunk in relazione alla tabella degli indirizzi di importazione utilizzata nei file EXE per importare le funzioni utilizzate nelle DLL esterne?Tabella thunk nella tabella degli indirizzi di importazione?

Questa tabella thunk è solo una tabella che contiene "Thunks" per altre funzioni?

+0

Un buon punto di partenza: http://sandsprite.com/CodeStuff/Understanding_imports.html – quantumSoup

risposta

5

Thunk sono una parte della tabella Importa (IMAGE_DIRECTORY_ENTRY_IMPORT) e Delay Importa tabella (IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT). Sono descritti http://msdn.microsoft.com/en-us/library/ms809762.aspx.

Guarderò il mio vecchio codice sorgente e pubblicherò in seguito un codice funzionante che consente di scaricare entrambe le tabelle includendo informazioni di associazione.

aggiornamento:

Ecco un codice che ho appassionato in uno dei miei vecchio programma. Supporta solo PE a 32 bit, ma può essere facilmente modificato a 64 bit. Dal modo in cui si può vedere, che si scaricano anche informazioni vincolanti. Per testare questo bind il PE che si desidera eseguire il dump in relazione a bind.exe (utilizzare ad esempio, bind.exe -u -v Test.dll).

Il codice è composto da circa 1000 righe, quindi non ho potuto postarlo qui. Ricevo un messaggio di errore

Oops! La tua modifica non può essere inviata perché:

  • il corpo è limitato a 30000 caratteri; immesso 55095

Così ho messo qui: http://www.ok-soft-gmbh.com/ForStackOverflow/PEInfo.c. Spero che il codice ti aiuterà meglio come una lunga descrizione.

AGGIORNATO 2: Vedo che la mia vecchia risposta non va bene per la ricerca del motore. Così ho comprende la parte del codice di PEInfo.c (le funzioni DumpImports e DumpExports) al di sotto:

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

Ciao Dr. Kiriljuk; è impressionante! Mi è davvero piaciuto provare il tuo programma, oltre che attraversare la sua uscita. È abbastanza illuminante. Ho cercato modi di rilevare DLL con cui è stata creata una DLL o EXE, memorizzata nel suo IAT statico; Nient'altro che i loro nomi. Ho notato che con alcuni degli EXE che ho attraversato in raw, posso individuare i nomi delle DLL occasionalmente, ma non sono così sicuro che questo sia a prova di tutto. Pensi che l'uso di un'espressione regolare per i nomi DLL sia un modo sicuro e stupido per attraversare piccoli binari compilati o dovrei giocare più vicino alla convenzione? –

+1

@kayleeFrye_onDeck: Sono lontano dall'argomento degli ultimi anni. Penso che non ci sia una regola del 100% per rilevare se un PE è un EXE o una DLL. Tuttavia le DLL hanno in genere il flag "IMAGE_FILE_DLL' in" IMAGE_FILE_HEADER' e le DLL hanno una sezione di esportazione non vuota. – Oleg

+0

Grazie, dott. Kiriljuk. Ho la sensazione che questo sarà un interessante viaggio inaugurale in Windows Internals, hah! –

Problemi correlati