首页
社区
课程
招聘
[旧帖] [求助]共享内存和进程 0.00雪花
发表于: 2013-11-19 10:55 6347

[旧帖] [求助]共享内存和进程 0.00雪花

2013-11-19 10:55
6347
请教一个困扰了很久的问题:有没有什么工具可以查看某个共享内存是哪个进程创建的,还有哪些进程在访问该共享内存,我现在用WinObj可以查看到共享内存名称和占用内存大小。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 160
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
hook api
系统并不保存这些信息(谁创建),好像只有引用计数一说。
本质上是不同进程的虚拟地址指向了同一块物理内存,个人见解。
2013-11-19 12:49
0
雪    币: 41
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
ObReferenceObjectByHandle
2013-11-20 12:44
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
首先还是定义非托管调用,如下:

const int INVALID_HANDLE_VALUE = -1;
const int PAGE_READWRITE = 0x04;
  //共享内存
  [DllImport("Kernel32.dll",EntryPoint="CreateFileMapping")]
  private static extern IntPtr CreateFileMapping(IntPtr hFile, //HANDLE hFile,
   UInt32 lpAttributes,//LPSECURITY_ATTRIBUTES lpAttributes,  //0
   UInt32 flProtect,//DWORD flProtect
   UInt32 dwMaximumSizeHigh,//DWORD dwMaximumSizeHigh,
   UInt32 dwMaximumSizeLow,//DWORD dwMaximumSizeLow,
   string lpName//LPCTSTR lpName
   );

  [DllImport("Kernel32.dll",EntryPoint="OpenFileMapping")]
  private static extern IntPtr OpenFileMapping(
   UInt32 dwDesiredAccess,//DWORD dwDesiredAccess,
   int bInheritHandle,//BOOL bInheritHandle,
   string lpName//LPCTSTR lpName
   );

  const int FILE_MAP_ALL_ACCESS = 0x0002;
  const int FILE_MAP_WRITE = 0x0002;

  [DllImport("Kernel32.dll",EntryPoint="MapViewOfFile")]
  private static extern IntPtr MapViewOfFile(
   IntPtr hFileMappingObject,//HANDLE hFileMappingObject,
   UInt32 dwDesiredAccess,//DWORD dwDesiredAccess
   UInt32 dwFileOffsetHight,//DWORD dwFileOffsetHigh,
   UInt32 dwFileOffsetLow,//DWORD dwFileOffsetLow,
   UInt32 dwNumberOfBytesToMap//SIZE_T dwNumberOfBytesToMap
   );

  [DllImport("Kernel32.dll",EntryPoint="UnmapViewOfFile")]
  private static extern int UnmapViewOfFile(IntPtr lpBaseAddress);

  [DllImport("Kernel32.dll",EntryPoint="CloseHandle")]
  private static extern int CloseHandle(IntPtr hObject);
然后分别在AB两个进程中定义如下两个信号量及相关变量;
  private Semaphore m_Write;  //可写的信号
  private Semaphore m_Read;  //可读的信号
  private IntPtr handle;     //文件句柄
  private IntPtr addr;       //共享内存地址
  uint mapLength;            //共享内存长

定义这两个信号量是为读写互斥用的。
在A进程中创建共享内存:

m_Write = new Semaphore(1,1,"WriteMap");
m_Read = new Semaphore(0,1,"ReadMap");
mapLength = 1024;
IntPtr hFile = new IntPtr(INVALID_HANDLE_VALUE);   
handle = CreateFileMapping(hFile,0,PAGE_READWRITE,0,mapLength,"shareMemory");
addr = MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0);
然后再向共享内存中写入数据:

m_Write.WaitOne();
byte[] sendStr = Encoding.Default.GetBytes(txtMsg.Text + '\0');
//如果要是超长的话,应另外处理,最好是分配足够的内存
if(sendStr.Length < mapLength)
      Copy(sendStr,addr);
m_Read.Release();

这是在一个单独的方法中实现的,可多次调用,但受信号量的控制。其中txtMsg是一个文本框控件,实际中可用任意字符串,加最后的'\0'是为了让在共享内存中的字符串有一个结束符,否则在内存中取出时是以'\0'为准的,就会出现取多的情况。
Copy方法的实现如下:

static unsafe void Copy(byte[] byteSrc,IntPtr dst)
  {
   fixed (byte* pSrc = byteSrc)
   {
    byte* pDst = (byte*)dst;
    byte* psrc = pSrc;
    for(int i=0;i<byteSrc.Length;i++)
    {
     *pDst = *psrc;
     pDst++;
     psrc ++;
    }
   }
  }
注意unsafe 关键字,在编译时一定要打开非安全代码开关。
最后不要忘了在A进程中关闭共享内存对象,以免内存泄露。
   UnmapViewOfFile(addr);
   CloseHandle(handle);

要在B进程中读取共享内存中的数据,首先要打开共享内存对象:
m_Write = Semaphore.OpenExisting("WriteMap");
m_Read = Semaphore.OpenExisting("ReadMap");
handle = OpenFileMapping(0x0002,0,"shareMemory");
读取共享内存中的数据:
   m_Read.WaitOne();
   string str = MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0);
   txtMsg.Text = str;
   m_Write.Release();
这里获取了字符串,如果要获取byte数组,请参考上面的Copy函数实现。
2013-11-23 15:43
0
雪    币: 2
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
线程才可以共享内存?
2013-11-24 14:51
0
雪    币: 3496
活跃值: (749)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习一下,进程也可以共享吧!
2014-1-4 07:09
0
雪    币: 28
活跃值: (42)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
工具是有的,用 procexp.exe 可以查看到所有进程打开的内核对象,不过没有在这基础上做的更人性化,比如哪些进程持有相同的对象之类的,但是自己一个一个比一下就知道了。希望可以帮助到你。
2014-1-4 10:18
0
雪    币: 28
活跃值: (42)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
你也可以写一个驱动分析一下每个进程的句柄表,如果知道对象的地址,那么解引用进程中的句柄,如果得到了相同地址的对象,那些这些进程就是共享了这个对象。
2014-1-4 10:22
0
游客
登录 | 注册 方可回帖
返回
//