Làm thế nào tôi có thể xác định nếu một hội đồng .NET được xây dựng cho x86 hoặc x64?


327

Tôi đã có một danh sách các cụm .NET tùy ý.

Tôi cần kiểm tra theo chương trình nếu mỗi DLL được xây dựng cho x86 (trái ngược với x64 hoặc Any CPU). Điều này có thể không?



2
Bạn cũng có thể muốn kiểm tra cái này: check-if-unmanaged-dll-is-32-bit-or-64-bit .
Matt

2
Trong phiên bản sau của CorFlags, tương ứng với .NET 4.5, "32BIT" đã được thay thế bằng "32BITREQ" và "32BITPREF". .
Peter Mortensen

Câu trả lời:


280

Nhìn vào System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

Bạn có thể kiểm tra siêu dữ liệu lắp ráp từ phiên bản hội đồng được trả về:

Sử dụng PowerShell :

[36] C: \> [Reflection.assinstallname] :: GetAss lanhName ("$ {pwd} \ Microsoft.GLEE.dll") | fl

Tên: Microsoft.GLEE
Phiên bản: 1.0.0.0
Văn hóa Thông tin:
CodeBase: file: /// C: / dự án / powershell / BuildAnalyzer / ...
EscopedCodeBase: file: /// C: / dự án / powershell / BuildAnalyzer / ...
ProcessorArch architecture: MSIL
Cờ: PublicKey
Thuật toán băm: SHA1
Phiên bản tương thích: SameMachine
KeyPair:
Tên đầy đủ: Microsoft.GLEE, Phiên bản = 1.0.0.0, Văn hóa = trung tính ... 

Ở đây, ProcessorArch architecture xác định nền tảng đích.

  • Amd64 : Bộ xử lý 64 bit dựa trên kiến ​​trúc x64.
  • Cánh tay : Một bộ xử lý ARM.
  • IA64 : Chỉ bộ xử lý Intel Itanium 64 bit.
  • MSIL : Trung lập liên quan đến bộ xử lý và bit-per-word.
  • X86 : Bộ xử lý Intel 32 bit, có nguồn gốc hoặc trong môi trường Windows trên Windows trên nền tảng 64 bit (WOW64).
  • Không có : Một sự kết hợp không xác định hoặc không xác định của bộ xử lý và bit-per-word.

Tôi đang sử dụng PowerShell trong ví dụ này để gọi phương thức.


60
Tha thứ cho câu hỏi ngu ngốc - nhưng điều này cho bạn biết đó là x86?
George Mauer

53
Trường ProcessorArch architecture là một bảng liệt kê; trong ví dụ trên, nó được đặt thành MSIL, có nghĩa là "Trung lập đối với bộ xử lý và bit-per-word." Các giá trị khác bao gồm X86, IA64, Amd64. Xem msdn.microsoft.com/en-us/l Library / Google để biết thêm chi tiết.
Brian Gillespie

