我看过一些内存取证教程,它们首先在“受害者”进程内存中寻找注入的代码。他们似乎总是在具有 RWX 访问权限(即 PAGE_EXECUTE_READWRITE)的页面中找到注入的代码。
这个假设总是成立吗?注入(例如恶意软件)到“受害者”进程内存中的代码是否总是属于具有 RWX 访问权限的页面?或者可以通过注入的代码更改页面访问权限吗?如果是这样,如何通过 winapi 完成此更改?
我看过一些内存取证教程,它们首先在“受害者”进程内存中寻找注入的代码。他们似乎总是在具有 RWX 访问权限(即 PAGE_EXECUTE_READWRITE)的页面中找到注入的代码。
这个假设总是成立吗?注入(例如恶意软件)到“受害者”进程内存中的代码是否总是属于具有 RWX 访问权限的页面?或者可以通过注入的代码更改页面访问权限吗?如果是这样,如何通过 winapi 完成此更改?
该假设不成立,因为在分配内存后可以更改页面保护标志。
Windows上通常的代码注入机制如下:
OpenProcess
目标进程,以获取具有适当访问权限的句柄。VirtualAllocEx
在目标进程中分配一个缓冲区,带有一组内存页访问标志。WriteProcessMemory
的内存复制到目标。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文档。注入的代码应该是可执行和可读的,但不一定是可写的。