assemblies dll 32bit - .NETアセンブリがx86またはx64向けに構築されているかどうかを判断する方法





7 Answers

CorFlags CLIツール(たとえば、C:¥Program Files¥Microsoft SDKs¥Windows¥v7.0¥Bin¥CorFlags.exe)を使用して、アセンブリの出力に基づいてアセンブリのステータスを判断し、アセンブリをバイナリアセットでは、32BITフラグが1( x86 )か0( PEに応じて任意のCPUまたはx64 )に設定されているかどうかを調べる必要があるかどうかを判断できるはずです。

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

ブログ投稿x64 .NETでの開発には、 corflagsに関する情報がいくつかあります。

さらに、 Module.GetPEKind使用して 、アセンブリがPortableExecutableKindsPE32Plus (64ビット)、 Required32Bit (32ビットおよびWOW)、またはILOnly (すべてのCPU)であるかILOnlyかを他の属性でILOnlyできます。

64bit 混在 corflags

私は.NETアセンブリの任意のリストを持っています。

私は、各DLLが(x64または任意のCPUとは対照的に)x86用に構築されているかどうかをプログラムでチェックする必要があります。 これは可能ですか?




あなたはあなた自身のことを書いてどうですか? 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.

しかし、この方法では、新しい定数の可能性を考慮して、適切と思われるようにリターンを検証します。




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



以下は現在の作業ディレクトリとすべてのサブディレクトリのすべてのcorflags.execorflags.exeに対してcorflags.exeを実行し、結果を解析し、それぞれのターゲットアーキテクチャを表示するバッチファイルです。

使用されているcorflags.exeのバージョンに応じて、出力の行項目には32BIT または 32BITREQ (および32BITPREF )が含まれます。 これらの2つのうちAny CPUが出力に含まれているかは、 Any CPUx86を区別するためにチェックする必要がある重要なライン項目です。 以前のバージョンのcorflags.exe (Windows SDK v8.0以前)を使用している場合、過去の回答で示されているように、 32BIT申込情報のみが出力に表示されます。 それ以外の場合は32BITREQ32BITPREF置き換えます。

これは、 corflags.exe%PATH%にあると仮定しています。 これを確実にする最も簡単な方法は、 Developer Command Promptを使用することです。 あるいは、 デフォルトの場所からコピーすることもできます。

下のバッチファイルをアンマネージdllまたはexeに対して実行すると、 Corflags.exeの実際の出力はCorflags.exeようなエラーメッセージになるため、 x86と誤って表示されます。

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.



.NETアセンブリのターゲットプラットフォームをチェックするもう1つの方法は、 .NET Reflectorを使用してアセンブリを検査することです。

@#〜#€〜! 私はちょうど新しいバージョンが無料ではないことに気づいた! したがって、.NET Reflectorの無料版を使用している場合は、それを使用してターゲットプラットフォームを確認できます。




そのための高度なアプリケーションをここで見つけることができます: 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



より一般的な方法 - ファイル構造を使用してビット数とイメージタイプを判断する:

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で説明付きのソースコード




Related