如何查找本机DLL文件是否被编译为x64或x86?

我想确定本机程序集是否从托pipe代码应用程序( C# )编译为x64或x86。

我认为它必须在PE头的某个地方,因为OS加载器需要知道这个信息,但我找不到它。 当然,我更喜欢用托pipe代码来做,但如果有必要,我可以使用本机C ++。

你也可以使用DUMPBIN 。 使用/headers/all标志及其列出的第一个文件头。

 dumpbin /headers cv210.dll 

64位

 Microsoft (R) COFF/PE Dumper Version 10.00.30319.01 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file cv210.dll PE signature found File Type: DLL FILE HEADER VALUES 8664 machine (x64) 6 number of sections 4BBAB813 time date stamp Tue Apr 06 12:26:59 2010 0 file pointer to symbol table 0 number of symbols F0 size of optional header 2022 characteristics Executable Application can handle large (>2GB) addresses DLL 

32位

 Microsoft (R) COFF/PE Dumper Version 10.00.30319.01 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file acrdlg.dll PE signature found File Type: DLL FILE HEADER VALUES 14C machine (x86) 5 number of sections 467AFDD2 time date stamp Fri Jun 22 06:38:10 2007 0 file pointer to symbol table 0 number of symbols E0 size of optional header 2306 characteristics Executable Line numbers stripped 32 bit word machine Debug information stripped DLL 

“发现”可以使生活稍微轻松一些:

 dumpbin /headers cv210.dll |find "machine" 8664 machine (x64) 

使用CorFlags有一个简单的方法。 打开Visual Studio命令提示符并input“corflags [your assembly]”。 你会得到这样的东西:

c:\ Program Files(x86)\ Microsoft Visual Studio 9.0 \ VC> corflags“C:\ Windows \ Microsoft.NET \ Framework \ v2.0.50727 \ System.Data.dll”

Microsoft(R).NET Framework CorFlags转换工具。 版本3.5.21022.8版权所有(c)Microsoft Corporation。 版权所有。

版本:v2.0.50727 CLR标题:2.5 PE:PE32 CorFlags:24 ILONLY:0 32BIT:0签名:1

你正在看PE和32BIT。

  • 任何CPU

    PE:PE32
    32BIT:0

  • x86

    PE:PE32
    32BIT:1

  • 64位:

    PE:PE32 +
    32BIT:0

IMAGE_OPTIONAL_HEADERMagic字段(尽pipeWindows可执行映像(DLL / EXE文件)中的头文件没有任何可选项)会告诉您PE的体系结构。

以下是从文件中获取体系结构的示例。

 public static ushort GetImageArchitecture(string filepath) { using (var stream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, System.IO.FileAccess.Read)) using (var reader = new System.IO.BinaryReader(stream)) { //check the MZ signature to ensure it's a valid Portable Executable image if (reader.ReadUInt16() != 23117) throw new BadImageFormatException("Not a valid Portable Executable image", filepath); // seek to, and read, e_lfanew then advance the stream to there (start of NT header) stream.Seek(0x3A, System.IO.SeekOrigin.Current); stream.Seek(reader.ReadUInt32(), System.IO.SeekOrigin.Begin); // Ensure the NT header is valid by checking the "PE\0\0" signature if (reader.ReadUInt32() != 17744) throw new BadImageFormatException("Not a valid Portable Executable image", filepath); // seek past the file header, then read the magic number from the optional header stream.Seek(20, System.IO.SeekOrigin.Current); return reader.ReadUInt16(); } } 

目前唯一的两个架构常量是:

 0x10b - PE32 0x20b - PE32+ 

干杯

更新自从我发布这个答案已经有一段时间了,但是我仍然看到它一次又一次得到了一些赞扬,所以我觉得值得更新。 我写了一个方法来获得一个Portable Executable的架构,它也检查是否编译为AnyCPU 。 不幸的是,答案是在C ++中,但是如果你有几分钟的时间去查找WinNT.h的结构, WinNT.h移植到C#应该不会WinNT.h 。 如果人们有兴趣,我会用C#编写一个端口,但除非人们真正需要它,否则我不会花太多时间来强调它。

 #include <Windows.h> #define MKPTR(p1,p2) ((DWORD_PTR)(p1) + (DWORD_PTR)(p2)) typedef enum _pe_architecture { PE_ARCHITECTURE_UNKNOWN = 0x0000, PE_ARCHITECTURE_ANYCPU = 0x0001, PE_ARCHITECTURE_X86 = 0x010B, PE_ARCHITECTURE_x64 = 0x020B } PE_ARCHITECTURE; LPVOID GetOffsetFromRva(IMAGE_DOS_HEADER *pDos, IMAGE_NT_HEADERS *pNt, DWORD rva) { IMAGE_SECTION_HEADER *pSecHd = IMAGE_FIRST_SECTION(pNt); for(unsigned long i = 0; i < pNt->FileHeader.NumberOfSections; ++i, ++pSecHd) { // Lookup which section contains this RVA so we can translate the VA to a file offset if (rva >= pSecHd->VirtualAddress && rva < (pSecHd->VirtualAddress + pSecHd->Misc.VirtualSize)) { DWORD delta = pSecHd->VirtualAddress - pSecHd->PointerToRawData; return (LPVOID)MKPTR(pDos, rva - delta); } } return NULL; } PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) { // Parse and validate the DOS header IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER*)pImageBase; if (IsBadReadPtr(pDosHd, sizeof(pDosHd->e_magic)) || pDosHd->e_magic != IMAGE_DOS_SIGNATURE) return PE_ARCHITECTURE_UNKNOWN; // Parse and validate the NT header IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS*)MKPTR(pDosHd, pDosHd->e_lfanew); if (IsBadReadPtr(pNtHd, sizeof(pNtHd->Signature)) || pNtHd->Signature != IMAGE_NT_SIGNATURE) return PE_ARCHITECTURE_UNKNOWN; // First, naive, check based on the 'Magic' number in the Optional Header. PE_ARCHITECTURE architecture = (PE_ARCHITECTURE)pNtHd->OptionalHeader.Magic; // If the architecture is x86, there is still a possibility that the image is 'AnyCPU' if (architecture == PE_ARCHITECTURE_X86) { IMAGE_DATA_DIRECTORY comDirectory = pNtHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]; if (comDirectory.Size) { IMAGE_COR20_HEADER *pClrHd = (IMAGE_COR20_HEADER*)GetOffsetFromRva(pDosHd, pNtHd, comDirectory.VirtualAddress); // Check to see if the CLR header contains the 32BITONLY flag, if not then the image is actually AnyCpu if ((pClrHd->Flags & COMIMAGE_FLAGS_32BITREQUIRED) == 0) architecture = PE_ARCHITECTURE_ANYCPU; } } return architecture; } 

该函数接受一个指向内存中的PE映像的指针(所以你可以select你的毒药如何获得它的内存映射或读取整个内存到任何东西)。

对于非托pipe的DLL文件,您需要首先检查它是否是一个16位的DLL文件(希望不是)。 然后检查IMAGE\_FILE_HEADER.Machine字段。

其他人花了时间来解决这个问题,所以我只想在这里重复一遍:

要区分32位和64位PE文件,您应该检查IMAGE_FILE_HEADER.Machine字段。 基于下面的Microsoft PE和COFF规范,我列出了此字段的所有可能值: http : //download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/ pecoff_v8.doc

IMAGE_FILE_MACHINE_UNKNOWN 0x0该字段的内容假定适用于任何机器types

IMAGE_FILE_MACHINE_AM33 0x1d3松下AM33

IMAGE_FILE_MACHINE_AMD64 0x8664 x64

IMAGE_FILE_MACHINE_ARM 0x1c0 ARM小端

IMAGE_FILE_MACHINE_EBC 0xebc EFI字节码

IMAGE_FILE_MACHINE_I386 0x14c英特尔386或更高版本的处理器和兼容的处理器

IMAGE_FILE_MACHINE_IA64 0x200英特尔安腾处理器家族

IMAGE_FILE_MACHINE_M32R 0x9041三菱M32R小端

IMAGE_FILE_MACHINE_MIPS16 0x266 MIPS16

带有FPU的IMAGE_FILE_MACHINE_MIPSFPU 0x366 MIPS

带有FPU的IMAGE_FILE_MACHINE_MIPSFPU16 0x466 MIPS16

IMAGE_FILE_MACHINE_POWERPC 0x1f0 Power PC小端

IMAGE_FILE_MACHINE_POWERPCFP 0x1f1具有浮点支持的Power PC

IMAGE_FILE_MACHINE_R4000 0x166 MIPS小端

IMAGE_FILE_MACHINE_SH3 0x1a2日立SH3

IMAGE_FILE_MACHINE_SH3DSP 0x1a3日立SH3 DSP

IMAGE_FILE_MACHINE_SH4 0x1a6日立SH4

IMAGE_FILE_MACHINE_SH5 0x1a8日立SH5

IMAGE_FILE_MACHINE_THUMB 0x1c2拇指

IMAGE_FILE_MACHINE_WCEMIPSV2 0x169 MIPS小端WCE v2

是的,您可以检查64位的IMAGE_FILE_MACHINE_AMD64 | IMAGE_FILE_MACHINE_IA64和32位的IMAGE_FILE_MACHINE_I386。

这个技巧的作品,只需要记事本。

使用文本编辑器(如记事本)打开dll文件,findstringPE的第一个匹配项。 以下字符定义如果dll是32位或64位。

32位:

 PE L 

64位:

 PE d† 

您可以在这里findIMAGE_FILE_HEADER解决scheme的C#示例实现

64位二进制文​​件以PE32 +格式存储。 尝试阅读http://www.masm32.com/board/index.php?action=dlattach;topic=6687.0;id=3486

使用hex编辑器(如HxD)打开dll

如果第9行有“dt”,则为64位。

如果有一个“L.” 在9号线是32位。

快速和可能的肮脏的方式来描述这里: https : //superuser.com/a/889267 。 在编辑器中打开DLL,并检查“PE”序列后的第一个字符。

显然你可以在可移植可执行文件的头文件中find它。 corflags.exe实用程序能够显示您是否以x64为目标。 希望这可以帮助你find更多的信息。

我在PowerShell脚本的第一个答案重写了C ++解决scheme 。 脚本可以确定这种types的.exe和.dll文件:

 #Description C# compiler switch PE type machine corflags #MSIL /platform:anycpu (default) PE32 x86 ILONLY #MSIL 32 bit pref /platform:anycpu32bitpreferred PE32 x86 ILONLY | 32BITREQUIRED | 32BITPREFERRED #x86 managed /platform:x86 PE32 x86 ILONLY | 32BITREQUIRED #x86 mixed n/a PE32 x86 32BITREQUIRED #x64 managed /platform:x64 PE32+ x64 ILONLY #x64 mixed n/a PE32+ x64 #ARM managed /platform:arm PE32 ARM ILONLY #ARM mixed n/a PE32 ARM 

这个解决scheme比corflags.exe有更多的优势,并且通过C#中的Assembly.Load加载程序集 – 你永远不会得到BadImageFormatException或者关于无效头​​的消息。

 function GetActualAddressFromRVA($st, $sec, $numOfSec, $dwRVA) { [System.UInt32] $dwRet = 0; for($j = 0; $j -lt $numOfSec; $j++) { $nextSectionOffset = $sec + 40*$j; $VirtualSizeOffset = 8; $VirtualAddressOffset = 12; $SizeOfRawDataOffset = 16; $PointerToRawDataOffset = 20; $Null = @( $curr_offset = $st.BaseStream.Seek($nextSectionOffset + $VirtualSizeOffset, [System.IO.SeekOrigin]::Begin); [System.UInt32] $VirtualSize = $b.ReadUInt32(); [System.UInt32] $VirtualAddress = $b.ReadUInt32(); [System.UInt32] $SizeOfRawData = $b.ReadUInt32(); [System.UInt32] $PointerToRawData = $b.ReadUInt32(); if ($dwRVA -ge $VirtualAddress -and $dwRVA -lt ($VirtualAddress + $VirtualSize)) { $delta = $VirtualAddress - $PointerToRawData; $dwRet = $dwRVA - $delta; return $dwRet; } ); } return $dwRet; } function Get-Bitness2([System.String]$path, $showLog = $false) { $Obj = @{}; $Obj.Result = ''; $Obj.Error = $false; $Obj.Log = @(Split-Path -Path $path -Leaf -Resolve); $b = new-object System.IO.BinaryReader([System.IO.File]::Open($path,[System.IO.FileMode]::Open,[System.IO.FileAccess]::Read, [System.IO.FileShare]::Read)); $curr_offset = $b.BaseStream.Seek(0x3c, [System.IO.SeekOrigin]::Begin) [System.Int32] $peOffset = $b.ReadInt32(); $Obj.Log += 'peOffset ' + "{0:X0}" -f $peOffset; $curr_offset = $b.BaseStream.Seek($peOffset, [System.IO.SeekOrigin]::Begin); [System.UInt32] $peHead = $b.ReadUInt32(); if ($peHead -ne 0x00004550) { $Obj.Error = $true; $Obj.Result = 'Bad Image Format'; $Obj.Log += 'cannot determine file type (not x64/x86/ARM) - exit with error'; }; if ($Obj.Error) { $b.Close(); Write-Host ($Obj.Log | Format-List | Out-String); return $false; }; [System.UInt16] $machineType = $b.ReadUInt16(); $Obj.Log += 'machineType ' + "{0:X0}" -f $machineType; [System.UInt16] $numOfSections = $b.ReadUInt16(); $Obj.Log += 'numOfSections ' + "{0:X0}" -f $numOfSections; if (($machineType -eq 0x8664) -or ($machineType -eq 0x200)) { $Obj.Log += 'machineType: x64'; } elseif ($machineType -eq 0x14c) { $Obj.Log += 'machineType: x86'; } elseif ($machineType -eq 0x1c0) { $Obj.Log += 'machineType: ARM'; } else{ $Obj.Error = $true; $Obj.Log += 'cannot determine file type (not x64/x86/ARM) - exit with error'; }; if ($Obj.Error) { $b.Close(); Write-Output ($Obj.Log | Format-List | Out-String); return $false; }; $curr_offset = $b.BaseStream.Seek($peOffset+20, [System.IO.SeekOrigin]::Begin); [System.UInt16] $sizeOfPeHeader = $b.ReadUInt16(); $coffOffset = $peOffset + 24;#PE header size is 24 bytes $Obj.Log += 'coffOffset ' + "{0:X0}" -f $coffOffset; $curr_offset = $b.BaseStream.Seek($coffOffset, [System.IO.SeekOrigin]::Begin);#+24 byte magic number [System.UInt16] $pe32 = $b.ReadUInt16(); $clr20headerOffset = 0; $flag32bit = $false; $Obj.Log += 'pe32 magic number: ' + "{0:X0}" -f $pe32; $Obj.Log += 'size of optional header ' + ("{0:D0}" -f $sizeOfPeHeader) + " bytes"; #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, $COMIMAGE_FLAGS_ILONLY = 0x00000001; $COMIMAGE_FLAGS_32BITREQUIRED = 0x00000002; $COMIMAGE_FLAGS_32BITPREFERRED = 0x00020000; $offset = 96; if ($pe32 -eq 0x20b) { $offset = 112;#size of COFF header is bigger for pe32+ } $clr20dirHeaderOffset = $coffOffset + $offset + 14*8;#clr directory header offset + start of section number 15 (each section is 8 byte long); $Obj.Log += 'clr20dirHeaderOffset ' + "{0:X0}" -f $clr20dirHeaderOffset; $curr_offset = $b.BaseStream.Seek($clr20dirHeaderOffset, [System.IO.SeekOrigin]::Begin); [System.UInt32] $clr20VirtualAddress = $b.ReadUInt32(); [System.UInt32] $clr20Size = $b.ReadUInt32(); $Obj.Log += 'clr20VirtualAddress ' + "{0:X0}" -f $clr20VirtualAddress; $Obj.Log += 'clr20SectionSize ' + ("{0:D0}" -f $clr20Size) + " bytes"; if ($clr20Size -eq 0) { if ($machineType -eq 0x1c0) { $Obj.Result = 'ARM native'; } elseif ($pe32 -eq 0x10b) { $Obj.Result = '32-bit native'; } elseif($pe32 -eq 0x20b) { $Obj.Result = '64-bit native'; } $b.Close(); if ($Obj.Result -eq '') { $Obj.Error = $true; $Obj.Log += 'Unknown type of file'; } else { if ($showLog) { Write-Output ($Obj.Log | Format-List | Out-String); }; return $Obj.Result; } }; if ($Obj.Error) { $b.Close(); Write-Host ($Obj.Log | Format-List | Out-String); return $false; }; [System.UInt32]$sectionsOffset = $coffOffset + $sizeOfPeHeader; $Obj.Log += 'sectionsOffset ' + "{0:X0}" -f $sectionsOffset; $realOffset = GetActualAddressFromRVA $b $sectionsOffset $numOfSections $clr20VirtualAddress; $Obj.Log += 'real IMAGE_COR20_HEADER offset ' + "{0:X0}" -f $realOffset; if ($realOffset -eq 0) { $Obj.Error = $true; $Obj.Log += 'cannot find COR20 header - exit with error'; $b.Close(); return $false; }; if ($Obj.Error) { $b.Close(); Write-Host ($Obj.Log | Format-List | Out-String); return $false; }; $curr_offset = $b.BaseStream.Seek($realOffset + 4, [System.IO.SeekOrigin]::Begin); [System.UInt16] $majorVer = $b.ReadUInt16(); [System.UInt16] $minorVer = $b.ReadUInt16(); $Obj.Log += 'IMAGE_COR20_HEADER version ' + ("{0:D0}" -f $majorVer) + "." + ("{0:D0}" -f $minorVer); $flagsOffset = 16;#+16 bytes - flags field $curr_offset = $b.BaseStream.Seek($realOffset + $flagsOffset, [System.IO.SeekOrigin]::Begin); [System.UInt32] $flag32bit = $b.ReadUInt32(); $Obj.Log += 'CorFlags: ' + ("{0:X0}" -f $flag32bit); #Description C# compiler switch PE type machine corflags #MSIL /platform:anycpu (default) PE32 x86 ILONLY #MSIL 32 bit pref /platform:anycpu32bitpreferred PE32 x86 ILONLY | 32BITREQUIRED | 32BITPREFERRED #x86 managed /platform:x86 PE32 x86 ILONLY | 32BITREQUIRED #x86 mixed n/a PE32 x86 32BITREQUIRED #x64 managed /platform:x64 PE32+ x64 ILONLY #x64 mixed n/a PE32+ x64 #ARM managed /platform:arm PE32 ARM ILONLY #ARM mixed n/a PE32 ARM $isILOnly = ($flag32bit -band $COMIMAGE_FLAGS_ILONLY) -eq $COMIMAGE_FLAGS_ILONLY; $Obj.Log += 'ILONLY: ' + $isILOnly; if ($machineType -eq 0x1c0) {#if ARM if ($isILOnly) { $Obj.Result = 'ARM managed'; } else { $Obj.Result = 'ARM mixed'; } } elseif ($pe32 -eq 0x10b) {#pe32 $is32bitRequired = ($flag32bit -band $COMIMAGE_FLAGS_32BITREQUIRED) -eq $COMIMAGE_FLAGS_32BITREQUIRED; $is32bitPreffered = ($flag32bit -band $COMIMAGE_FLAGS_32BITPREFERRED) -eq $COMIMAGE_FLAGS_32BITPREFERRED; $Obj.Log += '32BIT: ' + $is32bitRequired; $Obj.Log += '32BIT PREFFERED: ' + $is32bitPreffered if ($is32bitRequired -and $isILOnly -and $is32bitPreffered) { $Obj.Result = 'AnyCpu 32bit-preffered'; } elseif ($is32bitRequired -and $isILOnly -and !$is32bitPreffered){ $Obj.Result = 'x86 managed'; } elseif (!$is32bitRequired -and !$isILOnly -and $is32bitPreffered) { $Obj.Result = 'x86 mixed'; } elseif ($isILOnly) { $Obj.Result = 'AnyCpu'; } } elseif ($pe32 -eq 0x20b) {#pe32+ if ($isILOnly) { $Obj.Result = 'x64 managed'; } else { $Obj.Result = 'x64 mixed'; } } $b.Close(); if ($showLog) { Write-Host ($Obj.Log | Format-List | Out-String); } if ($Obj.Result -eq ''){ return 'Unknown type of file';}; $flags = ''; if ($isILOnly) {$flags += 'ILONLY';} if ($is32bitRequired) { if ($flags -ne '') {$flags += ' | ';} $flags += '32BITREQUIRED'; } if ($is32bitPreffered) { if ($flags -ne '') {$flags += ' | ';} $flags += '32BITPREFERRED'; } if ($flags -ne '') {$flags = ' (' + $flags +')';} return $Obj.Result + $flags; } 

用法示例:

 #$filePath = "C:\Windows\SysWOW64\regedit.exe";#32 bit native on 64bit windows $filePath = "C:\Windows\regedit.exe";#64 bit native on 64bit windows | should be 32 bit native on 32bit windows Get-Bitness2 $filePath $true; 

如果您不需要查看详细信息,则可以省略第二个参数