2010-08-07 9 views
5

¿Qué es una tabla de procesador en relación con la tabla de direcciones de importación que se utiliza en los archivos EXE para importar funciones utilizadas en archivos DLL externos?¿Tabla de acceso en la tabla de direcciones de importación?

¿Es esta tabla thunk solo una tabla que contiene 'Thunks' para otras funciones?

+0

Un buen lugar para empezar: http://sandsprite.com/CodeStuff/Understanding_imports.html – quantumSoup

Respuesta

5

Thunks son una parte de la tabla de importación (IMAGE_DIRECTORY_ENTRY_IMPORT) y Delay Tabla Importación (IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT). Se describen http://msdn.microsoft.com/en-us/library/ms809762.aspx.

Miraré mi código fuente anterior y publicaré más tarde un código de trabajo que arrojará ambas tablas incluyendo información vinculante.

Actualizado:

Aquí es un código que me gustan en una de mi viejo programa. Solo admite PE de 32 bits, pero puede modificarse fácilmente a 64 bits. Por cierto, puede ver que también descarga información vinculante. Para probar esto, vincule el archivo PE que desea volcar con respecto a bind.exe (use por ejemplo, bind.exe -u -v Test.dll).

El código consta de aproximadamente 1000 líneas, por lo que no pude publicarlo aquí. Recibo un mensaje de error

¡Vaya! No se pudo enviar su edición porque:

  • cuerpo está limitado a 30000 caracteres; usted ingresó 55095

Así que lo puse aquí: http://www.ok-soft-gmbh.com/ForStackOverflow/PEInfo.c. Espero que el código te ayude mejor como una descripción larga.

ACTUALIZADO 2: Veo que mi respuesta anterior no es buena para la búsqueda del motor. Por lo que incluye la parte del código de PEInfo.c (las funciones y DumpImportsDumpExports) a continuación:

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

Hola Dr. Kiriljuk; ¡Eso es impresionante! Realmente me gustó probar tu programa, así como atravesar su salida. Es bastante iluminador. He estado buscando formas de detectar archivos DLL con los que se ha creado un archivo DLL o EXE, almacenados en su IAT estático; nada más que sus nombres. Me he dado cuenta de que con algunos de los EXEs que he cruzado en bruto, puedo detectar nombres de DLL ocasionalmente, pero no estoy tan seguro de que esto sea a prueba completa. ¿Crees que usar una expresión regular para los nombres de DLL sería una forma segura y tonta de recorrer pequeños binarios compilados, o debería jugar más cerca de la convención? –

+1

@kayleeFrye_onDeck: estoy lejos del tema de los últimos años. Creo que no hay una regla del 100% para detectar si un PE es un EXE o DLL. Sin embargo, las DLL tienen típicamente el indicador 'IMAGE_FILE_DLL' en' IMAGE_FILE_HEADER' y las DLL tienen una sección de exportación no vacía. – Oleg

+0

Gracias, Dr. Kiriljuk. Tengo la sensación de que este será un viaje inaugural interesante en Windows Internals, ¡ja! –

Cuestiones relacionadas