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?
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?
Réponses:
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.
J'utilise PowerShell dans cet exemple pour appeler la méthode.
[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)
// 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
.
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 PortableExecutableKinds
valeur PE32Plus
(64 bits), Required32Bit
(32 bits et WOW) ou ILOnly
(n'importe quel CPU) avec d'autres attributs.
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:
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)
CD dans le répertoire contenant la DLL en question
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:
32BITREQ
et 32BITPREF
non plus une seule 32BIT
valeur.
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.
Essayez d'utiliser CorFlagsReader de ce projet chez CodePlex . Il ne fait référence à aucun autre assemblage et peut être utilisé tel quel.
[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);
}
}
Vous trouverez ci-dessous un fichier de commandes qui s'exécutera corflags.exe
sur tous dlls
et exes
dans 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.exe
utilisé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 CPU
et 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 32BITREQ
et 32BITPREF
remplacez-le.
Cela suppose qu'il se corflags.exe
trouve 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 dll
ou non géré exe
, il l'affichera de manière incorrecte x86
, car la sortie réelle de Corflags.exe
sera 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.
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>
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
J'ai cloné un outil super pratique qui ajoute une entrée de menu contextuel pour les assemblages dans l'explorateur Windows pour afficher toutes les informations disponibles:
Téléchargez ici: https://github.com/tebjan/AssemblyInformation/releases
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.
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".
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
Une alternative aux outils déjà mentionnés est Telerik JustDecompile (outil gratuit) qui affichera les informations à côté du nom de l'assembly: