145 votes

Comment trouver si un fichier DLL natif est compilé en x64 ou x86 ?

Je veux déterminer si une assembly native est compilée en x64 ou x86 à partir d'une application de code managé (C#).

Je pense que cela doit se trouver quelque part dans l'en-tête PE puisque le chargeur du système d'exploitation a besoin de cette information, mais je n'ai pas pu la trouver. Bien sûr, je préfère le faire en code managé, mais si nécessaire, je peux utiliser du C++ natif.

0 votes

Pour être clair, la dll en question est également une assembly .Net? Vous mentionnez une DLL native dans le titre du post, mais une assembly native dans la description... si vous regardez toujours activement ce post de 09 :)

1 votes

Vous voudrez peut-être aussi vérifier celui-ci: check-if-unmanaged-dll-is-32-bit-or-64-bit.

0 votes

147voto

Mark McDonald Points 2503

Vous pouvez également utiliser DUMPBIN. Utilisez le drapeau /headers ou /all et c'est le premier en-tête de fichier répertorié.

dumpbin /headers cv210.dll

64-bit

Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file cv210.dll

PE signature found

File Type: DLL

FILE HEADER VALUES
            8664 machine (x64)
               6 number of sections
        4BBAB813 time date stamp Tue Apr 06 12:26:59 2010
               0 file pointer to symbol table
               0 number of symbols
              F0 size of optional header
            2022 characteristics
                   Executable
                   Application can handle large (>2GB) addresses
                   DLL

32-bit

Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file acrdlg.dll

PE signature found

File Type: DLL

FILE HEADER VALUES
             14C machine (x86)
               5 number of sections
        467AFDD2 time date stamp Fri Jun 22 06:38:10 2007
               0 file pointer to symbol table
               0 number of symbols
              E0 size of optional header
            2306 characteristics
                   Executable
                   Line numbers stripped
                   32 bit word machine
                   Debug information stripped
                   DLL

'find' peut rendre la vie un peu plus facile:

dumpbin /headers cv210.dll |find "machine"
        8664 machine (x64)

4 votes

Un peu plus convivial pour les utilisateurs ;)

4 votes

DUMPBIN ne fonctionne pas pour les EXE .NET. J'ai un EXE .NET 64 bits que DUMPBIN indique comme étant 32 bits ("machine 14C (x86)"), mais corflags le considère comme étant Any CPU ("PE: PE32, 32BIT: 0"). Dependency Walker fait également un diagnostic erroné.

2 votes

