Як я можу визначити, чи була побудована збірка .NET для x86 або x64?


327

У мене є довільний перелік .NET-збірок.

Мені потрібно програмно перевірити, чи була створена кожна DLL для x86 (на відміну від x64 чи будь-якого процесора). Чи можливо це?



2
Ви також можете перевірити це: check-if-unmanaged-dll-is-32-bit-or-64-bit .
Мет

2
У пізнішій версії CorFlags, що відповідає .NET 4.5, "32BIT" було замінено на "32BITREQ" і "32BITPREF". .
Пітер Мортенсен

Відповіді:


280

Подивись на System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)

Ви можете вивчити метадані збирання з поверненого екземпляра AssemblyName:

Використання PowerShell :

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

Ім'я: Microsoft.GLEE
Версія: 1.0.0.0
КультураІнфо:
CodeBase: файл: /// C: / проекти / повноваження / BuildAnalyzer / ...
EscapedCodeBase: файл: /// C: / Проекти / powershell / BuildAnalyzer / ...
Процесорна архітектура: MSIL
Прапори: PublicKey
HashAlgorithm: SHA1
VersionCompatibility: SameMachine
KeyPair:
FullName: Microsoft.GLEE, версія = 1.0.0.0, культура = нейт ... 

Тут ProcessorArchitecture визначає цільову платформу.

  • Amd64 : 64-бітний процесор, заснований на архітектурі x64.
  • Рука : процесор ARM.
  • IA64 : 64-бітний процесор Intel Itanium.
  • MSIL : Нейтральний щодо процесора та бітів на слово.
  • X86 : 32-розрядний процесор Intel, рідний або в середовищі Windows для Windows на 64-бітній платформі (WOW64).
  • Ні : Невідома або не визначена комбінація процесора та біт на слово.

У цьому прикладі я використовую PowerShell для виклику методу.


60
Пробачте дурне запитання - але що в цьому говорить вам, що це x86?
Джордж Мауер

53
Поле ProcessorArchitecture - це перерахування; у наведеному вище прикладі встановлено MSIL, що означає "Нейтральний щодо процесора та біт на слово". Інші значення включають X86, IA64, Amd64. Докладніше див. У msdn.microsoft.com/en-us/library/… .
Брайан Гілзпі

4
Спробуйте, [reflection.assemblyname]::GetAssemblyName("${pwd}\name.dll")як іноді поточний каталог процесу не такий, як поточний провайдер (саме там я припускаю, що DLL призначений для вас)
x0n

2
Ще один застереження, на який слід звернути увагу, - це забути "розблокувати" DLL, якщо ви завантажили його з мереж. Використовуйте файл розблокування або клацніть правою кнопкою миші / властивості / розблокувати з Explorer. Вам потрібно буде перезапустити оболонку, щоб він розпізнав статус розблокованого, якщо ви вже не
працювали

1
У коді MVC ASP.NET є коментар // 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.На жаль, немає можливості прочитати ProcessorArchitecture без використання GetName instance method; використовуючи AssemblyName constructorполе, завжди встановлюється None.
метадінги

221

Ви можете використовувати інструмент CLI CorFlags (наприклад, C: \ Program Files \ Microsoft SDKs \ Windows \ v7.0 \ Bin \ CorFlags.exe) для визначення статусу збірки, виходячи з її результату та відкриття складання як бінарний актив, ви повинні мати змогу визначити, куди потрібно шукати, щоб визначити, чи встановлено прапор 32BIT на 1 ( x86 ) або 0 ( будь-який процесор або x64 , залежно від ):PE

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

У блозі x64 Development з .NET є деяка інформація про corflags.

Ще краще, ви можете використовувати,Module.GetPEKind щоб визначити, чи збірка є PortableExecutableKindsзначенням PE32Plus(64-бітним), Required32Bit(32-бітним і WOW), або ILOnly(будь-яким процесором) разом з іншими атрибутами.


1
Побачивши оновлення, використання GetPEKind - це правильний спосіб зробити це. Я позначив вашу як відповідь.
Іуда Габріель Хіманго

9
GetPEKind виходить з ладу в 64-бітовому процесі під час перевірки 32-бітових збірок
jjxtra

2
Вам потрібно зателефонувати GetPEKind з 32-
бітного

2
Я встановлюю VS 2008, VS 2010, VS 2012 та VS 2013. У мене є 8 файлів CorFlags.exe в папках C: \ Program Files (x86) \ Microsoft SDKs \ Windows \. Яким я повинен користуватися?
Кікенет

5
Як зазначено у цій відповіді , у .NET 4.5 замість прапора 32BIT є 32BITREQ та 32BITPREF. PE32 / 0/0 і PE32 / 0/1 є AnyCPU і AnyCPU, 32-бітні переважні відповідно.
angularsen

141

Тільки для уточнення CorFlags.exe є частиною .NET Framework SDK . На моїй машині у мене є інструменти розробки, і найпростіший спосіб визначити, чи є DLL 32-бітним, це:

  1. Відкрийте командний рядок Visual Studio (У Windows: меню Пуск / Програми / Microsoft Visual Studio / Інструменти Visual Studio / Командний рядок Visual Studio 2008)

  2. Компакт-диск до каталогу, що містить відповідну DLL

  3. Виконайте такі корфлаги: corflags MyAssembly.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  : 3
ILONLY    : 1
32BIT     : 1
Signed    : 0

