Comment puis-je déterminer si un assembly .NET a été créé pour x86 ou x64?


327

J'ai une liste arbitraire d'assemblys .NET.

Je dois vérifier par programme si chaque DLL a été créée pour x86 (par opposition à x64 ou à n'importe quel processeur). Est-ce possible?



2
Vous pouvez également consulter celui-ci: check-if-unmanaged-dll-is-32-bit-or-64-bit .
Matt

2
Dans une version ultérieure de CorFlags, correspondant à .NET 4.5, "32BIT" a été remplacé par "32BITREQ" et "32BITPREF". .
Peter Mortensen

Réponses:


281

Regarder System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

Vous pouvez examiner les métadonnées d'assembly à partir de l'instance AssemblyName retournée:

Utilisation de PowerShell :

[36] C: \> [réflexion.assemblyname] :: GetAssemblyName ("$ {pwd} \ Microsoft.GLEE.dll") | fl

Nom: Microsoft.GLEE
Version: 1.0.0.0
CultureInfo:
CodeBase: fichier: /// C: / projects / powershell / BuildAnalyzer / ...
EscapedCodeBase: fichier: /// C: / projets / powershell / BuildAnalyzer / ...
ProcesseurArchitecture: MSIL
Indicateurs: PublicKey
HashAlgorithm: SHA1
VersionCompatibility: SameMachine
KeyPair:
Nom complet: Microsoft.GLEE, Version = 1.0.0.0, Culture = neut ... 

Ici, ProcessorArchitecture identifie la plate-forme cible.

  • Amd64 : un processeur 64 bits basé sur l'architecture x64.
  • Arm : un processeur ARM.
  • IA64 : Un processeur Intel Itanium 64 bits uniquement.
  • MSIL : Neutre vis-à-vis du processeur et des bits par mot.
  • X86 : un processeur Intel 32 bits, natif ou dans l'environnement Windows sur Windows sur une plate-forme 64 bits (WOW64).
  • Aucun : une combinaison inconnue ou non spécifiée de processeur et de bits par mot.

J'utilise PowerShell dans cet exemple pour appeler la méthode.


60
Pardonnez la question stupide - mais qu'est-ce qui vous indique que c'est x86?
George Mauer

53
Le champ ProcessorArchitecture est une énumération; dans l'exemple ci-dessus, il est défini sur MSIL, ce qui signifie «neutre par rapport au processeur et aux bits par mot». Les autres valeurs incluent X86, IA64, Amd64. Voir msdn.microsoft.com/en-us/library/… pour plus de détails.
Brian Gillespie

4
Essayez avec [reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")car parfois le répertoire courant du processus n'est pas le même que celui du fournisseur actuel (c'est là que je suppose que la DLL est pour vous)
x0n

2
Une autre mise en garde à surveiller est d'oublier de "débloquer" la DLL si vous l'avez téléchargée à partir des internets. Utilisez unblock-file ou faites un clic droit sur / properties / unblock from explorer. Vous devrez redémarrer le shell pour qu'il reconnaisse l'état débloqué si vous avez déjà échoué une fois dans la session en cours (blâmez Internet Explorer pour cela - oui, vraiment.)
x0n

1
Dans le code ASP.NET MVC, il y a un commentaire // DevDiv 216459: This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in medium trust. However, Assembly.FullName *is* accessible in medium trust.Malheureusement, il n'y a aucun moyen de lire ProcessorArchitecture sans utiliser le GetName instance method; en utilisant AssemblyName constructor, le champ est toujours défini sur None.
métadonnées du

221

Vous pouvez utiliser l' outil CLI CorFlags (par exemple, C: \ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe) pour déterminer l'état d'un assembly, en fonction de sa sortie et de l'ouverture d'un assembly en tant que actif binaire, vous devriez être en mesure de déterminer où vous devez chercher pour déterminer si l'indicateur 32BIT est défini sur 1 ( x86 ) ou 0 ( tout processeur ou x64 , selon ):PE

Option    | PE    | 32BIT
----------|-------|---------
x86       | PE32  | 1
Any CPU   | PE32  | 0
x64       | PE32+ | 0

Le billet de blog Développement x64 avec .NET contient des informations sur corflags.

Encore mieux, vous pouvez utiliserModule.GetPEKind pour déterminer si un assembly est une PortableExecutableKindsvaleur PE32Plus(64 bits), Required32Bit(32 bits et WOW) ou ILOnly(n'importe quel CPU) avec d'autres attributs.


1
Après avoir vu votre mise à jour, utiliser GetPEKind semble être le bon moyen de le faire. J'ai marqué la vôtre comme réponse.
Judah Gabriel Himango

9
GetPEKind échoue dans un processus 64 bits lors de la vérification des assemblages 32 bits
jjxtra

2
Vous devez appeler GetPEKind à partir du processus 32 bits
Ludwo

2
J'installe VS 2008, VS 2010, VS 2012 et VS 2013. J'ai 8 fichiers CorFlags.exe dans des sous-dossiers dans C: \ Program Files (x86) \ Microsoft SDKs \ Windows \. Que dois-je utiliser?
Kiquenet

5
Comme indiqué dans cette réponse , dans .NET 4.5, il y a 32BITREQ et 32BITPREF au lieu de l'indicateur 32BIT. PE32 / 0/0 et PE32 / 0/1 sont respectivement AnyCPU et AnyCPU 32 bits préférés.
angularsen

141

Pour plus de précision, CorFlags.exe fait partie du SDK .NET Framework . J'ai les outils de développement sur ma machine, et le moyen le plus simple pour moi de déterminer si une DLL est 32 bits uniquement est de:

  1. Ouvrez l'invite de commandes de Visual Studio (sous Windows: menu Démarrer / Programmes / Microsoft Visual Studio / Visual Studio Tools / Visual Studio 2008 Command Prompt)

  2. CD dans le répertoire contenant la DLL en question

  3. Exécutez corflags comme ceci: corflags MyAssembly.dll

Vous obtiendrez quelque chose comme ceci:

Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  3.5.21022.8
Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32
CorFlags  : 3
ILONLY    : 1
32BIT     : 1
Signed    : 0

Selon les commentaires, les drapeaux ci-dessus doivent être lus comme suit:

  • N'importe quel CPU: PE = PE32 et 32BIT = 0
  • x86: PE = PE32 et 32BIT = 1
  • 64 bits: PE = PE32 + et 32BIT = 0

12
Cela semble avoir changé entre-temps; corflags s'affiche désormais 32BITREQet 32BITPREFnon plus une seule 32BITvaleur.
OR Mapper

1
Microsoft .NET 4.5 a introduit une nouvelle option, Any CPU 32-bit Preferred. Voici les détails.
RBT

L'invite de commande Visual Studio est aujourd'hui appelée " invite de commande développeur Visual Studio 2019 ".
Uwe Keim

22

Et si vous écriviez juste votre propre? Le cœur de l'architecture PE n'a pas été sérieusement modifié depuis sa mise en œuvre dans Windows 95. Voici un exemple C #:

    public static ushort GetPEArchitecture(string pFilePath)
    {
        ushort architecture = 0;
        try
        {
            using (System.IO.FileStream fStream = new System.IO.FileStream(pFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                using (System.IO.BinaryReader bReader = new System.IO.BinaryReader(fStream))
                {
                    if (bReader.ReadUInt16() == 23117) //check the MZ signature
                    {
                        fStream.Seek(0x3A, System.IO.SeekOrigin.Current); //seek to e_lfanew.
                        fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin); //seek to the start of the NT header.
                        if (bReader.ReadUInt32() == 17744) //check the PE\0\0 signature.
                        {
                            fStream.Seek(20, System.IO.SeekOrigin.Current); //seek past the file header,
                            architecture = bReader.ReadUInt16(); //read the magic number of the optional header.
                        }
                    }
                }
            }
        }
        catch (Exception) { /* TODO: Any exception handling you want to do, personally I just take 0 as a sign of failure */}
        //if architecture returns 0, there has been an error.
        return architecture;
    }
}

Maintenant, les constantes actuelles sont:

0x10B - PE32  format.
0x20B - PE32+ format.

Mais avec cette méthode, elle permet les possibilités de nouvelles constantes, il suffit de valider le retour comme bon vous semble.


1
Intéressant, merci pour le code avec explication. Module.GetPEKind est probablement le chemin le plus simple. Mais cela est utile pour l'apprentissage. Merci.
Judah Gabriel Himango

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

GetPEArchitecture fonctionne pour les assemblages compilés à l'aide de .net 3.5, 4.0, 4.5 et 4.5.1? Quoi qu'il en soit, je pense que Module.GetPEKind échoue dans un processus 64 bits lors de la vérification des assemblages 32 bits.
Kiquenet

9

Essayez d'utiliser CorFlagsReader de ce projet chez CodePlex . Il ne fait référence à aucun autre assemblage et peut être utilisé tel quel.


1
C'est la réponse la plus précise et la plus utile.
Kirill Osenkov

Le lien fonctionne toujours à ce jour, mais comme CodePlex est sur le point d'être fermé, il serait bon de prendre les mesures appropriées avant qu'il ne soit trop tard.
Peter Mortensen


6
[TestMethod]
public void EnsureKWLLibrariesAreAll64Bit()
{
    var assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies().Where(x => x.FullName.StartsWith("YourCommonProjectName")).ToArray();
    foreach (var assembly in assemblies)
    {
        var myAssemblyName = AssemblyName.GetAssemblyName(assembly.FullName.Split(',')[0] + ".dll");
        Assert.AreEqual(ProcessorArchitecture.MSIL, myAssemblyName.ProcessorArchitecture);
    }
}

Merci pour cela, Une de nos applications doit être construite en x86, l'ajout d'un test unitaire garantit que les bibliothèques de construction du serveur de construction seront à 32 bits et éviteront ces erreurs de se produire :)
Mido

5

Vous trouverez ci-dessous un fichier de commandes qui s'exécutera corflags.exesur tous dllset exesdans le répertoire de travail actuel et tous les sous-répertoires, analysera les résultats et afficher l'architecture cible de chacun.

Selon la version corflags.exeutilisée, les éléments de ligne dans la sortie incluront 32BIT, ou 32BITREQ (et 32BITPREF). Quel que soit l'un de ces deux éléments inclus dans la sortie, l'élément de campagne critique doit être vérifié pour différencier entre Any CPUet x86. Si vous utilisez une ancienne version de corflags.exe(avant Windows SDK v8.0A), seul l' 32BITélément de campagne sera présent dans la sortie, comme d'autres l'ont indiqué dans les réponses précédentes. Sinon 32BITREQet 32BITPREFremplacez-le.

Cela suppose qu'il se corflags.exetrouve dans le %PATH%. Le moyen le plus simple de garantir cela est d'utiliser a Developer Command Prompt. Vous pouvez également le copier depuis son emplacement par défaut .

Si le fichier de commandes ci-dessous est exécuté sur un dllou non géré exe, il l'affichera de manière incorrecte x86, car la sortie réelle de Corflags.exesera un message d'erreur similaire à:

corflags: erreur CF008: le fichier spécifié n'a pas d'en-tête géré valide

@echo off

echo.
echo Target architecture for all exes and dlls:
echo.

REM For each exe and dll in this directory and all subdirectories...
for %%a in (.exe, .dll) do forfiles /s /m *%%a /c "cmd /c echo @relpath" > testfiles.txt

for /f %%b in (testfiles.txt) do (
    REM Dump corflags results to a text file
    corflags /nologo %%b > corflagsdeets.txt

   REM Parse the corflags results to look for key markers   
   findstr /C:"PE32+">nul .\corflagsdeets.txt && (      
      REM `PE32+` indicates x64
        echo %%~b = x64
    ) || (
      REM pre-v8 Windows SDK listed only "32BIT" line item, 
      REM newer versions list "32BITREQ" and "32BITPREF" line items
        findstr /C:"32BITREQ  : 0">nul /C:"32BIT     : 0" .\corflagsdeets.txt && (
            REM `PE32` and NOT 32bit required indicates Any CPU
            echo %%~b = Any CPU
        ) || (
            REM `PE32` and 32bit required indicates x86
            echo %%~b = x86
        )
    )

    del corflagsdeets.txt
)

del testfiles.txt
echo.

2

Une autre façon serait d'utiliser la benne à partir des outils Visual Studio sur DLL et de rechercher la sortie appropriée

dumpbin.exe /HEADERS <your dll path>
    FILE HEADER VALUE
                 14C machine (x86)
                   4 number of sections
            5885AC36 time date stamp Mon Jan 23 12:39:42 2017
                   0 file pointer to symbol table
                   0 number of symbols
                  E0 size of optional header
                2102 characteristics
                       Executable
                       32 bit word machine
                       DLL

Remarque: ci-dessus o / p est pour une DLL 32 bits

Une autre option utile avec dumpbin.exe est / EXPORTS, il vous montrera la fonction exposée par la DLL

dumpbin.exe /EXPORTS <PATH OF THE DLL>

2

Méthode plus générique - utilisez la structure du fichier pour déterminer le type de témoin et d'image:

public static CompilationMode GetCompilationMode(this FileInfo info)
{
    if (!info.Exists) throw new ArgumentException($"{info.FullName} does not exist");

    var intPtr = IntPtr.Zero;
    try
    {
        uint unmanagedBufferSize = 4096;
        intPtr = Marshal.AllocHGlobal((int)unmanagedBufferSize);

        using (var stream = File.Open(info.FullName, FileMode.Open, FileAccess.Read))
        {
            var bytes = new byte[unmanagedBufferSize];
            stream.Read(bytes, 0, bytes.Length);
            Marshal.Copy(bytes, 0, intPtr, bytes.Length);
        }

        //Check DOS header magic number
        if (Marshal.ReadInt16(intPtr) != 0x5a4d) return CompilationMode.Invalid;

        // This will get the address for the WinNT header  
        var ntHeaderAddressOffset = Marshal.ReadInt32(intPtr + 60);

        // Check WinNT header signature
        var signature = Marshal.ReadInt32(intPtr + ntHeaderAddressOffset);
        if (signature != 0x4550) return CompilationMode.Invalid;

        //Determine file bitness by reading magic from IMAGE_OPTIONAL_HEADER
        var magic = Marshal.ReadInt16(intPtr + ntHeaderAddressOffset + 24);

        var result = CompilationMode.Invalid;
        uint clrHeaderSize;
        if (magic == 0x10b)
        {
            clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 208 + 4);
            result |= CompilationMode.Bit32;
        }
        else if (magic == 0x20b)
        {
            clrHeaderSize = (uint)Marshal.ReadInt32(intPtr + ntHeaderAddressOffset + 24 + 224 + 4);
            result |= CompilationMode.Bit64;
        }
        else return CompilationMode.Invalid;

        result |= clrHeaderSize != 0
            ? CompilationMode.CLR
            : CompilationMode.Native;

        return result;
    }
    finally
    {
        if (intPtr != IntPtr.Zero) Marshal.FreeHGlobal(intPtr);
    }
}

