web-dev-qa-db-ja.com

実行可能ファイルがコンパイルされているプラ​​ットフォームを判別するにはどうすればよいですか?

X86、x64、およびIA64用に作成されたWindows実行可能ファイルを使用する必要があります。ファイル自体を調べて、プログラムでプラットフォームを見つけたいと思います。

私のターゲット言語はPowerShellですが、C#の例で十分です。これらのいずれかが失敗しても、必要なロジックがわかっていればそれはすばらしいことです。

49
halr9000

(削除されたため、別のQから)

マシンタイプ:これは、リンカのタイムスタンプを取得するコードに基づいた簡単なコードです。これは同じヘッダーにあり、動作するようです-コンパイルするとI386(任意のCPU)を返し、それをターゲットプラットフォームとしてコンパイルするとx64を返します。

別の回答で指摘されているように、オフセットを示したExploring PE Headers(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;
}
25
Andrew Backer

Visual Studioがインストールされている場合は、_dumpbin.exe_を使用できます。 PowerShell Community Extensions には、実行可能イメージのテストに使用できる_Get-PEHeader_コマンドレットもあります。

DumpbinはDLLをmachine (x86)またはmachine (x64)として報告します

Get-PEHeaderはDLLを_PE32_または_PE32+_として報告します

38
Keith Hill

GetBinaryType win32関数が必要です。これは、PE形式の実行可能ファイルの関連部分を返します。

通常、BinaryTypeフィールドにはSCS_32BIT_BINARYまたはSCS_64BIT_BINARYが表示されます。

または、PE形式自体をチェックして、実行可能ファイルがコンパイルされているアーキテクチャを確認できます。

IMAGE_FILE_HEADER.Machineフィールドには、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に相当します)。次のバイトは this header であり、最初の2バイトは、バイナリがどのマシン用に設計されているかを示します(0x8664 = x86_64、0x0200 = IA64、0x014c = i386)。

(エグゼクティブサマリー:ファイルのバイト65と66を読み取り、イメージタイプを取得します)

11
gbjbaanb
Assembly assembly = Assembly.LoadFile(Path.GetFullPath("ConsoleApplication1.exe"));
Module manifestModule = Assembly.ManifestModule;
PortableExecutableKinds peKind;
ImageFileMachine machine;
manifestModule.GetPEKind(out peKind, out machine);

これで、ターゲットマシンはマシン内にあるはずです。

ただし、これは.NETアセンブリでのみ機能します。

8
ICR

この 投稿 によると、DLLまたはEXEが32または64であるかどうかをNotePadそして最初に「PE」を探します。次の文字が「L」の場合、プラットフォームは32ビットです。文字が「D」の場合、プラットフォームは64ビットです。

私のdllで試してみましたが、正確なようです。

2
mrelva

dumpbin.exe Visual Studioのbinディレクトリで使用できます.libおよび.dll

 dumpbin.exe /headers *.dll |findstr machine
 dumpbin.exe /headers *.lib |findstr machine
1
Saad Saadi

私は いくつかのC#コードへのリンク をIMAGE_FILE_HEADERにアクセスするために提供できます。これは、(簡単に)PowerShellコマンドレットにコンパイルできると思います。このメソッドにはポインターとPInvoke機能がないため、PowerShellスクリプトでこのメソッドを直接使用することはできません。

ただし、PEヘッダー形式の広範な知識を使用して、;-)正しいバイトに「まっすぐ」進み、それを理解することができるはずです。これはwillがPowerShellスクリプトで機能し、 TasosのブログからのこのC#コード をスクリプトに変換できるだけです。私のコードではないので、ここでコードを繰り返す必要はありません。

1
Jaykul

Unix OSには、ファイルを識別する「ファイル」と呼ばれるユーティリティがあります。識別のルールは、「マジック」と呼ばれる記述ファイルに保存されています。 fileを試して、ファイルを正しく識別できるかどうかを確認し、マジックファイルから適切なルールを取得できます。

0
Sec

これは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;
}
0
Jiminion

これが私の独自の実装で、さらにいくつかのチェックがあり、常に結果を返します。

// 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」はクロスプラットフォーム(すべてのプラットフォーム)であるため、この情報を取得するための良いベースです。この情報のソースはおそらく他にもありますが、それらはgoogle ca-caでひざの深さにネストされているようで、Google-fuで10段の黒帯を見つける必要があります。

0
Kraang Prime