X86、x64、およびIA64用に作成されたWindows実行可能ファイルを使用する必要があります。ファイル自体を調べて、プログラムでプラットフォームを見つけたいと思います。
私のターゲット言語はPowerShellですが、C#の例で十分です。これらのいずれかが失敗しても、必要なロジックがわかっていればそれはすばらしいことです。
(削除されたため、別の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;
}
Visual Studioがインストールされている場合は、_dumpbin.exe
_を使用できます。 PowerShell Community Extensions には、実行可能イメージのテストに使用できる_Get-PEHeader
_コマンドレットもあります。
DumpbinはDLLをmachine (x86)
またはmachine (x64)
として報告します
Get-PEHeaderはDLLを_PE32
_または_PE32+
_として報告します
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を読み取り、イメージタイプを取得します)
Assembly assembly = Assembly.LoadFile(Path.GetFullPath("ConsoleApplication1.exe"));
Module manifestModule = Assembly.ManifestModule;
PortableExecutableKinds peKind;
ImageFileMachine machine;
manifestModule.GetPEKind(out peKind, out machine);
これで、ターゲットマシンはマシン内にあるはずです。
ただし、これは.NETアセンブリでのみ機能します。
この 投稿 によると、DLLまたはEXEが32または64であるかどうかをNotePadそして最初に「PE」を探します。次の文字が「L」の場合、プラットフォームは32ビットです。文字が「D」の場合、プラットフォームは64ビットです。
私のdllで試してみましたが、正確なようです。
dumpbin.exe
Visual Studioのbin
ディレクトリで使用できます.lib
および.dll
dumpbin.exe /headers *.dll |findstr machine
dumpbin.exe /headers *.lib |findstr machine
私は いくつかのC#コードへのリンク をIMAGE_FILE_HEADERにアクセスするために提供できます。これは、(簡単に)PowerShellコマンドレットにコンパイルできると思います。このメソッドにはポインターとPInvoke機能がないため、PowerShellスクリプトでこのメソッドを直接使用することはできません。
ただし、PEヘッダー形式の広範な知識を使用して、;-)正しいバイトに「まっすぐ」進み、それを理解することができるはずです。これはwillがPowerShellスクリプトで機能し、 TasosのブログからのこのC#コード をスクリプトに変換できるだけです。私のコードではないので、ここでコードを繰り返す必要はありません。
Unix OSには、ファイルを識別する「ファイル」と呼ばれるユーティリティがあります。識別のルールは、「マジック」と呼ばれる記述ファイルに保存されています。 fileを試して、ファイルを正しく識別できるかどうかを確認し、マジックファイルから適切なルールを取得できます。
これは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;
}
これが私の独自の実装で、さらにいくつかのチェックがあり、常に結果を返します。
// 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段の黒帯を見つける必要があります。