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

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

最佳答案

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

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

  • 分配足够的内存来容纳可执行文件。当然,它不能驻留在托管堆上,因此像本练习中的几乎所有内容一样,您需要PInvoke。 (实际上,我建议使用C++/CLI,以免使自己过于疯狂)。请特别注意应用于分配的内存页面的属性位:弄错它们,您将打开一个巨大的安全漏洞,或者被DEP关闭您的进程(即,您将崩溃)。参见http://msdn.microsoft.com/en-us/library/aa366553(VS.85).aspx
  • 在程序集的资源库中找到可执行文件,并为其获取了pinned handle
  • Memcpy()从托管堆的固定区域到 native 块的代码。
  • 释放GCHandle。
  • 调用VirtualProtect以防止进一步写入可执行存储块。
  • 根据您从VirtualAlloc获得的句柄和文件中的偏移量(如DUMPBIN或类似工具所示),在进程的虚拟地址空间内计算可执行文件的Main函数的地址。
  • 将所需的命令行参数放在堆栈上。 (Windows Stdcall convention)。当然,任何指针都必须指向本地或固定区域。
  • 跳转到计算的地址。可能最容易使用_call(内联汇编语言)。
  • 向上帝祈祷,可执行镜像中没有任何绝对跳转,可以通过以正常方式调用LoadLibrary来解决该跳转。 (当然,除非您感觉要在步骤3中重新实现LoadLibrary的大脑)。
  • 从@eax寄存器中获取返回值。
  • 调用VirtualFree。

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

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

    关于executable - 如何从内存而不是光盘运行不受管的可执行文件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1224149/

    10-09 03:11
    查看更多