Il nécessitait mspdb100.dll :(

59voto

BLogan Points 416

Il existe une manière simple de le faire avec CorFlags. Ouvrez l'invite de commandes Visual Studio et tapez "corflags [votre assembly]". Vous obtiendrez quelque chose comme ceci :

c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC>corflags "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll"

Microsoft (R) .NET Framework CorFlags Outil de conversion. Version 3.5.21022.8 Droits d'auteur (c) Microsoft Corporation. Tous droits réservés.

Version : v2.0.50727 En-tête CLR : 2.5 PE : PE32 CorFlags : 24 ILONLY : 0 32BIT : 0 Signé : 1

Vous regardez en particulier PE et 32BIT.

  • Any CPU:

    PE: PE32
    32BIT: 0

  • x86:

    PE: PE32
    32BIT: 1

  • x64:

    PE: PE32+
    32BIT: 0

22 votes

@BLogan vous devriez regarder mon commentaire à Steven Behnke ci-dessus. Je suis au courant de l'utilitaire corflags mais il ne fonctionne pas sur les assemblies natifs.

9 votes

Ce que Corflags produit a changé dans les versions ultérieures (Windows SDK 8 ou supérieur). Maintenant, au lieu de 32BIT, il y a 32BITREQUIRED et 32BITPREFERRED. Voir la description dans CorHdr.h situé à C:\Program Files (x86)\Windows Kits\8.0\Include\um\CorHdr.h. D'après ce que je peux dire, 32BITREQUIRED remplace 32BIT. Voir également la réponse à cette question.

27voto

Jason Larke Points 2305

Le champ Magic du IMAGE_OPTIONAL_HEADER (bien que le header des images exécutables Windows (fichiers DLL/EXE) ne soit en réalité pas optionnel) vous donnera l'architecture du PE.

Voici un exemple pour récupérer l'architecture à partir d'un fichier.

public static ushort GetImageArchitecture(string filepath) {
    using (var stream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
    using (var reader = new System.IO.BinaryReader(stream)) {
        // Vérifier la signature MZ pour s'assurer qu'il s'agit d'une image exécutable Portable valide
        if (reader.ReadUInt16() != 23117) 
            throw new BadImageFormatException("Pas une image exécutable Portable valide", filepath);

        // rechercher, puis lire, e_lfanew puis avancer le flux jusqu'à cet endroit (début de l'en-tête NT)
        stream.Seek(0x3A, System.IO.SeekOrigin.Current); 
        stream.Seek(reader.ReadUInt32(), System.IO.SeekOrigin.Begin);

        // Assurer que l'en-tête NT est valide en vérifiant la signature "PE\0\0"
        if (reader.ReadUInt32() != 17744)
            throw new BadImageFormatException("Pas une image exécutable Portable valide", filepath);

        // passer l'en-tête de fichier, puis lire le numéro magique de l'en-tête optionnel
        stream.Seek(20, System.IO.SeekOrigin.Current); 
        return reader.ReadUInt16();
    }
}

Les seules constantes d'architecture actuelles sont :

0x10b - PE32
0x20b - PE32+

Santé

MISE À JOUR Cela fait un moment que j'ai posté cette réponse, mais je vois qu'elle reçoit encore quelques votes de temps en temps, donc j'ai pensé qu'elle valait la peine d'être mise à jour. J'ai écrit un moyen d'obtenir l'architecture d'une image Portable Executable, qui vérifie également si elle a été compilée en AnyCPU. Malheureusement, la réponse est en C++, mais il ne devrait pas être trop difficile de la porter en C# si vous avez quelques minutes pour rechercher les structures dans WinNT.h. Si les gens sont intéressés, j'écrirai une version en C#, mais à moins que les gens ne le veuillent vraiment, je ne passerai pas beaucoup de temps à m'en préoccuper.

#include 

#define MKPTR(p1,p2) ((DWORD_PTR)(p1) + (DWORD_PTR)(p2))

typedef enum _pe_architecture {
    PE_ARCHITECTURE_UNKNOWN = 0x0000,
    PE_ARCHITECTURE_ANYCPU  = 0x0001,
    PE_ARCHITECTURE_X86     = 0x010B,
    PE_ARCHITECTURE_x64     = 0x020B
} PE_ARCHITECTURE;

LPVOID GetOffsetFromRva(IMAGE_DOS_HEADER *pDos, IMAGE_NT_HEADERS *pNt, DWORD rva) {
    IMAGE_SECTION_HEADER *pSecHd = IMAGE_FIRST_SECTION(pNt);
    for(unsigned long i = 0; i < pNt->FileHeader.NumberOfSections; ++i, ++pSecHd) {
        // Rechercher quelle section contient cette RVA pour traduire l'adresse VA en un décalage de fichier
        if (rva >= pSecHd->VirtualAddress && rva < (pSecHd->VirtualAddress + pSecHd->Misc.VirtualSize)) {
            DWORD delta = pSecHd->VirtualAddress - pSecHd->PointerToRawData;
            return (LPVOID)MKPTR(pDos, rva - delta);
        }
    }
    return NULL;
}

PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) {
    // Analyser et valider l'en-tête DOS
    IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER*)pImageBase;
    if (IsBadReadPtr(pDosHd, sizeof(pDosHd->e_magic)) || pDosHd->e_magic != IMAGE_DOS_SIGNATURE)
        return PE_ARCHITECTURE_UNKNOWN;

    // Analyser et valider l'en-tête NT
    IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS*)MKPTR(pDosHd, pDosHd->e_lfanew);
    if (IsBadReadPtr(pNtHd, sizeof(pNtHd->Signature)) || pNtHd->Signature != IMAGE_NT_SIGNATURE)
        return PE_ARCHITECTURE_UNKNOWN;

    // Première vérification naive basée sur le numéro 'Magic' dans l'en-tête optionnel.
    PE_ARCHITECTURE architecture = (PE_ARCHITECTURE)pNtHd->OptionalHeader.Magic;

    // Si l'architecture est x86, il y a encore une possibilité que l'image soit 'AnyCPU'
    if (architecture == PE_ARCHITECTURE_X86) {
        IMAGE_DATA_DIRECTORY comDirectory = pNtHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
        if (comDirectory.Size) {
            IMAGE_COR20_HEADER *pClrHd = (IMAGE_COR20_HEADER*)GetOffsetFromRva(pDosHd, pNtHd, comDirectory.VirtualAddress);
            // Vérifier si l'en-tête CLR contient le drapeau 32BITONLY, sinon l'image est en réalité AnyCpu
            if ((pClrHd->Flags & COMIMAGE_FLAGS_32BITREQUIRED) == 0)
                architecture = PE_ARCHITECTURE_ANYCPU;
        }
    }

    return architecture;
}

