Bagaimana saya bisa menentukan apakah perakitan .NET dibangun untuk x86 atau x64?

327

Saya punya daftar arbitrer. NET rakitan.

Saya perlu memeriksa secara terprogram apakah setiap DLL dibangun untuk x86 (sebagai lawan dari x64 atau CPU apa pun). Apakah ini mungkin?

Yehuda Gabriel Himango
sumber
2
Anda mungkin juga ingin memeriksa yang ini: check-if-unmanaged-dll-is-32-bit-or-64-bit .
Matt
2
Dalam versi terbaru dari CorFlags, yang sesuai dengan .NET 4.5, "32BIT" digantikan oleh "32BITREQ" dan "32BITPREF". .
Peter Mortensen

Jawaban:

281

Melihat System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

Anda dapat memeriksa metadata perakitan dari instance AssemblyName yang dikembalikan:

Menggunakan PowerShell :

[36] C: \> [reflection.assemblyname] :: GetAssemblyName ("$ {pwd} \ Microsoft.GLEE.dll") | fl

Nama: Microsoft.GLEE
Versi: 1.0.0.0
Info budaya:
CodeBase: file: /// C: / proyek / PowerShell / BuildAnalyzer / ...
EscapedCodeBase: file: /// C: / proyek / PowerShell / BuildAnalyzer / ...
Prosesor Arsitektur: MSIL
Bendera: PublicKey
Algoritma Hash: SHA1
VersionCompatibility: SameMachine
KeyPair:
Nama Lengkap: Microsoft.GLEE, Versi = 1.0.0.0, Kultur = netral ... 

Di sini, ProcessorArchitecture mengidentifikasi platform target.

  • Amd64 : Prosesor 64-bit berdasarkan arsitektur x64.
  • Lengan : Prosesor ARM.
  • IA64 : Prosesor Intel Itanium 64-bit saja.
  • MSIL : Netral sehubungan dengan prosesor dan bit per kata.
  • X86 : Prosesor Intel 32-bit, baik asli atau di lingkungan Windows pada Windows pada platform 64-bit (WOW64).
  • Tidak ada : Kombinasi prosesor dan bit per kata yang tidak diketahui atau tidak spesifik.

Saya menggunakan PowerShell dalam contoh ini untuk memanggil metode.

