确定程序集的PEFileKind的好方法?

时间:2018-09-07 23:40:40

标签: c# .net vb.net reflection portable-executable

在C#或VB.NET中,我想知道哪种方法是确定通过 Reflection 加载的程序集的PEFileKinds的最佳方法。换句话说,确定程序集是WinExe,控制台应用程序还是动态链接库。

我找到了this解决方案(该问题中提出的其他解决方案均无效),但是如果我没记错,我认为这意味着要假定加载的文件是.NET程序集,并且看来手动整理PE标头需要一些整理。

我还找到了this other解决方案,但阅读注释在某些情况下似乎无效。

由于这些原因,我想知道是否存在一种真正安全,可管理的方式,最好通过 Reflection 来确定已加载程序集的PE文件类型。

我确定System.Reflection.Emit.PEFileKinds枚举不仅仅出于装饰目的而存在,如果该枚举存在,则其逻辑认为在 Reflection内可能缺少我想要的成员/功能在内部使用该枚举返回Assembly对象的PE文件类型的名称空间,但是,我设法通过 Reflection 来查看Assembly类的私有成员和其他相关的类,我发现没有任何相关性。

1 个答案:

答案 0 :(得分:2)

根据a search of the reference sourcePEFileKinds枚举仅用于AssemblyBuilderModuleBuilder(以及它们的非公共帮助程序类型)中。该枚举和类可在System.Reflection.Emit namespace中找到-例如,它们用于编写程序集,而不是用于读取。

但是,the official System.Reflection.Metadata NuGet package在其System.Reflection.PortableExecutable namespace中公开了程序集PE标头的相关值。您可以使用这些标头对等效的PEFileKinds值进行反向工程。这是C#中的示例:

using (var stream = File.OpenRead(filenameAndExtension))
{
    using (var peFile = new PEReader(stream))
    {
        var headers = peFile.PEHeaders;
        Console.WriteLine($"Reading {filenameAndExtension} with System.Reflection.Metadata");
        Console.WriteLine($"  IsDll: {headers.IsDll}");
        Console.WriteLine($"  IsExe: {headers.IsExe}");
        Console.WriteLine($"  IsConsoleApplication: {headers.IsConsoleApplication}");

        PEFileKinds reverseEngineeredKind;

        // NOTE: the header values cause IsConsoleApplication to return
        //       true for DLLs, so we need to check IsDll first
        if (headers.IsDll)
        {
            reverseEngineeredKind = PEFileKinds.Dll;
        }
        else if (headers.IsConsoleApplication)
        {
            reverseEngineeredKind = PEFileKinds.ConsoleApplication;
        }
        else
        {
            reverseEngineeredKind = PEFileKinds.WindowApplication;
        }
        Console.WriteLine($"  Reverse-engineered kind: {reverseEngineeredKind}");
    }
}

我在用System.Reflection.Emit生成的程序集中运行了这段代码,以确保其准确性。完整程序位于this gist中。

您可能还可以通过第三方库(例如Mono.Cecil或Lex Li提到的PeNet)来获取此信息。