赞
踩
这种方法仅适合于Windows的GUI程序。利用WM_COPYDATA消息来进行进程间通信。其原理是如下:
在x86下,由于保护模式下进程都具有虚拟内存。所以每个进程都拥有4GB的虚存空间,并通过分页机制进行寻址管理。其中2GB的内核空间是进程共享的而2GB的用户空间则是每个进程独立拥有。
WM_COPYDATA消息会在内核空间开辟一段缓冲区。然后把要输入的内容传递进去。由于内核空间是共享的,所以其他进程可以直接获取。
这种方法比较消耗资源,不推荐携带大量数据。
看一下演示程序:
这是发送消息程序Send的主要代码:
这是接受消息程序Recv的主要代码
结果如下:
当DLL被映射到多个进程空间时,其中包含的变量数据各个都是不受影响的。也就是说数据是不共享的。如果这些数据是共享的那就可以达到进程间通信的目的。可以通过添加一个共享段并把数据丢在里面达到共享数据的目的
接下来使用这个dll的进程就可以共享这个g_iNum的变量了。
文件映射是利用把磁盘上的文件映射到各个进程中。虽然多个进程空间内都有该映射,但实际上内存中只有一份。对映射到内存的文件进行修改也会影响到磁盘上的文件。
直接看代码:
- #include <windows.h>
- #include <cstdio>
-
- #define FILENAME "E:\\Projects\\FileMapping\\FileMapping\\MsgSnd.exe"
-
- VOID ShowError(const char *pcszErrFuncName)
- {
- char szErrInfoBuf[MAX_PATH] = { 0 };
-
- if (NULL == pcszErrFuncName)
- {
- return;
- }
- wsprintf(szErrInfoBuf,
- "Error Information: %s Error code: %d\r\n",
- pcszErrFuncName,
- GetLastError());
- OutputDebugString(szErrInfoBuf);
- }
-
- // 含有文件的文件映射
- int main()
- {
- HANDLE hFile = INVALID_HANDLE_VALUE;
- HANDLE hFileMapping = NULL;
- LPVOID lpAddr = NULL;
-
- do
- {
- hFile = CreateFile(FILENAME,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL
- );
- if (INVALID_HANDLE_VALUE == hFile)
- {
- ShowError("CreateFile");
- break;
- }
-
- hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, "Test");
- if (NULL == hFileMapping)
- {
- ShowError("CreateFileMapping");
- break;
- }
-
- lpAddr = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
- if (NULL == lpAddr)
- {
- ShowError("MapViewOfFile");
- break;
- }
- system("pause");
- UnmapViewOfFile(lpAddr);
- } while (FALSE);
-
- if (INVALID_HANDLE_VALUE != hFile)
- {
- CloseHandle(hFile);
- hFile = INVALID_HANDLE_VALUE;
- }
-
- if (NULL != hFileMapping)
- {
- CloseHandle(hFileMapping);
- hFileMapping = NULL;
- }
- system("pause");
-
- return(0);
- }
接下来使用另一个进程打开该内存映射, 即可实现进程间通信:
- #include <windows.h>
- #include <cstdio>
-
- #define FILENAME "E:\\Projects\\FileMapping\\FileMapping\\MsgSnd.exe"
-
- VOID ShowError(const char *pcszErrFuncName)
- {
- char szErrInfoBuf[MAX_PATH] = { 0 };
-
- if (NULL == pcszErrFuncName)
- {
- return;
- }
- wsprintf(szErrInfoBuf,
- "Error Information: %s Error code: %d\r\n",
- pcszErrFuncName,
- GetLastError());
- OutputDebugString(szErrInfoBuf);
- }
-
- // 含有文件的文件映射
- int main()
- {
- HANDLE hFileMapping = NULL;
- LPVOID lpAddr = NULL;
-
- do
- {
- hFileMapping = OpenFileMapping(FILE_MAP_WRITE, FALSE, "Test");
- if (NULL == hFileMapping)
- {
- ShowError("CreateFileMapping");
- break;
- }
-
- lpAddr = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
- if (NULL == lpAddr)
- {
- ShowError("MapViewOfFile");
- break;
- }
- system("pause");
- UnmapViewOfFile(lpAddr);
- } while (FALSE);
-
- if (NULL != hFileMapping)
- {
- CloseHandle(hFileMapping);
- hFileMapping = NULL;
- }
- system("pause");
-
- return(0);
- }
代码都差不多唯一的差别就是CreateFile和CreateFileMapping直接替换成OpenFileMapping打开对应内存文件映射即可。
有一点需要注意的。就是MapViewOfFile这个API。来看一下对应的MSDN文档:
其中的dwFileOffsetLow参数中指出,映射的偏移位置必须是对齐粒度的整数倍。我的计算机的粒度目前是0x10000即64KB。所以这里需要时0x10000的倍数才行
经过调试也可以发现MapViewOfFile的返回基址是0x02d30000也是0x10000的整数倍。
接下来看一种无文件的内存映射,这种情况的下不需要CreateFile,其会在内存中开辟一段空间,这段空间会被进程之间共享。
- #include <windows.h>
- #include <cstdio>
-
- VOID ShowError(const char *pcszErrFuncName)
- {
- char szErrInfoBuf[MAX_PATH] = { 0 };
-
- if (NULL == pcszErrFuncName)
- {
- return;
- }
- wsprintf(szErrInfoBuf,
- "Error Information: %s Error code: %d\r\n",
- pcszErrFuncName,
- GetLastError());
- OutputDebugString(szErrInfoBuf);
- }
-
- // 无文件内存映射
- int main()
- {
- HANDLE hFileMapping = NULL;
- LPVOID lpAddr = NULL;
-
- do
- {
- hFileMapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0x1000, "Test");
- if (NULL == hFileMapping)
- {
- ShowError("CreateFileMapping");
- break;
- }
-
- lpAddr = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
- if (NULL == lpAddr)
- {
- ShowError("MapViewOfFile");
- break;
- }
- system("pause");
- UnmapViewOfFile(lpAddr);
- } while (FALSE);
-
- if (NULL != hFileMapping)
- {
- CloseHandle(hFileMapping);
- hFileMapping = NULL;
- }
- system("pause");
-
- return(0);
- }
另一个进程去打开这段内存空间然后即可实现进程间通讯。
- #include <windows.h>
- #include <cstdio>
-
- VOID ShowError(const char *pcszErrFuncName)
- {
- char szErrInfoBuf[MAX_PATH] = { 0 };
-
- if (NULL == pcszErrFuncName)
- {
- return;
- }
- wsprintf(szErrInfoBuf,
- "Error Information: %s Error code: %d\r\n",
- pcszErrFuncName,
- GetLastError());
- OutputDebugString(szErrInfoBuf);
- }
-
- // 无文件内存映射
- int main()
- {
- HANDLE hFileMapping = NULL;
- LPVOID lpAddr = NULL;
-
- do
- {
- hFileMapping = OpenFileMapping(FILE_MAP_WRITE, FALSE, "Test");
- if (NULL == hFileMapping)
- {
- ShowError("CreateFileMapping");
- break;
- }
-
- lpAddr = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
- if (NULL == lpAddr)
- {
- ShowError("MapViewOfFile");
- break;
- }
- system("pause");
- UnmapViewOfFile(lpAddr);
- } while (FALSE);
-
- if (NULL != hFileMapping)
- {
- CloseHandle(hFileMapping);
- hFileMapping = NULL;
- }
- system("pause");
-
- return(0);
- }
在利用文件映射进程共享数据的过程中,记得不要关闭CreateFileMapping生成的句柄和MapViewOfFile返回的地址。
管道分为匿名管道和命名管道。其中匿名管道主要用于进程间通信但只能是父子进程之间。
利用这个特性可以写出一些有趣的小程序。比如:
该程序可以输入dos命令并执行对应命令。看上去像是一个shell一样。实际上其只是利用管道借用了cmd.exe来执行命令后把结果返回到edit控件中。
贴核心代码:
- DWORD WINAPI RecvInfoThread(LPVOID lpThreadParameter)
- {
- CString strResult, strTmp, strTmp1;
- DWORD dwTotalAvail = 0;
- DWORD dwReaded = 0;
- char szBuf[129] = { 0 };
- BOOL fOk = FALSE;
- BOOL fFirst = TRUE;
- BOOL fOriginalFirst = TRUE;
- INT iIdx = 0;
-
- while (!g_fExit)
- {
- // 检测到管道内有数据
- if ((fOk = PeekNamedPipe(g_hReadPipe_, NULL, 0, NULL, &dwTotalAvail, NULL)) &&
- dwTotalAvail > 0)
- {
- fFirst = TRUE;
- // 读取管道内的数据并显示
- do
- {
- // 每次从管道内读取128个字节
- RtlZeroMemory(szBuf, sizeof(szBuf));
- fOk = ReadFile(g_hReadPipe_, szBuf, sizeof(szBuf) - 1, &dwReaded, NULL);
- if (!fOk)
- {
- break;
- }
- strTmp = szBuf;
- // 截取左边3个字符判定是否是cls命令或者exit命令
- strTmp1 = strTmp.Left(5);
- if (!strTmp1.Compare("cls\r\n"))
- {
- iIdx = strTmp.GetLength() - strTmp.Find("\f") - 1;
- strTmp = strTmp.Right(iIdx);
- }
- strTmp1 = strTmp.Left(6);
- // 如果是exit命令则退出自身进程
- if (!strTmp1.Compare("exit\r\n"))
- {
- // 退出进程
- TerminateProcess(GetCurrentProcess(), 0);
- }
- if (!fOriginalFirst)
- {
- if (fFirst)
- {
- int iIdx = strTmp.GetLength() - strTmp.Find("\n") - 1;
- strTmp = strTmp.Right(iIdx);
- fFirst = FALSE;
- }
- }
- else
- {
- fOriginalFirst = FALSE;
- }
-
- strResult += strTmp;
- dwTotalAvail -= dwReaded;
- } while (dwTotalAvail > 0);
- SetDlgItemTextA(g_MainWnd, IDC_EDIT_CONTENT, strResult);
- strResult = "";
- dwTotalAvail = 0;
- }
- Sleep(100);
- }
-
- return(0);
- }
-
- BOOL Init()
- {
- SECURITY_ATTRIBUTES sa = { 0 };
- BOOL fOk = FALSE;
- STARTUPINFO si = { sizeof(si) };
- PROCESS_INFORMATION pi = { 0 };
- HANDLE hThread = NULL;
- char szBuf[] = "cmd.exe";
-
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
- sa.nLength = sizeof(sa);
-
- // 创建2条匿名管道
- fOk = CreatePipe(&g_hReadPipe, &g_hWritePipe, &sa, 0);
- if (!fOk)
- {
- return(FALSE);
- }
- fOk = CreatePipe(&g_hReadPipe_, &g_hWritePipe_, &sa, 0);
- if (!fOk)
- {
- return(FALSE);
- }
- si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
- si.wShowWindow = SW_HIDE;
- si.hStdInput = g_hReadPipe;
- si.hStdOutput = g_hWritePipe_;
- si.hStdError = g_hWritePipe_;
- // 创建隐秘cmd进程
- fOk = CreateProcess(NULL, szBuf, &sa, NULL, TRUE, 0, NULL, NULL, &si, &pi);
- if (!fOk)
- {
- return(FALSE);
- }
- g_hProcess = pi.hProcess;
-
- // 创建管道监视线程
- hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RecvInfoThread, NULL, 0, NULL);
- if (NULL != hThread)
- {
- CloseHandle(hThread);
- hThread = NULL;
- }
-
- return(TRUE);
- }
-
- void CEasyTrojanDlg::OnBnClickedBtnSendcmd()
- {
- // TODO: 在此添加控件通知处理程序代码
- CString strCmd;
- CEdit *pCEdit = NULL;
-
- GetDlgItemText(IDC_EDIT_CMD, strCmd);
- if (strCmd.IsEmpty())
- {
- return;
- }
- // 先把命令转成小写简化
- strCmd.MakeLower();
- strCmd += "\r\n";
-
- DWORD dwWritten = 0;
-
- WriteFile(g_hWritePipe,
- strCmd.GetBuffer(0),
- strCmd.GetLength(),
- &dwWritten,
- NULL);
- SetDlgItemText(IDC_EDIT_CMD, "");
- GetDlgItem(IDC_EDIT_CMD)->SetFocus();
- }
-
-
- BOOL CEasyTrojanDlg::OnInitDialog()
- {
- CDialogEx::OnInitDialog();
- BOOL fOk = FALSE;
-
- // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
- // 执行此操作
- SetIcon(m_hIcon, TRUE); // 设置大图标
- SetIcon(m_hIcon, FALSE); // 设置小图标
-
- // TODO: 在此添加额外的初始化代码
- g_MainWnd = GetSafeHwnd();
- if (!g_MainWnd)
- {
- return(FALSE);
- }
- fOk = Init();
- if (!fOk)
- {
- return(FALSE);
- }
- GetDlgItem(IDC_EDIT_CMD)->SetFocus();
-
- return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
- }
(完)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。