2010-07-22 2 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

+0

이것은 리눅스에서'''cat/proc/pid/maps''와 비슷합니다.이 코드를 사용하면 각 메모리 블록이 어느 모듈에 속해 있는지 알 수 없습니다. 그 정보를 어떻게 든 얻을 수 있습니까? – alexandernst

+0

아, 방금 찾은 방법을 찾았습니다. :)'''GetModuleFileNameA ((HINSTANCE) mbi.AllocationBase, szModName, _countof (szModName));''' – alexandernst

1

프로세스 메모리가 프로세스의 전체 상태를 나타내는 것은 아닙니다. 운영 체제는 프로세스 범위를 벗어나는 비 페이징 풀과 같은 장소에서 프로세스 대신 개체 (예 : 파일 핸들, 동기화 개체 등)를 보유합니다.

관리 가능한 노력으로 관련 상태를 직렬화 및 비 직렬화 할 수있을 때까지 리팩토링하는 것이 더 나을 것이라고 생각합니다.

+0

이해 하겠지만 새로운 핸들을 만들거나 삭제하지 않는다고 가정합니다. 그들에 대한 수정은 프로세스 상태에 대해 의미가 없다고 생각합니다. 물론 직렬화에 동의합니다. 그것은 길이어야합니다 ... – Luca

관련 문제