C++ 从内存缓冲区创建进程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/305203/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:28:31  来源:igfitidea点击:

CreateProcess from memory buffer

c++winapivisual-c++

提问by ggambett

I can use CreateProcess to launch an EXE. I want to have the contents of an EXE in a memory buffer and do CreateProcess (or an equivalent) on it without having to write it to a file. Is there any way to do that?

我可以使用 CreateProcess 来启动一个 EXE。我想将 EXE 的内容保存在内存缓冲区中,并对其执行 CreateProcess(或等效程序),而不必将其写入文件。有没有办法做到这一点?

The backstory : we make games. We send a plain EXE to our distributors, which then wrap it using their favorite DRM and sell it to their users. There have been instances where users find crashes. Most of the crashes take 5 minutes to fix, but the patch must go through the distributor and it may take several days, even weeks. I can't just send the patched EXE to the players because it wouldn't have the distributor's DRM. I'm thinking of distributing the real game EXE inside an encrypted datafile so what gets wrapped (the external EXE) just decrypts and launches the real EXE. This way I could safely distribute a fix without disabling the DRM.

背景故事:我们制作游戏。我们将一个普通的 EXE 发送给我们的经销商,然后他们使用他们最喜欢的 DRM 将其打包并出售给他们的用户。曾有用户发现崩溃的情况。大多数崩溃需要 5 分钟才能修复,但补丁必须通过分销商,可能需要几天甚至几周的时间。我不能只将修补后的 EXE 发送给玩家,因为它没有发行商的 DRM。我正在考虑将真正的游戏 EXE 分发到一个加密的数据文件中,这样被包装的内容(外部 EXE)就可以解密并启动真正的 EXE。这样我就可以在不禁用 DRM 的情况下安全地分发修复程序。

回答by arul

It's actually quite easy. Similar technique has been described in a paper I read like 3 years ago.

这实际上很容易。类似的技术在我 3 年前读过的一篇论文中有所描述。

Windows allow you to call the CreateProcessfunction with CREATE_SUSPENDEDflag, that tells the API to keep the process suspended until the ResumeThreadfunction is called.

Windows 允许您使用CREATE_SUSPENDED标志调用CreateProcess函数,标志告诉 API 保持进程挂起,直到调用 ResumeThread函数。

This gives us time to grab the suspended thread's context using GetThreadContextfunction, then the EBX register will hold a pointer to the PBE(Process Enviroment Block)structure, which we need to determine the base address.

这让我们有时间使用GetThreadContext函数获取挂起线程的上下文,然后 EBX 寄存器将保存一个指向PBE(进程环境块)结构的指针,我们需要确定基地址。

From the layout of the PBE structure we can see that the ImageBaseAddress is stored at the 8th byte, therefore [EBX+8] will give us actual base address of the process being suspended.

从 PBE 结构的布局我们可以看到 ImageBaseAddress 存储在第 8 个字节,因此 [EBX+8] 将为我们提供正在挂起的进程的实际基地址。

Now we need the in-memory EXE and do appropiate alignment if the alignment of memory and in-memory EXE differs.

现在我们需要内存中的 EXE 并在内存和内存中 EXE 的对齐方式不同时进行适当的对齐。

If the base address of suspended process and in-memory exe matches, plus if the imageSize of the in-memory exe is lesser or equal to the suspended process' we can simply use WriteProcessMemoryto write in-memory exe into the memory space of the suspended process.

如果挂起进程和内存中exe的基地址匹配,并且如果内存中exe的imageSize小于或等于挂起进程'我们可以简单地使用WriteProcessMemory将内存中的exe写入到内存空间挂起的进程。

But if the aforementioned conditions weren't met, we need a little more magic. First, we need to unmap the original image using ZwUnmapViewOfSection, and then allocate enough memory using VirtualAllocExwithin the memory space of the suspended process. Now we need to write the in-memory exe into the memory space of the suspended process using the WriteProcessMemoryfunction.

但如果上述条件不满足,我们需要更多的魔法。首先,我们需要使用ZwUnmapViewOfSection取消映射原始图像,然后在挂起进程的内存空间内使用VirtualAllocEx分配足够的内存。现在我们需要使用WriteProcessMemory函数将内存中的exe写入挂起进程的内存空间。

Next, patch the BaseAddress of the in-memory exe into the PEB->ImageBaseAddress of the suspended process.

接下来,将内存中 exe 的 BaseAddress 修补到挂起进程的 PEB->ImageBaseAddress 中。

EAX register of the thread context holds EntryPoint address, which we need to rewrite with the EntryPoint address of the in-memory exe. Now we need to save the altered thread context using the SetThreadContextfunction.

线程上下文的 EAX 寄存器保存了 EntryPoint 地址,我们需要用内存中的 exe 的 EntryPoint 地址重写它。现在我们需要使用SetThreadContext函数保存更改的线程上下文。

Voila! We're ready to call the ResumeThreadfunction on the suspended process to execute it!

瞧!我们准备好在挂起的进程上调用ResumeThread函数来执行它!

回答by smt

You can compile the game as a DLL and put the DLL in the encrypted data file. A DLL can be loaded from memory without writing it to disk. Please see this tutorial (with sample code at the end): Loading a DLL From Memory

您可以将游戏编译为 DLL 并将 DLL 放入加密的数据文件中。可以从内存加载 DLL,而无需将其写入磁盘。请参阅本教程(最后附有示例代码):从内存中加载 DLL

回答by Mark

What you want to do requires NtCreateProcess, but it's undocumented and therefore brittle. This bookapparently covers its use.

你想做的事情需要 NtCreateProcess,但它没有记录,因此很脆弱。 这本书显然涵盖了它的使用。

Perhaps you could build a patch system? E.g. on launch, program checks for patch DLL in same directory, and loads it if it exists.

也许你可以建立一个补丁系统?例如,在启动时,程序会检查同一目录中的补丁 DLL,如果存在则加载它。

回答by Will Dean

Why do you need to create a new process? I would have thought you could run in the context of process which does the unpacking/decryption.

为什么需要创建新流程?我原以为您可以在进行解包/解密的进程的上下文中运行。

回答by Frans-Willem

What you want can be achieved with something called a "Packer". Actually launching an exe from memory might be possible, but it's a lot harder than a packer ;)

你想要的东西可以通过一个叫做“Packer”的东西来实现。实际上从内存中启动 exe 可能是可能的,但它比打包程序要困难得多;)

One of the best known packers is UPX (google it). There are tools to decrypt it, but it should at least give you a starting point to work froim. I'm also fairly certain UPX is open-source.

最著名的加壳程序之一是 UPX(谷歌它)。有一些工具可以解密它,但它至少应该为您提供一个开始工作的起点。我也相当肯定 UPX 是开源的。

回答by Frans-Willem

Look at BoxedAppSDK

看看BoxedAppSDK

It supports launching exe from a memory buffer.

它支持从内存缓冲区启动 exe。

hope it helps.

希望能帮助到你。