您的位置:首页 > 其它

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

2014-08-07 16:30 260 查看
本文由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仍然提供了读写其他进程内存的工具,分别是ReadProcessMemory和WriteProcessMemory

(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号
于天津
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: