C# で DLL ファイルが CLR アセンブリであるかどうかを確認する最良の方法

StackOverflow https://stackoverflow.com/questions/1366503

  •  21-09-2019
  •  | 
  •  

質問

DLL ファイルが Win32 DLL であるか、CLR アセンブリであるかを確認する最良の方法は何ですか。現時点ではこのコードを使用しています

    try
    {
        this.currentWorkingDirectory = Path.GetDirectoryName(assemblyPath);

        //Try to load the assembly.
        assembly = Assembly.LoadFile(assemblyPath);

        return assembly != null;
    }
    catch (FileLoadException ex)
    {
        exception = ex;
    }
    catch (BadImageFormatException ex)
    {
        exception = ex;
    }
    catch (ArgumentException ex)
    {
        exception = ex;
    }
    catch (Exception ex)
    {
        exception = ex;
    }

    if (exception is BadImageFormatException)
    {
        return false;
    }

しかし、私はそれらの例外(時間)を望まないため、ロード前にチェックすることを好みます。

もっと良い方法はありますか?

役に立ちましたか?

解決

PE ヘッダーを確認します。

DOS ヘッダーは 0x0 で始まり、DWORD は 0x3c には PE へのポインターが含まれています signature (通常は 0x80) は 4 です。 bytes の場合、次の 20 バイトは COFF です ヘッダーがあり、PE ヘッダーがあります (0x9時。PE ヘッダーは 224 バイトです データディレクトリ(96 PE ヘッダーへのバイト数 = 0xf。ザ 15 番目のエントリ (0x16 は CLR ヘッダーです 記述子 (COM と呼ばれることもあります) ディスクリプタですが、これは COMと関係のあるもの)。もしこれが 空 (つまり、0x168 から 8 バイトの 0 0x16f)の場合、ファイルは.NETではありません 集会。確認したい場合 は COM DLL であり、 GetClassObject がエクスポートされるかどうかを確認します。

参照。

アップデート:これを実現するには、より「.NET」的な方法があります。

使用 Module.GetPEKind 方法を確認してください PortableExecutableKinds 列挙:

NotAPortableExecutableImage ファイルは、ポータブル実行可能ファイル(PE)ファイル形式ではありません。

ILのみ 実行可能ファイルには、Microsoft Intermediate Language のみが含まれています (MSIL) であるため、 32ビットまたは64ビットプラットフォームに関して。

必須32ビット 実行可能ファイルは、32ビットプラットフォームで、または64ビットプラットフォーム上のWindows(WOW)環境上の32ビットWindowsで実行できます。

PE32プラス 実行可能ファイルには 64 ビット プラットフォームが必要です。

アンマネージド32ビット 実行可能ファイルには純粋なアンマネージ コードが含まれています。

他のヒント

アセンブリがロードされた場合、たとえば Assembly.LoadFile(dotNetDllorExe) 例外はスローされず、有効な .NET アセンブリです。そうでない場合は、「BadImageFormatException」がスローされます。

ファイルをロードし、例外がスローされるかどうかを確認することで、ファイルがアセンブリであるかどうかを確認するというアイデア。あまりきれいではないようです。結局のところ、例外は例外的に使用されることになっています。


.NET アセンブリは通常の Win32 PE ファイルであり、オペレーティング システムは .NET アセンブリと Win32 実行可能バイナリを区別せず、同じ通常の PE ファイルです。では、DLL または EXE がマネージド アセンブリである場合、CLR を読み込むためにシステムはどのように動作するのでしょうか?

ファイル ヘッダーを検証して、マネージド アセンブリであるかどうかを確認します。.NET SDK とともに出荷される ECMA 仕様パーティション II – メタデータには、PE 形式の別個の CLI ヘッダーがあることがわかります。それは PE の 15 番目のデータ ディレクトリ オプション ヘッダー. 。したがって、簡単に言うと、このデータ ディレクトリに値がある場合は、これが有効な .NET アセンブリであることを意味し、そうでない場合はそうではありません。

internal static class PortableExecutableHelper
{
    internal static bool IsDotNetAssembly(string peFile)
    {
        uint peHeader;
        uint peHeaderSignature;
        ushort machine;
        ushort sections;
        uint timestamp;
        uint pSymbolTable;
        uint noOfSymbol;
        ushort optionalHeaderSize;
        ushort characteristics;
        ushort dataDictionaryStart;
        uint[] dataDictionaryRVA = new uint[16];
        uint[] dataDictionarySize = new uint[16];


        Stream fs = new FileStream(peFile, FileMode.Open, FileAccess.Read);
        BinaryReader reader = new BinaryReader(fs);

        //PE Header starts @ 0x3C (60). Its a 4 byte header.
        fs.Position = 0x3C;

        peHeader = reader.ReadUInt32();

        //Moving to PE Header start location...
        fs.Position = peHeader;
        peHeaderSignature = reader.ReadUInt32();

        //We can also show all these value, but we will be       
        //limiting to the CLI header test.

        machine = reader.ReadUInt16();
        sections = reader.ReadUInt16();
        timestamp = reader.ReadUInt32();
        pSymbolTable = reader.ReadUInt32();
        noOfSymbol = reader.ReadUInt32();
        optionalHeaderSize = reader.ReadUInt16();
        characteristics = reader.ReadUInt16();

        /*
            Now we are at the end of the PE Header and from here, the
                        PE Optional Headers starts...
                To go directly to the datadictionary, we'll increase the      
                stream’s current position to with 96 (0x60). 96 because,
                        28 for Standard fields
                        68 for NT-specific fields
            From here DataDictionary starts...and its of total 128 bytes. DataDictionay has 16 directories in total,
            doing simple maths 128/16 = 8.
            So each directory is of 8 bytes.
                        In this 8 bytes, 4 bytes is of RVA and 4 bytes of Size.

            btw, the 15th directory consist of CLR header! if its 0, its not a CLR file :)
     */
        dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fs.Position) + 0x60);
        fs.Position = dataDictionaryStart;
        for (int i = 0; i < 15; i++)
        {
            dataDictionaryRVA[i] = reader.ReadUInt32();
            dataDictionarySize[i] = reader.ReadUInt32();
        }
        if (dataDictionaryRVA[14] == 0)
        {
            Console.WriteLine("This is NOT a valid CLR File!!");
            return false;
        }
        else
        {
            Console.WriteLine("This is a valid CLR File..");
            return true;
        }
        fs.Close();
    }
}

ECMA 参照, ブログ参照

あなたは、コードでこれを行う必要があるかどうかを指定していない、またはあなただけの個人的にあなたがあなたのシステム上で探しているファイルは、.NETアセンブリであるならば、多分あなたがあなたを記述する必要が考えている(知っておく必要がある場合そうするための独自のコード)。後者の場合、あなたはそれが.NETランタイムエンジンであるにMscoree.dll、に依存しているかどうかを確認するために依存関係ウォーカーを使用することができます。

  

あなたはバイトが「MZ」であれば、その後のhref = "http://msdn.microsoft.com/en-us/ <(決定するためにアセンブリ名を読み取ろうと、ファイルから最初の2つのバイトを読み取ることができますライブラリ/ ms173100.aspx」のrel = "nofollowを">マイクロソフト遅い方法の)アセンブリの妥当性ます。

    public static bool isValidAssembly (string sFileName)
    {
        try
        {
            using (FileStream fs = File.OpenRead(sFileName))
            {
                if ((fs.ReadByte() != 'M') || (fs.ReadByte() != 'Z'))
                {
                    fs.Close();
                    return false;
                }
                fs.Close();
            }

            // http://msdn.microsoft.com/en-us/library/ms173100.aspx
            object foo = SR.AssemblyName.GetAssemblyName(sFileName);
            return true;
        }
        catch 
        {
            return false;
        }
    }
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top