⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jiurl玩玩win2k内存篇 内存共享(二) copyonwrite.htm

📁 关于win2000核心编程的文章
💻 HTM
📖 第 1 页 / 共 3 页
字号:
      NOTEPAD<BR>0328F000 84130860 01F8 NOTEPAD<BR>018EF000 8323F180 0100 
      CopyOnWrite-Er<BR>06AB8000 83091020 02BC CopyOnWrite-Er<BR>*00030000 
      8046BB60 0000 Idle<BR><BR>看到了2个 CopyOnWrite-Er ,进程ID 分别是 0100 和 
      02BC<BR><BR>这2个 CopyOnWrite-Er 
      的输出都是<BR>_________________________________________<BR><BR>JiurlSegData 
      Address: 0x0040a000<BR>JiurlSegData Pte Address: 
      0xc0001028<BR>JiurlSegData: aaaaaaaaaaaaaaaaaaaaaaaa<BR><BR>Input New 
      String to 
      JiurlSegData<BR>_________________________________________<BR><BR>CopyOnWrite-Er 
      100<BR><BR>使用 addr 命令转换到 CopyOnWrite-Er 100 的地址空间<BR>:addr 100<BR><BR>再看一下 
      CopyOnWrite-Er 100 的段的情况,看到了 ".jiurl" 段,<BR>地址范围在 0040A000 大小为 
      00000020<BR>和程序的输出 JiurlSegData Address: 0x0040a000 相符<BR>:map32 
      -u<BR>Owner Obj Name Obj# Address Size Type<BR>CopyOnWrit.text 0001 
      001B:00401000 00004D73 CODE RO<BR>CopyOnWrit.rdata 0002 0023:00406000 
      00000890 IDATA RO<BR>CopyOnWrit.data 0003 0023:00407000 000021C8 IDATA 
      RW<BR>CopyOnWrit.jiurl 0004 0023:0040A000 00000020 IDATA RW<BR>kernel32 
      .text 0001 001B:77E61000 0005D1AE CODE RO<BR>kernel32 .data 0002 
      0023:77EBF000 00001A30 IDATA RW<BR>kernel32 .rsrc 0003 0023:77EC1000 
      00070000 IDATA RO<BR>kernel32 .reloc 0004 0023:77F31000 0000359C IDATA 
      RO<BR>ntdll .text 0001 001B:77F81000 00042492 CODE RO<BR>ntdll ECODE 0002 
      001B:77FC4000 00004371 CODE RO<BR>ntdll PAGE 0003 001B:77FC9000 00003983 
      CODE RO<BR>ntdll .data 0004 0023:77FCD000 00002350 IDATA RW<BR>ntdll .rsrc 
      0005 0023:77FD0000 00026D08 IDATA RO<BR>ntdll .reloc 0006 0023:77FF7000 
      00001DA8 IDATA RO<BR><BR>根据我们计算出的 JiurlSegData Pte Address: 0xc0001028 
      ,显示该页表项<BR>:dd c0001028 l 10<BR>0010:C0001028 06AC7225 00000000 00000000 
      00000000 %r..............<BR><BR>可以看到<BR>CopyOnWrite-Er 100 的 JiurlSegData 
      地址范围的 页表项值为 06AC7225<BR>注意物理页为 06AC7 ,标志为 225(hex)= 0010 0010 0101 
      (bin)&nbsp;<BR>bits1-1 Write 标志为0,表示只读。bits9-9 CopyOnWrite 标志为1,表示使用 Copy 
      On Write 。<BR><BR>CopyOnWrite-Er 2bc<BR><BR>转换到 CopyOnWrite-Er 2bc 
      的地址空间<BR>:addr 2bc<BR><BR>根据我们计算出的 JiurlSegData Pte Address: 0xc0001028 
      ,显示该页表项<BR>:dd c0001028 l 10<BR>0010:C0001028 06AC7225 00000000 00000000 
      00000000 %r..............<BR>可以看到<BR>CopyOnWrite-Er 2bc 的 JiurlSegData 
      地址范围的 页表项值也为 06AC7225<BR>首先就是它和 CopyOnWrite-Er 100 映射了同样的物理页 06AC7 
      ,页中的内容当然是一样的。他们共享了这个数据页。标志位同样也说明了使用 Copy On Write。<BR><BR>2. 向 
      CopyOnWrite-Er 2bc 的全局变量写入<BR><BR>向 CopyOnWrite-Er 2bc 的全局变量写入 
      bbbbbbbbb<BR>程序输出如下<BR><BR>_________________________________________<BR><BR>Input 
      New String to JiurlSegData<BR>:bbbbbbbbb<BR>JiurlSegData: 
      bbbbbbbbb<BR>_________________________________________<BR><BR>可以看到正确读出了输入的 
      bbbbbbbbb<BR><BR><BR>转换到 CopyOnWrite-Er 2bc 的地址空间<BR>:addr 2bc<BR><BR>显示 
      CopyOnWrite-Er 2bc 的 0xc0001028 处的页表项<BR>:dd c0001028 l 
      10<BR>0010:C0001028 04427067 00000000 00000000 00000000 
      gpB.............<BR>该页表项值为 04427067 ,可以看到映射的物理页变成了 04427 
      ,这说明分配并使用了新的物理页。<BR>标志为 067(hex)= 0000 0110 0111 (bin) 可以看到<BR>bits1-1 
      Write 标志为1,表示可写了。bits9-9 CopyOnWrite 标志为0。<BR>对于 CopyOnWrite-Er 2bc ,Copy 
      On Write 机制得到了验证<BR><BR><BR>对于 CopyOnWrite-Er 100 的情况<BR><BR>转换到 
      CopyOnWrite-Er 100 的地址空间<BR>:addr 100<BR><BR>显示 CopyOnWrite-Er 100 的 
      0xc0001028 处的页表项<BR>:dd c0001028 l 10<BR>0010:C0001028 06AC7225 00000000 
      00000000 00000000 %r..............<BR>可以看到该页表项的值仍然是 06AC7225 
      ,说明<BR>CopyOnWrite-Er 100 继续使用原来的物理页<BR>这也符合前面描述的 Copy On Write 
      机制<BR><BR><BR>3. 向 CopyOnWrite-Er 100 的全局变量写入<BR><BR>向 CopyOnWrite-Er 2bc 
      的全局变量写入 
      cccccccccc<BR>程序输出如下<BR>_________________________________________<BR><BR>Input 
      New String to JiurlSegData<BR>:cccccccccc<BR>JiurlSegData: 
      cccccccccc<BR>_________________________________________<BR><BR>可以看到正确读出了输入的 
      cccccccccc&nbsp;<BR><BR>转换到 CopyOnWrite-Er 100 的地址空间<BR>:addr 
      100<BR><BR>显示 CopyOnWrite-Er 100 的 0xc0001028 处的页表项<BR>:dd c0001028 l 
      10<BR>0010:C0001028 00D07067 00000000 00000000 00000000 
      gp..............<BR>可以看到,写入导致了使用新的物理页,并且改变了标志<BR><BR><BR>转换到 
      CopyOnWrite-Er 2bc 的地址空间&nbsp;<BR>:addr 2bc<BR><BR>显示 CopyOnWrite-Er 2bc 的 
      0xc0001028 处的页表项<BR>:dd c0001028 l 10<BR>0010:C0001028 04427067 00000000 
      00000000 00000000 gpB.............<BR>还是刚才的<BR><BR>通过这个例子,我们看到了 Win2k 使用 
      Copy On Write 的效果<BR><BR>4. PfnDataBaseEntry 和 Copy On 
      Write<BR><BR>我们再来观察一下被共享的物理页的 PfnDataBaseEntry 中的情况。<BR><BR>运行一个 
      CopyOnWrite-Er 我们观察它的物理页的页帧号<BR>:addr CopyOnWrite-Er<BR>:dd c0001028 l 
      10<BR>0010:C0001028 06AC7225 00000000 00000000 00000000 
      %r..............<BR>页帧号为 06AC7<BR><BR>计算 06AC7 的页帧号数据库项的地址,页帧号数据库的首地址在全局变量 
      MmPfnDatabase 中,<BR>在我机子上它的值为 81456000 ,每项大小 0x18 个字节<BR><BR>我们可以看到 物理页 
      6ac7<BR>/*08*/ uint32 blink / share count = 00000001<BR>/*0D*/ byte page 
      state = 06<BR>:dd 81456000+18*6ac7 l 18<BR>0010:814F62A8 0000009B E301F2A8 
      00000001 00010608 ................<BR>0010:814F62B8 907B64B8 00004727 
      00000000 C03B37D8 .d{.'G.......7;.<BR>说明该物理页处在 Active 
      状态,并且共享数为1<BR><BR>我们又运行了两个 CopyOnWrite-Er&nbsp;<BR>我们可以看到 物理页 
      6ac7<BR>/*08*/ uint32 blink / share count = 00000003<BR>/*0D*/ byte page 
      state = 06<BR>:dd 81456000+18*6ac7 l 18<BR>0010:814F62A8 0000009B E301F2A8 
      00000003 00010608 ................<BR>0010:814F62B8 907B64B8 00004727 
      00000000 C03B37D8 .d{.'G.......7;.<BR>说明该物理页处在 Active 
      状态,并且共享数增为3<BR><BR>对一个 CopyOnWrite-Er 写入数据<BR>我们可以看到 物理页 6ac7<BR>/*08*/ 
      uint32 blink / share count = 00000002<BR>/*0D*/ byte page state = 
      06<BR>:dd 81456000+18*6ac7 l 18<BR>0010:814F62A8 0000009B E301F2A8 
      00000002 00010608 ................<BR>0010:814F62B8 907B64B8 00004727 
      00000000 C03B37D8 .d{.'G.......7;.<BR>并且共享减为2,写数据的进程由于 Copy On Write 
      而不再使用本物理页<BR><BR>对剩下所有的 CopyOnWrite-Er 写入数据<BR>我们可以看到 物理页 6ac7<BR>/*08*/ 
      uint32 blink / share count = 000068B9<BR>/*0D*/ byte page state = 
      02<BR>:dd 81456000+18*6ac7 l 18<BR>0010:814F62A8 FFFFFFFF E301F2A8 
      000068B9 00000208 .........h......<BR>0010:814F62B8 907B64B8 00004727 
      00000000 C03B37D8 .d{.'G.......7;.<BR>没有进程再使用这个物理页,所以状态变为了 Standby ,而且 
      /*08*/ 由于状态的变化含义也变成了 blink<BR><BR><B>广泛存在的 Copy On Write</B></FONT> 
      <P><FONT face=宋体>&nbsp;&nbsp;&nbsp; 观察一个进程的页表,你会发现除了我们设计的例子之外,很难找到其他的设置了 
      CopyOnWrite 标志的页表项(还是可以找到的,我用一个小工具就在记事本进程中找到了几项,标志位为 205),难道 Copy On Write 
      只有如此少量的应用?实际上 Win2k 中大量使用了 Copy On Write 我们使用 SoftICE 就可以观察到。&nbsp;</FONT> 

      <P><FONT face=宋体>&nbsp;&nbsp;&nbsp; 当向 Copy On Write 页写时,会引发 Page-Fault 
      异常,CPU 会执行异常处理程序 ntoskrnl!KiTrap0E ntoskrnl!KiTrap0E 会调用 
      ntoskrnl!MmAccessFault ,分析 ntoskrnl!MmAccessFault 的汇编代码,可以知道 CopyOnWrite 
      引起的异常将由 ntoskrnl!MiCopyOnWrite 处理。分析汇编代码我们还可以看出 MiCopyOnWrite 
      函数有两个传入参数,第一个参数是引发异常的指令访问的虚拟地址,我们叫做 BadAddress 。第二个参数是该虚拟地址的页表项地址,我们叫做 
      PteAddress 。MiCopyOnWrite 使用 fastcall 调用协议,第一个参数 BadAddress 通过 ecx 
      寄存器传入,第二个参数 PteAddress 通过 edx 寄存器传入。只要向 CopyOnWrite 页写入数据,我们就应该可以断到 
      MiCopyOnWrite ,并且从 ecx 和 edx 当中看到 引发异常的指令访问的虚拟地址 和 该地址的 PTE 地址。<BR><BR>我们在 
      SoftICE 中下这样的断点<BR>BPX 8044BE22 DO "db ((ffdff124-&gt;0)+44)-&gt;0+1fc l 
      10 ; dd ecx l 4 ; dd edx l 4"&nbsp;<BR>其中,8044BE22 是 MiCopyOnWrite 的入口地址( 
      Win2k Build 2195 ),通过使用 kd , u MiCopyOnWrite 获得。断到之后,让 SoftICE 执行 db 
      ((ffdff124-&gt;0)+44)-&gt;0+1fc l 10 ,这将显示当前运行的进程名。然后再显示出 ecx 和 edx 
      中的内容。<BR><BR>当我们运行一个程序时,这里我运行了一记事本程序,SoftICE 窗口立刻弹出,说明有 Copy On Write 
      发生。<BR><BR>// 这就是下的断点。<BR>:bl<BR>00) * BPX #0008:8044BE22 DO "db 
      ((ffdff124-&gt;0)+44)-&gt;0+1fc l 10 ; dd ecx l 4 ; d<BR>:be 0<BR>// 退出 
      SoftICE 窗口<BR><BR>// 打开一个文本文件,运行了记事本程序,SoftICE 窗口立刻弹出<BR>NTICE: Load32 
      START=1000000 SIZE=10000 KPEB=80D5AD40 MOD=NOTEPAD<BR>NTICE: Load32 
      START=77F80000 SIZE=79000 KPEB=80D5AD40 MOD=ntdll<BR>Break due to BPX 
      #0008:8044BE22 DO "db ((ffdff124-&gt;0)+44)-&gt;0+1fc l 10 ; dd ecx<BR>l 4 
      ; dd edx l 4" (ET=4.09 seconds)<BR>// 可以看到当前进程是 
      NOTEPAD.EXE<BR>0023:80D5AF3C 4E 4F 54 45 50 41 44 2E-45 58 45 00 00 00 00 
      00 NOTEPAD.EXE.....<BR>// ecx 也就是 BadAddress 为 
      77FCD34C&nbsp;<BR>0023:77FCD34C FFFFFFFF 00000000 00000000 00000000 
      ................<BR>// edx 也就是 PteAddress 为 C01DFF34 ,可以看到页表项中标志位的 
      CopyOnWrite位 被设置,Write位 没// 有被设置<BR>0023:C01DFF34 006AA225 00000000 
      00000000 00000000 %.j.............<BR><BR>// 只有 NOTEPAD 和 ntdll 
      ,BadAddress= 77FCD34C 在 ntdll .data 范围内。<BR>// 只有 NOTEPAD 和 ntdll 说明了其他的 
      dll 还没有被载入,也就是说在 ntdll 被载入,执行 DllMain 中// 对 ntdll 初始化时,就向使用了 CopyOnWrite 
      的数据页中写入数据,这将导致数据页的页表项中的物理页// 为新分配的物理页,并且标志将从 ReadOnly CopyOnWrite 变成 
      ReadWrite。<BR>:map32 -u<BR>Owner Obj Name Obj# Address Size 
      Type<BR>NOTEPAD .text 0001 001B:01001000 000065CA CODE RO<BR>NOTEPAD .data 
      0002 0023:01008000 00001944 IDATA RW<BR>NOTEPAD .rsrc 0003 0023:0100A000 
      00005238 IDATA RO<BR>ntdll .text 0001 001B:77F81000 00042492 CODE 
      RO<BR>ntdll ECODE 0002 001B:77FC4000 00004371 CODE RO<BR>ntdll PAGE 0003 
      001B:77FC9000 00003983 CODE RO<BR>ntdll .data 0004 0023:77FCD000 00002350 
      IDATA RW<BR>ntdll .rsrc 0005 0023:77FD0000 00026D08 IDATA RO<BR>ntdll 
      .reloc 0006 0023:77FF7000 00001DA8 IDATA RO<BR><BR>// Ctrl+D , SoftICE 
      立刻(322ms后)又被中断,ET=322.23 microseconds<BR>Break due to BPX #0008:8044BE22 
      DO "db ((ffdff124-&gt;0)+44)-&gt;0+1fc l 10 ; dd ecx<BR>l 4 ; dd edx l 4" 
      (ET=322.23 microseconds)<BR>0023:80D5AF3C 4E 4F 54 45 50 41 44 2E-45 58 45 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -