Chcę ustalić, czy natywny zestaw jest zgodny jako x64 lub x86 z aplikacji kodu zarządzanego ( C # ).
Myślę, że musi to być gdzieś w nagłówku PE, ponieważ moduł ładujący systemu operacyjnego musi znać te informacje, ale nie mogłem ich znaleźć. Oczywiście wolę to robić w kodzie zarządzanym, ale w razie potrzeby mogę użyć natywnego C ++.
Odpowiedzi:
Możesz też użyć DUMPBIN . Użyj flagi
/headers
lub/all
i jej pierwszego wymienionego nagłówka pliku.64-bitowy
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-bitowy
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
„znajdź” może nieco ułatwić życie:
dumpbin /headers cv210.dll |find "machine" 8664 machine (x64)
źródło
mspdb100.dll
:(mspdb100.dll
do folderu, w którymdumpbin.exe
się znajduje.DUMPBIN
może biec po tym. Dla mnie<Visual Studio Install folder>\VC\bin
plik EXE jest pod adresem, a plik DLL jest pod adresem<Visual Studio Install folder>\Common7\IDE
.Z CorFlags można to łatwo zrobić . Otwórz wiersz polecenia programu Visual Studio i wpisz „corflags [twój zestaw]”. Otrzymasz coś takiego:
Patrzysz konkretnie na PE i 32BIT.
Dowolny procesor :
PE: PE32
32BIT: 0
x86 :
PE: PE32
32BIT: 1
x64:
PE: PE32 +
32BIT: 0
źródło
Ta sztuczka działa i wymaga tylko Notatnika.
Otwórz plik dll za pomocą edytora tekstu (takiego jak Notatnik) i znajdź pierwsze wystąpienie ciągu
PE
. Poniższy znak określa, czy dll ma 32 czy 64 bity.32 bity:
64 bity:
źródło
Magic
DziedzinaIMAGE_OPTIONAL_HEADER
(choć nie ma nic opcjonalnie o nagłówku w systemie Windows (pliki wykonywalne zdjęć DLL / EXE)) powie architekturę PE.Oto przykład pobierania architektury z pliku.
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(); } }
Obecnie jedyne dwie stałe architektury to:
0x10b - PE32 0x20b - PE32+
Twoje zdrowie
AKTUALIZACJA Minęło trochę czasu, odkąd opublikowałem tę odpowiedź, ale nadal widzę, że od czasu do czasu dostaje kilka pozytywnych głosów, więc pomyślałem, że warto to zaktualizować. Napisałem sposób na uzyskanie architektury
Portable Executable
obrazu, który również sprawdza, czy został skompilowany jakoAnyCPU
. Niestety odpowiedź jest w C ++, ale nie powinno być zbyt trudno przenieść się do C #, jeśli masz kilka minut na sprawdzenie strukturWinNT.h
. Jeśli ludzie są zainteresowani, napiszę port w C #, ale jeśli ludzie tego nie chcą, nie spędzę zbyt wiele czasu na stresowaniu się tym.#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; }
Funkcja akceptuje wskaźnik do obrazu PE w pamięci (więc możesz wybrać swoją truciznę, jak ją zdobyć; mapowanie pamięci lub wczytywanie całości do pamięci ... cokolwiek).
źródło
32BIT
flagę w PE, nie wiem od początku mojej głowy.W przypadku niezarządzanego pliku DLL musisz najpierw sprawdzić, czy jest to 16-bitowy plik DLL (miejmy nadzieję, że nie). Następnie sprawdź
IMAGE\_FILE_HEADER.Machine
pole.Ktoś inny poświęcił trochę czasu, aby to już rozwiązać, więc powtórzę tutaj:
źródło
Tutaj możesz znaleźć przykładową implementację C # dla
IMAGE_FILE_HEADER
rozwiązaniaźródło
64-bitowe pliki binarne są przechowywane w formacie PE32 +. Spróbuj przeczytać http://www.masm32.com/board/index.php?action=dlattach;topic=6687.0;id=3486
źródło
Otwórz bibliotekę dll za pomocą edytora szesnastkowego, takiego jak HxD
Jeśli w dziewiątej linii znajduje się „dt”, jest to 64-bitowy.
Jeśli występuje litera „L.” w dziewiątej linii jest to 32 bity.
źródło
Przepisałem rozwiązanie C ++ w pierwszej odpowiedzi w skrypcie PowerShell. Skrypt może określić następujące typy plików .exe i .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
to rozwiązanie ma pewne zalety w stosunku do corflags.exe i ładowania zestawu przez Assembly.Load w C # - nigdy nie otrzymasz BadImageFormatException ani wiadomości o nieprawidłowym nagłówku.
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; }
przykład użycia:
#$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;
możesz pominąć drugi parametr, jeśli nie chcesz widzieć szczegółów
źródło
Szybki i prawdopodobnie brudny sposób na zrobienie tego jest opisany tutaj: https://superuser.com/a/889267 . Otwierasz bibliotekę DLL w edytorze i sprawdzasz pierwsze znaki po sekwencji „PE”.
źródło
Najwyraźniej można go znaleźć w nagłówku przenośnego pliku wykonywalnego. Narzędzie corflags.exe może pokazać, czy jest przeznaczony dla x64. Mamy nadzieję, że pomoże ci to znaleźć więcej informacji na ten temat.
źródło
>corflags libzmq.dll \n\n ... corflags : error CF008 : The specified file does not have a valid managed header