2010-07-22 64 views
8

我正在尋找一種用於存儲進程內存的方法,並在稍後在特定條件下進行恢復。用於恢復狀態的運行時進程內存修補程序

...

它其實我讀過的問題......這似乎是一個很大的挑戰!因此,讓我們來分析一下:應用程序是分佈式應用程序,但許多進程是無狀態的(向中央服務器請求其狀態)。進程使用網絡連接和共享內存與其他進程進行通信。

中央服務器應通過轉儲其進程內存來保存其狀態,該進程內存應在稍後的一定條件下恢復。 (1)

我知道約ReadProcessMemoryWriteProcessMemory功能,它允許進程自己讀取並覆蓋已分配的內存,不是嗎? 所以,我需要的是我開始讀/寫的地址,以及要讀/寫的字節數。所以... 什麼地址?我讀過的許多代碼使用VirtualAlloc返回的地址,但我不知道這對我是否有用。

我假定進程可執行段沒有改變,所以他們不需要紅色/書寫。 在還原時,我還可以假設當主線程讀取內存時,所有進程線程都處於相同的執行位置。

它仍然棧內存,堆內存,其內存段正是我感興趣的

這可能嗎?

(1)問爲什麼我試圖這樣做是完全合法的。原因是...像往常一樣複雜。但是,假設應用程序有一個非常複雜的狀態,那就需要一個太複雜的狀態保存算法。另一個備選方案(這是分析的主題)是記錄器/重放機制的實現,該機制能夠重現造成修改狀態的每個事件。


它來到我的腦海裏malloc & co. hook。所以我可以跟蹤進程分配的內存。但實際上我注意到了_CrtMemState結構,但我不知道它對我是否有用。

回答

8

ReadProcessMemory用於讀取內存的另一個進程。在一個進程內部,這是不必要的 - 你可以在同一個進程中取消引用一個指針來讀取內存。

要查找進程中的內存塊,可以使用VirtualQuery。每個塊都會被標記爲狀態,類型,大小等等。下面是幾年前我寫的一些代碼,用於指定特定進程的塊列表(使用VirtualQueryEx)。除非您不必指定進程,因爲它總是遍歷其運行的進程,您幾乎以相同的方式使用VirtualQuery

#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)\t", 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("\t"); 
     switch (info.Type) { 
     case MEM_IMAGE: 
      printf("Code Module"); 
      break; 
     case MEM_MAPPED: 
      printf("Mapped  "); 
      break; 
     case MEM_PRIVATE: 
      printf("Private "); 
     } 
     printf("\t"); 

     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("\tguard page"); 
     if (nocache) 
      printf("\tnon-cachable"); 
     printf("\n"); 
    } 
} 

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\n", usage/1024); 
    return 0; 
}   
+0

很好的例子。它確實有效,但對於非常有限的情況。謝謝! – Luca 2010-08-03 16:23:20

+0

這就像Linux中的cat/proc/pid/maps''一樣,除了這個代碼你不知道每塊內存屬於哪個模塊。有可能以某種方式獲得這些信息嗎? – alexandernst 2014-01-30 12:05:31

+0

嗯,我剛剛發現該怎麼做:)'''GetModuleFileNameA((HINSTANCE)mbi.AllocationBase,szModName,_countof(szModName));''' – alexandernst 2014-01-30 13:11:04

1

進程內存不代表整個進程狀態。操作系統將代表您的進程(例如,文件句柄,同步對象等)在非頁面緩衝池等位於您的進程範圍之外的對象保留對象。

我認爲在重構之前,您可以更好地進行重構,直到您可以使用可管理的工作對相關狀態進行序列化和反序列化。

+0

我明白了,但假設沒有新的句柄被創建/刪除並且對它們的修改對於進程狀態沒有意義,我認爲這可以起作用。 當然我同意序列化。它應該是... – Luca 2010-07-23 06:07:01

相關問題