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

时间:2009-01-26 17:50:31

标签: c# .net winapi 64-bit x86-64

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

我认为它必须在PE头中的某处,因为OS加载器需要知道这些信息,但我找不到它。当然我更喜欢在托管代码中执行此操作,但如果有必要,我可以使用本机C ++。

12 个答案:

答案 0 :(得分:136)

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

答案 1 :(得分:53)

使用CorFlags可以轻松完成此操作。打开Visual Studio命令提示符并键入“corflags [your assembly]”。你会得到这样的东西:

  

c:\ Program Files(x86)\ Microsoft Visual Studio 9.0 \ VC> corflags   “C:\的Windows \ Microsoft.NET \框架\ 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   非正式:0   32位:0   签名:1

你正在专注于PE和32BIT。

  • 任何CPU

    PE:PE32
    32BIT:0

  • 86

    PE:PE32
    32BIT:1

  • 64:

    PE:PE32 +
    32BIT:0

答案 2 :(得分:26)

trick有效,只需要记事本。

使用文本编辑器(如记事本)打开dll文件,找到第一次出现的字符串PE。以下字符定义dll是32位还是64位。

32位:

PE  L

64位:

PE  d†

答案 3 :(得分:21)

Magic的{​​{1}}字段(尽管Windows可执行映像(DLL / EXE文件)中的标题没有任何可选项)将告诉您PE的体系结构。

以下是从文件中获取架构的示例。

IMAGE_OPTIONAL_HEADER

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

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。不幸的是答案是在C ++中,但如果你有几分钟的时间来查找AnyCPU中的结构,那么移植到C#应该不会太难。如果人们有兴趣我会用C#写一个端口,但除非人们真的想要它,否则我不会花太多时间来强调它。

WinNT.h

该函数接受指向内存中PE图像的指针(因此您可以选择如何获取它们的毒药;内存映射或将整个内容读入内存......无论如何)。

答案 4 :(得分:14)

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

Someone else已花时间解决这个问题,所以我将在此重复一遍:

  

要区分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假设此字段的内容适用于任何机器类型

     

IMAGE_FILE_MACHINE_AM33 0x1d3 Matsushita AM33

     

IMAGE_FILE_MACHINE_AMD64 0x8664 x64

     

IMAGE_FILE_MACHINE_ARM 0x1c0 ARM little endian

     

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三菱M32R小端

     

IMAGE_FILE_MACHINE_MIPS16 0x266 MIPS16

     

IMAGE_FILE_MACHINE_MIPSFPU带有FPU的0x366 MIPS

     

IMAGE_FILE_MACHINE_MIPSFPU16 0x466 MIPS16 with FPU

     

IMAGE_FILE_MACHINE_POWERPC 0x1f0 Power PC little endian

     

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日立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 little-endian WCE v2

     

是的,你可以查一下   IMAGE_FILE_MACHINE_AMD64 | 64位的IMAGE_FILE_MACHINE_IA64和32位的IMAGE_FILE_MACHINE_I386。

答案 5 :(得分:4)

您可以找到IMAGE_FILE_HEADER解决方案的C# sample implementation here

答案 6 :(得分:3)

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

答案 7 :(得分:3)

使用十六进制编辑器打开dll,例如HxD

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

如果有“L”在第9行它是32位。

答案 8 :(得分:1)

我在powershell脚本的第一个回答中重写了c++ solution。脚本可以确定这种类型的.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;

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

答案 9 :(得分:1)

这里描述了一种快速且可能很脏的方法:https://superuser.com/a/889267。在编辑器中打开DLL并检查“PE”序列后面的第一个字符。

答案 10 :(得分:0)

显然你可以在便携式可执行文件的标题中找到它。 corflags.exe实用程序能够显示它是否以x64为目标。希望这有助于您找到有关它的更多信息。

答案 11 :(得分:0)

由于第三方工具总是安装在 %Program files (x86)% 中(即使 x64 安装!)并且需要首先在 %path% 上列出适当的 x32|x64 fortran 运行时才能正确运行,我收集了 { {3}} 和 c++ 解到 matlab 中返回:

  • 种类Executable|Library|Other
  • 代码类型Native|Mixed|Managed
  • 平台x32|x64|AnyCpu|x32Preferred|Other

一旦在内存中有原始 PE 结构,应该很容易适应其他语言。

function [simplifiedInfo] = GetPortableExecutableSimplifiedInfo(filename)
%[
    % Checking arguments
    if (nargin <1), error('MATLAB:minrhs', 'Not enough input argments.'); end

    % Initializing simplified info    
    simplifiedInfo.Kind = 'Other';
    simplifiedInfo.CodeType = 'Other';
    simplifiedInfo.Platform = 'Other';

    % Obtaining raw info
    [rawInfo, PEConstants] = GetPortableExecutableRawInfo(filename);

    % Determining 'Kind' of PE
    if (isfield(rawInfo, 'PEOptionalHeader') && (rawInfo.COFFHeader.Characteristics.IMAGE_FILE_EXECUTABLE_IMAGE))
        if (rawInfo.COFFHeader.Characteristics.IMAGE_FILE_DLL)
            simplifiedInfo.Kind = 'Library';
        else
            simplifiedInfo.Kind = 'Executable';
        end
    else
        % No optional header or no IMAGE_FILE_EXECUTABLE_IMAGE flag ... 
        % Maybe just .obj or other thing
        simplifiedInfo.Kind = 'Other';
    end

    % Determining 'CodeType'
    % NB: 'COR20Header' is present for MSIL code, but not for native code
    if (isfield(rawInfo, 'COR20Header'))
        if (rawInfo.COR20Header.Flags.COMIMAGE_FLAGS_ILONLY)
            simplifiedInfo.CodeType = 'Managed';
        else
            simplifiedInfo.CodeType = 'Mixed';
        end
    else
        simplifiedInfo.CodeType = 'Native';
    end

    % Determining platform
    if (rawInfo.COFFHeader.Machine == PEConstants.IMAGE_FILE_MACHINE_AMD64)
        simplifiedInfo.Platform = 'x64';
    elseif (rawInfo.COFFHeader.Machine == PEConstants.IMAGE_FILE_MACHINE_I386)
        if (isfield(rawInfo, 'COR20Header'))
            % PE contains MSIL code, need more checks
            if (rawInfo.COR20Header.Flags.COMIMAGE_FLAGS_32BITREQUIRED)
                if (rawInfo.COR20Header.Flags.COMIMAGE_FLAGS_32BITPREFERRED)
                    simplifiedInfo.Platform = 'x32Preferred';
                else
                    simplifiedInfo.Platform = 'x32';
                end
            else
                simplifiedInfo.Platform = 'AnyCpu';
            end
        else
            % This is native code so ...
            simplifiedInfo.Platform = 'x32';
        end
    else
        % ARM, ...
        simplifiedInfo.Platform = 'Other';
    end
%]
end

内部GetPortableExecutableRawInfo函数的源码可以在powershell获取。