如何从内存而不是光盘运行非托管可执行文件

时间:2009-08-03 19:23:40

标签: executable unmanaged embedded-resource memorystream

我想在我的C#应用​​程序中嵌入一个命令行实用程序,这样我就可以将其字节作为数组获取并运行可执行文件而无需将其作为单独的文件保存到磁盘(避免将可执行文件存储为单独的文件并避免需要能够在任何地方写临时文件。)

我找不到一个只从其字节流运行可执行文件的方法。 Windows是否要求它在磁盘上,还是有办法从内存中运行它? 如果windows要求它在磁盘上,那么在.NET框架中有一种简单的方法来创建某种虚拟驱动器/文件并将文件映射到可执行文件的内存流吗?

4 个答案:

答案 0 :(得分:11)

您要求在高级别的托管环境中实现非常低级别的特定于平台的功能。一切皆有可能......但是没有人说这很容易......

(顺便说一句,我不知道为什么你认为临时文件管理很麻烦.BCL为你做的是:http://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename.aspx


  1. 分配足够的内存来保存可执行文件。当然,它不能驻留在托管堆上,因此就像本练习中几乎所有内容一样,您需要PInvoke。 (实际上,我推荐使用C ++ / CLI,以免自己开车疯狂)。特别注意你应用于分配的内存页面的属性位:弄错了,你要么打开一个有缺陷的安全漏洞,要么让你的进程被DEP关闭(即你会崩溃)。请参阅http://msdn.microsoft.com/en-us/library/aa366553(VS.85).aspx

  2. 在程序集的资源库中找到可执行文件,并为其获取pinned handle

  3. Memcpy()从托管堆的固定区域到本机块的代码。

  4. 释放GCHandle。

  5. 调用VirtualProtect以防止进一步写入可执行内存块。

  6. 根据您从VirtualAlloc获得的句柄和文件中的偏移量(如DUMPBIN或类似工具所示)计算进程虚拟地址空间中可执行文件的Main函数的地址。

  7. 将所需的命令行参数放在堆栈上。 (Windows Stdcall convention)。当然,任何指针都必须指向原生或固定区域。

  8. 跳转到计算地址。可能最容易使用_call(内联汇编语言)。

  9. 向上帝祈祷,可执行图像中没有任何绝对跳跃,而这些跳跃是通过正常方式调用LoadLibrary来修复的。 (当然,除非您想在步骤#3中重新实现LoadLibrary的大脑)。

  10. 从@eax寄存器中检索返回值。

  11. 致电VirtualFree。

  12. 步骤#5和#11应在finally块中完成和/或使用IDisposable模式。


    另一个主要选项是创建RAMdrive,在那里写可执行文件,运行它和清理。这可能会更安全,因为您不是在尝试编写自修改代码(在任何情况下都很难,但特别是当代码甚至不是您的代码时)。但我相当肯定它需要比动态代码注入选项更多的平台API调用 - 所有这些都需要C ++或PInvoke,当然。

答案 1 :(得分:2)

查看本文的“内存”部分。从远程DLL注入的角度来看,它应该是相同的。

Remote Library Injection

答案 2 :(得分:1)

创建RAMdisk或将代码转储到内存然后执行它们都是可能的,但是非常复杂的解决方案(在托管代码中可能更多)。

它需要是可执行文件吗?如果将它打包为程序集,则可以使用内存流中的Assembly.Load() - 一些简单的代码行。

或者如果真的必须是可执行文件,那么编写临时文件实际上有什么问题?它需要几行代码才能将其转储到临时文件,执行它,等待它退出,然后删除临时文件 - 它甚至可能在你删除它之前就没有磁盘缓存了!有时,简单明了的解决方案是最好的解决方案。

答案 3 :(得分:-1)

Vista +中明确禁止这样做。您可以在XP中使用一些未记录的Win32 API调用来执行此操作,但它在Vista +中被破坏,因为它是一个巨大的安全漏洞,并且唯一使用它的人是恶意软件编写者。