如何确定.NET程序集是为x86还是x64生成的?
我有一个任意的.NET程序集列表 我需要以编程方式检查每个DLL是否是为x86(而不是x64或任何CPU)构建的。这是否可行?您可以使用该工具(例如,C:\Program Files\Microsoft SDK\Windows\v7.0\Bin\CorFlags.exe)根据程序集的输出和以二进制资源打开程序集来确定程序集的状态。您应该能够确定需要在何处查找以确定32位标志设置为1(x86)还是0(任何CPU或x64,取决于如何确定.NET程序集是为x86还是x64生成的?,.net,assemblies,x86,64-bit,x86-64,.net,Assemblies,X86,64 Bit,X86 64,我有一个任意的.NET程序集列表 我需要以编程方式检查每个DLL是否是为x86(而不是x64或任何CPU)构建的。这是否可行?您可以使用该工具(例如,C:\Program Files\Microsoft SDK\Windows\v7.0\Bin\CorFlags.exe)根据程序集的输出和以二进制资源打开程序集来确定程序集的状态。您应该能够确定需要在何处查找以确定32位标志设置为1(x86)还是0(任何CPU或x64,取决于PE): 这篇博文中有一些关于corflags的信息 更好的是,您可以确
PE
):
这篇博文中有一些关于corflags的信息
更好的是,您可以确定一个程序集是
portableexecutabletypes
valuePE32Plus
(64位)、Required32Bit
(32位和WOW),还是ILOnly
(任何CPU)以及其他属性。查看System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)
您可以从返回的AssemblyName实例检查程序集元数据:
使用PowerShell:
[36] C:\> [reflection.assemblyname]::GetAssemblyName("${pwd}\Microsoft.GLEE.dll") | fl
Name : Microsoft.GLEE
Version : 1.0.0.0
CultureInfo :
CodeBase : file:///C:/projects/powershell/BuildAnalyzer/...
EscapedCodeBase : file:///C:/projects/powershell/BuildAnalyzer/...
ProcessorArchitecture : MSIL
Flags : PublicKey
HashAlgorithm : SHA1
VersionCompatibility : SameMachine
KeyPair :
FullName : Microsoft.GLEE, Version=1.0.0.0, Culture=neut...
[36]C:\>[reflection.assemblyname]::GetAssemblyName(“${pwd}\Microsoft.GLEE.dll”)| fl
名称:Microsoft.GLEE
版本:1.0.0.0
文化资讯:
代码库:file:///C:/projects/powershell/BuildAnalyzer/...
转义代码库:file:///C:/projects/powershell/BuildAnalyzer/...
处理器架构:MSIL
标志:公钥
哈希算法:SHA1
版本兼容性:同一台机器
密钥对:
全名:Microsoft.GLEE,版本=1.0.0.0,区域性=neut。。。
这里,标识目标平台
- Amd64:基于x64体系结构的64位处理器
- Arm:一种Arm处理器
- IA64:仅限64位英特尔安腾处理器
- MSIL:与处理器和每个字的位无关
- X86:32位英特尔处理器,本机或在64位平台(WOW64)上的Windows on Windows环境中
- 无:处理器和每个字的位的未知或未指定的组合
在本例中,我使用PowerShell调用该方法。为了澄清,CorFlags.exe是的一部分。我的机器上有开发工具,确定DLL是否仅为32位的最简单方法是:
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
根据注释,上述标志应如下所示:
- 任意CPU:PE=PE32,32位=0
- x86:PE=PE32,32位=1
- 64位:PE=PE32+和32位=0
@#~#€~!我刚刚意识到新版本不是免费的!因此,更正一下,如果你有一个免费版本的.NET reflector,你可以用它来检查目标平台。你自己写怎么样?PE体系结构的核心自在Windows 95中实现以来没有发生过重大变化。下面是一个C#示例: 现在,当前常数为:
0x10B - PE32 format.
0x20B - PE32+ format.
但是,使用此方法,它允许使用新常量,只需验证您认为合适的返回值。尝试使用CorFlagsReader。它没有对其他程序集的引用,可以按原样使用。cfeduke注意到调用GetPEKind的可能性。从PowerShell执行此操作可能会很有趣 例如,下面是可以使用的cmdlet的代码:
或者,注意到“中还有Get-PEHeader cmdlet,可用于测试可执行映像。”下面是一个批处理文件,它将针对当前工作目录和所有子目录中的所有
DLL
和exe
运行corflags.exe
,分析结果并显示每个目录的目标体系结构
根据所使用的corflags.exe
版本,输出中的行项目将包括32BIT
,或32BITREQ
(和32bitref
)。输出中包含的这两项中的任何一项都是必须检查的关键行项目,以区分任何CPU
和x86
。如果您使用的是较旧版本的corflags.exe
(Windows SDK v8.0A之前版本),则只有32BIT
行项目将出现在输出中,正如其他人在过去的回答中所指出的那样。否则32BITREQ
和32bitref
将其替换
这假设corflags.exe
位于%PATH%
中。确保这一点的最简单方法是使用开发人员命令提示符
。或者,您可以从它的
如果下面的批处理文件是针对非托管的dll
或exe
运行的,它将错误地将其显示为x86
,因为Corflags.exe
的实际输出将是一条类似于以下内容的错误消息:
corflags:错误CF008:指定的文件没有有效的托管标头
您可以在此处找到更高级的应用程序: 示例:
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
另一种方法是在DLL上使用VisualStudioTools中的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
dumpbin.exe/HEADERS
文件头值
14C机器(x86)
4节数
5885AC36时间日期戳2017年1月23日星期一12:39:42
0指向符号表的文件指针
0符号数
[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);
}
}
@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.
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
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
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
}
// linq2db, Version=3.0.0.0, Culture=neutral, PublicKeyToken=e41013125f9e410a
// Global type: <Module>
// Architecture: AnyCPU (64-bit preferred)
// Runtime: v4.0.30319
// This assembly is signed with a strong name key.
// This assembly was compiled using the /deterministic option.
// Hash algorithm: SHA1