x0n
sumber
60
Maafkan pertanyaan bodoh - tetapi apa artinya ini memberitahu Anda bahwa itu x86?
George Mauer
53
Bidang ProcessorArchitecture adalah enumerasi; dalam contoh di atas diatur ke MSIL, yang berarti "Netral sehubungan dengan prosesor dan bit per kata." Nilai-nilai lain termasuk X86, IA64, Amd64. Lihat msdn.microsoft.com/en-us/library/… untuk lebih jelasnya.
Brian Gillespie
4
Coba dengan [reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")kadang-kadang direktori proses saat ini tidak sama dengan penyedia saat ini (yang mana saya menganggap DLL adalah untuk Anda)
x0n
2
Peringatan lain yang harus diperhatikan adalah lupa untuk "membuka blokir" DLL jika Anda mengunduhnya dari internet. Gunakan unblock-file, atau klik kanan / properties / unblock dari explorer. Anda harus memulai ulang shell untuk mengenali status yang tidak diblokir jika Anda sudah gagal sekali dalam sesi saat ini (salahkan penjelajah internet untuk itu - ya, sungguh.)
x0n
1
Dalam kode ASP.NET MVC, ada komentar // 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.Sayangnya, tidak ada cara untuk membaca ProcessorArchitecture tanpa menggunakan GetName instance method; menggunakan AssemblyName constructor, bidang selalu diatur ke None.
metadings
221

Anda dapat menggunakan alat CorFlags CLI (misalnya, C: \ Program Files \ Microsoft SDKs Windows \ v7.0 \ Bin \ CorFlags.exe) untuk menentukan status perakitan, berdasarkan outputnya dan membuka perakitan sebagai aset biner Anda harus dapat menentukan di mana Anda perlu mencari untuk menentukan apakah flag 32BIT diatur ke 1 ( x86 ) atau 0 ( Setiap CPU atau x64 , tergantung pada PE):

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

Posting blog Pengembangan x64 dengan .NET memiliki beberapa informasi tentang corflags.

Bahkan lebih baik, Anda dapat menggunakanModule.GetPEKind untuk menentukan apakah suatu perakitan PortableExecutableKindsbernilai PE32Plus(64-bit), Required32Bit(32-bit dan WOW), atau ILOnly(CPU apa saja) bersama dengan atribut lainnya.

cfeduke
sumber
1
Setelah melihat pembaruan Anda, menggunakan GetPEKind tampaknya menjadi cara yang tepat untuk melakukan ini. Saya menandai jawaban Anda sebagai jawabannya.
Yehuda Gabriel Himango
9
GetPEKind gagal dalam proses 64 bit saat memeriksa 32 bit rakitan
jjxtra
2
Anda harus memanggil GetPEKind dari proses 32bit
Ludwo
2
Saya menginstal VS 2008, VS 2010, VS 2012 dan VS 2013. Saya punya 8 file CorFlags.exe di subfolder di C: \ Program Files (x86) \ Microsoft SDKs \ Windows \. Yang mana yang harus saya gunakan?
Kiquenet
5
Seperti yang ditunjukkan dalam jawaban ini , di .NET 4.5 ada 32BITREQ dan 32BITPREF sebagai ganti flag 32BIT. PE32 / 0/0 dan PE32 / 0/1 masing-masing adalah AnyCPU dan AnyCPU 32-bit.
angularsen
141

Hanya untuk klarifikasi, CorFlags.exe adalah bagian dari .NET Framework SDK . Saya memiliki alat pengembangan di komputer saya, dan cara paling sederhana bagi saya untuk menentukan apakah DLL hanya 32-bit adalah dengan:

  1. Buka Visual Studio Command Prompt (Di Windows: menu Start / Programs / Microsoft Visual Studio / Visual Studio Tools / Visual Studio 2008 Command Prompt)

  2. CD ke direktori yang berisi DLL yang dimaksud

  3. Jalankan corflags seperti ini: corflags MyAssembly.dll

Anda akan mendapatkan hasil seperti ini:

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

Sesuai komentar, bendera di atas harus dibaca sebagai berikut:

  • Setiap CPU: PE = PE32 dan 32BIT = 0
  • x86: PE = PE32 dan 32BIT = 1
  • 64-bit: PE = PE32 + dan 32BIT = 0
JoshL
sumber
12
Ini tampaknya telah berubah sementara itu; corflags sekarang menampilkan 32BITREQdan 32BITPREFbukannya 32BITnilai tunggal .
ATAU Mapper
1
Microsoft .NET 4.5 memperkenalkan opsi baru, Apa Saja CPU 32-bit yang Diinginkan. Berikut detailnya.
RBT
"Visual Studio Command Prompt" saat ini disebut " Visual Studio 2019 Command Prompt Developer ".
Uwe Keim
22

Bagaimana kalau Anda hanya menulis milik Anda sendiri? Inti dari arsitektur PE belum berubah secara serius sejak penerapannya pada Windows 95. Berikut ini adalah contoh 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;
    }
}

Sekarang konstanta saat ini adalah:

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

Tetapi dengan metode ini memungkinkan untuk kemungkinan konstanta baru, hanya memvalidasi pengembalian sesuai keinginan Anda.

Jason
sumber
1
Menarik, terima kasih untuk kodenya dengan penjelasan. Module.GetPEKind mungkin jalan yang paling mudah. Tetapi ini bermanfaat untuk pembelajaran. Terima kasih.
Yehuda Gabriel Himango
3
Sangat menarik tetapi ketika saya memiliki aplikasi yang dikompilasi dengan CPU Apa pun, hasilnya adalah 0x10B. Ini salah karena aplikasi saya dijalankan di sistem x64. Apakah ada bendera lain untuk diperiksa?
Samuel
GetPEArchitecture berfungsi untuk rakitan yang dikompilasi menggunakan .net 3.5, 4.0, 4.5 dan 4.5.1? Bagaimanapun, saya pikir, Module.GetPEKind gagal dalam proses 64 bit ketika memeriksa 32 bit rakitan.
Kiquenet
9

