如何确定本地DLL文件是否编译为x64或x86?

151

我想确定一个本地汇编程序是以 x64 还是 x86 编译的,从一个托管代码应用程序 (C#) 中进行。

我认为这个信息应该在 PE 头文件中某个位置,因为操作系统加载器需要知道这个信息,但我找不到它。当然,我更喜欢在托管代码中完成,但如果必要,我可以使用本机 C++。


请明确一下,所提到的dll也是一个.Net程序集吗?您在帖子标题中说原生DLL,但在描述中说原生程序集…如果您仍然在关注这篇来自09年的帖子,请澄清一下。 - Vikas Gupta
1
你可能也想查看这个链接:check-if-unmanaged-dll-is-32-bit-or-64-bit - Matt
12个回答

148

你也可以使用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

使用'find'可以让生活变得稍微容易一些:

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

4
DUMPBIN无法用于.NET EXE文件。我有一个64位的.NET EXE文件,DUMPBIN显示为32位(“14C机器(x86)”),但corflags显示为Any CPU(“PE:PE32,32BIT:0”)。Dependency Walker也诊断错误。 - Pierre
2
需要 mspdb100.dll:( - Dmitry
1
@Altaveron 我曾经遇到过同样的问题,但是通过将 DLL 文件 mspdb100.dll 复制到 dumpbin.exe 所在的文件夹中解决了这个问题。之后 DUMPBIN 就可以运行了。对我来说,EXE 文件位于 <Visual Studio 安装文件夹>\VC\bin,而 DLL 文件位于 <Visual Studio 安装文件夹>\Common7\IDE - ADTC
对于已安装Visual Studio的用户,可以从Visual Studio命令提示符中获取DUMPBIN。 - Alan Macdonald
很好,那就是我的问题了。(rg = ripgrep 现在可以在 Windows 上使用) 我在 VS 终端上使用了这个命令: dumpbin.exe /headers .\ImGuiExtension.dll | rg machine - Richard Lalancette
现在已经添加了AA64机器(ARM64)。 - Lex Li

67

这个技巧非常有用,只需要使用记事本就可以操作。

打开dll文件并使用文本编辑器(比如Notepad)搜索第一个出现的字符串PE,接下来的字符会告诉你该dll是32位还是64位。

32位:

PE  L

64位:

PE  d†

60

使用CorFlags可以很容易地完成此操作。打开Visual Studio命令提示符并键入“corflags [您的程序集]”。您将会得到类似以下内容:

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 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 : 24 ILONLY : 0 32BIT : 0 Signed : 1

你需要查看PE和32BIT。

  • Any CPU:

    PE: PE32
    32BIT: 0

  • x86:

    PE: PE32
    32BIT: 1

  • x64:

    PE: PE32+
    32BIT: 0


22
@BLogan 你应该看一下我在给Steven Behnke的评论中的内容。我知道corflags工具,但它无法用于本机汇编程序。 - Ohad Horesh
9
自Windows SDK 8版以后,Corflags输出的内容发生了变化。现在,它已经不再使用32BIT标记,而是将其分为32BITREQUIRED和32BITPREFERRED两个标记。可以在C:\Program Files (x86)\Windows Kits\8.0\Include\um\CorHdr.h文件中查看这些标记的描述。从我的理解来看,32BITREQUIRED取代了原先的32BIT标记。同时,您也可以参考这个问题的答案:https://dev59.com/XmYr5IYBdhLWcg3wVYsg。 - Wes

28

IMAGE_OPTIONAL_HEADERMagic 字段(虽然在 Windows 可执行映像文件(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+

干杯

更新 自从我发布这个答案以来已经过了一段时间,然而我仍然看到它时不时地得到一些赞,所以我觉得值得更新。我写了一种获取可移植可执行文件图像结构的方法,它还会检查它是否被编译为AnyCPU。不幸的是,答案是用C++编写的,但如果你有几分钟时间查找WinNT.h中的结构,它应该不难转换到C#。如果人们感兴趣,我会写一个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映像的指针(因此您可以选择如何获取它们;内存映射或将整个映像读入内存...等等)。


非常有趣,但是当我使用 Any CPU 编译应用程序时,结果为 0x10B。这是错误的,因为我的应用程序在 x64 系统中运行。是否有其他标志可以检查? - Samuel
4
AnyCPU的意思就是:任意CPU,因此在PE头文件中以0x10B列出,以便与32位向后兼容。如果要检查它和纯32位之间的区别,则需要找出CorFlags从PE中获取其“32BIT”标志的位置,我不知道在脑海中。 - Jason Larke
@Samuel 更新了检查 AnyCPU 标志。 - Jason Larke
当检查32位程序集时,那段C#代码在64位进程中是否有效?例如,Module.GetPEKind http://msdn.microsoft.com/en-us/library/system.reflection.module.getpekind%28VS.80%29.aspx 会失败。 - Kiquenet
它应该能正常工作,它只是执行基本的IO操作并解释所读取的内容,没有太花哨的东西。@Kiquenet - Jason Larke

14

对于非托管的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
const value descr
IMAGE_FILE_MACHINE_UNKNOWN 0x0 假定该字段的内容适用于任何机器类型
IMAGE_FILE_MACHINE_AM33 0x1d3 Matsushita AM33
IMAGE_FILE_MACHINE_AMD64 0x8664 x64
IMAGE_FILE_MACHINE_ARM 0x1c0 ARM小端
IMAGE_FILE_MACHINE_EBC 0xebc EFI字节码
IMAGE_FILE_MACHINE_I386 0x14c Intel 386或更高版本处理器和兼容处理器
IMAGE_FILE_MACHINE_IA64 0x200 Intel Itanium处理器系列
IMAGE_FILE_MACHINE_M32R 0x9041 Mitsubishi M32R小端
IMAGE_FILE_MACHINE_MIPS16 0x266 MIPS16
IMAGE_FILE_MACHINE_MIPSFPU 0x366 带有FPU的MIPS
IMAGE_FILE_MACHINE_MIPSFPU16 0x466 带有FPU的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 Hitachi SH3
IMAGE_FILE_MACHINE_SH3DSP 0x1a3 Hitachi SH3 DSP
IMAGE_FILE_MACHINE_SH4 0x1a6 Hitachi SH4
IMAGE_FILE_MACHINE_SH5 0x1a8 Hitachi SH5
IMAGE_FILE_MACHINE_THUMB 0x1c2 Thumb
IMAGE_FILE_MACHINE_WCEMIPSV2 0x169 MIPS小端WCE v2

你的第二个链接已经失效了 :s - gpalex
1
更多信息:https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types 和 https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#COFF_Header,因为“_64位_”不仅指ARM或Itanium,还包括PowerPC、Alpha或RISCV。 - AmigoJack

5

您可以在这里找到与IMAGE_FILE_HEADER解决方案相关的C#样例实现。


4

我在第一个答案中重写了C++解决方案,用PowerShell脚本实现。该脚本可以确定以下类型的.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  

相比于使用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;

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


3

3
用十六进制编辑器打开dll文件,例如HxD
如果第9行有“dt”,则为64位。
如果第9行有“L.”,则为32位。

在“Far Manager”十六进制查看器中找不到“dt”和“L.”。 - Dmitry
显示为 d. 和 L. - Zax

2
这里提供了一种快速而可能不太干净的方法:https://superuser.com/a/889267。您需要打开编辑器并检查"PE"序列后的第一个字符来查看DLL文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接