要点回顾
前文提到了也目标基址,也就是说通过0xC0300000这个线性地址可以访问页目录表(PDT),有了这个地址,就可以任意修改页目录表。
但是,如果要设置某个线性地址PDE和PTE,且还要能够访问PTT,该如何访问呢?
任何一个线性地址是由PDT和PTE决定的。能访问PDT就说明能访问任意一个线性地址的PDE,但如果仅仅能访问PDE的话,还没有办法控制任意一个线性地址。
也就是说还需要访问页表(PTT),那么该怎么访问PTT呢?
如果没有一个线性地址能访问PTT的话,就没有意义,那么操作系统有没有办法访问PTT呢?一定是有的,当我们申请内存的时候,它为什么能够给我们申请的某个线性地址挂上正确的物理页呢?就说明操作系统不但能够访问PDT,也能访问PTT。只有这样,它才能为我们分配的线性地址挂上正确的PDE和PTE。
拆分PTT表
1.寻找目标程序CR3
!process 0 0
2.直接访问CR3值
可以获得页目录表(PDT):
页目录表中的每一项成员,称为PDE,也就是页目录项。
这个表中有多少个PDE呢?1024个,每一个PDE占4个字节,只不过上图中并没有全部列出,因为根本用不了那么多,真正有值的可能就前面几个。
页目录表(PDT)中的每一个成员,也就是PDE(页目录项),都指向一个PTT(页表)。
决定一个线性地址需要一个PDE和PTE,如果想修改线性地址的PDE和PTE,就必须能访问PDT和PTT。
3.查看PDE
1.查看第一个PDE(它对应第一张页表(PTT))
!dd 3e9e8000:因为后面3位是属性,所以记得修改为0后再执行命令。
得到了第一张页表(PTT)。该表有1024个成员,一共有4KB的大小,每个成员占4个字节。
2.查看第二个PDE(它对应第二张页表(PTT))
!dd 1919f000:别忘了后三位是属性,要修改为0。
得到了第二章页表(PTT)。同样的,该表中有1024个成员,一共有4KB的大小,每个成员占4个字节。
3.查看第三个PDE(它对应第三张页表(PTT))
!dd 3ef8e000:同样的,后三位修改为0,不解释。
得到第三张页表(PTT),且其中是空的。
拆分0xC0000000/0xC0001000
已经知道了如何通过一个线性地址访问页目录表(PDT),如果能通过线性地址访问PTT表的话,意味着我们能掌握一个进程的所有内存。
对于一个进程来说,它最重要的就是内存,对于它的内存来说,最重要的就是PDE和PTE。
拆分C0000000
0xC0000000 = 1100 0000 0000 0000 0000 0000 0000 0000
前十位二进制:1100 0000 00 -> 300*4 = C00
再十位二进制:00 0000 0000 -> 0*4 = 0
0000 0000 0000
1.寻找目标程序CR3
!process 0 0
2.寻找PDE
!dd 24450000+C00
3.寻找PTE
!dd 24450000 + 0,因为偏移是0,所以可以直接 !dd 24450000
4.查看物理页
!dd 3e9e8000
可以发现和找到的第一个PTT是一样的。
C0000000找到的就是第一个页表(PTT)。
拆分C0001000
可以发现线性地址:0xC0001000和线性地址:0xC0000000相差1000,也就是说这两个线性地址中间刚好相差一个页,也就是4KB。
0xC0001000 = 1100 0000 0000 0000 0001 0000 0000 0000
前十位二进制:1100 0000 00 -> 300*4 = C00
再十位二进制:00 0000 0001 -> 1*4 = 4
0000 0000 0000
1.寻找目标程序CR3
!process 0 0
2.寻找PDE
!dd 24450000+C00
3.寻找PTE
!dd 24450000+4
4.查看物理页
!dd 1919f000
C0000000对应的刚好是第一个PTT,C0001000对应的刚好是第二个PTT。
总结
- 页表被映射到了从0xC0000000到0xC03FFFFF的4MB地址空间,因为一个PTT是4KB,有1024个PTT,所以它占用的内存空间是4MB。
- 在这1024个表中有一张特殊的表:0xC0300000页目录表(PDT),它既是PDT,也是PTT,也是物理页。
- 页目录被映射到了0xC0300000开始处的4KB地址空间。
也就是说,前文中为了便于理解,先列出了一个页目录表(PDT),该表中每一个成员对应一个PTT,有1024个PTT。
但是到目前为止,可以发现根本不存在PDT这张表,它的整个表的结构变成了如下这样:
也就是该表中的0xC0300000访问PDT表,0xC0000000访问的是第一个PTT表。
有了0xC0300000和0xC0000000,可以做什么?
掌握了这两个地址,就掌握了一个进程所有的物理内存读写权限。
公式总结
- 1.什么是PDI与PTI?
PDE称为页目录表项,PTE称为页表项。PDI与PTI中的I就是index,索引。
也就是说,pdi = 页目录表索引,pti = 页表索引。
一个线性地址可以分为10-10-12,三个部分,第一个10就是PDI,第二个10就是PTI,第三个12是物理页的页内偏移。
- 2.访问某个线性地址的页目录表(PDE)的公式
0xC0300000 + PDI * 4
- 3.访问某个线性地址的页表(PTE)的公式
0xC0000000 + PDI * 4096 + PTI *4