Windows进程通信之进程内存读写

来源:互联网 发布:心动网络 面试时间截止 编辑:程序博客网 时间:2024/05/12 16:36

本文由danny发表于 http://blog.csdn.net/danny_share

 

说明:建议先下载本文配套工程,其中

ProcessMemoryMain工程、ProcessMemorySubA工程,ProcessMemorySubB工程分别用于演示进程间通信的主进程和两个子进程

下载地址:http://download.csdn.net/detail/danny_share/7726765 

注意:

1.不要F5直接运行2.编译生成debug目录或者release目录以后,手动双击ProcessMemoryMain.exe点击Test按钮即可

 

 

1.       概念

1)虚拟地址空间

对运行在保护模式的进程而言,每个进程的地址空间都是虚拟的,且即使两个进程的虚拟地址相同,操作系统也可能将该虚拟地址映射到不同的物理地址空间(详见http://msdn.microsoft.com/zh-cn/library/hh439648(v=vs.85).aspx

 

2)进程内存读写

虚拟地址空间本身的设计能够更好的隔离不同的应用,但Windows仍然提供了读写其他进程内存的工具,分别是ReadProcessMemoryWriteProcessMemory

 

3)通信

相比于前面三篇文章(事件有wait机制,消息有WM_COPYDATA,剪贴板有SetClipboardViewer),进程内存读写并没有给我们提供类似的监听和监控内容变化的机制,所以个人认为在一般的软件系统开发中(外挂、漏洞修复除外),进程内存读写单独用作通信的情况较少。

 

2.       实现

和前面几篇单独使用某一种技术(或者叫工具)通信不同,根据刚刚所描述的,进程内存读写不具备通知或者监控功能,所以本文将联合使用消息和进程内存读写来实现进程通信。详见工程

(1)      主进程启动以后,通过CreateProcess创建两个子进程

 

void CProcessMemoryMainDlg::openProcess(){    STARTUPINFO siA;    siA.cb = sizeof(STARTUPINFO);    siA.lpReserved = NULL;    siA.lpDesktop = NULL;    siA.lpTitle = NULL;    siA.dwFlags = 0;    siA.cbReserved2 = 0;    siA.lpReserved2 = NULL;    BOOL bresA = ::CreateProcess(NULL,"ProcessMemorySubA.exe",NULL,NULL,false,NORMAL_PRIORITY_CLASS,NULL,NULL,&siA,&piA);     STARTUPINFO siB;    siB.cb = sizeof(STARTUPINFO);    siB.lpReserved = NULL;    siB.lpDesktop = NULL;    siB.lpTitle = NULL;    siB.dwFlags = 0;    siB.cbReserved2 = 0;    siB.lpReserved2 = NULL;    BOOL bres = ::CreateProcess(NULL,"ProcessMemorySubB.exe",NULL,NULL,false,NORMAL_PRIORITY_CLASS,NULL,NULL,&siB,&piB);}


 

2)主进程为子进程申请虚拟内存空间,并写入数据,然后向子进程发送消息,并传入刚申请的虚拟地址

 

    if(!this->openProcessFlag)    {       this->openProcess();       openProcessFlag=true;    }    myHandleA=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,this->piA.dwProcessId);    myHandleB=::OpenProcess(PROCESS_ALL_ACCESS,FALSE,this->piB.dwProcessId);    Sleep(1000);    if(NULL!=myHandleA)    {      <span style="color:#ff0000;"> lpBaseAddressA=VirtualAllocEx(myHandleA, 0, 4, MEM_COMMIT, PAGE_READWRITE);        WriteProcessMemory(myHandleA, lpBaseAddressA, buffer, 4, NULL);</span>           }    if(NULL!=myHandleB)    {       lpBaseAddressB=VirtualAllocEx(myHandleB, 0, 4, MEM_COMMIT, PAGE_READWRITE);        WriteProcessMemory(myHandleB, lpBaseAddressB, buffer, 4, NULL);    }     ::PostMessage(::FindWindow(NULL,"ProcessMemorySubA"),WM_PMCommA,0,(LPARAM)lpBaseAddressA);    ::PostMessage(::FindWindow(NULL,"ProcessMemorySubB"),WM_PMCommB,0,(LPARAM)lpBaseAddressB);


 

3)子进程收到消息以后,读取数据,然后向主进程发回响应消息,这里以进程A为例

 

    LPVOID lpBaseAddress=(LPVOID)lParam;    HANDLE hProcess=GetCurrentProcess();    char data[4];   <span style="color:#ff0000;"> ReadProcessMemory(hProcess, lpBaseAddress, data,4, NULL);</span>    ::PostMessage(::FindWindow(NULL,"ProcessMemoryMain"),WM_PMCommA,0,0);    MessageBox("A receive command","Info",MB_OK);    return 0;



  

4)主进程收到响应消息,回收内存,这里用于演示,实际在这里回收内存有可能发生内存泄露

 LRESULT CProcessMemoryMainDlg::OnMyMessageA(WPARAM wParam, LPARAM lParam){    VirtualFreeEx(myHandleA,lpBaseAddressA, 0, 4);    MessageBox("A response","Info",MB_OK);    return 0;}


 

 

4.总结

1)不同的进程拥有不同的虚拟地址空间

2)演示工程中国的主进程M分配的内存是打开子进程A以后,在A的进程地址空间里分配

3)读写内存空间工具没有提供检测或者通知功能,在交互式的多进程环境中,一般较少单独使用。

 

 danny

2014年8月7号

于天津


0 0
原创粉丝点击