Windows驱动开发(12)——驱动附加进程读写内存
绕过句柄权限过滤的内存保护
句柄权限过滤在之前学的常规进程保护种,在驱动层是通过注册打开进程句柄的回调,通过过滤一些权限的方式防止其它进程对指定进程进行跨进程的一些操作,包括进程读写等等。
绕过思路它可以相当于是对用户层的 OpenProcess 这个 API 作了拦截,那么我们绕过的思路自然也很清楚,那肯定不能通过这个 API 再去获取句柄了,而是可以直接使用驱动附加进程,然后通过 R0 和 R3 通信的方式去读取内存,这里我们做一个简单的小测试,目前代码已经上传至 Github,供大家学习使用。这个里一共包含四个项目,分别对应了游戏程序,外挂程序,游戏驱动和外挂驱动。
这里有一个测试的小技巧,如果觉得每次测试驱动都要安装卸载麻烦,可以把加载驱动写在窗体初始化的时候,把卸载卸载窗体对象析构的时候。
在保护指定进程的时候,通过注册回调的方式过滤句柄权限,用的还是之前的代码:
123456789101112131415161718192021222324OB_PREOP_CALLBACK_STATUS MyProtect( PVOID RegistrationContext, ...
概率论(1)
常见的变量分布
随便记了,不是很想管格式。
主要记住一下常见的随机分布的函数和密度函数。
随机变量随机变量可以分为两种类型:离散随机变量和连续随机变量。
离散随机变量:离散随机变量的取值是可数的,通常表示为整数。它们描述了在离散事件中可能发生的不同结果,例如掷硬币的结果(正面或反面),骰子的点数(1、2、3、4、5或6)等。离散随机变量的概率分布由概率质量函数(Probability Mass Function,PMF)描述。
连续随机变量:连续随机变量的取值是连续的,可以是实数范围内的任意值。它们描述了在连续事件中可能发生的结果,例如测量温度、身高、时间等。连续随机变量的概率分布由概率密度函数(Probability Density Function,PDF)描述。
概率分布函数一般是这个函数是计算随机变量 < 某个值的概率。
不难看出,当变量趋于负无穷的时候,概率的极限为 0,概率趋于 1 的时候,概率的极限为 1。
对于连续的随机变量来说,变量取某个值的概率为 0。很经典的一个例子就是,在数轴 0 - 1 的位置上随机取一个实数,取得 0.5 的概率是多少,0-1上 ...
Windows驱动开发(11)——驱动内存属性读写
在R0层中Hook函数
R0层内存属性修改同样的R0层的内存也有读写保护,如果写了不可写的内存或者读了不可读的内存,此时会直接触发蓝屏。这里也是搜集到了一些修改 R0 层内存属性的方法,可以使用以下代码来修改内存属性:
123456789101112131415161718KIRQL WPOFFx64(){ KIRQL irql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); cr0 &= 0xfffffffffffeffff; __writecr0(cr0); _disable(); return irql;}void WPONx64(KIRQL irql){ UINT64 cr0 = __readcr0(); cr0 |= 0x10000; _enable(); __writecr0(cr0); KeLowerIrql(irql);}
WPOFFx64函数可以关闭内存写保护,使我们可以写任何一块区域的内存, ...
数据结构复习(4)
第四章——串
字符串存储一般有定长空间分配法,不定长分配两种方式。
后者以 \0 字符来作为字符串结尾,前者需要再存储一个字符串长度,超出长度之外的字符是无效的。
串的模式匹配算法假设主串长度为 n,模式串长度为 m。
暴力匹配即对于每一个可能出现模式串的位置(n)对模式串进行匹配判断(m),时间复杂度显而易见的是 O(mn)。
KMP算法会构建一个 Next 数组,在匹配的时候,每一次失配,我们都让模式串指针跳转到 next[j] 的位置上去,主串位置不变。
构建Next数组的方法:
12345678910111213for(int i=1;i<n;i++){ int t=next[i]; while(t!=1&&s[i]!=s[t]){ t=next[t]; } if(s[t]==s[i]){ next[i+1]=t+1; } else{ next[i+1]=1; }}next[1]=0;
匹 ...
《被讨厌的勇气》读后感
很多人推这本书,看了之后感觉挺不错的,特此写读后感。
第一章我们的不幸是谁造成的?其实是自己。很多时候并不是因为曾经怎么怎么样,或者说现在怎么怎么样我们无法改变命运带来的结果,其实很多时候我们是可以改变的,只不过我们不愿意改变。
这里使用了乍一听非常难以接受的理论——目的论,我们的不幸是因为我们选择了不幸,阿德勒心理学主张人是可以改变的,你可以选择,但是没有足够的勇气!因为你知道你一旦做出改变,你可能要面对很多未知的问题,或者可能是要接受失败的结果,所以你选择了不成功。并因为你选择了不成功,你选择放大自己的缺点并会解释,如果自己没有这些缺点就好了。那只是你不愿意做出改变罢了,没有这样的勇气。
书中举了一个例子来佐证你以为的原因论,实际是目的驱使的:
家长在训斥自己的孩子的时候发怒,一般理解就是是因为女儿成绩不理想,所以家长才那么生气,家长的怒气完全是因为女儿的这个问题。如果说此时是因为家长想发怒而制造出来怒气可能有点诡辩论了,但是实际上在这个情景下,如果家长接到女儿班主任的电话,父母马上就会和颜悦色地去跟老师沟通,完全没有了之前的愤怒情绪。这里想要证明的一个观点是:愤怒是一种手段 ...
数据结构复习(3)
第三章——线性数据结构
栈身为 ACMer,其它基本也不用花太多时间记,只需要记一些没有见过的概念就差不多了。基本特性就是先进后出,常见应用就是函数调用,深度优先搜索(迷宫算法),递归函数,括号匹配,表达式扫描。
卡特兰数n 个不同的元素入栈,得到不同出栈结果的个数。
结论:$\frac{1}{n+1}C_{2n}^n$
共享栈指两个栈共用一个大数组,其中一个栈顺序增长,另一个栈反方向增长,更大程度避免上溢出,两个栈顶重叠的时候,栈满。
队列只允许从一端插入,另一端删除,先进先出。
有两种情况需要细致考虑:一个是头指针指向队尾元素,一个是头指针指向队尾的后一个位置,这两个情况略微有差别,此时队列判空判满的条件也有差别。
队头一般使用 head 或者 front,队尾一般使用 tail 或者 rear 变量。为了防止假溢出,出现了循环队列,但是要注意,循环队列需要牺牲一个单元,否则无法判断队满或者队空,因为它们的指针指向一模一样。
双端队列开放了其中一端插入或者删除,或者都开放。
做这个题目的时候,一般会出现输入限制或者输出限制的双端队列,然后问你,哪项出队顺序不符合或者符合。其实很 ...
数据结构复习(2)
线性表章节。
线性表的定义和操作线性表的定义线性表是具有相同数据类型的 n 个数据元素的有限序列。
线性表是逻辑结构,表示了元素之间一对一的相邻关系。而顺序表(顺序存取表)和链表(链式存储表)是指存储结构。
线性表具有先后顺序。
线性表每个元素具有相同大小的存储空间。
线性表的操作有以下操作:
初始化分配内存空间。
求表长。
按值查找。
读取某个元素。
插入操作。
删除操作
顺序输出所有元素。
判断元素个数是否为 0。
销毁线性表。
线性表的顺序实现概念顺序表是指,逻辑上相邻的数据元素在物理地址上也相邻。
结论就是:
随机存取方便,插入删除困难,顺序表是一种随机存取的数据结构。
例题遇到的概念没什么好说的,连续多次删除元素的话不一定要重复 k 次的移动,可以一次移动完。具体算法思路是这样的:
定义一个下表 index=0 和循环变量 i=0。
循环遍历:
如果该元素要被删除,则不作任何操作。
如果该元素不会被删除,把它存入下标为 index 的数组,并使得 index++。
结束循环
最后让长度 = index 即可。
或者用下面的思路:
...
计算机网络复习(1)
计算机网络体系结构
计算机网络概述这一章比较多的是概念,记一下主要的就好了。
计算机网络的概念将分散的,具有独立功能的计算机系统,通过通信设备与线路连接起来,由功能完善的软件实现资源共享和信息传递的系统。计算机网络就是一些互联的、自治的计算机系统的集合。
广义观点只要能实现远程信息处理的系统,或者资源共享就是计算机网络。
资源共享观点跟开头差不多,包含三层涵义:
目的——资源共享
组成单元——分布在不同地理位置的多台独立的自治计算机
计算机必须遵守的统一规则——网络协议
计算机网络的组成组成部分上来看完整的计算机网络上包括硬件、软件、协议三大部分组成。
硬件主要由端系统,链路,交换设备,网卡等组成。
软件主要由一些应用程序实现。
协议是计算机网络的核心。
工作方式上来看计算机网络可分为边缘网络和核心网络。
从功能上来看计算机网络由通信子网和资源子网组成。
计算机网络的功能
数据通信:最基本最重要的功能
资源共享
分布式处理
提高可靠性
负载均衡
计算机网络的分类分布范围分类
广域网
城域网
局域网
个域网
按传输分类
广播式网络
点对点网络
按拓扑结构分类
总线型
星 ...
高等数学复习(8)
高等数学复习(8)——一元积分学概念
概念原函数存在定理:
当函数 $f(x)$ 在任意一点上都具有 $\int f(x)=F(x)+C$ ,则称 $F(x)$ 是 $f(x)$ 的一个原函数。
只有含有有界震荡间断点的函数具有原函数,其余情况没有原函数。
定积分概念:
即是黎曼积分的定义 $\int a ^b f(x)dx=\sum^{n}{i=1}\lim\limits _{n\to \infty} f(a+\frac{b-a}{n}i)\frac{b-a}{n}$
特别的,当 a=0,b=1 的时候,式子退化成 $\int 0 ^1 f(x)dx=\sum^{n}{i=1}\lim\limits _{n\to \infty} f(\frac{i}{n})\frac{1}{n}$
所以做数列极限题的时候,可以尝试化成这样的式子,转而求定积分。
定积分存在定理:
$f(x)$ 在 $[a,b]$ 上连续,则 $\int _a ^b f(x)dx$ 存在。
$f(x)$ 在 $[a,b]$ 上单调,则 $ ...
Windows驱动开发(10)——内核保护进程
在内核中保护特定进程
本来想着掌握一种方法差不多就够了,后面想想还是一步一步走过来吧。
获取进程名在回调中,每有一个进程相关事件,就会触发这个回调。一般我们很多跨进程的操作第一步都是 OpenProcess 去获得进程句柄,后续操作都通过句柄操作。在回调函数中我们可以使用 OperationInformation->Object 这个对象拿到当前被操作进程的结构体指针。
这样子我们获得了一个 EProcess 的指针,可以用这个所指向的结构来取得进程名,通过访问使用API PsGetProcessImageFileName 来获得进程名。
最后我们使用 _stricmp((char *)processName, "msedge.exe") 进行一波判断即可。
通过进程ID保护进程同样,还有一个 API 是 PsGetCurrentProcessId 用来获取当前进程的 pid 的,同样我们可以使用这个 API 来和预期的进程 id 进行比较,相同就保护起来,因为我们很可能不确定要保护的进程 ID 是多少,因此不能再 sys 中写死,我们可能需要实现一些驱动 ...