使用 windows api 和 C++,我如何从硬盘驱动器加载 exe 并在自己的线程中运行它?

Posted

技术标签:

【中文标题】使用 windows api 和 C++,我如何从硬盘驱动器加载 exe 并在自己的线程中运行它?【英文标题】:Using the windows api and C++, how could I load an exe from the hard drive and run it in its own thread? 【发布时间】:2011-01-10 07:18:26 【问题描述】:

为了学习,我正在尝试执行操作系统在启动程序时所做的事情,即。解析PE文件并给它一个执行线程。

如果我有两个 exe,一个叫做 foo.exe,另一个叫做 bar.exe,我怎么能让 foo.exe 将 bar.exe 的内容加载到内存中,然后让它在自己的线程中执行?我知道如何使用 MapViewOfFile 或简单地将硬盘驱动器上的内容加载到缓冲区中来将其放入内存。我假设只是将磁盘上 bar.exe 的内容复制到它自己的挂起线程中并运行它是行不通的。我对PE文件内部结构半熟悉。非常感谢所有帮助,当然:)

【问题讨论】:

虽然我可能是错的,但我不认为你可以手动加载可执行文件并期望它在调用时能够工作......通常有很多关于成为主要运行者的假设的当前进程,我认为如果您尝试将其托管在另一个进程中,事情将无法正常工作。 @Lambert:如果不是线程,那么进程会工作吗?使用 CreateProcess。 @returneax:嗯……为什么不呢?这不是正确的做法吗? @Lambert : “手工”....哈哈! @Lambert:好吧,如果它可以在进程中工作,为什么它不能在线程中工作?从根本上说,进程不是执行的主线程。如果您可以提供一个执行线程并保证与任何其他线程不冲突,那么线程和进程之间有什么不同? 【参考方案1】:

首先,兰伯特是正确的。 EXE 在自己的进程中运行。 EXE 无法加载到另一个进程的原因是因为它们不是为相对寻址而编译的,并且不能轻易地将其代码重新映射到另一个地址。开发人员使用 Win32 系统调用“CreateProcess”启动其他 EXE 程序。但我不认为这是你的问题......

我想您想知道如何手动将代码从二进制文件加载到正在运行的进程中(并让它在专用线程上运行)。大多数开发人员只是调用 LoadLibrary/GetProcessAddress 将 DLL 映射到进程空间并调用 CreateThread 来启动线程。

所以我认为您基本上要问的是,“我如何实现内核和操作系统的核心组件,即加载程序?”或者换一种说法,“我如何自己实现 CreateProcess 和 LoadLibrary?”

操作系统加载器不仅仅将二进制文件解析到内存中,并将指令指针设置为第一行代码。它还加载其他相关的 DLL。因为进程可能已经分配了其他代码以在 DLL 编译到的目标地址处运行,所以它可能还必须修复 DLL 的地址以将其加载到另一个地址。我可能会遗漏许多其他步骤,包括为二进制代码本身分配虚拟内存。

我确实建议查看Richter book 中有关进程、线程和 DLL 的部分。他讨论了这一点以及解析 DLL 的 PE 格式的一些细节。

研究如何将 .SO 文件加载到进程空间的 Linux 内核实现也可能是值得研究的。

【讨论】:

如果我没记错的话,这主要是加载时 DLL 的问题,对吧?如果所有 DLL 都在运行时加载到程序中,则可以避免很多这些问题。还是我误会了? Edit:我基于我最近了解到的情况:程序绝对会使用的 DLL 以硬编码方式存储在导入地址表中。 @returneax:即使是那些也需要检查;你不能假设他们声明的基地址是可用的。您在内存 COW 中加载 DLL,这就是为什么最好将它们加载到它们的首选基地址:无需修补即可保存 COW 副本。【参考方案2】:

可执行文件始终作为单独的进程运行。它不能在其他一些进程线程中运行。但是,您可以将可执行文件作为进程从其他进程的线程中运行。看看CreateProcess()函数!

【讨论】:

技术上可能不是,但这里有一个非常简单的例子。想象一个“Hello, world”程序。现在,如果我们提取所述程序中所有功能的操作码……主要是打印“Hello, world”。如果我们将提取的操作码放入它们自己的挂起线程并恢复该线程,我们将拥有与“Hello, world”相同的功能。在磁盘上,对吧? @returneax:对。但是怎么做呢?我不认为 Windows API 可以帮助您提取操作码。您需要编写自己的 API 来解析可执行文件并提取操作码。但这本身就是一个巨大的项目! @returneax:您确实知道您需要手动重新构建 EXE 的基础,对吗? (不是说不可能,但也许不实用。) @Lambert:是的,但这可能不是最难的部分。 最困难的部分是尝试在 ReactOS 上获得准确的代码以使其工作(我之前尝试过但失败了)......其他一切(调整它等.) 可以稍后来...【参考方案3】:

由于我个人不喜欢“你为什么要这样做?”的答案,here is a link 这将非常有帮助。但请注意,您可能不会成功,因为 EXE 根本不希望在另一个进程的线程中运行。

【讨论】:

谢谢,这是一个很棒的链接。我认为这很可能是因为 PE 文件中的元数据不是太大。似乎大多数问题都在于加载正确的 DLL,这可以通过使用 LoadLibrary 等来避免。

以上是关于使用 windows api 和 C++,我如何从硬盘驱动器加载 exe 并在自己的线程中运行它?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中使用 Windows API 隐藏桌面图标?

Windows 防火墙 C++ API - 如何正确清理 COM 资源?

如何在 Windows 中从任何格式转换为 PCM

我们如何在 C++ 和 windows API 中验证 openssl 数字签名

C++ Win32api 从用户输入输出 Unicode

Windows C++ API:如何将整个二进制文件读入缓冲区?