

如何判断一个 Dot Net 程序是 32 位还是 64 位?
source link: https://bianchengnan.gitee.io/articles/how-to-check-a-dot-net-program-is-32-or-64/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前阵子,朋友遇到一个 .net
程序启动不起来的问题。根据之前的经验,一般是依赖的动态库加载失败导致的。或者找不到(依赖的动态库没有放到相应的目录下,一般放到应用程序所在目录即可),或者不匹配(64
位的程序加载 32
位的动态库,或者 32
位的程序加载 64
位的动态库)。整个排查过程并不复杂,本文不打算介绍整个排查过程,而是想介绍一些 .net
程序的基本常识(比如,以 Any CPU
编译出来的程序,是 32
位的还是 64
位的?),还会介绍几个我认为不错的查看工具。
在介绍查看方法之前,先介绍一些基本常识。
Any CPU
做过 .net
开发的小伙伴一定接触过 Any CPU
,新建一个 c#
测试工程,默认的编译选项就是这个。
目标平台(G)
和 首选 32 位(P)
两个选项共同决定了传递给 csc.exe
的 /platform
选项的值。
在目标平台(G)
是 Any CPU
的情况下,如果勾选了 首选 32 位(P)
,那么 /platform
的值是 anycpu32bitpreferred
,如果未勾选,那么 /platform
的值是 anycpu
。
说明:
首选 32 位(P)
选项在dll
工程中不允许修改。虽然编译的时候不能改,但是我们可以手动修改编译后的文件。:)
/platform
选项对生成的模块的影响以及在运行时的影响,参考下表:
说明:以上表格摘录自 《CLR via c#》(第4版)第一章
PE 头相关字段
一般,一个标准的 PE
文件由四大部分组成: DOS
头,PE
头,节表,节内容。这里只关心 PE
头中相关字段。
32
位 PE
头定义如下:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
其中,Signature
的内容是 PE\0\0
,非常好认。
FileHeader
对应的结构体定义如下:
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
Machine
,对于32
位程序,这个值一般是0x14c
,对于64
位程序一般是0x8664
。但对于.net
程序,不能以此字段作为判断依据。
OptionalHeader
对应的结构体定义如下:
typedef struct _IMAGE_OPTIONAL_HEADER32 {
WORD Magic;
// ... 省略无关字段
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 一共16项
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
Magic
如果为010B
,表示这是一个PE32
文件,如果为020B
表示这是一个PE32+
文件,也就是64
位的PE
文件。与
FileHeader.Machine
一样,对于.net
程序,不能以此字段作为判断依据。DataDirectory
中一共有16
项。其中,最后一项是保留项,第14
项(索引从0
开始)指向了CLR
的结构。
这个结构是 IMAGE_COR20_HEADER
,定义如下:
typedef struct IMAGE_COR20_HEADER
{
// Header versioning
DWORD cb;
WORD MajorRuntimeVersion;
WORD MinorRuntimeVersion;
// Symbol table and startup information
IMAGE_DATA_DIRECTORY MetaData;
DWORD Flags; // 这个字段的意义,参考 ReplacesCorHdrNumericDefines
// The main program if it is an EXE (not used if a DLL?)
// If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint.
// If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint
// (depricated for DLLs, use modules constructors intead).
union {
DWORD EntryPointToken;
DWORD EntryPointRVA;
};
// This is the blob of managed resources. Fetched using code:AssemblyNative.GetResource and
// code:PEFile.GetResource and accessible from managed code from
// System.Assembly.GetManifestResourceStream. The meta data has a table that maps names to offsets into
// this blob, so logically the blob is a set of resources.
IMAGE_DATA_DIRECTORY Resources;
// IL assemblies can be signed with a public-private key to validate who created it. The signature goes
// here if this feature is used.
IMAGE_DATA_DIRECTORY StrongNameSignature;
IMAGE_DATA_DIRECTORY CodeManagerTable; // Depricated, not used
// Used for manged codee that has unmaanaged code inside it (or exports methods as unmanaged entry points)
IMAGE_DATA_DIRECTORY VTableFixups;
IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
// null for ordinary IL images. NGEN images it points at a code:CORCOMPILE_HEADER structure
IMAGE_DATA_DIRECTORY ManagedNativeHeader;
} IMAGE_COR20_HEADER, *PIMAGE_COR20_HEADER;
其中,Flags
的值可以参考如下枚举:
typedef enum ReplacesCorHdrNumericDefines
{
// COM+ Header entry point flags.
COMIMAGE_FLAGS_ILONLY =0x00000001,
COMIMAGE_FLAGS_32BITREQUIRED =0x00000002,
COMIMAGE_FLAGS_IL_LIBRARY =0x00000004,
COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008,
COMIMAGE_FLAGS_NATIVE_ENTRYPOINT =0x00000010,
COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000,
COMIMAGE_FLAGS_32BITPREFERRED =0x00020000,
// 省略一些无关的内容
} ReplacesCorHdrNumericDefines;
说明:以上定义可以在
CorHdr.h
中找到。
了解了以上知识,就可以手动查看 PE
文件来进行判断了。但是手动判断既容易错,又麻烦,还得时不时得翻看一下 PE
文件格式,很不方便。除了通过手动查看 PE
文件来查看,还可以通过工具来查看。本文简单介绍几个常用工具及其查看方法。
dumpbin
dumpbin
可以查看很多信息,对于.net
程序,可以使用dumpbin /clrheader
选项查看clr
头信息。如下图:上图是两个以不同编译选项生成的程序的对比效果,我第一次查看
dumpbin
的显示结果没看懂,对比后才明白。
除了这几个工具,还有很多其它工具也可以查看,就不一一列举了。
Recommend
-
14
Performance in .NET – Part 1 Updated: thanks, Paulo Morgado! Updated: see the second post here and the thi...
-
5
js或vue中 如何判断浏览器时关闭还是刷新?? ...
-
7
一、概念及详解在各种体系的计算机中通常采用的字节存储机制主要有两种: Big-Endian和Little-Endian,即大端模式和小端模式。 Big-Endian和Little-Endian的定义如下: 1) Little-E...
-
17
Dot Net Developer at Chetu (2-6 Yrs Exp) Immediate HiringChetu is a US-based software development...
-
5
App secrets in dot net core Create new application in dotnet core using CLI or Visual Studio IDE Go to project directory and run below command dotnet user-secrets init dotnet user-...
-
5
Announcing dot.net in Japanese and Simplified Chinese Maira December 7th, 2021 .NET is your platform for building all y...
-
8
NEC Way is the common values that form basis for how entire NEC Group will conduct itself. Within N...
-
2
What the hell is Forth?February 20, 2019Forth is perhaps the tiniest possible useful interactive programming language. It is tiny along a number of dimensions: The amount of code required to implement...
-
7
我们该怎样判断一个小程序商城是否靠谱呢? 增长黑客,
-
8
Print from dot,net application on MySq Skip to Content Do you have a...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK