我有一个.NET程序集的任意列表。
我需要以编程方式检查每个DLL是否为x86(而不是x64或Any CPU)构建的。这可能吗?
我有一个.NET程序集的任意列表。
我需要以编程方式检查每个DLL是否为x86(而不是x64或Any CPU)构建的。这可能吗?
Answers:
看着 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: 代码库:file:/// C:/ projects / powershell / BuildAnalyzer / ... EscapedCodeBase:file:/// C:/ projects / powershell / BuildAnalyzer / ... 处理器架构:MSIL 标志:公钥 哈希算法:SHA1 版本兼容性:SameMachine 密钥对: FullName:Microsoft.GLEE,Version = 1.0.0.0,Culture = neut ...
在这里,ProcessorArchitecture标识目标平台。
在本示例中,我使用PowerShell来调用该方法。
[reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")
有时尝试使用该进程的当前目录与当前提供程序的目录不同(这是我认为DLL适合您的位置)
// 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.
可悲的是,如果不使用GetName instance method
; ,就无法读取ProcessorArchitecture 。使用时AssemblyName constructor
,该字段始终设置为None
。
您可以使用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
博客文章x64通过.NET开发具有有关.NET的一些信息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工具” /“ 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
值。
你自己写自己怎么样?自从Windows 95中实施以来,PE体系结构的核心并未发生重大变化。这是一个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;
}
}
现在,当前常量为:
0x10B - PE32 format.
0x20B - PE32+ format.
但是通过这种方法,它允许使用新的常量,只需根据需要验证返回值即可。
尝试从CodePlex的此项目中使用CorFlagsReader 。它没有引用其他程序集,可以按原样使用。
[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);
}
}
下面是将运行一个批处理文件,corflags.exe
对所有dlls
与exes
当前工作目录及其所有子目录,解析结果,并显示每个目标架构。
取决于版本corflags.exe
所使用,在输出线的项目将包括32BIT
,或 32BITREQ
(及32BITPREF
)。输出中包括这两者中的哪一个是关键行项目,必须对其进行检查以区分Any CPU
和x86
。如果您使用的是旧版corflags.exe
(Windows SDK v8.0A之前的版本),则32BIT
输出中将仅显示该订单项,如其他人在过去的答案中指出的那样。否则32BITREQ
,请32BITPREF
更换它。
假设corflags.exe
位于中%PATH%
。确保这一点的最简单方法是使用Developer Command Prompt
。另外,您也可以从默认位置复制它。
如果下面的批处理文件是针对非托管dll
或运行的exe
,它将错误地显示为x86
,因为的实际输出Corflags.exe
将是类似于以下内容的错误消息:
corflags:错误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.
另一种方法是在DLL上使用Visual Studio工具中的dumpbin并查找适当的输出
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
注意:以上o / p是针对32位dll的
dumpbin.exe的另一个有用选项是/ EXPORTS,它将向您显示dll公开的功能
dumpbin.exe /EXPORTS <PATH OF THE DLL>
更通用的方式-使用文件结构确定位数和图像类型:
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源代码
我已经克隆了一个超级方便的工具,该工具在Windows资源管理器中为程序集添加了一个上下文菜单项,以显示所有可用信息:
在这里下载:https : //github.com/tebjan/AssemblyInformation/releases
检查.NET程序集目标平台的另一种方法是使用.NET Reflector检查程序集 ...
@#〜#€〜!我刚刚意识到新版本不是免费的!因此,更正一下,如果您拥有.NET反射器的免费版本,则可以使用它来检查目标平台。
cfeduke指出了调用GetPEKind的可能性。从PowerShell执行此操作可能很有趣。
例如,以下是可使用的cmdlet的代码:https : //stackoverflow.com/a/16181743/64257
或者,在 https://stackoverflow.com/a/4719567/64257上注意到,“ PowerShell社区扩展中还有Get-PEHeader cmdlet ,可用于测试可执行映像。”
您可以在这里找到更高级的应用程序:CodePlex-ApiChange
例子:
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
已经提到的工具的替代方法是Telerik JustDecompile(免费工具),它将在程序集名称旁边显示信息: