C++ C或C++;:装载机/包装机如何工作?
这里有一个例子来说明我的意思C++ C或C++;:装载机/包装机如何工作?,c++,windows,loader,C++,Windows,Loader,这里有一个例子来说明我的意思 用户运行LOADER.EXE程序 LOADER.EXE下载另一个EXE,但将其全部保存在内存中,而不将其保存到磁盘 运行下载的EXE,就像从磁盘执行一样,但直接从内存执行吗 我见过一些这样的应用程序,但我从未见过一个例子或解释它是如何工作的 有人知道吗 另一个例子是在另一个文件中嵌入加密的EXE。它在内存中被提取和解密,在执行之前从未保存到磁盘 我已经在一些应用程序中看到了用于防止盗版的 编辑:作为旁注,像UPX这样的程序是这样工作的吗?我看了代码,但对我来说很
- 用户运行LOADER.EXE程序
- LOADER.EXE下载另一个EXE,但将其全部保存在内存中,而不将其保存到磁盘
- 运行下载的EXE,就像从磁盘执行一样,但直接从内存执行吗
编辑:作为旁注,像UPX这样的程序是这样工作的吗?我看了代码,但对我来说很难破译,我问的主要是出于好奇,我不需要它。如果你知道可执行文件入口点的偏移量在哪里,并且知道它需要什么参数,那么你所需要做的就是调用地址“exeBase+entryPointOffset”处的函数使用函数指针 值得注意的是,至少在x86系统上,操作系统不允许执行标记为数据的内存。例如,在windows下,可以使用“”函数将内存标记为可执行文件来更改
事实上,在过去的好日子里,这是一个保存内存的通用系统。您将拥有“”,这样您可以根据需要交换代码以节省内存 很多这样做的程序只是解压缩到%TEMP%(我知道我是这么做的),但是大公司基本上重新实现了OS可执行加载程序,它必须:
- 将可执行文件映射到内存中。这并不像听起来那么简单,因为.exe包含多个“部分”,这些“部分”必须以页面对齐方式加载(它们必须从4K的倍数地址开始),并且每个部分都有特定的请求-只读、写时复制、零初始化等
- 通过更新导入表节(通常使用LoadLibrary()和GetProcAddress()来满足静态导入
- 对于dll(实际上几乎相同,重要的区别是它们有导出和导入),如果编译加载dll的内存地址已经在使用中(这是很常见的),则加载程序可能还必须重新设置dll的基础。但是,对于exe来说,这通常是不可能的,因为它们不包括重新定位部分,重新定位部分列出了加载代码中需要更新的位置,因为通常情况下,它们是加载到进程中的第一件事情,因此不能被某些东西阻止。这意味着加载程序必须为其自身的exe设置一个不寻常的加载地址,该地址不会阻止加载的exe
总之:这是一个很大的工作。如果您感兴趣,请查看描述.exe和.dll文件的PE格式规范,以及
VirtualAlloc()
函数。这真的有效吗?如何确保在可执行代码中没有跳转到绝对地址(这将在加载时解析)?绝对地址修正在EXE数据中。这就是Vista的ASLR功能的工作原理。不过,加载程序可能会将其引导代码移开,以便EXE在其正常基址处加载。@Hans:我很确定EXE没有(尽管它们可以)包含重新定位部分,因为EXE是在地址空间中分配的第一个内容,因此永远不必重新定位(ASLR仅用于.dll)@Goz:这不起作用,因为原始文件数据中的部分没有页面对齐:请参阅PE规范中关于文件偏移量和RVA之间的差异。请注意,创建包装时,它将知道要包装的EXE。因此它可以选择另一个基址。哇,听起来比我想象的要复杂得多。你有UPX的经验吗?它是这样工作的吗?(我对包装工不太了解)。我希望能够找到一些源代码来演示这一点,这将有点容易理解。@guitar:我只是快速浏览了一下代码。加载器存根是一个非常重宏的程序集,但是如果这项工作正常的话,看起来打包程序正在进行大量的预处理,因此存根可以将一个已经对齐的文件解压缩到内存中,然后获得导入。显然,这对于您的第二个和第三个示例是不够的。包装机的东西更近了,但我相信其他地方的特殊案例较少。这似乎是一个好的开始,尽管它不太符合商业质量。