企业网站维护合同,网站更新步骤,巩义网站优化公司,天津建设工程信息网网页版关于准备
我们在之前的学习中#xff0c;已经学习了相当一部分有关段的知识#xff0c;CPU提供了段的机制来给我们的内存进行保护#xff0c;但实际上我们在x86下的段base是0#xff0c;实际上并没有偏移
两种分页模式
我们有两种分页模式#xff0c;29912分页和101012…关于准备
我们在之前的学习中已经学习了相当一部分有关段的知识CPU提供了段的机制来给我们的内存进行保护但实际上我们在x86下的段base是0实际上并没有偏移
两种分页模式
我们有两种分页模式29912分页和101012分页这里先不细说先给自己的实验环境设置成为相对简单的101012分页
win7 32位机子管理员权限输入以下命令
bcdedit /copy {current} /d debug-101012//自己起个名字bcdedit /displayorder {} /addlast//大括号里面是自己的标识符在输入上一个命令后就会出现bcdedit /dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200bcdedit /bootdebug {} ONbcdedit /debug {} ONbcdedit /timeout 30然后重启电脑之后继续打开管理员权限输入以下命令之后再重启
bcdedit /set /pae ForceDisable //先把pae关了bcdedit /set nx AlwaysOff //再关nx
最后的效果在windbg中用!process 0 0指令检验如果DirBase结尾都是000那么就成功了 基础知识
我们之前提到了在段的视角下CPU如何访问的数据那么现在我们进入到了页的这个过程来看
比如当我们执行mov eax ds:[0x12345678]的时候首先查询缓存和TLB里面有没有之前的记录如果有直接返回到CPU如果没有则进入MMU中进行处理
MMU
CPU为了方便管理物理内存在实际中是按照页的方式进行管理内存的对于32位来说它分别有10-10-12分页和2-9-9-12分页我们在上面已经配置好了10-10-12的分页环境。
我们都知道在所有进程的视角里面其占有了整个进程也就是在win7中每个进程都有4GB的虚拟地址空间。
它们并不是真正的地址而是一个索引通过转换来指向真正的的物理地址而这样的转换就是通过MMU来达成的它会解析我们送给CPU的地址
这里先介绍一个寄存器CR3寄存器
CR3寄存器
每个进程都会有自己的物理起始地址我们称之为DirBase。通过CR3去查询页目录表再查询页表最后查询到具体的物理页而这个DirBase就被存储在CR3中 1: kd !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 9f979d08 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000DirBase: 00185000//在这里 ObjectTable: a6401bb8 HandleCount: 452.Image: System首先每个进程都有一个CR3寄存器我们先暂时不需要知道太复杂只要记住这个寄存器里面存了我们进程真正的物理地址的起点因为它指向了我们进程的页目录表
对于我们马上要研究的10-10-12分页来说虚拟地址是有具体的含义的 这里再次借用羽夏 大佬的图
前10个位指的是PDE页目录表号中间是PTE页表号大小都是4个字节这里我们要和PDT页目录表和PTT页表作一个区分
实践一下
学到这里的理论知识已经足够我们实践来在我们已经设置好的Win7中来验证一下我们寻址的理论
首先打开一个记事本随便输入一个字符串然后用CE的字符串搜索来找到我们的这个字符串 可以看见现在是有四个结果但是这肯定是不对的所以我们略微改下字符串Next Scan一下 这时候只有两个结果了我们就以第一个0x0045e8b0为例
我们按照10-10-12的分页方式来看这个地址 我们就知道了PDE是1PTE是5e页内偏移为8B0
用windbg来找
0: kd !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 86cdd8e8 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000DirBase: 00185000 ObjectTable: 8ec01b28 HandleCount: 492.Image: System
..........................................
PROCESS 86e62d40 SessionId: 1 Cid: 0848 Peb: 7ffdc000 ParentCid: 062cDirBase: 8dbaf000 ObjectTable: b5b6bb88 HandleCount: 63.Image: notepad.exePROCESS 887ea898 SessionId: 1 Cid: 0ec4 Peb: 7ffd6000 ParentCid: 0374DirBase: 1dbb1000 ObjectTable: b5bf53f8 HandleCount: 185.Image: cheatengine-i386.exe0: kd !dd 8dbaf0001*4//这里按照4字节偏移来找
#8dbaf004 97e76867 8f1f2867 97f67867 00000000
#8dbaf014 00000000 94b48867 9474a867 00000000
#8dbaf024 00000000 00000000 00000000 00000000
#8dbaf034 00000000 00000000 00000000 00000000
#8dbaf044 00000000 00000000 00000000 00000000
#8dbaf054 00000000 00000000 00000000 00000000
#8dbaf064 00000000 00000000 00000000 00000000
#8dbaf074 00000000 00000000 00000000 00000000
0: kd !dd 97e76000 4*5E//还是4字节
#97e76178 96156867 9a558847 99857847 9995b847
#97e76188 9695a847 95970847 8f671847 93a77847
#97e76198 98576847 00000000 00000000 00000000
#97e761a8 00000000 00000000 00000000 00000000
#97e761b8 00000000 00000000 00000000 00000000
#97e761c8 00000000 00000000 00000000 00000000
#97e761d8 00000000 00000000 00000000 00000000
#97e761e8 00000000 00000000 00000000 00000000
0: kd !dd 96156000 8B0//这里已经找到了我们要的内容
#961568b0 00680054 00200065 006c0070 00630061
#961568c0 00200065 00680077 00720065 00200065
#961568d0 00650077 00620020 00670065 006e0069
#961568e0 00000000 00000000 00000000 00000000
#961568f0 00000000 00000000 00000000 00000000
#96156900 00000000 00a90004 4151296f 000003f9
#96156910 004600a0 0045a158 0045e598 0045e5d8
#96156920 0045e618 0045e658 5550297a 080003f1
0: kd !du 961568b0//把这里地址所反汇编一下
#961568b0 The place where PDE和PTE
在具体操作过这两个结构之后我们来继续学习理论知识 在上面搜索字符串的例子中有一个细节我使用PDE来寻址的时候去掉了低12位这个细节现在由上图得到了回答——前12位是属性位用来描述结构的属性
P位
P位决定了当前结构是否有效这和我们在之前学习段的知识时是一样的
R/W位
0为可读1为可写
U/S位
User和super为1时可以被R3访问为0时只能被R0访问这也是我们R3时无法访问到一些内存的原因
回答一个之前的问题
我们在之前的学习中提到了如果是被声明/被分配的内存必须要主动置零再使用这里我们可以用一次实践来给出为什么要这么做的原因了
// Page Alloc.cpp : 定义控制台应用程序的入口点。
//#include stdafx.h
#includeWindows.hint _tmain(int argc, _TCHAR* argv[])
{PVOID Base VirtualAlloc(NULL,0x2000,MEM_COMMIT,PAGE_READWRITE);printf(%x\r\n,Base);system(pause);memset(Base,0,0x200);system(pause);return 0;
}我们运行这段代码首先知道基址 根据之前学习的知识PDE为0PTE为D页内偏移还是0 我们这时候用windbg去找到我们的进程找到相关的页结果却发现没有挂上页
0: kd !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 86cdd8e8 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000DirBase: 00185000 ObjectTable: 8ec01b28 HandleCount: 513.Image: System
.......................................................
PROCESS 873e9d40 SessionId: 1 Cid: 0fb4 Peb: 7ffdb000 ParentCid: 02b8DirBase: 47e8a000 ObjectTable: b9742ec0 HandleCount: 24.Image: Page Alloc.exePROCESS 873b7d40 SessionId: 1 Cid: 0fe4 Peb: 7ffdf000 ParentCid: 01a8DirBase: 228c3000 ObjectTable: b5cc7a28 HandleCount: 62.Image: conhost.exePROCESS 87733d40 SessionId: 1 Cid: 0cd4 Peb: 7ffdd000 ParentCid: 0fb4DirBase: 83e68000 ObjectTable: b99319f8 HandleCount: 30.Image: cmd.exe0: kd !dd 47e8a000
#47e8a000 53e16867 17d4d867 33365867 00000000
#47e8a010 00000000 00000000 00000000 00000000
#47e8a020 00000000 00000000 00000000 00000000
#47e8a030 00000000 00000000 00000000 00000000
#47e8a040 00000000 00000000 00000000 00000000
#47e8a050 00000000 00000000 00000000 00000000
#47e8a060 00000000 00000000 00000000 00000000
#47e8a070 00000000 00000000 00000000 00000000
0: kd !dd 53e16000d0*4//我们发现这里没有被挂上页也就是没有办法被直接使用
#53e16340 00000000 00000000 00000000 00000000
#53e16350 00000000 00000000 00000000 00000000
#53e16360 00000000 00000000 00000000 00000000
#53e16370 00000000 00000000 00000000 00000000
#53e16380 00000000 00000000 00000000 00000000
#53e16390 00000000 00000000 00000000 00000000
#53e163a0 00000000 00000000 00000000 00000000
#53e163b0 00000000 00000000 00000000 00000000
这时候我们继续运行程序用memset向内存中写入值再用Windbg来看值
1: kd !dd 53e16000d0*4//这时候我们的页就被成功分配了
#53e16340 1486e867 00000000 00000000 00000000
#53e16350 00000000 00000000 00000000 00000000
#53e16360 00000000 00000000 00000000 00000000
#53e16370 00000000 00000000 00000000 00000000
#53e16380 00000000 00000000 00000000 00000000
#53e16390 00000000 00000000 00000000 00000000
#53e163a0 00000000 00000000 00000000 00000000
#53e163b0 00000000 00000000 00000000 00000000所以我们知道在WIn系统中当我们申请一块内存时系统并不会会给我们真的直接挂上页它必须要在我们真正使用了这块内存之后才会真正的挂页。
我们之前提到过操作系统里面的进程每个都认为自己占了整个内存如果我们真的申请一块内存就分配一块内存那么每个程序你申请一块我申请一块我们的内存根本就不够用
我们C盘里面有一个隐藏的文件pagefile.sys正是为了解决这种情况而出现的这里面就存了一些暂时没有使用的内存比如申请了一块内存但是一段时间没有用其他的程序同时页申请了同一块内存所以就会暂时储存起来 我们还可以知道一个新的知识那就是VirtualAlloc里面MEM_COMMIT属性这个属性的意思就是当我们使用这块内存的时候为我们挂上页如果我们没有设置COMMIT那么使用了之后也不会挂上页