我有一个任意的.NET程序集列表。
我需要编程方式检查每个DLL是否是为x86构建的(而不是x64或Any CPU)。这是否可能?
我有一个任意的.NET程序集列表。
我需要编程方式检查每个DLL是否是为x86构建的(而不是x64或Any CPU)。这是否可能?
看一下System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
。
你可以从返回的AssemblyName实例中查看程序集元数据:
使用PowerShell:
[36] C:\> [reflection.assemblyname]::GetAssemblyName("${pwd}\Microsoft.GLEE.dll") | fl
名称 : Microsoft.GLEE 版本 : 1.0.0.0 CultureInfo : CodeBase : file:///C:/projects/powershell/BuildAnalyzer/... EscapedCodeBase : file:///C:/projects/powershell/BuildAnalyzer/... 处理器架构 : MSIL 标志 : PublicKey 哈希算法 : SHA1 版本兼容性 : SameMachine KeyPair : 完整名称 : Microsoft.GLEE, Version=1.0.0.0, Culture=neut...
在这里,ProcessorArchitecture标识目标平台。
我在这个例子中使用PowerShell调用了该方法。
Exception calling "GetAssemblyName" with "1" argument(s): "Could not load file or assembly '[DLLName].dll' or one of its dependencies. The system cannot find the file specified."
(是的,我已经正确拼写了它)。 - PeterX[reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")
。 - x0n您可以使用CorFlags CLI工具(例如,C:\ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe)来确定程序集的状态,根据其输出和将程序集作为二进制资产打开,您应该能够确定需要查找的位置,以确定32BIT标志是否设置为1(x86)或0(任何CPU或x64,取决于PE
):
Option | PE | 32BIT
----------|-------|---------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0
博客文章使用.NET进行x64开发提供了一些关于corflags
的信息。
更好的是,您可以使用Module.GetPEKind
确定程序集是否为PortableExecutableKinds
值PE32Plus
(64位)、Required32Bit
(32位和WoW)或ILOnly
(任何CPU),以及其他属性。
仅作澄清,CorFlags.exe是.NET Framework SDK的一部分。我在我的机器上安装了开发工具,最简单的方法来确定一个DLL是否只支持32位是:
打开Visual Studio命令提示符(在Windows中:开始菜单/程序/Microsoft Visual Studio/Visual Studio Tools/Visual Studio 2008命令提示符)
CD到包含所询问的DLL的目录
像这样运行corflags:corflags MyAssembly.dll
你将会得到类似于以下的输出:
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
根据评论,上面的标志应该被解读如下:
32BITREQ
和32BITPREF
,而不是单独的32BIT
值。 - O. R. Mapper请自己编写。PE体系结构的核心自 Windows 95 实施以来并没有发生过重大改变。
以下是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))
{
// Check the MZ signature
if (bReader.ReadUInt16() == 23117)
{
// Seek to e_lfanew.
fStream.Seek(0x3A, System.IO.SeekOrigin.Current);
// Seek to the start of the NT header.
fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin);
if (bReader.ReadUInt32() == 17744) // Check the PE\0\0 signature.
{
// Seek past the file header,
fStream.Seek(20, System.IO.SeekOrigin.Current);
// Read the magic number of the optional header.
architecture = bReader.ReadUInt16();
}
}
}
}
}
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;
}
}
0x10B - PE32 format.
0x20B - PE32+ format.
但是使用这种方法可以允许新常量的可能性。只需根据需要验证返回值即可。
尝试使用来自CodePlex项目的CorFlagsReader。它没有对其他程序集的引用,可以直接使用。
corflags : error CF008 : 指定的文件没有有效的托管标头
@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.
[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);
}
}
一种更通用的方法是使用文件结构来确定位数和图像类型:
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);
}
}
[Flags]
public enum CompilationMode
{
Invalid = 0,
Native = 0x1,
CLR = Native << 1,
Bit32 = CLR << 1,
Bit64 = Bit32 << 1
}
源代码及其解释,请查看GitHub。