2010-10-28 39 views

Répondre

4

PE Les exportations de fichiers

Le contraire de l'importation d'une fonction exporte une fonction pour une utilisation par d'autres ou EXEs DLL. Un fichier PE stocke des informations sur ses fonctions exportées dans la section .edata. Généralement, les fichiers PE EXE générés par les liens Microsoft n'exportent rien, donc ils n'ont pas de section .edata. TLINK32 de Borland exporte toujours au moins un symbole à partir d'un fichier EXE. La plupart des DLL exportent des fonctions et ont une section .edata. Les composants principaux d'une section .edata (alias table d'exportation) sont des tables de noms de fonctions, d'adresses de points d'entrée et de valeurs ordinales d'exportation. Dans un fichier NE, les équivalents d'une table d'exportation sont la table d'entrée, la table des noms résidents et la table des noms non résidents. Ces tables sont stockées dans l'en-tête NE, plutôt que dans des segments ou des ressources distincts.

Au début d'une section .edata se trouve une structure IMAGE_EXPORT_DIRECTORY (voir Tableau 10). Cette structure est immédiatement suivie de données pointées par des champs dans la structure.

Tableau 10. IMAGE_EXPORT_DIRECTORY Format

DWORD Characteristics 

Ce champ semble être utilisé et est toujours à 0.

DWORD TimeDateStamp 

Le timbre heure/date indiquant le moment où ce fichier a été créé.

WORD MajorVersion 
WORD MinorVersion 

Ces champs semblent être inutilisés et sont mis à 0.

DWORD Name 

La RVA d'une chaîne ASCIIZ avec le nom de cette DLL.

DWORD Base 

Numéro d'ordre de départ pour les fonctions exportées. Par exemple, si le fichier exporte des fonctions avec des valeurs ordinales de 10, 11 et 12, ce champ contient 10. Pour obtenir l'ordinal exporté d'une fonction, vous devez ajouter cette valeur à l'élément approprié du tableau AddressOfNameOrdinals.

DWORD NumberOfFunctions 

Le nombre d'éléments dans le tableau AddressOfFunctions. Cette valeur correspond également au nombre de fonctions exportées par ce module. Théoriquement, cette valeur peut être différente du champ NumberOfNames (suivant), mais en réalité, ils sont toujours les mêmes.

DWORD NumberOfNames 

Le nombre d'éléments dans le tableau AddressOfNames. Cette valeur semble toujours être identique au champ NumberOfFunctions, tout comme le nombre de fonctions exportées.

PDWORD *AddressOfFunctions 

Ce champ est un RVA et pointe vers un tableau d'adresses de fonctions. Les adresses de fonction sont les points d'entrée (RVA) pour chaque fonction exportée dans ce module.

PDWORD *AddressOfNames 

Ce champ est un RVA et pointe vers un tableau de pointeurs de chaîne. Les chaînes sont les noms des fonctions exportées dans ce module.

PWORD *AddressOfNameOrdinals 

Ce champ est un RVA et pointe vers un tableau de mots. Les WORD sont les ordinaux d'exportation de toutes les fonctions exportées dans ce module. Cependant, n'oubliez pas d'ajouter le nombre ordinal de départ spécifié dans le champ Base.

La disposition de la table d'exportation est quelque peu étrange (voir Figure 4 et Tableau 10). Comme je l'ai mentionné plus tôt, les exigences pour l'exportation d'une fonction sont un nom, une adresse et un ordinal d'exportation. On pourrait penser que les concepteurs du format PE auraient mis tous ces trois éléments dans une structure, et ensuite avoir un tableau de ces structures. Au lieu de cela, chaque composant d'une entrée exportée est un élément d'un tableau. Il y a trois de ces tableaux (AddressOfFunctions, AddressOfNames, AddressOfNameOrdinals), et ils sont tous parallèles les uns aux autres. Pour trouver toutes les informations sur la quatrième fonction, vous devez rechercher le quatrième élément de chaque tableau.

alt text

Figure 4. disposition de la table d'exportation

Tableau 11. Tableau Exportations typiques d'un fichier EXE

Name:   KERNEL32.dll 
    Characteristics: 00000000 
    TimeDateStamp: 2C4857D3 
    Version:   0.00 
    Ordinal base: 00000001 
    # of functions: 0000021F 
    # of Names:  0000021F 

    Entry Pt Ordn Name 
    00005090  1 AddAtomA 
    00005100  2 AddAtomW 
    00025540  3 AddConsoleAliasA 
    00025500  4 AddConsoleAliasW 
    00026AC0  5 AllocConsole 
    00001000  6 BackupRead 
    00001E90  7 BackupSeek 
    00002100  8 BackupWrite 
    0002520C  9 BaseAttachCompleteThunk 
    00024C50 10 BasepDebugDump 
    // Rest of table omitted... 

Soit dit en passant, si vous videz les exportations de la DLL système Windows NT (par exemple, KERNEL32.DLL et USER32.DLL), vous remarquerez que dans de nombreux cas, il existe deux fonctions qui ne diffèrent que par un caractère à la fin du nom, par exemple CreateWindowExA et CreateWindowExW. C'est ainsi que le support UNICODE est implémenté de manière transparente. Les fonctions qui se terminent par A sont les fonctions compatibles ASCII (ou ANSI), tandis que celles qui se terminent par W sont la version UNICODE de la fonction. Dans votre code, vous ne spécifiez pas explicitement quelle fonction appeler. Au lieu de cela, la fonction appropriée est sélectionnée dans WINDOWS.H, via le préprocesseur #ifdefs. Cet extrait du Windows NT WINDOWS.H montre un exemple de la façon dont cela fonctionne: Copy

#ifdef UNICODE 
#define DefWindowProc DefWindowProcW 
#else 
#define DefWindowProc DefWindowProcA 
#endif // !UNICODE 

// 
// Export Format 
// 

typedef struct _IMAGE_EXPORT_DIRECTORY { 
    DWORD Characteristics; 
    DWORD TimeDateStamp; 
    WORD MajorVersion; 
    WORD MinorVersion; 
    DWORD Name; 
    DWORD Base; 
    DWORD NumberOfFunctions; 
    DWORD NumberOfNames; 
    DWORD AddressOfFunctions;  // RVA from base of image 
    DWORD AddressOfNames;   // RVA from base of image 
    DWORD AddressOfNameOrdinals; // RVA from base of image 
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; 

EDIT: Dans le tableau des exportations de format PE n'est pas diffrent, adresse fonctions est une RVA d'adresse 64 bits uniquement.

Source:http://msdn.microsoft.com/en-us/library/ms809762.aspx

+1

+1 pour la longueur de la réponse :) –

+1

Merci beaucoup pour la réponse détaillée !! – Elad

+0

Avez-vous un morceau de code en C# qui fait cela? – Elad