4
Hãy thử với [reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")đôi khi thư mục hiện tại của tiến trình không giống với nhà cung cấp hiện tại (đó là nơi tôi cho rằng DLL là dành cho bạn)
x0n

2
Một cảnh báo khác cần chú ý là quên "bỏ chặn" DLL nếu bạn đã tải xuống từ mạng nội bộ. Sử dụng bỏ chặn tệp, hoặc nhấp chuột phải / thuộc tính / bỏ chặn từ explorer. Bạn sẽ cần khởi động lại trình bao cho nó để nhận ra trạng thái bỏ chặn nếu bạn đã thất bại một lần trong phiên hiện tại (đổ lỗi cho trình thám hiểm internet cho điều đó - vâng, thực sự.)
x0n

1
Trong mã ASP.NET MVC, có một nhận xét // DevDiv 216459: This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in medium trust. However, Assembly.FullName *is* accessible in medium trust.Đáng buồn thay, không có cách nào để đọc ProcessorArch architecture mà không sử dụng GetName instance method; sử dụng AssemblyName constructor, trường luôn được đặt thành None.
cuộc họp

221

Bạn có thể sử dụng công cụ CorFlags CLI (ví dụ: C: \ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe) để xác định trạng thái của một hội đồng, dựa trên đầu ra của nó và mở một tổ hợp thành một tài sản nhị phân bạn sẽ có thể xác định nơi bạn cần tìm để xác định xem cờ 32BIT được đặt thành 1 ( x86 ) hay 0 ( Bất kỳ CPU hoặc x64 , tùy thuộc vào PE):

Option    | PE    | 32BIT
----------|-------|---------
x86       | PE32  | 1
Any CPU   | PE32  | 0
x64       | PE32+ | 0

Bài đăng blog x64 Phát triển với .NET có một số thông tin về corflags.

Thậm chí tốt hơn, bạn có thể sử dụngModule.GetPEKind để xác định xem một tổ hợp là PortableExecutableKindsgiá trị PE32Plus(64 bit), Required32Bit(32 bit và WOW) hay ILOnly(bất kỳ CPU nào) cùng với các thuộc tính khác.


1
Sau khi xem cập nhật của bạn, sử dụng GetPEKind dường như là cách thích hợp để làm điều này. Tôi đã đánh dấu câu trả lời của bạn.
Judah Gabriel Himango

9
GetPEKind không thành công trong quy trình 64 bit khi kiểm tra các cụm 32 bit
jjxtra

2
Bạn phải gọi GetPEKind từ quy trình 32 bit
Ludwo

2
Tôi cài đặt VS 2008, VS 2010, VS 2012 và VS 2013. Tôi có 8 tệp CorFlags.exe trong các thư mục con trong C: \ Program Files (x86) \ Microsoft SDKs \ Windows \. Tôi nên sử dụng cái nào?
Kiquenet

5
Như đã chỉ ra trong câu trả lời này , trong .NET 4.5 có 32BITREQ và 32BITPREF thay vì cờ 32BIT. PE32 / 0/0 và PE32 / 0/1 lần lượt là ưu tiên AnyCPU và AnyCPU 32 bit.
angensesen

141

Chỉ cần làm rõ, CorFlags.exe là một phần của .NET Framework SDK . Tôi có các công cụ phát triển trên máy của mình và cách đơn giản nhất để tôi xác định liệu DLL có phải là 32 bit hay không là:

  1. Mở Dấu nhắc lệnh của Visual Studio (Trong Windows: menu Start / Programs / Microsoft Visual Studio / Visual Studio Tools / Visual Studio 2008 Command Prompt)

  2. CD vào thư mục chứa DLL trong câu hỏi

  3. Chạy corflags như thế này: corflags MyAssembly.dll

Bạn sẽ nhận được kết quả như thế này:

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

Theo nhận xét, các cờ ở trên sẽ được đọc như sau:

  • Bất kỳ CPU: PE = PE32 và 32BIT = 0
  • x86: PE = PE32 và 32BIT = 1
  • 64 bit: PE = PE32 + và 32BIT = 0

12
Điều này dường như đã thay đổi trong khi đó; corflags bây giờ hiển thị 32BITREQ32BITPREFthay vì một 32BITgiá trị duy nhất .
HOẶC Mapper

1
Microsoft .NET 4.5 đã giới thiệu một tùy chọn mới, Bất kỳ CPU 32 bit ưa thích nào. Dưới đây là chi tiết.
RBT

"Dấu nhắc lệnh của Visual Studio" ngày nay được gọi là " Dấu nhắc lệnh của nhà phát triển Visual Studio 2019 ".
Uwe Keim

22

Làm thế nào về bạn chỉ viết bạn sở hữu? Cốt lõi của kiến ​​trúc PE đã không bị thay đổi nghiêm trọng kể từ khi triển khai trong Windows 95. Dưới đây là ví dụ về C #:

    public static ushort GetPEArchitecture(string pFilePath)
    {
        ushort architecture = 0;
        try
        {
            using (System.IO.FileStream fStream = new System.IO.FileStream(pFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            {
                using (System.IO.BinaryReader bReader = new System.IO.BinaryReader(fStream))
                {
                    if (bReader.ReadUInt16() == 23117) //check the MZ signature
                    {
                        fStream.Seek(0x3A, System.IO.SeekOrigin.Current); //seek to e_lfanew.
                        fStream.Seek(bReader.ReadUInt32(), System.IO.SeekOrigin.Begin); //seek to the start of the NT header.
                        if (bReader.ReadUInt32() == 17744) //check the PE\0\0 signature.
                        {
                            fStream.Seek(20, System.IO.SeekOrigin.Current); //seek past the file header,
                            architecture = bReader.ReadUInt16(); //read the magic number of the optional header.
                        }
                    }
                }
            }
        }
        catch (Exception) { /* TODO: Any exception handling you want to do, personally I just take 0 as a sign of failure */}
        //if architecture returns 0, there has been an error.
        return architecture;
    }
}

Bây giờ các hằng số hiện tại là:

0x10B - PE32  format.
0x20B - PE32+ format.

Nhưng với phương pháp này, nó cho phép các khả năng của các hằng số mới, chỉ cần xác nhận lợi nhuận khi bạn thấy phù hợp.


1
Thật thú vị, cảm ơn mã đã giải thích. Module.GetPEKind có lẽ là con đường dễ nhất. Nhưng điều này rất hữu ích cho việc học. Cảm ơn.
Giu-đa Gabriel Himango

3
Rất thú vị nhưng khi tôi có một ứng dụng được biên dịch với Any CPU, kết quả là 0x10B. Điều này là sai vì ứng dụng của tôi được chạy trong hệ thống x64. Có cờ nào khác để kiểm tra không?
Samuel

GetPEArch architecture hoạt động cho các hội đồng được biên dịch bằng .net 3.5, 4.0, 4.5 và 4.5.1? Dù sao, tôi nghĩ, Module.GetPEKind thất bại trong quy trình 64 bit khi kiểm tra các cụm 32 bit.
Kiquenet

9

Hãy thử sử dụng CorFlagsReader từ dự án này tại CodePlex . Nó không có tài liệu tham khảo cho các hội đồng khác và nó có thể được sử dụng như là.


1
Đây là câu trả lời chính xác và hữu ích nhất.
Kirill Osenkov

Liên kết vẫn hoạt động như khi viết bài này, nhưng vì CodePlex sắp ngừng hoạt động, sẽ rất tốt để thực hiện hành động thích hợp trước khi quá muộn.
Peter Mortensen

7

DotPeek từ JetBrians cung cấp cách nhanh chóng và dễ dàng để xem msil (anycpu), x86, x64 dotPeek


6
[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);
    }
}