La fonction accepte un pointeur vers une image PE en mémoire (donc vous pouvez choisir votre méthode pour y accéder ; mapping en mémoire ou lecture de l'ensemble en mémoire...peu importe).

0 votes

Très intéressant mais lorsque j'ai une application compilée avec Any CPU, le résultat est 0x10B. C'est faux car mon application s'exécute dans un système x64. Y a-t-il un autre drapeau à vérifier?

4 votes

AnyCPU signifie exactement cela : AnyCPU, il est donc répertorié comme 0x10B dans l'en-tête PE pour assurer la compatibilité ascendante avec le 32 bits. Pour vérifier la différence entre cela et le simple 32 bits, vous devriez trouver d'où provient le drapeau 32BIT dans le PE, je ne le sais pas de mémoire.

0 votes

@JasonLarke Je suis arrivé ici grâce à une recherche sur Google et votre extrait de code m'a beaucoup aidé. Merci beaucoup!

14voto

ShuggyCoUk Points 24204

Pour un fichier DLL non géré, vous devez d'abord vérifier s'il s'agit d'un fichier DLL 16 bits (j'espère que non). Ensuite, vérifiez le champ IMAGE\_FILE_HEADER.Machine.

Quelqu'un d'autre a pris le temps de résoudre cela déjà, donc je vais simplement répéter ici :

Pour distinguer entre un fichier PE 32 bits et 64 bits, vous devriez vérifier le champ IMAGE\_FILE\_HEADER.Machine. Sur la spécification Microsoft PE et COFF ci-dessous, j'ai listé toutes les valeurs possibles pour ce champ : http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/pecoff_v8.doc

const

valeur

descr

IMAGE_FILE_MACHINE_UNKNOWN

0x0

Le contenu de ce champ est supposé être applicable à tout type de machine

IMAGE_FILE_MACHINE_AM33

0x1d3

Matsushita AM33

IMAGE_FILE_MACHINE_AMD64

0x8664

x64

IMAGE_FILE_MACHINE_ARM

0x1c0

ARM little endian

IMAGE_FILE_MACHINE_EBC

0xebc

EFI byte code

IMAGE_FILE_MACHINE_I386

0x14c

Processeurs Intel 386 ou ultérieurs et processeurs compatibles

IMAGE_FILE_MACHINE_IA64

0x200

Famille de processeurs Intel Itanium

IMAGE_FILE_MACHINE_M32R

0x9041

Mitsubishi M32R little endian

IMAGE_FILE_MACHINE_MIPS16

0x266

MIPS16

IMAGE_FILE_MACHINE_MIPSFPU

0x366

MIPS avec FPU

IMAGE_FILE_MACHINE_MIPSFPU16

0x466

MIPS16 avec FPU

IMAGE_FILE_MACHINE_POWERPC

0x1f0

Power PC little endian

IMAGE_FILE_MACHINE_POWERPCFP

0x1f1

Power PC avec support des nombres à virgule flottante

IMAGE_FILE_MACHINE_R4000

0x166

MIPS little endian

IMAGE_FILE_MACHINE_SH3

0x1a2

Hitachi SH3

IMAGE_FILE_MACHINE_SH3DSP

0x1a3

Hitachi SH3 DSP

IMAGE_FILE_MACHINE_SH4

0x1a6

Hitachi SH4

IMAGE_FILE_MACHINE_SH5

0x1a8

Hitachi SH5

IMAGE_FILE_MACHINE_THUMB

0x1c2

Thumb

IMAGE_FILE_MACHINE_WCEMIPSV2

0x169

MIPS little-endian WCE v2

Oui, vous pouvez vérifier IMAGE\_FILE\_MACHINE_AMD64|IMAGE\_FILE\_MACHINE_IA64 pour 64 bits et IMAGE\_FILE\_MACHINE_I386 pour 32 bits.

0 votes

Votre deuxième lien est mort :s

5voto

yoyoyoyosef Points 2311

Vous pouvez trouver une implementation d'exemple C# ici pour la solution IMAGE_FILE_HEADER

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X