如何确定一个.NET程序集是否包含非托管代码?

12

.NET程序集中包含托管代码和非托管代码的混合,无法与其他程序集进行ILMerge。

如何验证给定的.NET程序集是否仅包含托管代码或包含托管和非托管代码的混合?

8个回答

10

如nobugz所建议的那样,查看CLR标志的更简单的方法是使用corflags实用程序,该实用程序是.NET 2.0 SDK的一部分。

如果未指定任何选项,则显示给定图像的标志:

C:\>corflags Foo.dll
Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32
CorFlags  : 9
ILONLY    : 1
32BIT     : 0
Signed    : 1

“ILONLY”位表示这是一个纯托管程序集还是混合程序集。

请注意,用户“nobugz”的评论表明这些标志不能保证正确性,因此此方法可能不是百分之百可靠的。


6
运行PEVerify工具来检查您的程序集。

PEVerify.exe随Visual Studio一起安装,例如这个版本与Visual Studio 2012一起提供:

C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\PEVerify.exe


运行此实用程序后,如何确定它是否是纯托管代码?我只得到:“<foo> 中的所有类和方法已验证。” - Dan W
1
@DanW:那就没问题了。否则你会遇到错误。如果从脚本或其他程序中调用,可以检查非零的退出代码表示错误。您可以通过在C#中使用“unsafe”关键字来测试此功能。 - Wim Coenen

4

在Visual Studio命令提示符中运行ildasm,方法如下:

ildasm file.exe /headers /noil /text

在输出的最后,你会看到以下内容:

// ----- CLR Header:
// Header size: ...
// Major runtime version: ...
// Minor runtime version: ...
// ...
// Flags: 0x00000000

如果Flags的最低位被设置(例如0x00000001),则该程序集是纯CLR;否则(例如0x00000000),该程序集是混合模式。请注意,其他标志可能存在,因此您只需要关注最低位(因此,如果最后一位是1、3、5、7、9、b、d或f,则为纯CLR)。

(编辑:您也可以以图形方式运行ildasm,打开相关的可执行文件,并从“查看”菜单中选择“Headers”以查看相同的信息。)


3
据我所知,并不是一件易如反掌的事情,即使你使用/clr:pure编译,C++/CLI编译器/链接器也不能正确设置此位。Corflags.exe也显示了这一点。 - Hans Passant

2
改进以上提供的答案Wim...。
  1. 找到你的"PEVerify.exe" - 如果你安装了VS,你就有它了。- 复制PEVerify.exe文件的完整路径,你的路径将不同 - - 这是一个例子:C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\PEVerify.exe

  2. 打开Visual Studio命令提示符(不要以管理员身份运行)

  3. 键入:cd C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools

  4. 你的命令提示符现在应该是这个长文本,而不仅仅是C:\或其他什么......它将指向PEVerify.exe所在的路径。

  5. 现在输入:peverify "你想要检查的dll的完整路径" - 然后按Enter键 - 这是我的例子:peverify "G:\TestFolder\My_Managed_OR_Unmanaged.dll"

  6. 按下Enter键后,如果你得到以下消息,则说明它是100%托管的dll - My_Managed_OR_Unmanaged.dll中的所有类和方法都经过验证。


1
使用System.Reflection API可以从C#中获取PE标志:http://www.example8.com/category/view/id/6027

...

Assembly a = Assembly.GetExecutingAssembly();
Module m = a.ManifestModule;

PortableExecutableKinds peKinds;
ImageFileMachine imageFileMachine;
m.GetPEKind(out peKinds, out imageFileMachine);

if ((peKinds & PortableExecutableKinds.ILOnly) != 0)

...


0

我需要再确认一下,但我相信您可以通过Redgate的Reflector找到答案。


1
似乎不是一个好主意 - 挖掘程序集的所有方法需要大量工作。 - ironic
怎么办?我在 Reflector 5.1.6.0 中找不到任何关于这个的东西。 - Daniel Fortunov

0

ILMerge只能合并托管程序集,在这里引用他们的下载页面上说,“ILMerge是一个用于将多个.NET程序集合并成一个单一.NET程序集的实用工具”。

我没有看到过将托管程序集与本地二进制文件合并的情况。从技术上讲,您可以通过将不受管理的二进制文件作为嵌入式资源包含在内来将它们合并,但我以前没有看到过将嵌入式资源加载到内存中作为二进制代码的情况。我曾尝试使用内存映射技术来实现这种技术,但失败了。

检查的另一种方法是查看二进制文件本身,如果它在数据目录中具有第15个条目,并且非零,则为.NET二进制文件,本地二进制文件没有此项。请参见这里,在那里我回答了一个类似的问题。

希望对你有所帮助, 最好的问候, 汤姆。


0
我认为你应该使用.NET反射来遍历程序集中的所有类型和方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接