Cảm ơn vì điều này, Một trong những ứng dụng của chúng tôi phải được xây dựng là x86, thêm một bài kiểm tra đơn vị đảm bảo rằng các thư viện xây dựng của máy chủ xây dựng sẽ là 32 bit và tránh những lỗi đó xảy ra :)
Mido

5

Dưới đây là một tệp bó sẽ chạy corflags.exevới tất cả dllsexestrong thư mục làm việc hiện tại và tất cả các thư mục con, phân tích kết quả và hiển thị kiến ​​trúc đích của mỗi thư mục.

Tùy thuộc vào phiên bản của corflags.exemà được sử dụng, các chi tiết đơn trong đầu ra một trong hai sẽ bao gồm 32BIT, hoặc 32BITREQ (và 32BITPREF). Bất kỳ mục nào trong hai mục này được bao gồm trong đầu ra là mục hàng quan trọng phải được kiểm tra để phân biệt giữa Any CPUx86. Nếu bạn đang sử dụng phiên bản cũ hơn corflags.exe(trước Windows SDK v8.0A), thì chỉ có 32BITchi tiết đơn hàng sẽ xuất hiện trong đầu ra, như những người khác đã chỉ ra trong các câu trả lời trước đây. Nếu không 32BITREQ32BITPREFthay thế nó.

Giả định corflags.exenày là trong %PATH%. Cách đơn giản nhất để đảm bảo điều này là sử dụng a Developer Command Prompt. Ngoài ra, bạn có thể sao chép nó từ vị trí mặc định của nó .

Nếu tệp bó bên dưới được chạy không được quản lý dllhoặc exe, nó sẽ hiển thị không chính xác vì x86, vì đầu ra thực tế Corflags.exesẽ là một thông báo lỗi tương tự như:

corflags: error CF008: Tệp được chỉ định không có tiêu đề được quản lý hợp lệ

@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.

2

Một cách nữa là sử dụng dumpbin từ các công cụ Visual Studio trên DLL và tìm đầu ra thích hợp

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

Lưu ý: Trên o / p là cho dll 32 bit

Một tùy chọn hữu ích hơn với dumpbin.exe là / XUẤT KHẨU, Nó sẽ hiển thị cho bạn chức năng được hiển thị bởi dll

dumpbin.exe /EXPORTS <PATH OF THE DLL>

2

Cách chung hơn - sử dụng cấu trúc tệp để xác định độ bit và loại hình ảnh:

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);
    }
}

Bảng liệt kê chế độ biên dịch

[Flags]
public enum CompilationMode
{
    Invalid = 0,
    Native = 0x1,
    CLR = Native << 1,
    Bit32 = CLR << 1,
    Bit64 = Bit32 << 1
}

Mã nguồn với lời giải thích tại GitHub



1

Một cách khác để kiểm tra nền tảng đích của lắp ráp .NET là kiểm tra lắp ráp bằng .NET Reflector ...

@ # ~ # € ~! Tôi mới nhận ra rằng phiên bản mới không miễn phí! Vì vậy, điều chỉnh, nếu bạn có một phiên bản .NET Reflector miễn phí, bạn có thể sử dụng nó để kiểm tra nền tảng đích.


9
Sử dụng ILSpy , đây là một ứng dụng mã nguồn mở cơ bản thực hiện nhiều thao tác tương tự như Reflector
Binary Worrier

1

cfeduke lưu ý khả năng gọi GetPEKind. Nó có khả năng thú vị để làm điều này từ PowerShell.

Ví dụ, đây là mã cho một lệnh ghép ngắn có thể được sử dụng: https://stackoverflow.com/a/16181743/64257

Ngoài ra, tại https://stackoverflow.com/a/4719567/64257 lưu ý rằng "cũng có lệnh ghép ngắn Get-PEHeader trong Tiện ích mở rộng cộng đồng PowerShell có thể được sử dụng để kiểm tra các hình ảnh thực thi."


1

Một ứng dụng nâng cao hơn mà bạn có thể tìm thấy ở đây: CodePlex - ApiChange

Ví dụ:

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

0

Một thay thế cho các công cụ đã được đề cập là Telerik JustDecompile (công cụ miễn phí) sẽ hiển thị thông tin bên cạnh tên lắp ráp:

Bất kỳ hoặc x86 hoặc x64 thông tin trong Telerik

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.