Відповідно до коментарів, прапорці вище повинні читатися наступним чином:

  • Будь-який процесор: PE = PE32 і 32BIT = 0
  • x86: PE = PE32 і 32BIT = 1
  • 64-розрядні: PE = PE32 + і 32BIT = 0

12
Це, здається, тим часом змінилося; CorFlags тепер відображається 32BITREQі 32BITPREFзамість єдиного 32BITзначення.
АБО Mapper

1
Microsoft .NET 4.5 представив нову опцію, будь-який 32-розрядний процесор. Ось деталі.
RBT

«Командний рядок візуальної студії» в наш час називається « командний рядок для розробників Visual Studio 2019 ».
Уве

22

Як щодо того, що ти просто пишеш, що ти власний? Ядро архітектури PE не було серйозно змінено після її впровадження в Windows 95. Ось приклад 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;
    }
}

Зараз поточними константами є:

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

Але за допомогою цього методу він допускає можливості нових констант, просто перевіряйте повернення, як вважаєте за потрібне.


1
Цікаво, дякую за код з поясненнями. Модуль.GetPEKind - це, мабуть, найпростіший шлях. Але це корисно заради навчання. Дякую.
Іуда Габріель Хіманго

3
Дуже цікаво, але коли у мене є програма, складена з будь-яким процесором, результат 0x10B. Це неправильно, оскільки моя програма запускається в системі x64. Чи є ще якийсь прапор для перевірки?
Самуель

GetPEArchitecture працює для збірок, складених за допомогою .net 3.5, 4.0, 4.5 та 4.5.1? У будь-якому випадку, я думаю, що модуль.GetPEKind виходить з ладу в 64-бітовому процесі при перевірці 32-бітових збірок.
Кікенет

9

Спробуйте використовувати CorFlagsReader з цього проекту на CodePlex . Він не має посилань на інші збірки, і його можна використовувати як є.


1
Це найточніша і корисна відповідь.
Кирило Осенков

Посилання все ще працює з цього письма, але оскільки CodePlex вже припиняється, було б добре зробити відповідні дії до того, як буде занадто пізно.
Пітер Мортенсен


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

Дякуємо за це, одне з наших додатків має бути побудовано як x86, додаючи тестовий модуль, гарантує, що бібліотеки збірки сервера складання будуть 32-бітовими і не дозволяє цим помилкам траплятися :)
Mido

5

Нижче наведено пакетний файл, який буде працювати corflags.exeпроти всіх dllsта exesв поточному робочому каталозі та всіх підкаталогах, аналізувати результати та відображати цільову архітектуру кожного.

В залежності від версії corflags.exe, яка використовується, окремі позиції в виході буде або включати в себе 32BIT, або 32BITREQ32BITPREF). Що б із цих двох не було включено до виводу, - це найважливіша позиція, яку необхідно перевірити, щоб розмежовувати значення між Any CPUі x86. Якщо ви використовуєте старішу версію corflags.exe(до Windows SDK v8.0A), 32BITу висновку буде присутній лише позиція, як зазначено в попередніх відповідях. В іншому випадку 32BITREQі 32BITPREFзамініть його.

Це передбачає corflags.exe, що в %PATH%. Найпростіший спосіб забезпечити це - використовувати Developer Command Prompt. Крім того, ви можете скопіювати його з місця за замовчуванням .

Якщо пакетний файл, запущений нижче, запускається без керованого, dllабо exeвін буде неправильно відображати його як x86, оскільки фактичним результатом Corflags.exeбуде повідомлення про помилку, подібне до:

corflags: помилка CF008: В зазначеному файлі немає дійсного керованого заголовка

@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

Ще один спосіб - використовувати dumpbin з інструментів Visual Studio на DLL і шукати відповідний вихід

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

Примітка: Вище o / p - 32 біт dll

Ще один корисний варіант з dumpbin.exe - / ЕКСПОРТ, він покаже вам функцію, яку зазнає dllbin

dumpbin.exe /EXPORTS <PATH OF THE DLL>

2

Більш загальний спосіб - використовуйте структуру файлів для визначення бітовості та типу зображення:

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

Перерахування режиму компіляції

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

Вихідний код з поясненнями на GitHub



1

Ще один спосіб перевірити цільову платформу .NET збірки - це перевірка складання за допомогою .NET Reflector ...

@ # ~ # € ~! Я щойно зрозумів, що нова версія не безкоштовна! Отже, виправлення, якщо у вас є безкоштовна версія рефлектора .NET, ви можете використовувати його для перевірки цільової платформи.


9
Використовуйте ILSpy , це основний додаток з відкритим кодом, який робить те саме, що і Reflector
Binary Worrier

1

cfeduke відзначає можливість виклику GetPEKind. Це можливо зробити цікаво від PowerShell.

Ось, наприклад, код для командлета, який можна використовувати: https://stackoverflow.com/a/16181743/64257

Крім того, на веб-сторінці https://stackoverflow.com/a/4719567/64257 зазначається, що "в розширеннях PowerShell Community також існує командлет Get-PEHeader, який можна використовувати для тестування зображень, що виконуються."


1

Більш просунуте додаток для цього ви можете знайти тут: CodePlex - ApiChange

Приклади:

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

Альтернативою вже згаданим інструментам є Telerik JustDecompile (безкоштовний інструмент), який відображатиме інформацію поруч із назвою збірки:

Будь-яка інформація про x86 або x64 у Telerik

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.