실행 파일이 컴파일된 플랫폼을 확인하려면 어떻게 해야 합니까?
x86, x64 및 IA64용 Windows 실행 파일을 사용해야 합니다.저는 파일 자체를 검토하여 플랫폼을 프로그래밍 방식으로 파악하고 싶습니다.
제 목표 언어는 PowerShell이지만 C# 예제를 사용하면 됩니다.둘 중 하나라도 실패한다면, 필요한 논리를 알고 있다면 좋을 것입니다.
Visual Studio가 설치되어 있는 경우dumpbin.exe
그리고 또.Get-PEHeader
실행 가능한 이미지를 테스트하는 데 사용할 수 있는 PowerShell Community Extensions의 cmdlet입니다.
Dumpbin은 DLL을 다음과 같이 보고합니다.machine (x86)
또는machine (x64)
Get-PEHeader는 DLL을 다음 중 하나로 보고합니다.PE32
또는PE32+
(다른 Q에서, 제거된 이후)
컴퓨터 유형:이것은 링커 타임스탬프를 얻는 일부 코드에 기반한 간단한 코드입니다.이것은 동일한 헤더에 있으며 작동하는 것 같습니다. 컴파일 시 I386을 반환합니다. 컴파일 시 - any cpu-를 반환하고 있습니다.
다른 응답이 기록한 대로 오프셋을 보여준 탐색 PE 헤더(K. Stanton, MSDN) 블로그 항목.
public enum MachineType {
Native = 0, I386 = 0x014c, Itanium = 0x0200, x64 = 0x8664
}
public static MachineType GetMachineType(string fileName)
{
const int PE_POINTER_OFFSET = 60;
const int MACHINE_OFFSET = 4;
byte[] data = new byte[4096];
using (Stream s = new FileStream(fileName, FileMode.Open, FileAccess.Read)) {
s.Read(data, 0, 4096);
}
// dos header is 64 bytes, last element, long (4 bytes) is the address of the PE header
int PE_HEADER_ADDR = BitConverter.ToInt32(data, PE_POINTER_OFFSET);
int machineUint = BitConverter.ToUInt16(data, PE_HEADER_ADDR + MACHINE_OFFSET);
return (MachineType)machineUint;
}
GetBinaryType win32 기능이 필요합니다.PE 형식 실행 파일의 관련 부분이 반환됩니다.
일반적으로 SCS_32B가 제공됩니다.IT_BINARY 또는 SCS_64BBinaryType 필드의 IT_BINARY,
또는 PE 형식 자체를 확인하여 실행 파일이 컴파일되는 아키텍처를 확인할 수 있습니다.
IMAGE_FILE_HEADER.시스템 필드에는 IA64 이진에 대해 "IMAGE_FILE_MACHINE_IA64"가 설정되고 32비트에 대해 IMAGE_FILE_MACHINE_I386이 설정되며 64비트(즉 x86_64)에 대해 IMAGE_FILE_MACHINE_AMD64가 설정됩니다.
MSDN 매거진 기사가 있습니다.
부록:이것은 당신에게 조금 더 도움이 될 수 있습니다.바이너리를 파일로 읽습니다. 처음 2바이트를 "MZ"라고 입력한 다음, 다음 58바이트를 건너뛰고 60바이트에서 마법의 32비트 값을 이미지로 읽습니다(PE 실행 파일의 경우 0x00004550에 해당).다음 바이트는 이 헤더이며, 처음 2바이트는 바이너리가 어떤 시스템용으로 설계되었는지 알려줍니다(0x8664 = x86_64, 0x0200 = IA64, 0x014c = i386).
(실행 요약: 파일의 바이트 65 및 66을 읽어 이미지 유형을 가져옵니다.)
"애플리케이션이 32비트용으로 컴파일되었는지 64비트용으로 컴파일되었는지 확인하는 10가지 방법"에 따라 DLL 또는 EXE가 32비트인지 64비트인지 확인하려면 메모장을 사용하여 해당 파일을 열고PE
시작할 때 - 그 이후의 세 번째 문자가 다음인 경우:
- 하나의
L
- a
d
DLL로 해봤는데 정확한 것 같습니다.
Assembly assembly = Assembly.LoadFile(Path.GetFullPath("ConsoleApplication1.exe"));
Module manifestModule = assembly.ManifestModule;
PortableExecutableKinds peKind;
ImageFileMachine machine;
manifestModule.GetPEKind(out peKind, out machine);
그런 다음 대상 시스템이 시스템에 있어야 합니다.
그것은 에만 적용됩니다.하지만 NET 어셈블리.
dumpbin.exe
에서 이용 합니다.bin
는 Visual Studio에서 합니다..lib
그리고..dll
dumpbin.exe /headers *.dll |findstr machine
dumpbin.exe /headers *.lib |findstr machine
유닉스 OS에는 파일을 식별하는 "file"이라는 유틸리티가 있습니다.식별 규칙은 "매직"이라는 설명 파일에 보관됩니다.파일을 사용하여 파일을 올바르게 식별하고 마법 파일에서 적절한 규칙을 가져올 수 있는지 확인할 수 있습니다.
IMAGE_FILE_HEADER에 액세스하기 위한 일부 C# 코드에 대한 링크를 제공할 수 있습니다. 이 링크는 PowerShell cmdlet으로 쉽게 컴파일할 수 있을 것 같습니다.그 방법은 포인터와 핀보케 기능이 없기 때문에 PowerShell 스크립트에서 직접 사용할 수 없습니다.
하지만 지금까지는 PE 헤더 형식에 대한 광범위한 지식을 사용할 수 있어야 합니다;-). 올바른 바이트로 바로 이동하여 파악할 수 있습니다.이것은 PowerShell 스크립트에서 작동하며 Tasos의 블로그에서 스크립트로 이 C# 코드를 변환하기만 하면 됩니다.제 것이 아니기 때문에 여기서 코드를 반복하지 않겠습니다.
여기 C의 구현이 있습니다.
// Determines if DLL is 32-bit or 64-bit.
#include <stdio.h>
int sGetDllType(const char *dll_name);
int main()
{
int ret;
const char *fname = "sample_32.dll";
//const char *fname = "sample_64.dll";
ret = sGetDllType(fname);
}
static int sGetDllType(const char *dll_name) {
const int PE_POINTER_OFFSET = 60;
const int MACHINE_TYPE_OFFSET = 4;
FILE *fp;
unsigned int ret = 0;
int peoffset;
unsigned short machine;
fp = fopen(dll_name, "rb");
unsigned char data[4096];
ret = fread(data, sizeof(char), 4096, fp);
fclose(fp);
if (ret == 0)
return -1;
if ( (data[0] == 'M') && (data[1] == 'Z') ) {
// Initial magic header is good
peoffset = data[PE_POINTER_OFFSET + 3];
peoffset = (peoffset << 8) + data[PE_POINTER_OFFSET + 2];
peoffset = (peoffset << 8) + data[PE_POINTER_OFFSET + 1];
peoffset = (peoffset << 8) + data[PE_POINTER_OFFSET];
// Check second header
if ((data[peoffset] == 'P') && (data[peoffset + 1] == 'E')) {
machine = data[peoffset + MACHINE_TYPE_OFFSET];
machine = (machine)+(data[peoffset + MACHINE_TYPE_OFFSET + 1] << 8);
if (machine == 0x014c)
return 32;
if (machine == 0x8664)
return 64;
return -1;
}
return -1;
}
else
return -1;
}
파일 헤더 정보를 기록하는 C++ MFC 콘솔 응용 프로그램입니다.시스템 유형(IMAGE_FILE_HEADER Machine 멤버) 또는 IMAGE_FILE_32B를 확인할 수 있습니다.파일이 어떤 플랫폼용으로 구축되었는지 확인하려면 특성에 IT_MACHINE 플래그를 지정합니다.구조에 대한 자세한 내용은 WinNT.h를 참조하십시오.
#include "stdafx.h"
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
int nrd;
IMAGE_DOS_HEADER idh;
IMAGE_NT_HEADERS inth;
IMAGE_FILE_HEADER ifh;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
return 1;
}
if (argc != 2) {
_ftprintf(stderr, _T("Usage: %s filename\n"), argv[0]);
return 1;
}
// Try to open the file
CFile ckf;
CFileException ex;
DWORD flags = CFile::modeRead | CFile::shareDenyNone;
if (!ckf.Open(argv[1], flags, &ex)) {
TCHAR szError[1024];
ex.GetErrorMessage(szError, 1024);
_tprintf_s(_T("Couldn't open file: %1024s"), szError);
return 2;
}
// The following is adapted from:
// https://stackoverflow.com/questions/495244/how-can-i-test-a-windows-dll-file-to-determine-if-it-is-32-bit-or-64-bit
// https://stackoverflow.com/questions/46024914/how-to-parse-exe-file-and-get-data-from-image-dos-header-structure-using-c-and
// Seek to beginning of file
ckf.Seek(0, CFile::begin);
// Read DOS header
int nbytes = sizeof(IMAGE_DOS_HEADER);
nrd = ckf.Read(&idh, nbytes);
// The idh.e_lfanew member is the offset to the NT_HEADERS structure
ckf.Seek(idh.e_lfanew, CFile::begin);
// Read NT headers
nbytes = sizeof(IMAGE_NT_HEADERS);
nrd = ckf.Read(&inth, nbytes);
ifh = inth.FileHeader;
_ftprintf(stdout, _T("File machine type: "));
switch (ifh.Machine) {
case IMAGE_FILE_MACHINE_I386:
_ftprintf(stdout, _T("I386\n"));
break;
case IMAGE_FILE_MACHINE_IA64:
_ftprintf(stdout, _T("IA64\n"));
break;
case IMAGE_FILE_MACHINE_AMD64:
_ftprintf(stdout, _T("AMD64\n"));
break;
default:
_ftprintf(stdout, _T("Unknown (%d = %X)\n"), ifh.Machine, ifh.Machine);
break;
}
// Write characteristics (see WinNT.h)
_ftprintf(stdout, _T("Characteristics:\n"));
_ftprintf(stdout, _T("RELOCS_STRIPPED Relocation info stripped from file: %c\n"),
(ifh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("EXECUTABLE_IMAGE File is executable (i.e. no unresolved externel references): %c\n"),
(ifh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("LINE_NUMS_STRIPPED Line nunbers stripped from file: %c\n"),
(ifh.Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("LOCAL_SYMS_STRIPPED Local symbols stripped from file: %c\n"),
(ifh.Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("AGGRESIVE_WS_TRIM Agressively trim working set: %c\n"),
(ifh.Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("LARGE_ADDRESS_AWARE App can handle >2gb addresses: %c\n"),
(ifh.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("BYTES_REVERSED_LO Bytes of machine word are reversed: %c\n"),
(ifh.Characteristics & IMAGE_FILE_BYTES_REVERSED_LO ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("32BIT_MACHINE 32 bit word machine: %c\n"),
(ifh.Characteristics & IMAGE_FILE_32BIT_MACHINE ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("DEBUG_STRIPPED Debugging info stripped from file in .DBG file: %c\n"),
(ifh.Characteristics & IMAGE_FILE_DEBUG_STRIPPED ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("REMOVABLE_RUN_FROM_SWAP If Image is on removable media, copy and run from the swap file: %c\n"),
(ifh.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("NET_RUN_FROM_SWAP If Image is on Net, copy and run from the swap file: %c\n"),
(ifh.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("SYSTEM System File: %c\n"),
(ifh.Characteristics & IMAGE_FILE_SYSTEM ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("DLL File is a DLL: %c\n"),
(ifh.Characteristics & IMAGE_FILE_DLL ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("UP_SYSTEM_ONLY File should only be run on a UP machine: %c\n"),
(ifh.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY ? _T('Y') : _T('N')));
_ftprintf(stdout, _T("BYTES_REVERSED_HI Bytes of machine word are reversed: %c\n"),
(ifh.Characteristics & IMAGE_FILE_BYTES_REVERSED_HI ? _T('Y') : _T('N')));
ckf.Close();
return nRetCode;
}
다음은 몇 가지 검사를 더 수행하고 항상 결과를 반환하는 저만의 구현입니다.
// the enum of known pe file types
public enum FilePEType : ushort
{
IMAGE_FILE_MACHINE_UNKNOWN = 0x0,
IMAGE_FILE_MACHINE_AM33 = 0x1d3,
IMAGE_FILE_MACHINE_AMD64 = 0x8664,
IMAGE_FILE_MACHINE_ARM = 0x1c0,
IMAGE_FILE_MACHINE_EBC = 0xebc,
IMAGE_FILE_MACHINE_I386 = 0x14c,
IMAGE_FILE_MACHINE_IA64 = 0x200,
IMAGE_FILE_MACHINE_M32R = 0x9041,
IMAGE_FILE_MACHINE_MIPS16 = 0x266,
IMAGE_FILE_MACHINE_MIPSFPU = 0x366,
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466,
IMAGE_FILE_MACHINE_POWERPC = 0x1f0,
IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1,
IMAGE_FILE_MACHINE_R4000 = 0x166,
IMAGE_FILE_MACHINE_SH3 = 0x1a2,
IMAGE_FILE_MACHINE_SH3DSP = 0x1a3,
IMAGE_FILE_MACHINE_SH4 = 0x1a6,
IMAGE_FILE_MACHINE_SH5 = 0x1a8,
IMAGE_FILE_MACHINE_THUMB = 0x1c2,
IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169,
}
// pass the path to the file and check the return
public static FilePEType GetFilePE(string path)
{
FilePEType pe = new FilePEType();
pe = FilePEType.IMAGE_FILE_MACHINE_UNKNOWN;
if(File.Exists(path))
{
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
byte[] data = new byte[4096];
fs.Read(data, 0, 4096);
ushort result = BitConverter.ToUInt16(data, BitConverter.ToInt32(data, 60) + 4);
try
{
pe = (FilePEType)result;
} catch (Exception)
{
pe = FilePEType.IMAGE_FILE_MACHINE_UNKNOWN;
}
}
}
return pe;
}
사용 방법:
string myfile = @"c:\windows\explorer.exe"; // the file
FilePEType pe = GetFilePE( myfile );
System.Diagnostics.WriteLine( pe.ToString() );
여기에 사용된 열거형 값의 경우 pe.go에서 가져옵니다.이것이 작동하는 이유는 'go'의 각 이진 분포에 대해 어셈블리에 올바른 플래그가 있어야 운영 체제 '여기서 실행할 수 있습니까?' 확인을 통과할 수 있기 때문입니다.'go'는 크로스 플랫폼(모든 플랫폼)이기 때문에 이 정보를 얻을 수 있는 좋은 기반입니다.아마도 이 정보에 대한 다른 출처가 있을 것이지만, 그것들은 구글-푸의 10번째 단 블랙 벨트가 필요한 구글 ca-ca에 무릎 깊이까지 내포되어 있는 것으로 보입니다.
다음은 C/C++를 독립 실행형 도구로 사용하여 필요한 모든 것에 적응할 수 있는 또 다른 솔루션입니다.
// Fri May 28, 2021 -two
#include <stdio.h>
#include <io.h>
#include <stdint.h>
#include <iostream.h>
using namespace std;
bool queryExeMachineType( const char *filename )
{
FILE *fp = fopen( filename, "rb" );
if (fp == NULL)
return false;
// DOS header is 64 bytes
const uint32_t fsize = filelength( fileno( fp ) );
char magic[ 2 ] = { 0 };
uint32_t offset = 0;
uint16_t machine = 0;
if (fread( magic, 1, 2, fp ) != 2 || magic[ 0 ] != 'M' || magic[ 1 ] != 'Z')
{
cerr << "not an executable file" << endl;
fclose( fp );
return false;
}
fseek( fp, 60, SEEK_SET );
fread( &offset, 1, 4, fp );
if (offset >= fsize)
{
cerr << "invalid pe offset" << endl;
fclose( fp );
return false;
}
fseek( fp, offset, SEEK_SET );
if (fread( magic, 1, 2, fp ) != 2 || magic[ 0 ] != 'P' || magic[ 1 ] != 'E')
{
cerr << "not a pe executable" << endl;
fclose( fp );
return false;
}
fread( magic, 1, 2, fp );
fread( &machine, 1, 2, fp );
switch (machine)
{
case 0x014c:
cout << "i386" << endl; // x86
break;
case 0x8664:
cout << "amd64" << endl; // x86_64
break;
case 0x0200:
cout << "ia64" << endl; // itanium
break;
default:
cerr << "unknown machine 0x" << hex << machine << endl;
break;
}
fclose( fp );
return true;
}
int main( int argc, char *argv[] )
{
const char *fn = (argc > 1) ? argv[ 1 ] : "test.dll";
if (queryExeMachineType( fn ))
cerr << "succeeded" << endl;
else
cerr << "failed" << endl;
return 0;
}
언급URL : https://stackoverflow.com/questions/197951/how-can-i-determine-for-which-platform-an-executable-is-compiled
'programing' 카테고리의 다른 글
PHP mysqli 인터페이스를 사용하여 MariaDB에 저장 프로시저를 호출하는 가장 좋은 방법은 무엇입니까? (0) | 2023.08.30 |
---|---|
포트 3306에서 MySQL을 시작할 수 없음 (0) | 2023.08.30 |
mysqdump에서 생성된 /*!xxxxxx 문 */의 의미는 무엇입니까? (0) | 2023.08.30 |
단추를 풀 너비로 설정하시겠습니까? (0) | 2023.08.30 |
다른 조각 문제에 대한 조각 (0) | 2023.08.30 |