如何将托管的.NET程序集从内存保存为EXE/DLL文件

5
我想知道是否有可能,如果可以的话 - 如何将动态加载的.net程序集(它是从字节数组而不是文件加载的)保存到磁盘上的文件中(exe/dll取决于程序集),并直接使用它(即如果它是exe,则它将包含所有exe头文件并可运行或至少是“可反射的”)。
此外,加载的程序集实际上是否会像在文件中一样完全存储在内存中,即所有PE EXE头文件、资源等都存在于内存中,还是以不同的方式存储在内存中,因此将无法将某个内存区域保存为dll/exe .net程序集?也就是说,如果我可以使用图像的类比:您可以将jpeg文件加载到内存中作为位图,其中在内存中表示图像的实际字节将与表示jpeg文件的实际字节非常不同。那么加载程序集是否也是如此?
最后,如何获取程序集实际位于进程内存中的内存地址(指针)?
仅澄清一下:我没有任何访问通过Assembly.Load()加载程序集的初始字节数组的权限。
这里有一个相关问题,但从答案中并不清楚是否有一种方法可以将通过字节数组加载的汇编代码从内存中转储到磁盘文件中。谢谢。

只需将字节数组转换为流并保存到磁盘即可。至于它们是否按文件存储在内存中,则是肯定和否定的。IL是一对一的,但一旦JIT编译完成,就完全取决于.NET框架。你实际上想做什么? - Tony Hopkinson
也许我没有解释清楚。我没有访问字节数组的权限。这就是重点。我只有一个托管程序集加载到某个进程的内存中,我知道该程序集是从字节数组加载的(即磁盘上不存在相应的文件),所以问题是:1)如何访问该内存?2)该内存与存储在exe/dll文件中的内容是否一一对应?3)如何保存它(例如使用第三方工具)? - Fit Dev
从未尝试过。Assembly有一个GetObjectData方法,显然返回了重新创建程序集所需的所有信息的序列化。您是否考虑过像codebase这样的事情?因为您拥有的程序集和您保存并从磁盘加载的程序集具有不同的来源,即使它们是完全匹配的功能,框架也会将它们标记为不同。也就是说,您可以同时加载它们两个... - Tony Hopkinson
感谢您的评论。这并不是问题。我只想澄清汇编的内存格式,以及是否可能将其以原始形式(即与原始字节数组中出现的形式相同)持久化到磁盘中。同时加载它们、解决它们、比较源码在这里并不重要。 - Fit Dev
这里有一个相关的问题,但它没有得到完全回答,而且仍然不清楚从字节数组加载的程序集到底可以做到什么程度。 - Fit Dev
显示剩余2条评论
1个回答

1
首先,在.NET中,一个程序集可以由位于不同位置的多个模块组成。因此,只能保存模块到程序集中。大部分情况下,您只需要主模块,所以可以使用Assembly.ManifestModule获取它。 Marshal.GetHINSTANCE将返回模块的HINSTANCE,即根据this文章,模块的基地址。尽管MSDN中的备注说明内存中的模块没有HINSTANCE,但这个方法似乎会返回内存中模块的基地址。

现在我们已经有了模块的基地址。接下来要做的是确定模块的大小。最简单的方法是解析PE文件的节表。例如:

Name   | Raw Size | Raw Address
.text  | 0x2000   | 0x400
.rsrc  | 0x400    | 0x2400
.reloc | 0x200    | 0x2800

在这种情况下,模块的大小是最大原始地址加上相应的原始大小,即0x2A00。

该方法不适用于 System.Reflection.Emit.InternalAssemblyBuilder。例如,Powershell在运行时构建此类程序集。 - groser

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