Énumération du mode de compilation

[Flags]
public enum CompilationMode
{
    Invalid = 0,
    Native = 0x1,
    CLR = Native << 1,
    Bit32 = CLR << 1,
    Bit64 = Bit32 << 1
}

Code source avec explication sur GitHub



1

Une autre façon de vérifier la plate-forme cible d'un assembly .NET consiste à inspecter l'assembly avec .NET Reflector ...

@ # ~ # € ~! Je viens de réaliser que la nouvelle version n'est pas gratuite! Donc, correction, si vous avez une version gratuite du réflecteur .NET, vous pouvez l'utiliser pour vérifier la plate-forme cible.


9
Utilisez ILSpy , c'est une application open source de base qui fait à peu près les mêmes choses que Reflector
Binary Worrier

1

cfeduke note la possibilité d'appeler GetPEKind. Il est potentiellement intéressant de le faire à partir de PowerShell.

Voici, par exemple, le code d'une applet de commande qui pourrait être utilisée: https://stackoverflow.com/a/16181743/64257

Alternativement, sur https://stackoverflow.com/a/4719567/64257, il est noté qu '"il existe également l'applet de commande Get-PEHeader dans les extensions de communauté PowerShell qui peut être utilisée pour tester des images exécutables".


1

Une application plus avancée pour cela vous pouvez trouver ici: CodePlex - ApiChange

Exemples:

C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\winhlp32.exe
File Name; Type; Size; Processor; IL Only; Signed
winhlp32.exe; Unmanaged; 296960; X86

C:\Downloads\ApiChange>ApiChange.exe -CorFlags c:\Windows\HelpPane.exe
File Name; Type; Size; Processor; IL Only; Signed
HelpPane.exe; Unmanaged; 733696; Amd64

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.