2010-07-22 35 views
8

Tôi đang tìm một phương pháp lưu trữ bộ nhớ quá trình và khôi phục lại sau này ở các điều kiện nhất định.Vá bộ nhớ thời gian chạy để khôi phục trạng thái

...

Thực ra tôi đã đọc câu hỏi về nó ... Có vẻ như là một thách thức lớn!

Vì vậy, hãy phân tích: Ứng dụng là một ứng dụng được phân phối, nhưng nhiều quy trình là không trạng thái (yêu cầu trạng thái của chúng thành máy chủ tập trung). Quy trình sử dụng kết nối mạng và bộ nhớ dùng chung để liên lạc với các quy trình khác.

Máy chủ trung tâm sẽ lưu trạng thái của nó bằng cách bán bộ nhớ quá trình của nó, bộ nhớ này sẽ được khôi phục sau một số điều kiện nhất định. (1)

Tôi biết về các chức năng ReadProcessMemoryWriteProcessMemory, cho phép quá trình đọc chính nó và ghi đè lên bộ nhớ đã cấp phát, phải không? Vì vậy, điều tôi cần là địa chỉ nơi tôi bắt đầu đọc/ghi và số byte để đọc/ghi. Vì vậy, ... địa chỉ là gì? Nhiều mã tôi đã đọc sử dụng địa chỉ được trả lại bởi VirtualAlloc, nhưng tôi không biết liệu điều này có thể hữu ích cho tôi hay không.

Tôi giả định rằng các phân đoạn thực thi quy trình không thay đổi, vì vậy chúng không cần phải có màu đỏ/ghi. Tại thời điểm khôi phục, tôi cũng có thể giả định rằng tất cả các luồng xử lý nằm trong cùng một vị trí thực thi khi bộ nhớ được đọc bởi luồng chính.

Nó vẫn còn nhớ chồng, và bộ nhớ heap, đó là những phân đoạn bộ nhớ những gì tôi quan tâm.

Có thể?

(1) Hoàn toàn hợp pháp khi hỏi tại sao tôi lại cố gắng thực hiện điều này. Lý do là ... phức tạp, như thường lệ. Tuy nhiên, nói rằng ứng dụng có một trạng thái rất phức tạp, đòi hỏi một thuật toán tiết kiệm trạng thái quá phức tạp. Một giải pháp thay thế khác (trong lĩnh vực phân tích) là việc thực hiện một cơ chế logger/replay có thể tái tạo mọi sự kiện đã góp phần vào trạng thái sửa đổi.


Tôi nghĩ đến số malloc & co. hook. Vì vậy, tôi có thể theo dõi bộ nhớ được phân bổ bởi quá trình. Nhưng thực ra tôi nhận thấy cấu trúc _CrtMemState, nhưng tôi không biết liệu nó có hữu ích cho tôi hay không.

Trả lời

8

ReadProcessMemory là để đọc bộ nhớ của một quy trình khác. Bên trong của một quá trình, nó không cần thiết - bạn chỉ có thể dereference một con trỏ để đọc bộ nhớ trong cùng một quá trình.

Để tìm các khối bộ nhớ trong một quá trình, bạn có thể sử dụng VirtualQuery. Mỗi khối sẽ được gắn thẻ với một trạng thái, loại, kích cỡ, vv Đây là một số mã tôi đã viết cách đây nhiều năm để đi bộ danh sách khối cho một quy trình cụ thể (sử dụng VirtualQueryEx). Bạn sử dụng VirtualQuery khá nhiều theo cùng một cách, ngoại trừ việc bạn không phải chỉ định quy trình vì nó luôn đi qua quá trình chạy của nó.

#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

Ví dụ tuyệt vời. Nó thực sự hoạt động, nhưng đối với trường hợp rất hạn chế. Cảm ơn bạn! – Luca

+0

Điều này giống như '' 'cat/proc/pid/maps''' trong Linux, ngoại trừ với mã này bạn không biết mô-đun nào từng khối bộ nhớ thuộc về. Có thể lấy thông tin đó bằng cách nào đó không? – alexandernst

+0

Ah, tôi chỉ tìm thấy cách làm điều đó :) '' 'GetModuleFileNameA ((HINSTANCE) mbi.AllocationBase, szModName, _countof (szModName));' '' – alexandernst

1

Bộ nhớ quá trình không đại diện cho toàn bộ quá trình. Hệ điều hành sẽ tổ chức các đối tượng thay mặt cho quá trình của bạn (ví dụ: xử lý tệp, đối tượng đồng bộ hóa, v.v.) ở những nơi như nhóm không được phân trang nằm ngoài phạm vi của quy trình của bạn.

Tôi nghĩ bạn nên cải thiện việc tái cấu trúc cho đến khi bạn có thể tuần tự hóa và deserialize trạng thái có liên quan với một nỗ lực có thể quản lý.

+0

Tôi hiểu nó, nhưng giả định rằng không có xử lý mới được tạo ra/xóa và sửa đổi chúng không có ý nghĩa đối với trạng thái quá trình, tôi nghĩ rằng điều này có thể hoạt động. Tất nhiên tôi đồng ý về việc tuần tự hóa. Nó phải là cách ... – Luca

Các vấn đề liên quan