注入进程内存的代码是否总是属于具有 RWX 访问权限的页面?

逆向工程 视窗 记忆 登录
2021-07-05 09:49:19

我看过一些内存取证教程,它们首先在“受害者”进程内存中寻找注入的代码。他们似乎总是在具有 RWX 访问权限(即 PAGE_EXECUTE_READWRITE)的页面中找到注入的代码。

这个假设总是成立吗?注入(例如恶意软件)到“受害者”进程内存中的代码是否总是属于具有 RWX 访问权限的页面?或者可以通过注入的代码更改页面访问权限吗?如果是这样,如何通过 winapi 完成此更改?

3个回答

该假设不成立,因为在分配内存可以更改页面保护标志

Windows上通常的代码注入机制如下:

  1. 调用OpenProcess目标进程,以获取具有适当访问权限的句柄。
  2. 用于VirtualAllocEx在目标进程中分配一个缓冲区,带有一组内存页访问标志。
  3. 使用WriteProcessMemory的内存复制到目标。
  4. 要么修补现有代码以跳转到新代码块,要么用于CreateRemoteThread通过新线程在进程内执行。

现在,这里有两个选择。第一个是您可以指定PAGE_EXECUTE_READWRITE一个标志 to VirtualAllocEx,以便您有权WriteProcessMemory在该页面上使用,并且在您到达第 4 步时也有权执行该内存。这是导致拥有的“懒惰”方式RWX 缓冲区到处都是。另一种方法是PAGE_READWRITE在分配块时传递,然后编写代码,并调用VirtualProtectEx将标志交换到PAGE_EXECUTE_READ第 4 步之前。这在复制数据时为您提供 RW 缓冲区,然后在执行时提供 RX 缓冲区。

伪代码:

rights = PROCESS_VM_OPERATION |
         PROCESS_VM_READ | PROCESS_VM_WRITE | 
         PROCESS_QUERY_INFORMATION | 
         PROCESS_CREATE_THREAD;

handle = OpenProcess(rights, false, pid);

targetAddr = VirtualAllocEx(handle, NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

buffer = "Hello, world!\0";
bytesWritten = 0;
WriteProcessMemory(handle, targetAddr, buffer, 14, &bytesWritten);

oldProtect = 0;
VirtualProtectEx(handle, targetAddr, 4096, PAGE_EXECUTE_READ, &oldProtect);

threadId = 0;
CreateRemoteThread(handle, NULL, 0, targetAddr, NULL, 0, &threadId);

针对 RWX 页面的原因是注入的代码最常携带与代码相同区域的数据,并且要求数据是可写的。因此需要 W 标志。X 标志需要支持 DEP,以防进程选择加入,或者如果系统对每个人强制执行它。请求页面时,R 标志是完全可选的。Windows 将确保它无论如何设置。恶意软件当然可以分配两个区域,一个 [R]X 和一个 [R]W,并且只写入可写部分,但我不记得曾经见过使用这种技术。一方面,它使注入的代码复杂化。

页面访问可以更改。请参阅VirtualProtect内存保护常量VirtualProtectEx文档。注入的代码应该是可执行和可读的,但不一定是可写的。