00:01
咱们今天讲的东西比较简单啊,不是下一个是那个anti ru k,就是那个p hunter,咱们照着p hunter简单实现一下,功能可能没人家多,但也差不了太多,那个我给你找一个啊,这个嗯,我per搁哪了,我找一下。找不见了,回头再说吧。啊,你也可以理解为火龙剑这种东西啊,也也行,也差,其实功能也差不多。但火龙剑这这玩意儿,它界面做的比较好看啊,这个比较难写。啊,你可以理解为这种东西啊。比如说他这里边的种这种进程啊,当然咱们进程数肯定没没人家画的好看啊,咱们就是按照P的那种那个MFC风格来写啊,像他这种就比较难搞啊,但是这火龙剑其实也不太行,这这火龙剑的UI动不动就死。有时候你看啊,动不动就出来啊,所以说其实也也也很离奇。
01:06
妈的,覆盖了还结束不了,就很很很暴躁。诶。哎。什么狗东西,我操。哎哟,我操,又死了。啊,烦烦烦烦烦。我不太爱用火龙剑,就有这个原因在内,就这个东西,动不动它就自己亮。你碰他一下,他就死。行了,没了死了啊,咱们今儿讲一下这个内存相关的一些东西啊。
02:05
你这东西它版本越高越难用,它因为因为兼容性的问题,你在WIN11上它这个玩意儿都跑不起来。嗯,今儿今儿呢,首先呢是这个讲一下,这个讲一下什么来着啊对,讲一下基础的一些内存相关的一些东西啊呃,然后今天呢,主要是三环的一些API的讲解,然后呢,明天开始讲原理,那咱们就把所有的这个常用API都捋一遍啊,就是告诉大家一下大概都怎么用,然后呢,以后在编程的时候咱们肯定也会用到,首先呢,咱们了解一下怎么来这个获取一下这个系统信息啊,这个其实非常简单一个啊,首先你需要包含windows.h这个PAPI呢,是因为一会儿要获取内存信息的时候要用到这个,这个API呢,是和这个进程相关啊,然后我们首先呢来这个写一下啊,就是get什么呢?Get system。
03:08
Get some info啊,我们用这么一个API来获取一下信度信息啊,你其实看它名字你就应该知道啊,它就是用来这个获取系统信息的,呃,然后呢,这个。我们可以看到啊,它里边呢,参数呢,就是什么呢?就是一个叫做这s INF的一个呃,结构的一个指针啊,这个RP你们懂的啊,LP代表其实它是一个指针的意思啊,也就是说呢,我们一会声明完这个system in这个结构的时候呢,我们需要呢,给它这个传递址进来,并且呢,你可以看到它前面的修饰呢,是一个out,也就是说什么呢,也就是说呢,我们这个是传出的啊,也就是我们给的一个空结构就行,那么我首先呢,来看一下这个结构啊,结构呢,大概就是长成这个样子。然后呢,这里边呢,我们主要呢,要了解一下呢,是与我们内存相关的几个成员啊,其他的成员呢,就跟我们啊关系不大了,是系统的一些其他信息,那比如说我们比较关注的成员呢,就有这个,那这个玩意呢,是什么东西,你可以看到啊DW啊,然后size啥意思呢?页啊页大小啊,这个东西呢,就是你当前的这个CPU默认页面的一个大小,那这个默认页面大小呢,咱们其实以前也学过这个页的一个概念啊,大家记不记得我也不知道啊,但这儿呢,给大家来说一下,在我们这个叉八六和叉八六-六四的这个主机里的我们页的大小呢,通常情况下呢,就是4096啊,4096通常情况下啊,但是它也区分大叶小叶嘛,那么我们这就是以这个4096页为例为例啊,然后呢,我们还有一种主机叫I64啊,这种主机里呢,它的页比较大啊,是我们这个X86X64这种的,这个主机的叶的两倍大小就是什么呢?就是8192啊,那我们通常情况下呢,在我们这种系统下。
04:53
啊,就是X6或者这个X6-零四的啊,一般情况下就是40961,然后呢,下边这个东西,这个东西呢,你就是进程里最小的可用的内存地址,那我们也知道啊,就是内存这个东西啊,我们有一个这个虚拟内存这么一个概念,咱们以前也说过啊,在讲很早期的时候啊,可能在讲C语还是汇编的时候,我就忘了啊,就那时候就说过虚拟虚拟内存这个概念对不对,然后呢,虚拟内存我们每个进程有一个自己的一个内存,然后呢,我们这个内存里头还有一部分呢,是用来管理内存的,那么我们啊用户呢,能用的这个可用空间呢,还是要去除掉我们的内核的这一部分内存空间,也就是这就有一扣除中间那一部分啊,因为最小的那一部那一部分内存地址是被占用的,然后高内存呢,是被这个内核占用的,也就是说呢,从呃大概这个6536或者0X10010X1000这种地址看超级统嘛,然后这种地址上开始的这个内存地址,这种你用户层可用的内存地址中最小的那个。
05:53
那一存地址就由它来显示的,然后最大的那个可用的呢,就用它来显示啊,这个就是他们的一个这个作用,然后呢,这底下呢,还有一个这个这东西啊,这个东西呢,是一个这个分配力度,通常情况下呢,这个东西呢,就是6536啊,这个东西很少变化啊,我们现在呢,了解完它基本的一个这个情况之后呢,我们把它这个拿过来啊,拿过来声明一下它这个结构,那我们首先呢,还是给它清清空一下它的结构啊,给它都制个零,制完零之后呢,我们接下来呢,把它的地址啊给传入我们的这个API内啊,然后我们直接进行一个获取,获取完之后呢,我们就不输出了啊,因为比较麻烦啊,我们还要挨个去指它,那我们现在呢,就直接运行,运行完之后呢,我们从这个监控里来看一下它每一个这个成员的一个情况啊,我们拿走过来之后,你可以看到啊,它里边现在呢,就是已经有值了,我们来监视里边啊,把它脱下来啊,来啊这个RP system info,然后呢,你打开一看,那我们刚才讲解的啊,你看它这。
06:53
小的是多少呢?最小的可进程可用地址就是什么呢?就是0X1万啊,这个呢,就是我们最小的可用地址,最大的呢是7FE啊,这个是我们进程可用的啊,最大的啊这个内存,然后呢,你看看啊,这个分配力度6536啊,这个是一般情况下默认的啊,没什么好说的,那这个呢,基本上就是我们获取一下我们的这个呃,系统信息的时候,能拿到的你内存相关的一些信息,然后呢,除了这个东西能拿到内存信息之外呢,我们还有其他的API啊,那比如说我们还可以有什么,还有一个叫做这个呃。
07:31
MY,嗯嗯,Memory啊,我们要我们用ex啊呃,它这个有两个版本的这个函数啊,一个是带ex的,一个是不带ex的,呃,它不带ex的那个版本的函数呢,它要用在什么呢?用在你的系统内存小于4GB的情况下啊,也就是当初叉P之前的那种那个呃32位这个32位系统啊,所以说呢,现在呢,咱们通常情况下啊,不推荐使用了啊,咱们就用ex版,Ex版的可以支持64位以上,不是64位上去的那个4GB以上的啊,然后呢,我们来看一下它的这个参数啊,你可以看到也就是一个这个memory的一个这个信息的这么一个结构啊,然后我们跟进去啊,看有这么多成员,这里头这个比较特殊的是什么呢?它这有一个这个长度,这个成员长度,这个成员呢,是需要你在这个呃,使用它传传进去之前啊,你要把它这个成员给初始化了,那初始化成什么呢?就是这个结构的大小,你塞塞off一下啊,然后给它传进去就行了。
08:32
然后这个呢,就呃就这样啊,那其他的就是他给你传出的这个信息啊,那比如说第一个第一个呢,这个呢是一个这个整数啊,这个整数呢,是介于这个零和100之间的一个数字啊,它呢是用于指定你现在正在使用的这个物理内存的一个这个百分比啊,零呢就是没有内存使用,100呢就是内存已满,那剩下的呢,就是你这个啊,当前使用的物理内存的一个百分比,但是这个呢,不是精确百分比啊,是一个大致上的啊,因为这个东西确实因为零到100之间的整数嘛,你没有办法把这个东西形容的太精确,因为你如果太精确的话,那你这个比如说一啊三啊之类的,这个没法形容啊,所以说它是一个大致百分比,然后呢,这个东西啊,这个东西呢,它是这个实际上的一个这个物理内存的一个这个内存量啊,然后呢,它以字节这个为单位,呃,这个东西呢,是这个我们当前啊可以使用的一个这个物理内存的一个,呃,内存量啊也是。
09:32
是呢,以字节为单位的,然后呢,这个东西呢,可以是什么呢?可以是这个立刻就重新使用啊,并且呢,不用把它的这个内容进行这个磁盘交换的一个这个物理内存量啊,它呢这个东西呢,是一个这个备用列表,还有这个空间列表,以及这个零列表之间的大小的一个这个总和啊这个东西,呃,然后这个东西呢,是这个系统我们当前的这个进程啊,已提交的一个内存限制啊,它也是一个这个呃,字节单位啊,然后这个是当前进程啊,然后可以提交的一个这个最大内存量啊,然后呢,是这个字节单位,这俩不要搞混,这个呢是呃已提交的啊,这个是可以提交的啊,这个是最大限度啊,这个是什么呢?这是已经使用啊,这有区别的啊,不要乱用,然后呢,这个东西呢,是这个调用这个叫什么来着,应该叫应该叫这个调用进程的一个虚拟,虚拟空间的一个这个用户模式的一个大小,就是说我们在这个去除了这个。
10:32
呃,内核模式所占用的内存之后,剩下的这个东西啊,剩下的虚拟空间有多大,就是给他的啊,然后这个啊,这个呢,是我们当前的这个进程的这个用户空间内啊,没有这个提交的啊,这个内存啊,然后呢,它也是以这个字节为单位的,最后这个东西啊,是这个保留的啊,这个东西呢,它的值始终是个零啊,你不用去理它,那么我们已经知道之后呢,我们就回到我们的这个函数上,然后呢,我们给他声明这么一个对象。
11:05
声明完之后呢,我们首先啊,还是给它进行一下初始化,初始化完之后啊,记得我刚才跟大家说了一下,它里边的长度呢,是要在使用前初始化的,所以说呢,我们要给它进行一个这个塞off,直接计算一下它结构大小啊,然后给它传进去,传进去之后呢,我们就可以把他这个成员啊,然后呢,取个地址给他传进去,这样呢,我们就可以来这个获取了,然后我们在这儿下断点,我们运行。F10,然后呢,它就值了啊,我们拿下来啊,现在你可以看到啊,它里边就有这个填充了啊,然后呢,你就可以根据我们刚才的啊给大家解释的,他每一个成员啊都是来做什么的,然后呢,就可以啊进行一个这个显示了啊,然后这个就是这么一个东西啊,它这里边呢,全都是内存相关的啊,跟刚才系统信息里呢,还是有一点区别,因为系统信息里呢,有些东西呢,还是和这个内存无关的,那么除了这个东西之外呢,我们还有什么这个内存相关的东西吗?还有啊,这个我们不是这个,这个东西呢,你叫应该叫做获取虚拟内存的一个状态,然后呢,还有一个API是用来获取进程内存的一个状态的,那这个东西呢,是这样的啊,就是你调用一个叫做这个get啊啊memory嗯,Info啊,这么一个API啊,需要注意的是这个API你可以看到它有个红嘛,它是保它是在生明在这个PSAPI里的,所以这个玩意儿呢,你要先包含头才能使用啊,跟上面不一样。
12:37
看的呢,你要你只要使用的Windows h都可以直接使用啊,然后呢,我们跟进去啊,你可以看到它呢,实际上是一个在它这个一个DeFine的一个宏啊,它呢实际上的这个API呢,叫做这个K32PROCESS memory INF这个东西之所以是这样的,是因为它这个有不同的这个版本啊,然后这啊这俩是一样的是吧?然后呢,我们来看一下它的成员啊,在这个位置上,我们在F12一下啊,你可以看到它一共有三个成员,第一个呢是一个进程的一个句柄,第二个呢是一个结构,第三个呢是一个or的一个CB,那这个句柄呢,不用说了,你要么呢,你就调用这个credit process或者说open price来获取一下这个进程句柄,拿到一个handle啊,要么你就这个直接啊,这个get一下自己的一个这个尾句柄啊,这这种操作都是可以的,那第二个呢,就是什么呢?就是这个能获取到的一个进程的一个信息啊,一个信息啊,内存信息,第三个呢,是第二个啊,第二个结构的大小啊,然后传进第三个里边啊这个东西虽然。
13:37
CB啊,别疑惑,他是第二个成员的大小,然后呢,第二个成员呢,你可以看到啊,一共是这么多一个成员,首先第一个啊,还是CB啊,刚才说了CB是啥呀,是结构的大小啊,它是以字节为单位的么一个东西,然后这个呢,是这个你这个页的一个这个错误的一个总数啊,然后呢,嗯,我等会儿我看一下啊,谁给我发信息了是。
14:09
然后这个东西啊,这个东西呢,是我们这个运行以来啊,就是我们进程啊,启动以后啊,所使用的啊内存啊,所使用的内存啊,使用的所有内存,然后呢,这个东西呢,是我们的这个当前呢,使用的内存的一个这个数据的这个尺寸啊或者说大小。然后这个呢,是这个我们分页啊分页这个分页内存啊,或者说叫分页池啊,分页池的一个这个这个是这个是这个就是一直以来啊,就是我们进程运行以来一直使用的一个这个使用量啊,以字节为单位,然后这个呢是我们当前啊分页池的一个这个内存使用使用单位啊这个呢是这个我们啊进程启动以来,我们非分页池的一个这个使用量,这个呢是我们内存启进程启动以来,非分当前不是不是进程启动以来,这是我们当前啊非分页池的一个使用量啊,这个你可以看到,其实就是我们在内核里讲过的什么呢,分页内存非分页内存啊,然后这个东西是什么呢?这个呢是我们在这个呃内存管理器啊,这个为我们正在进运行的这个进程所提交的一个这个内存总量,最后这个东西呢,是这个,呃,我们在整个进程的一个生命周期内啊,所提交的这个,呃,内存的一个这个种。
15:29
啊啊,大概就这么一个信息啊,然后呢,我们要使用它的时候呢,我们还是啊,直接拿到它的这个结构。啊,给它初始化一下啊,初始化成零,然后呢啊给他把地址传进去,这个呢不对啊,为什么不对呢?你看啊,它有三个参数,所以说第一个呢,你还要给他加一个啊,后边呢,还要给他加一个。后边这东西呢,你就直接set off啊,然后把它的这个结构大小啊给它传进去,第一个呢,你就你要么你就open process来获取别人的,要不然呢,你就直接get这个process啊,啊不对,不是get price是这样。
16:15
啊,这样啊,调用一下函数啊,来获取一下当前的一个这个句柄啊,啊这样就行了,好,然后呢,我们在这下断点来运行一下啊。你看啊,现在呢,我们就已经啊,成功的拿到了我们当前这个进程的内存的一个使用情况啊。好,那么我们这些呢,就是这个,呃,获取内存相关的一些这个信息啊,获取内存相关的一个这个信息,好,那我们现在已经就是查询内存这部分呢,我们就已经说的差不多了啊,那这部分有没有什么问题,没问题的话呢,我们就来下一步。
17:22
行,那我们下一步啊,嗯,那我们下一步呢,就是说我们现在呢,就要来这个。使用一些这个申请内存的这个API了啊,那比如说我们呃申请程内存,我们要申请本进程内存和其他进程内存的啊,它是有区别的,那我们如果要申请本进程内存呢,它是比较单纯的啊,就是一个visual,那visual呢,它的这个参数呢,也没有多少啊,我们直接跟进去看一下,首先第一个。你要申请的进这个内存,它位于哪一个地址上,但是呢,如果说你有指定要申请的内存呢,你有指定申请的那地址呢,你可以直接申请,但是如果你没有的情况下,你想要系统啊替你这个分配啊,那就怎么样呢?你就给他第一个参数传一个now啊,就是这样就可以了,然后第二个呢,是你要申请的内存的一个大小啊,你比如说我是要申请0X121024这么一个大小的内存啊,那你就填一个数,第三个呢,就是你内存的一个这个属性啊,这个呢,我们需要来看一下MSDN。
18:34
就是这边啊,那比如说呢,它这个每一个内存呢啊,都有这个各种各样的这个属性啊,这个呢,你可以去课后自己来看一下啊,通常情况下呢,我们在申请的时候,我们传这个啊,一般是不会有什么问题的,它的作用呢,是为这个我们什么呃,保留的内存页面啊,分配这个内存啊,然后什么怎么样怎么样的啊,内存是这个零啊然后呢,这个除非啊这个实际访问,否则不会分配这个实际的物理页,就是说呢,这个啊,你使用这个whichlo给他分配的时候,它虽然分配了虚拟地址,但是没有挂物理页,当你什么时候这个。
19:14
什么时候真正的要用它了啊,那你他才会真正的去给你挂上一个页啊,啊好,那么这样我们现在了解了,那我们就先给它来放一下这个东西。然后比如说我们再给他来一个,呃,下一个啊,是你的一个保护啊,那你这个是一个什么样的保护呢?我们可以看到啊,这个参数啊,不是这个参数啊,是这个参数啊,你可以看到要分配的页面的一个内存保护啊,如果说页面正在提交,可以说提交以下任何一个这个呃保护啊,然后你可以看到它有这么多保护的量啊,但这个东西呢,实际上并不全啊,我们来看一下这个东西。嗯,点错了,我聊天呢,啊这。
20:02
啊,你可以看到啊,这个呢,是比较全的一个保护啊,上边呢是常规保护,底下这仨呢,是通常情况下跟上边配合用的,底下这仨通常是在驱动里使用的啊,你比如说这个第一个就是什么呢?就是你如果说要去读页面,写页面或者执行页面啊,只要是这种啊这种是啥意思呢?其实就是没有访问权限啊,这个页,这个页你虽然是有页的,但是没有访问权限,那么这个时候呢,它就会干嘛呢?引发违规,也就是所谓的触发异常啊第二个呢,什么呢?你看啊read only啊,就是如果说read only是什么呢?就是只读的啊,那只读的那你就不能干嘛呢?不能写,不能执行啊,如果是写了或者执行了,它就会这个违规啊,那这个是什么呢?Read就是说呢,它可读可写,但是不可执行,那你执行的时候就会触发违规,这是什么?这是可执行啊,但是呢啊,这个读写是不行的啊,只能只能执行啊,既不能读也不能写啊,如果读写了就会这个违规,那这是什么?这是可执行可读,那也就是说什么呢?有可执行,有可读,没有可写,那就是写了他就违。
21:02
对,那这是啥呢?这是啊,可执行,可读可写,那就是说什么呢?对页面进行任何操作均不会出现问题啊,那这是啥呢?这个是比较特殊的啊,就是copy这个,如果看过咱们那个内核录播的那个驱动课啊,对这个东西应该是有点这个呃概念的,就是什么呢?这就是所谓的斜拷贝,如果说啊,你在这个呃执行这个代码的时候啊,那你如果要这个去执行这个东西啊,就会干嘛呢?就会违规啊,但是写入没问题,但是写入不是直接写进去,跟上边的写是有区别的,它的写会触发一个叫做写拷贝的机制啊,就会新增一个备份,然后你写在备份里。能理解吗?这个呢,通常呢,是用于这个系统内的一些关键部位的一个保护啊。啊,底下这个啊是什么呢?这是一个执行写拷贝,然后呢,对这个页面啊,有任何操作啊都不会触发违规,但是写入的时候,它会触发一个写拷贝,如果对写拷贝这个概念不太清楚的情况下啊,我们啊建议啊建议来。
22:18
嗯,让我我让我找一下啊,我想不起来写好贝在哪儿这儿呢,看一下这一集啊。这一集是去详细讲解写拷贝这个东西啊。但是这个东西说实话,你知道这个概念就行了。然后底下这三个呢,通常情况下呢,就是在内存里啊,对你这个进行的一些操作啊,然后呢,第一个啊,就是禁止对已经这个分配的这个页面进行缓存,然后第二个呢,就是啊允许多个写啊进行组合,这样呢可以提高性能,第三个呢,这个东西啊,这个东西也比较有用啊,就是在驱动的时候啊,你页面里任何一个字节啊被写入的时候都会得到通知这个东西啊,是不是有个有种那种虾这个虾C的这个感觉哈,啊这个呢,就是在驱动里比较常见的三个这个属性,那我们回来啊,回来之后呢,我们现在已经知道这些东西之后呢,我们现在呢就要给他一个属性,那我们现在申请这个内存呢,我们也不希望他去执行代码,那我们只需要有一个读写的权限就可以了,那我们就干嘛呢?我们就直接给他这个申请一个这个read we的一个一个页啊,一个一个不是一个内存啊好,那我们现在呢,就申请好了,那申请好了之后,它的内存在哪呢?它会返回一个lp word,一个指针啊,所以说呢,你要用一个lp word来存储。
23:35
返回的一个这个缓冲区指针啊,然后现在呢,如果成功了,它的缓冲区指针就拿到了,这时候呢,你可以做一个简单的判断,判断一下它的缓冲区指针是不是等于等于闹,如果等于闹的情况下呢,就说明什么呢?就说明啊这个东西啊,就分配失败了。啊,这个时候你如果想要给他打印一下这个L扣的,或者说你就直接给他写一下,它是失败了,然后呢,来给它输出一下code,这样就可以了啊,就是get。
24:25
好,然后呢,给他停顿一下。好,那如果说我们申请成功了呢,我们就在下边啊,我们可以给他做一个测试啊,比如说我们在里边随便给他,呃,写点东西啊什么的啊,那其实我们如果不写,我们给他做一个内存清空也可以,比如说这个r tr memory呃。不是啊,不是memory啊zero memory啊,我们给它清空内存啊,那我们首先这个zero memory呢,我们第一点啊就是干嘛呢,就是给它传一个指针啊,第二点就是它的一个长度,那长度呢,我们就0X1024这样呢,正常情况下呢,它是就能够给它干嘛呢,能够给它清工程零的啊这也相当于一种写操作了,然后呢啊,这个东西如果清空完之后,我们可以干嘛呢?这个是申请,那内存这个东西我们也知道啊,有申请必有释放啊,就跟我们的这个啊new delete和这个ma克free一样啊,不是麦克free去了那啊对,是麦lo克free啊呃,然后呢,这个我们啊来看一下啊,它的这个释放的就是什么呢?就是ver,呃,Free。
25:33
啊,它的这个free呢,它参数也相对而言比较多一点啊,首先第一个啊,就是你的一个buffer啊,8ER指针你要传进去,第二个呢,是一个长度啊,这个长度很迷惑啊,这里要注意听一下啊,这个长度很迷惑啊,你可以这个理论上而言,大家看到这个长度的时候,是不是就想你申请了多长,你就给传一个多长啊,但是实际上而言,维free这个函数而言啊,如果你传了实际上的大小,它会失败,而你真正应该传的是什么呢?是零啊是零啊是这样的啊,然后呢,第三个呢,就是它的一个这个释,释放的一个类型啊,释放的一个类型啊,然后呢,给他传一个这个release就可以了啊memory release啊就释放了啊,这样呢就可以正常释放的这个这个函数,我不知道具体它的作用起到什么,但是呢,就是呃,它确实你如果你比如说我们可以尝试一下啊,我们给他传一个0X1024啊,我不。
26:33
不知道它这个意义是什么啊,但是我们确实是这个情况啊,比如说我们现在先下断点。到这儿啊,我们现在内存呢,已经出来了啊,那就干嘛呢,就是我们的内存窗口我们看一下。你可以看到这个变量现在是有值的,是零-SA4啊,然后四个零啊,现在呢,有值了,然后呢,它已经初始化成零了啊,所以说呢,其实我们就现在这个东西干的没什么意义啊,那我们可以给给他再加一句啊,再加一句啊,我们这个初始化没什么意义,我们可以给他这个zero啊,不是zero去了这个RTRTL。
27:12
不是,应该是copy memory啊这个东西。嗯,慢copy,哎,算了,不玩了,就用一个常规的吧。然后呢,他第一个啊,我们给他考一下啊,第二个啊,第二个我们给他考一个,比如说这个。123456。然后第三个是一个size啊,那size呢,我们就给个啊不对,好,然后呢,我们现在呢,运。啊,我们现在啊,现在看他现在是CC,因为我们还没有分配地址给他,现在呢,有地址了啊,我们再拖过来。
28:01
看有地址了,然后没有失败的情况下,我们清空清空,因为它原来初始化的时候,我们传的这个啊,所以说呢,它直接就是零啊,我们清空清的毫无意义,然后呢,在memory copy copy完之后,你可以看到啊,123456就拷进去了,拷进去之后啊,我们走到这个visual free这你走一步,诶你看它是不是没有任何变化。是不是没有任何变化?这个时候啊,我们再来尝试一下,我们把它换成零。前边的都一样啊,拷贝完之后我们看一下这个内存,你看现在是123456是有的,然后我们再执行F10,你看没了。释放了。所以说这个呢,是一个小细节,他很迷惑。就是因为因为这个东西,它在这个描述里啊,写的都很迷惑。
29:10
这我稍微有点卡稍等啊。这不知道咋MSDN打开特别慢。看到没有,要释放内存区域的这个大小啊,以字节为单位,但是你要注意看什么呢?看到这一句了吗?但是啊,但是正常情况下,如果说你是直接看他这种,那就是这种函数的,它这个变量名的一个这个声明,你很难接受这个东西是这样的,如果说它的这个释放类型是memory,呃,这个release啊,那就干嘛呢,它的参数就必须是零啊,必须是零啊,这个函数在释放对这个L处理的处始调用,它会这个保存一下这个区域,那如果说它是这个东西啊,如果是这个东西,那么你就可以这个传其他的玩意儿啊,它这个东西是在这个有两个这个选项的啊,有两个选项的。
30:19
呃,然后呢,我们这个东西就说完了,说完之后呢,我们还要有一个东西啊,来这个简单给大家介绍一下什么呢?就比如说我们啊,我们现在呢,就要有一个保护属性这么一个概念,大家是不是已经理解了,就这个玩意儿。大家是不是已经知道有保属性这么一个东西了?那有保属性这个东西之后呢,我们啊,就要有两个函数要介入了啊,就是什么呢?就是一个是查询,一个是修改啊,那如果说你要查询呢,你就用这个。啊,T说。用这个玩意儿啊,然后呢,我们来看一下它的参数啊,参数一共是三个,一个是这个地址,然后第二个呢,是一个你要查询的内存的一个位置啊,这个结构啊,一个结构,然后第这个是一个输出的一个信息结构,然后第三个呢,是一个这个我们的一个这个呃长度啊,那我们现在呢,首先呢,还是要声明一下这个结构。
31:27
然后呢,第一个啊是我看一下第一个什么来着,第一个是一个地址啊,那地址呢,就是我们拿到的这个lp word的一个地址,我们就传进去,然后第二个呢是什么呢?第二个呢是这个结构啊,那我们传一下这个结构的一个指针进去啊,不是指针吗?我看一下。She是指真的?哎。啊,变量同名了啊,我给他改一下啊。好了,然后第三个啊,第三个呢,是这个长度啊长度,那这个长度呢,指的是这个结构的长度,那我们要给它这个计算一个塞豆腐进去,好现在呢,我们就给它进行了一个查询啊,然后查询之后呢,结果就保存,保存在这里边,那我们现在呢,在这个位置上下一个断点我们运行。
32:24
运行之后走一步啊,然后现在呢,我们就已经拿到了它的一个内存属性啊,我们来监视里看一下。啊,就这么多属性,呃,这个能看清吗?这个属性。字是不是有点小啊?看不清属性,咱们就知道一下,现在已经获取成功了,然后呢,我带你们去这里看啊,我们带你上这儿看,这是不是看的清楚点。啊,然后呢,它这里头获取的这个属性信息呢,就包括这么多啊,那首先是什么呢?这个东西啊,你看啊是一个这个基地址,它是这个,嗯,咋说呢?呃,就是基地址嘛,就就就是起始地址的意思啊,然后这个东西呢,是这个区域的一个啊,你申请的这个区域的一个基地址,然后这个东西呢,就是你要这个查询的这块内存的一个保护属性啊,包括是不是可读可写可执行啊,就这个东西,然后这个呢,是你区域的一个大小啊,一个字节数啊,然后这个状态呢,是你页面的一个状态,这个保护呢,和这个保护不一样,这个保护是你自己的保护,这个保护是相邻页面的保护啊,然后这个呢,是你的一个页面类型啊,这个就是一个查询你当前的这么一个属性的这么一个功能,但是查询的这个东西,其实我们查了就查了,就是判断一下这个内存是不是可读可写就行了,那真正如果说你要改它怎么改呢?啊,那还有一个函数可以把它内存保护属性给改掉,那我们现在这个东西是不是以。
33:54
理论上我们这块代码执行其实是没有问题的,对不对,刚才我们整个跑下来之后可以看到啊,正常的把这个内存写进去了,然后释放了是不是。
34:07
那这里头呢,其实呢,我们可以修改一下它的这个属性,比如说我们现在呢,不是要写吗?那我们啊把这一行去掉清空没什么意义,那我们就直接让他往里拷贝,那我们现在呢,就来修改一下啊,有一个函数啊叫这个。然后呢,它的这个首先第一个参数是它的这个地址啊函数这个buffer地址,第二个呢,是你要改的这个大小,第三个呢,是你要给它设置新的保护,然后第四个呢,是你判断一下要不要把原来的保护给这个保存起来,那如果你要保存呢,你要来给它声明一个dord,一个值,然后把地址给他传进去。好,首先呢,我们第一个啊,我们先要给他传一下这个8UFF分,传完八分之后呢,我们第二个呢是长度啊0S1024,第三个呢,就是新的保护啊,那新的保护呢,我们刚才这个是可读可写,所以现在可写,那我们给它用一个这个呃,可执行可读但不可写的这个页面属性啊,我们给它传进去。
35:21
啊,这样它就不写了啊,那底下那行呢,就会触发异常,因为这个页面是不可写的了,然后呢,我们后边啊,保存一下我们原有的这个页面属性。好,现在呢,我们就改好了啊,我们来运行一下试试啊。好,修改,修改完之后异常了。看到了吗?这个异常就是因为我们把它这个内存属性给改了。那么现在呢,我们就知道了这个它这个内存属性啊,本地的这个都是怎么修改的,那比如说你现在呢,就是在底下你这个给它,呃,搞定一些东西之后,你想给它改回去,那这个时候呢,你就干嘛呢,把它这个旧的啊保存的就给它填到这儿啊,然后就改回去了,这个东西呢,基本上呢,就是我们的一个这个本地内存的一个释放,但是呢,咱们今天讲的是相对简单的一个一个API使用啊,咱们天开始会讲一些这个啊,它相关的一些这个原理性的一个东西啊,然后呢,咱们这个呢,是读取本进程的啊内存和写本进程的内存对不对啊,那我们现在呢,还要干嘛呢,还要讲的一套配套的东西,就是进程的这个读写啊,就是进程读写其实很有意思,就是把他们所有的API后都加个ex啊能知道吧,都加ex,那比如说呢,首先呢,我们要操作别人的进程,那你先上来之后,你首先要干一事,就是干嘛呢,是不是就open这个。
36:59
啊,Open process对不对,你首先要把他权限拿回来,拿句柄啊把这或者说按咱们前两节课讲的说法,你把他对象拿回来,那个对象对不对。
37:12
一个所有的一个访问权限啊,然后啊,我们传一个这个。然后呢,我们找一个好欺负的进程啊,就别找那种带保护的什么东西的。嗯,跨进程读写的话算是进程间通信,跨进程读写算进程通信,你如果硬说它是进程间通信的话,你去指你去指定一个位置,你们俩就从这写来写去,读来读去也算通信,但是它里头有个问题,其他的东西都可以等待,那你这个东西呢,只能加一个事件,然后呢,你这边写了之后,你通知一下这个事件,然后呢,另一个是另一边呢,就是写一个那个外single single的那个函数去等的,然后呢,这边呢去这个触发,然后那边一等,等完之后呢,然后呢,就是他知道啊这个一触发,那这边就写完了,写完了之后呢,他这边一读,读完之后呢,再把这个事件给设置一下,然后呢,他们俩之间就互相通信了,这样确实也算是通信,但是它有一个问题,就是你们俩怎么确定啊,同一块这个内存,这块内存还一直都没人用。
38:26
能能理解我意思吗?啊,确实可以这么干,但是有一些东西你需要解决啊,但是也不是不行,因为确实有些地方它必然没人用啊。啊,我给你找一个什么呢?我找一个notepad吧,啊,我洗一个notpad这玩意比较好欺负啊。
39:06
155360啊。15360好,然后呢,我们用一个handle啊来接他一下,好拿到它的这个权限之后呢,我们接下来呢,就要开始这个,呃,在目标的体内申请一块内存啊,那怎么申请呢,我们还是用这个微。但是我我们这回用ex版本,那么这个ex版本它的最大的区别呢,就是你它是在这个跨进程这个创建内存啊,那我们现在呢,来首先把那个你要在谁的进程内啊,来这个搞事情啊,你就把它的记柄给传进去,第二个呢,就是它的一个这个内存地址啊,内存地址跟刚才一样啊,如果你有想指定的位置,你就在这儿给他填上,如果没有你就传个到,让系统给你找个地儿分配好。第三个啊就是大小,比如说我申请个这么大的,然后呢,后边啊,就是内存的一个属性啊。
40:23
哦,嗯。好,然后呢,我们最后啊还是一个夜保护,那我们这个业保护呢,我们要还是传一个读写啊,我们也不需要它执行什么东西,对不对,那就读写就行了,然后呢,它的返回值啊,跟刚才一样,还是一个lp word啊,一个这个地址指针。啊lp buffer啊,然后呢,我们现在拿到这个指针之后,现在呢,我们就要首先啊,我们可以验证一下这个我们是不是开辟成功了啊,但其实我们用这个东西我们就可以判断,但我们就不判断了,我们直接去写一下,写完之后我们再把它读回来,那这样的话,我们用两个buffuff啊干嘛呢?一个W叉啊,一个是这个size size s8分,然后。
41:46
我们用这两个八卦来搞事情,我们用它啊写进去,然后我们用它来读回来,如果我们这个东西读回来之后,它里边能成功的读到,就说明什么,说明读成功了,也写成功了,对不对啊,所以说我们就这么做一下。
42:05
那首先呢,我们用什么呢?我们用这个啊,Memory啊,远程读写啊,这也是跨进程间的读写,呃,然后呢,我们直接看一下啊,他这几个参数,第一个参数啊,聚柄,进程句柄,那我们要去哪写,我们就把进程句柄传给他,第二个啊,它是一个这个你要去哪写的这个地址,这个呢,是我们刚才自己申请的啊,我们直接拿回来啊在这写,然后呢,你要写什么东西啊,那我们把我们要写的东西传进去,第四个呢,是你写这个东西有多大啊,这个东西呢,你就得计算一下了,它是一个宽字符的,所以说你用一个WS啊,然后来计算一下我们要传的这个呃,Buff它有多大。然后呢,计算完之后呢,你要给给它干嘛呢?你要再加一啊,然后圈起来之后再乘二啊,这个是因为WX类型一个在两只节啊。好,这样呢就比较稳啊,然后呢,最后啊,最后呢,要传一个,你实际上写了多大的这么一个这个嗯。
43:03
啊,写外边去了,实际上写了多大的这么一个,那什么啊一个这个变量啊,那现在呢,我们就来给他写一下啊,就是底or啊,然后DW啊,然后是这个。啊啊。好,然后呢,我们把它地址传进去,这样就可以了,这样就是写,那读呢,它也是一个路子啊,就是read啊,就是它需要一个size read啊price memory。第一个呢,还是啊进程句柄去哪儿读,然后第二个呢,去哪哪里这个开始读啊就是lp buffer,第三个呢,是你要读回来放在哪啊,那我们就把这个我们这个read啊给它传在这儿,然后之后呢,是多读多大啊,那我们还读这么大。然后最后啊,是一个这个这个东西啊,实际上读了多长啊,那我们传递值给它放进去好,然后这样呢,我们读完之后呢,我们啊要释放内存的情况下啊,我们还是要干嘛呢。
44:11
啊微啊free ex啊,用ex版本啊,远程释放啊,我们就可以把它释放掉啊微说free ex呢,其实跟刚才版本差不多啊,只不过什么呢?首先第一个啊,你这个还要全一个进程句柄,确定在哪个进程里释放内存,第二个呢,是你要释放的一个指针啊,然后呢,是你这个要释放的一个这个长度。后呢,还有一个这个属性啊,内性才一我们还是用个release release。哎,这个长度跟刚才那个长度,这个是不是要传零啊,我操。我记得好像是要传零,我记错了啊,等会我看一下啊,我看是不是要传零啊。
45:02
对对对,这回还是要传零啊,我刚才写错了啊。刚才下意识的好,还是要穿零啊,传完零之后,我们这个free就已经搞定了啊,但是呢,这是我们还有一个资源没有释放,就是我们打开了一个句柄啊,那这个句柄呢,我们要调用一下这个close handle啊,把它释放掉。好这样呢就完成了,那我们现在呢,就可以给他在读完之后呢,给他进行一个这个打印啊。等会儿。啊,算了,我不打印了,我直接给他下个断点在这得了。好读读完之后,我们现在呢,就来内存窗口啊,我们来看一下这个,我们读这个buffer里边有没有东西。看啊,我们已经把东西成功的读到我们read里了,Read最初是空的啊,然后经过读取之后啊,它里边已经有内容了,说明什么呢?说明它是在这个啊,写到远程进程之后,在这远程进程的这块内存里把它给拿回来的,好那这个东西呢,就是我们在啊这个跨进程之间的啊内存的一个这个操作。
46:16
好,那这波有没有什么其他问题啊,可以可以可以可以可以,你说这个没毛病,可以用的就是什么呢?就是微说啊这个protect ex啊,你看微ex带一个这个进程句柄,你就应该知道这个函数它并不简单。这个函数的使用和我们本地的是一样的,它只是多了一个进程句柄,意味着它改的是其他的进程的内存。啥玩意儿,太简单了。
47:02
对呀,远程注入就是这么个路子。这个修改属性它本来就很简单,只不过呢,这个咱们玩内核玩多了之后,你这个你就你就懂了,这个里边弯弯绕,还有很多他改的呢,只是正常情况下就是都能改。别着急,咱们后边会分析这种东西的,正常情况下大致能改的,但是呢,咱们总出其不意啊,有一些比较奇怪的现象啊。咱们学内核也都知道啊,正常情况不适不适用于咱们啊,呃,然后呢,这个东西还有没有问题,没问题的话呢,咱们再说一下今天的最后一个内容啊。
48:05
好,那今天说一下最后最后一个内容啊,但这个内容呢,可能是咱们今天最重要的内容,但是呢,也是啊最简单的一个内容,因为这个东这个内容呢,实际上咱们应该明天讲,但是今天呢,先给大家告诉一下三环的基本操作啊,明天呢会讲它在这个呃,一些原理性的东西啊,咱们还是说啊,咱们要讲原理性的东西啊,就是堆堆这个概念的呢,大家应该多多少少应该是知道的啊,首先呢,你每一个进程都有一个默认堆。能理解吧?然后呢,你如果说你这个默认堆啊,你这个觉得你有处理一些情况的时候,你需要开辟一个新的堆,你的你现在的所有的这个内存实际上都是在默认堆上这个进行开辟,那如果说你现在现在需要一个这个新的堆的情况下,怎么办呢?它我们Windows呢,也替你提供了一个这个堆分配的这么一个呃函数啊,首先呢,你就什么呢,堆嘛堆。
49:05
啊,Create create之后呢,你就干嘛呢,你要给他传一下这个参数啊,那我们来看一下它的参数是一个什么情况啊,它就一共三个参数,但实际上你要传的传的东西非常草率啊,就是它这首先第一个参数就这么三个值,这个堆分配的一个选项啊,会影响后边一些这个访问,比如说啊,这个要强是不是强制执行这个什么数据执行保护啊,要把这个对分配的所有内存啊都允许这个代码执行,还有第二个,然后是什么这个什么内存不足什么而不返回,闹第三个什么什么东西的啊,那我们正常情况下呢,我们就使用这个玩意儿就可以了。后边两个我们都穿零,但是我们还是要来看一下,它后边两个是什么,一个属性啊,我们可以看到属性什么呢?一个是这个堆的一个初始化大小,然后一个是什么呢?一个是堆的最大化大小,但是他们后边又跟了一句话,跟刚才那个free一样,就是什么呢?如果我这个参数是零啊,折开函数啊,这个提交页啊,然后呢,后边这个什么呢?如果说是这个零,则堆的大小是可以增长的,就是说你这个堆的大小是不固定的啊,所以说呢,我们实际上下,我们要真的要用的情况下呢,我们直接穿俩零就行了啊,这个呢,就是一个堆分配啊,不是堆堆穿键啊,堆穿键呢,它这个东西呢,是返回一个什么呢?一个堆聚柄。
50:24
啊,你就可以看到我们聚柄这个玩意儿在Windows里啊,是不是一个广泛应用的一个东西啊,我们堆啊,它也有堆聚柄,那我们这个堆聚柄啊,我们拿到之后我们来干什么呢?啊,刚才也说了,我们这个堆是可以自动增长的,现在我们只是创建了一个堆,但是我们这个堆上面并没有分配什么内存,那我们要如果要在这个这个堆上分配内存怎么办?ILO克啊,还是申请它的参数呢,首先第一个参数呢,就是我们堆的一个聚柄,拿到堆聚柄之后,第二个呢,就是你的这个要分配的一个内存的一个内存属性,那它这个内存属性呢,和我们微艾的属性呢,也比较像啊,但是呢也不完全接近啊,就是它的属性比较少,就这么三种,然后呢,我们呢,可以看到啊,它有什么东西,什么不使用,什么序列化访问啊,这个系统什么引发异常啊,什么函数失败啊,而不是反反返返回闹啊什么的,那我们可以使用这个,这是什么呢?这意思呢,就是分配的内存啊,会被初始化成零啊,这几个呢,你可以给它和一下啊呃或一下你就可以全都使用啊,就是这个意思,然后第三个呢,是这个不是下一个呢,是啊,对,第三个是我们要分配的一个字节数,那我们第二个呢,我们就给他传一个啊,就是传初始化成零,其他属性我们先不填了,然后要字节数呢,比如说我们给他说话一个1024好,那这个时候呢,它呢,它的返回值呢,也是一个RP word,实际上而言呢,跟我们这个微戳呃。
51:51
啊,它其实类型呢比较接近啊,就是一个方法,其实就是创建回来了,只是visual说L呢是在默认对上分配,而这个啊,你可以指定在某一个对应上分配,然后分配完之后呢,我们呢,就可以把它正常的做一个buffer来使用的啊,就跟我们常规的buffer是一样的,比如说我们可以慢copy给他拷点东西进去。
52:23
啊,我们给拷一下,拷完之后呢,我们这个内存嘛,我们用完之后,我们要释放嘛,那我们这个我们用,那你就应该知道我们堆释放也是一个东一个东西了。呃,如果在默认堆上分配,确实是就跟V是一样了,而且有API是可以直接获取到默认堆的堆聚柄的呀。没错啊,它的作用跟也没什么本质区别啊,只是给你提供了一个选项,让你可以在新创建的堆上分配内存啊。能理解这意思吗?
53:01
呃,堆就是怎么说呢,咱们明天会讲解堆原理,但现在我先给你简述一下这个堆是什么?对,就是内存啊,就是一块内存啊。只是说呢,这个堆啊,是一块儿一块儿这个不断,你可以说它是这个一块大的内存,也可以说是一块不断增长的内存,然后比如说你默认的情况下,你的进程有一个默认堆,你正常的一个进程的内存分配都是在这个堆里进行一个分配的,你这个堆是不断增长的,不断变大的,然后呢,你的所有的这个堆的一个管理啊,都在你这个堆里边,因为堆是有堆管理的,它里边有这些链表什么的,你们应该知道啊,啊你们如果不知道,咱们后边过两天这两天就讲这个原理啊,里边什么堆链表什么的,然后呢,这里边堆是有管理的,对,也是堆啊,也是堆,也是在这个默认堆理了啊,然后呢,这里边呢,有这个堆管理啊这个东西,其实呢,说堆管理就是什么呢?就是比如说你申请了一块内存,就把它挂在什么地方,然后呢,你释放了一块内存,你这块内存就已经重新可以被使用了,那根据堆的大小不同,那这块内存呢,会被挂在不同的地方上。
54:14
啊,能理解这意思吗?你的申请释放内存和不是你比如说这个什么free new delete we说和这个free这种东西都是在默认堆上操作。那我们现在这个操作是什么呢?是在你在默认堆不能满足你的情况下,创建一个新的堆,一个新的管理系统,那你现在呢,就可以把你所有的内存都申请在你新的管理系统里。能理解这个意思吗?他这个堆这个东西是有一有一系列的这个管理操作的,不是说你想象的,我这一块大内存,我分配给你完事了,我释放了,我就删了,就啥也没有了,它是里头有管理的。
55:01
啊,这个这个一定要知道啊,它不是一块,这个就是简单的这么一个操作就完事了,要不然的话,咱们后两天也没有必要再给大家讲了,分配个内存拿过来就用,分配完释放了放了就走,那没有必要讲,他肯定里头是有一系列管理函数在的。那我们这个东西了,那对应的就是什么呢?对应我们释放的时候呢,我们就把它free掉啊free掉然后的时候呢,你要要提供什么呢?提供它的这个堆的一个句柄,然后后边呢,是它的一个这个flag啊flag呢,我们就给他提供个一样的就行。然后我想想啊,第三个我们分配的对内存啊,给他,然后释放是不是这个顺序啊,第一个是句柄啊,对,第一个是聚柄啊没错。释放啊,释放完之后呢,我们在这个释放啊,注意这个是free是释放啊,为什么要强调一下是这个呢?是因为我们的这个是和艾克定义上这个对应上的,我们这个堆啊,这个艾lo克和这个free瑞都是在这个堆里边进行操作,它们的内存释放了之后,并不影响它有这个堆,能理解这个意思吗?这个堆还在,你还可以在这个堆里申请释放内存。
56:15
明白吧?那直到什么时候这个堆才没了呢?把堆销毁了?这个时候这个堆没了。你就再也不能用这个堆了。我们来下个论点看一下啊。看abcd吗?然后现在啊,它没了,没完之后销毁堆消失,看到没有。这个就是堆的基本使用啊,就包括我们创建一个堆啊,然后销毁一个堆,以及在堆里头进行内存分配。
57:03
对,默认只有一个对。没看清是吧,咱们再看一下啊,就是它这个东西,其实嗯,没什么那个特殊的啊,嗯,等会儿啊,我重新来一下啊,刚才摁快了。首先啊,我们在这个位置上我们看啊,我们这是一个创建出来一个这个在堆里边创建一个空内存嘛,你看这是一个空内存嘛,空内存之后我们走一步,你看啊,我们abcd就拷进来了吗?拷进来之后,我们现在呢,进行的时候,你可以看到啊,这个东西呢,就被掉了的时候呢,你可以看到现在呢,我们这个聚柄啊,聚柄还是有值的,还是一个C94个零的一个值堆聚柄还在,也就是说我们堆还存在着,你看里边还有什么零零什么的,这是因为我们这个堆还在,当我们下一步我们堆销毁的时候,你可以看到它里边全变成问号了,看见没有,这个堆呢,就已经已经被销毁了,然后这时候你再去看它的这个句柄,但是句柄还在。
58:02
好,那还有什么问题吗?没问题的话,今天就这样了。堆和内存都只创建不释放会怎么样啊?没没没什么用啊。无所谓啊,就泄露嘛,你跑的时间长了,内存就不够了吗?这这这东西没啥其他作用啊,你你三环的内存是很多的,你灵魂内存比较少,灵环内存你如果一直不释放,容易蓝三环的话只会卡。当你那个三环的内存就已经这个就是特别多没释放的泄露的时候,你的这个Windows系统会有一个自救,但通常通常情况下那个他自救是救不回来的啊,所以说该死还是会死。呃,写小工具不释放就不释放,对呀,爱释放不释放啊,正常情况下小工具用两下就关了,这玩意儿无所谓啊,那点内存也不影响啥呀。
59:04
但是你要有一个良好的习惯啊,你如果养成习惯了,光申请光申请内存,不释放内存,你哪天写那个驱动的时候也不释放,你不就啪就凉了。这些东西养养成良好习惯啊,这东西都最好是对应着写你,你在写好创建的时候,你就最好是想好你在哪销毁的。啊,今天就这么多内容了,还有啥问题咱们就问一问啊,没有的话今天就结束了,明天开始讲内存原理,三环的这个基本API操作就这么点。
我来说两句