如果 exe 没有清单,如何通过反射加载 exe?

Posted

技术标签:

【中文标题】如果 exe 没有清单,如何通过反射加载 exe?【英文标题】:How to load exe with reflection if exe does not have a manifest? 【发布时间】:2021-10-02 09:05:21 【问题描述】:

我有一个可执行文件的转储(运行时:v2.0.50727)。它运行良好,没有任何错误。我可以将它加载到 DnSpy 进行调试或加载到 ILSpy。它们都表示所有引用都已成功解决。

但是,我无法使用此代码加载它:

try

    var second_module = System.Reflection.Assembly.LoadFrom("myprog.bin");

catch (Exception e)

    Console.WriteLine(e.ToString());

它给了我以下错误:

System.BadImageFormatException: Could not load file or assembly 'file:///myprog.bin' or one of its dependencies. The module was expected to contain an assembly manifest.
File name: 'file:///myprog.bin'
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)
   at System.Reflection.Assembly.LoadFrom(String assemblyFile)
   at myproggg.Program.Main(String[] args) in c:\Sources\My\myproggg\Program.cs:line 11

=== Pre-bind state information ===
LOG: Where-ref bind. Location = myprog.bin
LOG: Appbase = file:///c:/Sources/My/myproggg/bin/x86/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: c:\Sources\My\myproggg\bin\x86\Debug\myproggg.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Attempting download of new URL file:///c:/Sources/My/MPCExtractor/examples/MP/myprog.bin.
ERR: Failed to complete setup of assembly (hr = 0x80131018). Probing terminated.

我尝试执行以下步骤:

    将编译选项从“Any CPU”更改为“x86”。没有区别。

    将框架更改为 2.0 和 4.5。无论我使用什么框架,它都会向我询问清单。

以上都没有帮到我。

我还能做些什么来加载这个转储的可执行文件?

【问题讨论】:

试试System.Reflection.Assembly.Load(byte[] rawAssembly);重载。 谢谢你的魔法!但是为什么这种方法有效呢? 【参考方案1】:

您创建的.bin 文件可追溯到 .NET 2.0 运行时使用的 COFF。您也可以使用dumpbin 来获取.bin 文件。文档说明

Microsoft COFF 二进制文件转储程序 (DUMPBIN.EXE) 显示有关通用对象文件格式 (COFF) 二进制文件的信息。

因此,要正确加载它,您需要使用Assembly.Load(byte[], ...)。该文档声明其参数接受原始的COFF 字节数组:

一个字节数组,它是一个基于 COFF 的图像,包含一个发出的程序集。

以上来源的这部分也可能与您有关

考虑 C++ 可执行文件可能会抛出 BadImageFormatException。这很可能是由 C++ 编译器从可执行文件中剥离重定位地址或 .reloc 部分引起的。要为 C++ 可执行文件保留 .reloc 地址,请在链接时指定 /fixed:no

【讨论】:

其实我没有使用dumpbin。在执行开始之前,我已经将进程转储为挂起状态,重建它以修复虚拟大小并且......忘记恢复重定位。最后,你击中了钉子。谢谢。 很公平。这仍然基于该运行时版本追溯到 COFF。很高兴你没有被困住!

以上是关于如果 exe 没有清单,如何通过反射加载 exe?的主要内容,如果未能解决你的问题,请参考以下文章

如何在使用反射加载的程序集中使用 Castle.Windsor

反射机制

java反射系列二

java反射专题一

反射

如何将Java打包成exe文件在没有JRE环境的电脑上执行