Coba gunakan CorFlagsReader dari proyek ini di CodePlex . Itu tidak memiliki referensi ke majelis lain dan dapat digunakan apa adanya.

Ludwo
sumber
1
Ini adalah jawaban yang paling akurat dan bermanfaat.
Kirill Osenkov
Tautannya masih berfungsi hingga tulisan ini dibuat, tetapi karena CodePlex akan ditutup, alangkah baiknya untuk melakukan tindakan yang sesuai sebelum terlambat.
Peter Mortensen
7

DotPeek dari JetBrians menyediakan cara cepat dan mudah untuk melihat msil (anycpu), x86, x64 dotPeek

Prabhakaran Rajagopal
sumber
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);
    }
}
Morgan Mellor
sumber
Terima kasih untuk ini, Salah satu aplikasi kami harus dibangun sebagai x86, menambahkan tes unit memastikan bahwa perpustakaan build server akan menjadi 32bit dan menghindari kesalahan-kesalahan itu terjadi :)
Mido
5

Di bawah ini adalah file batch yang akan berjalan corflags.exemelawan semua dllsdan exesdalam direktori kerja saat ini dan semua sub-direktori, parsing hasil dan menampilkan arsitektur target masing-masing.

Bergantung pada versi corflags.exeyang digunakan, item baris dalam output akan termasuk 32BIT, atau 32BITREQ (dan 32BITPREF). Yang mana dari kedua ini yang termasuk dalam output adalah item baris kritis yang harus diperiksa untuk membedakan antara Any CPUdan x86. Jika Anda menggunakan versi yang lebih lama dari corflags.exe(pra Windows SDK v8.0A), maka hanya 32BITitem baris yang akan ada di output, seperti yang lain telah ditunjukkan dalam jawaban sebelumnya. Kalau tidak 32BITREQ, 32BITPREFganti saja.

Asumsi corflags.exeini ada dalam %PATH%. Cara paling sederhana untuk memastikan ini adalah dengan menggunakan a Developer Command Prompt. Atau Anda dapat menyalinnya dari lokasi default itu .

Jika file batch di bawah ini dijalankan terhadap yang tidak dikelola dllatau exe, itu akan salah menampilkannya x86, karena output aktual dari Corflags.exeakan menjadi pesan kesalahan yang mirip dengan:

corflags: error CF008: File yang ditentukan tidak memiliki header terkelola yang valid

@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.
Eric Lease
sumber
2

Satu cara lagi adalah dengan menggunakan dumpbin dari alat Visual Studio di DLL dan mencari output yang sesuai

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

Catatan: Di atas o / p untuk 32bit dll

Satu lagi opsi yang berguna dengan dumpbin.exe adalah / EKSPOR, Ini akan menunjukkan kepada Anda fungsi yang diekspos oleh dll

dumpbin.exe /EXPORTS <PATH OF THE DLL>
Ayush joshi
sumber
2

Cara yang lebih umum - gunakan struktur file untuk menentukan bitness dan tipe gambar:

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

Enumerasi mode kompilasi

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

Kode sumber dengan penjelasan di GitHub

BlackGad
sumber
1

Cara lain untuk memeriksa platform target rakitan .NET adalah memeriksa rakitan dengan .NET Reflector ...

@ # ~ # € ~! Saya baru sadar bahwa versi baru itu tidak gratis! Jadi, koreksi, jika Anda memiliki versi gratis .NET reflector, Anda dapat menggunakannya untuk memeriksa platform target.

sakito
sumber
9
Gunakan ILSpy , ini adalah aplikasi open source dasar yang melakukan banyak hal yang sama seperti Reflector
Binary Worrier
1

Aplikasi yang lebih canggih untuk itu dapat Anda temukan di sini: CodePlex - ApiChange

Contoh:

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
Wernfried Domscheit
sumber
0

Alternatif untuk alat yang telah disebutkan adalah Telerik JustDecompile (alat gratis) yang akan menampilkan informasi di sebelah nama majelis:

Setiap informasi x86 atau x64 di Telerik

Alexei
sumber