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

Tri*_*nko 8 executable memorystream unmanaged embedded-resource

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

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

Ric*_*erg 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. 在程序集的资源库中找到可执行文件,并获取其固定句柄.

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

  4. 释放GCHandle.

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

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

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

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

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

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

  11. 致电VirtualFree.

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


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


Jas*_*ams 1

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

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

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