代码之家  ›  专栏  ›  技术社区  ›  Luca

用于恢复状态的运行时进程内存修补

  •  8
  • Luca  · 技术社区  · 16 年前

    我正在寻找一种存储进程内存的方法,稍后在特定条件下恢复它。

    事实上,我读过有关它的问题…这似乎是一个巨大的挑战!

    因此,让我们分析一下:应用程序是分布式的,但许多进程是无状态的(向集中服务器请求它们的状态)。进程使用网络连接和共享内存与其他进程通信。

    中央服务器应通过转储进程内存来保存其状态,然后在特定条件下恢复。(1)

    我知道 ReadProcessMemory WriteProcessMemory 函数允许进程读取自身并覆盖已经分配的内存,不是吗? 所以,我需要的是我开始读/写的地址,以及要读/写的字节数。所以… 什么地址 ?我读过的许多代码使用返回的地址 VirtualAlloc 但我不知道这是否对我有用。

    我假设流程可执行段没有更改,因此它们不需要红色/书写。 在还原时,我还可以假定当主线程读取内存时,所有进程线程都处于相同的执行位置。

    它仍然是堆栈内存和堆内存,这是我感兴趣的内存段。

    有可能吗?

    问我为什么要这样做是完全合法的。原因是…像往常一样复杂。但是,假设应用程序有一个非常复杂的状态,这需要一个过于复杂的状态保存算法。另一种选择(在分析主题中)是日志记录器/重放机制的实现,该机制能够重现导致修改状态的每个事件。


    我想到了 malloc & co. hook . 所以我可以跟踪进程分配的内存。但实际上我注意到 _CrtMemState 结构,但我不知道它是否对我有用。

    2 回复  |  直到 16 年前
        1
  •  8
  •   Jerry Coffin    16 年前

    readprocessmemory用于读取 另一个 过程。在一个进程内部,这是不必要的——您可以取消引用一个指针来读取同一进程中的内存。

    要查找进程中的内存块,可以使用 VirtualQuery . 每个块都将被标记为状态、类型、大小等。这是我多年前为特定进程(使用 VirtualQueryEx )你用 虚拟查询 基本上是一样的,只是不需要指定进程,因为它总是在运行它的进程中进行。

    #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;
    }        
    
        2
  •  1
  •   Adrian McCarthy    16 年前

    进程内存不代表进程的整个状态。操作系统将代表进程将对象(例如,文件句柄、同步对象等)保存在进程范围之外的非页面池等位置。

    我认为,在可以用可管理的工作序列化和反序列化相关状态之前,最好不要重构。