在C#或VB.NET中,我想知道哪种方法是确定通过Reflection加载的程序集的PEFileKinds的最佳方法。换句话说,确定程序集是WinExe,控制台应用程序还是动态链接库。
我发现this解决方案(该问题中的其他提议解决方案无效),但如果我没错,我认为这意味着假设加载的文件是.NET程序集,并且,手动解析似乎有点整洁PE头。
我也找到了this other解决方案,但在某些情况下阅读它似乎无效的评论。
出于这些原因,我想知道是否存在一种真正安全,可管理的方式,最好是通过Reflection来确定加载程序集的PE文件类型。
我确定System.Reflection.Emit.PEFileKinds
枚举不仅仅出于装饰目的而存在,如果该枚举存在则其逻辑认为可能存在我在Reflection命名空间内错过的成员/函数,这些成员/函数在内部使用该枚举返回PE文件类型然而,一个Assembly
对象,我通过Reflection和其他相关课程设法查看了Assembly
类的私人成员,我发现没有任何相关性。
根据a search of the reference source,PEFileKinds
枚举仅用于AssemblyBuilder
和ModuleBuilder
(以及它们的非公共助手类型)。这个枚举和类可以在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。