运行时进程内存修补以恢复状态
我正在寻找一种方法来存储进程内存,并在以后在某些条件下恢复它.
I'm looking for a method for storing the process memory, and restore it later at certain conditions.
...
实际上我已经阅读了有关它的问题......这似乎是一个很大的挑战!
Actually I've read questions about it... It seems a big challenge!
那么,让我们分析一下:该应用程序是一个分布式应用程序,但许多进程是无状态的(向中央服务器请求它们的状态).进程使用网络连接和共享内存与其他进程通信.
So, let's analyse: The application is a distributed one, but many processes are stateless (request their state to a centralized server). Processes uses network connections and shared memory for communicating with other processes.
中央服务器应通过转储其进程内存来保存其状态,该内存应在特定条件下恢复.(1)
The central server shall save its state by dumping its process memory, which should be restored later a certain conditions. (1)
我知道 ReadProcessMemory 和 WriteProcessMemory 函数,允许进程读取自身并覆盖已经分配了内存,不是吗?所以,我需要的是我开始读/写的地址,以及要读/写的字节数.那么...什么地址?我读过的许多代码都使用 VirtualAlloc返回的地址a>,但我不知道这对我是否有用.
I known about ReadProcessMemory and WriteProcessMemory functions, which allow the process to read itself and overwrite already allocated memory, isn't it? So, which I need is address where I start to read/write, and the number of bytes to read/write. So... what addresses? Many code I've read uses the address returned by VirtualAlloc, but I don't known whether this could be useful to me.
我假设进程可执行段没有改变,所以它们不需要红色/写入.在恢复时,我也可以假设所有进程线程在主线程读取内存时都处于相同的执行位置.
I assume that the process executable segments are not changing, so they do not need red/written. At restore time, I could also assume that all process threads are in the same execution position when the memory was read by the main thread.
它仍然是堆栈内存和堆内存,它们是我感兴趣的内存段.
It remains the stack memory, and the heap memory, which are the memory segments what I'm interested in.
有可能吗?
(1) 问我为什么要这样做是完全合法的.原因是……复杂,像往常一样.但是,假设应用程序具有非常复杂的状态,则需要一个过于复杂的状态保存算法.另一种选择(正在分析中)是实现记录器/重放机制,能够重现对修改状态有贡献的每个事件.
(1) It is perfectly legal to ask why I'm trying to do this. The reason is... complicated, as usual. However, say that the application has a very complicated state, that requires a too complex state saving algorithm. The another alternative (which is in subject of analysis) is the implementation of a logger/replay mechanism able to reproduce every event which has contributed to the modified state.
我想到了 malloc &公司钩.所以我可以跟踪进程分配的内存.但实际上我注意到了 _CrtMemState 结构,但我不知道它是否对我有用.
It came to my mind the malloc & co. hook. So I can track the memory allocated by the process. But actually I noticed the _CrtMemState structure, but I don't known whether it could be useful to me.
推荐答案
ReadProcessMemory 用于读取另一个进程的内存.在进程内部,这是不必要的――您可以在同一进程中取消引用一个指向读取内存的指针.
ReadProcessMemory is for reading the memory of another process. Inside of a process, it's unnecessary -- you can just dereference a pointer to read memory within the same process.
要查找进程中的内存块,可以使用VirtualQuery
.每个块都将被标记为状态、类型、大小等.这是我多年前编写的一些代码,用于遍历指定进程的块列表(使用 VirtualQueryEx
).您使用 VirtualQuery
的方式几乎相同,只是您不必指定进程,因为它总是在其运行的进程中运行.
To find the blocks of memory in a process, you can use VirtualQuery
. Each block will be tagged with a state, type, size, etc. Here's some code I wrote years ago to walk the block list for a specified process (using VirtualQueryEx
). You use VirtualQuery
pretty much the same way, except that you don't have to specify a process, since it always walks the process in which its running.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
unsigned long usage;
void show_modules(HANDLE process) {
unsigned char *p = NULL;
MEMORY_BASIC_INFORMATION info;
for ( p = NULL;
VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info);
p += info.RegionSize )
{
printf("%#10.10x (%6uK) ", info.BaseAddress, info.RegionSize/1024);
switch (info.State) {
case MEM_COMMIT:
printf("Committed");
break;
case MEM_RESERVE:
printf("Reserved");
break;
case MEM_FREE:
printf("Free");
break;
}
printf(" ");
switch (info.Type) {
case MEM_IMAGE:
printf("Code Module");
break;
case MEM_MAPPED:
printf("Mapped ");
break;
case MEM_PRIVATE:
printf("Private ");
}
printf(" ");
if ((info.State == MEM_COMMIT) && (info.Type == MEM_PRIVATE))
usage +=info.RegionSize;
int guard = 0, nocache = 0;
if ( info.AllocationProtect & PAGE_NOCACHE)
nocache = 1;
if ( info.AllocationProtect & PAGE_GUARD )
guard = 1;
info.AllocationProtect &= ~(PAGE_GUARD | PAGE_NOCACHE);
switch (info.AllocationProtect) {
case PAGE_READONLY:
printf("Read Only");
break;
case PAGE_READWRITE:
printf("Read/Write");
break;
case PAGE_WRITECOPY:
printf("Copy on Write");
break;
case PAGE_EXECUTE:
printf("Execute only");
break;
case PAGE_EXECUTE_READ:
printf("Execute/Read");
break;
case PAGE_EXECUTE_READWRITE:
printf("Execute/Read/Write");
break;
case PAGE_EXECUTE_WRITECOPY:
printf("COW Executable");
break;
}
if (guard)
printf(" guard page");
if (nocache)
printf(" non-cachable");
printf("
");
}
}
int main(int argc, char **argv) {
int pid;
if (argc != 2) {
fprintf(stderr, "Usage: %s <process ID>", argv[0]);
return 1;
}
sscanf(argv[1], "%i", &pid);
HANDLE process = OpenProcess(
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
false,
pid);
show_modules(process);
printf("Total memory used: %luKB
", usage/1024);
return 0;
}
相关文章