3.2 Windows驱动开发:内核CR3切换读写内存
CR3是一种控制寄存器,它是CPU中的一个专用寄存器,用于存储当前进程的页目录表的物理地址。在x86体系结构中,虚拟地址的翻译过程需要借助页表来完成。页表是由页目录表和页表组成的,页目录表存储了页表的物理地址,而页表存储了实际的物理页框地址。因此,页目录表的物理地址是虚拟地址翻译的关键之一。
在操作系统中,每个进程都有自己的地址空间,地址空间中包含了进程的代码、数据和堆栈等信息。为了实现进程间的隔离和保护,操作系统会为每个进程分配独立的地址空间。在这个过程中,操作系统会将每个进程的页目录表的物理地址存储在它自己的CR3寄存器中。当进程切换时,操作系统会修改CR3寄存器的值,从而让CPU使用新的页目录表来完成虚拟地址的翻译。
利用CR3寄存器可以实现强制读写特定进程的内存地址,这种操作需要一定的权限和技术知识。在实际应用中,这种操作主要用于调试和漏洞挖掘等方面。同时,由于CR3寄存器的读写属于有痕读写,因此许多驱动保护都会禁止或者修改CR3寄存器的值,以提高系统的安全性,此时CR3读写就失效了,当然如果能找到CR3的正确地址,此方式也是靠谱的一种读写机制。
在读写进程的时候,我们需要先找到目标进程的PEPROCESS结构。PEPROCESS结构是Windows操作系统中描述进程的一个重要数据结构,它包含了进程的各种属性和状态信息,如进程ID、进程优先级、内存布局等等。对于想要读写目标进程的内存,我们需要获得目标进程的PEPROCESS结构,才能进一步访问和操作进程的内存。
每个进程都有一个唯一的进程ID(PID),我们可以通过遍历系统中所有进程的方式来查找目标进程。对于每个进程,我们可以通过读取进程对象的名称来判断它是否是目标进程。如果找到了目标进程,我们就可以从其进程对象中获得指向PEPROCESS结构的指针。
具体的查找过程可以分为以下几个步骤:
- 遍历系统中所有进程,获取每个进程的句柄(handle)和进程对象(process object)。
- 从进程对象中获取进程的名称,并与目标进程的名称进行比较。
- 如果找到了目标进程,从进程对象中获取指向PEPROCESS结构的指针。
需要注意的是,查找进程的过程可能会受到安全策略和权限的限制,因此需要在合适的上下文中进行。在实际应用中,需要根据具体的场景和要求进行合理的安全措施和权限管理。
#include <ntifs.h>
#include <windef.h>
#include <intrin.h>NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);// 定义全局EProcess结构
PEPROCESS Global_Peprocess = NULL;// 根据进程名获得EPROCESS结构
NTSTATUS GetProcessObjectByName(char *name)
{NTSTATUS Status = STATUS_UNSUCCESSFUL;SIZE_T i;__try{for (i = 100; i<20000; i += 4){NTSTATUS st;PEPROCESS ep;st = PsLookupProcessByProcessId((HANDLE)i, &ep);if (NT_SUCCESS(st)){char *pn = PsGetProcessImageFileName(ep);if (_stricmp(pn, name) == 0){Global_Peprocess = ep;}}}}__except (EXCEPTION_EXECUTE_HANDLER){return Status;}return Status;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("hello lyshark \n");NTSTATUS nt = GetProcessObjectByName("Tutorial-i386.exe");if (NT_SUCCESS(nt)){DbgPrint("[+] eprocess = %x \n", Global_Peprocess);}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
以打开Tutorial-i386.exe为例,打开后即可返回他的Proces,当然也可以直接传入进程PID同样可以得到进程Process结构地址。
// 根据PID打开进程
PEPROCESS Peprocess = NULL;
DWORD PID = 6672;
NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Peprocess);
通过CR3读取内存Tutorial-i386.exe里面的0x0009EDC8这段内存,读出长度是4字节,核心读取函数CR3_ReadProcessMemory其实现原理可概括为以下4步;
-
首先,函数的输入参数包括目标进程的
PEPROCESS结构指针Process、要读取的内存地址Address、读取的字节数Length以及输出缓冲区的指针Buffer。函数的返回值为布尔类型,表示读取操作是否成功。 -
接着,函数使用了
CheckAddressVal函数获取了目标进程页目录表的物理地址,并将其保存在变量pDTB中。如果获取页目录表的物理地址失败,函数直接返回FALSE,表示读取操作失败。 -
接下来,函数使用了汇编指令
_disable()来禁用中断,然后调用__readcr3()函数获取当前系统的CR3寄存器的值,保存在变量OldCr3中。接着,函数使用__writecr3()函数将CR3寄存器的值设置为目标进程的页目录表的物理地址pDTB。这样就切换了当前系统的地址空间到目标进程的地址空间。 -
然后,函数使用了
MmIsAddressValid()函数来判断要读取的内存地址是否可访问。如果可访问,函数就调用RtlCopyMemory()函数将目标进程内存中的数据复制到输出缓冲区中。函数最后打印了读入数据的信息,并返回TRUE表示读取操作成功。如果要读取的内存地址不可访问,函数就直接返回FALSE表示读取操作失败。
最后,函数使用了汇编指令_enable()来恢复中断,并使用__writecr3()函数将CR3寄存器的值设置为原来的值OldCr3,从而恢复了当前系统的地址空间。
需要注意的是,这段代码仅仅实现了对目标进程内存的读取操作,如果需要进行写操作,还需要在适当的情况下使用类似的方式切换地址空间,并使用相关的内存操作函数进行写操作。另外,这种方式的内存读取操作可能会受到驱动保护的限制,需要谨慎使用。
#include <ntifs.h>
#include <windef.h>
#include <intrin.h>#define DIRECTORY_TABLE_BASE 0x028#pragma intrinsic(_disable)
#pragma intrinsic(_enable)NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);// 关闭写保护
KIRQL Open()
{KIRQL irql = KeRaiseIrqlToDpcLevel();UINT64 cr0 = __readcr0();cr0 &= 0xfffffffffffeffff;__writecr0(cr0);_disable();return irql;
}// 开启写保护
void Close(KIRQL irql)
{UINT64 cr0 = __readcr0();cr0 |= 0x10000;_enable();__writecr0(cr0);KeLowerIrql(irql);
}// 检查内存
ULONG64 CheckAddressVal(PVOID p)
{if (MmIsAddressValid(p) == FALSE)return 0;return *(PULONG64)p;
}// CR3 寄存器读内存
BOOLEAN CR3_ReadProcessMemory(IN PEPROCESS Process, IN PVOID Address, IN UINT32 Length, OUT PVOID Buffer)
{ULONG64 pDTB = 0, OldCr3 = 0, vAddr = 0;pDTB = CheckAddressVal((UCHAR*)Process + DIRECTORY_TABLE_BASE);if (pDTB == 0){return FALSE;}_disable();OldCr3 = __readcr3();__writecr3(pDTB);_enable();if (MmIsAddressValid(Address)){RtlCopyMemory(Buffer, Address, Length);DbgPrint("读入数据: %ld", *(PDWORD)Buffer);return TRUE;}_disable();__writecr3(OldCr3);_enable();return FALSE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("hello lyshark \n");// 根据PID打开进程PEPROCESS Peprocess = NULL;DWORD PID = 6672;NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Peprocess);DWORD buffer = 0;BOOLEAN bl = CR3_ReadProcessMemory(Peprocess, (PVOID)0x0009EDC8, 4, &buffer);DbgPrint("readbuf = %x \n", buffer);DbgPrint("readbuf = %d \n", buffer);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
读出后输出效果如下:

如下所示是一个在Windows操作系统下写入目标进程内存的函数,函数CR3_WriteProcessMemory()使用了CR3寄存器的切换来实现对特定进程内存地址的强制写操作。
#include <ntifs.h>
#include <windef.h>
#include <intrin.h>#define DIRECTORY_TABLE_BASE 0x028#pragma intrinsic(_disable)
#pragma intrinsic(_enable)NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
NTKERNELAPI CHAR* PsGetProcessImageFileName(PEPROCESS Process);// 关闭写保护
KIRQL Open()
{KIRQL irql = KeRaiseIrqlToDpcLevel();UINT64 cr0 = __readcr0();cr0 &= 0xfffffffffffeffff;__writecr0(cr0);_disable();return irql;
}// 开启写保护
void Close(KIRQL irql)
{UINT64 cr0 = __readcr0();cr0 |= 0x10000;_enable();__writecr0(cr0);KeLowerIrql(irql);
}// 检查内存
ULONG64 CheckAddressVal(PVOID p)
{if (MmIsAddressValid(p) == FALSE)return 0;return *(PULONG64)p;
}// CR3 寄存器写内存
BOOLEAN CR3_WriteProcessMemory(IN PEPROCESS Process, IN PVOID Address, IN UINT32 Length, IN PVOID Buffer)
{ULONG64 pDTB = 0, OldCr3 = 0, vAddr = 0;// 检查内存pDTB = CheckAddressVal((UCHAR*)Process + DIRECTORY_TABLE_BASE);if (pDTB == 0){return FALSE;}_disable();// 读取CR3OldCr3 = __readcr3();// 写CR3__writecr3(pDTB);_enable();// 验证并拷贝内存if (MmIsAddressValid(Address)){RtlCopyMemory(Address, Buffer, Length);return TRUE;}_disable();// 恢复CR3__writecr3(OldCr3);_enable();return FALSE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("hello lyshark \n");// 根据PID打开进程PEPROCESS Peprocess = NULL;DWORD PID = 6672;NTSTATUS nt = PsLookupProcessByProcessId((HANDLE)PID, &Peprocess);DWORD buffer = 999;BOOLEAN bl = CR3_WriteProcessMemory(Peprocess, (PVOID)0x0009EDC8, 4, &buffer);DbgPrint("写出状态: %d \n", bl);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
写出后效果如下:

相关文章:
3.2 Windows驱动开发:内核CR3切换读写内存
CR3是一种控制寄存器,它是CPU中的一个专用寄存器,用于存储当前进程的页目录表的物理地址。在x86体系结构中,虚拟地址的翻译过程需要借助页表来完成。页表是由页目录表和页表组成的,页目录表存储了页表的物理地址,而页表…...
基于springBoot+Vue的停车管理系统
开发环境 IDEA JDK1.8 MySQL8.0Node 系统简介 本项目为前后端分离项目,前端使用vue,后端使用SpringBoot开发,主要的功能有用户管理,停车场管理,充值收费,用户可以注册登录系统,自主充值和预…...
ES开启安全认证
elasticsearch开启安全认证步骤 1.创建证书 进入到es主目录下执行 ./bin/elasticsearch-certutil ca Elasticsearch开启安全认证详细步骤 第一个证书名称默认,直接回车 第二个输入密码,直接回车 完成后会生成一个文件:elastic-stack-ca.p12…...
CS5511规格书|CS5511方案应用说明|DP转双路LVDS/eDP芯片方案
概述:CS5511是一个将DP/eDP输入转换为LVDS信号的桥接芯片,此外,CS5511可以用作在DP/eDP输入到DP/eDP输出场景中桥接芯片。CS5511的高级接收器支持VEDA DisplayPort(DP)1.3和嵌入式DisplayPort(eDP…...
JAVA小游戏“飞翔的小鸟”
第一步是创建项目 项目名自拟 第二步创建个包名 来规范class 再创建一个包 来存储照片 如下: package game; import java.awt.*; import javax.swing.*; import javax.imageio.ImageIO;public class Bird {Image image;int x,y;int width,height;int size;doubl…...
1410. HTML 实体解析器 --力扣 --JAVA
题目 「HTML 实体解析器」 是一种特殊的解析器,它将 HTML 代码作为输入,并用字符本身替换掉所有这些特殊的字符实体。 HTML 里这些特殊字符和它们对应的字符实体包括: 双引号:字符实体为 " ,对应的字符是 &qu…...
【开源】基于Vue.js的海南旅游景点推荐系统的设计和实现
项目编号: S 023 ,文末获取源码。 \color{red}{项目编号:S023,文末获取源码。} 项目编号:S023,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四…...
机器学习【01】相关环境的安装
学习实例 参考资料:联邦学习实战{杨强}https://book.douban.com/subject/35436587/ 项目地址:https://github.com/FederatedAI/Practicing-Federated-Learning/tree/main/chapter03_Python_image_classification 一、环境准备 GPU安装CUDA、cuDNN pytho…...
微服务实战系列之签名Sign
前言 昨日恰逢“小雪”节气,今日寒风如约而至。清晨的马路上,除了洋洋洒洒的落叶,就是熙熙攘攘的上班族。眼看着,暖冬愈明显了,叶子来不及泛黄就告别了树。变化总是在不经意中发生,容不得半刻糊涂。 上集博…...
家用小型洗衣机哪款性价比高?口碑最好迷你洗衣机排行榜
由于我们的内衣、内裤和袜子等等贴身小件衣物的清洁频率比一般的衣物要高。而且,如果我们人工手洗的话,不仅会大大浪费了我们的时间,而且还不能进行对这些贴身的以为进行深层消毒和除菌。这种情况下,就得需要一台专门用于清洗内衣…...
企业远程访问业务系统:对比MPLS专线,贝锐蒲公英为何更优优势?
如今,企业大多都会采用OA、ERP、CRM等各种数字化业务系统。 私有云、公有云混合架构也变得越来越常见。 比如:研发系统部署在公司本地私有云、确保数据安全,OA采用公有云方案、满足随时随地访问需求。 如此一来,也产生了远程访问…...
Maven项目下详细的SSM整合流程
文章目录 🎉SSM整合流程一、两个容器整合✨ 1、先准备好数据库config.properties连接、mybatis-config.xml🎊 2、容器一:优先配置spring.xml文件🎊 3、容器二:配置springMVC.xml文件🎊 4、Tomcat整合spring…...
Linux 设置文件开启数量限制
1、限制某个用户的 vim /etc/security/limits.confroot soft nofile 65535 root hard nofile 65535 *soft nofile 65535 *hard nofile 65535第一行指root用户的每个进程可开启最大的文件数(软限制,只警告)第二行指root用户的每个进程可开启最…...
详解Java中的异常体系机构(throw,throws,try catch,finally)
目录 一.异常的概念 二.异常的体系结构 三.异常的处理 异常处理思路 LBYL:Look Before You Leap EAFP: Its Easier to Ask Forgiveness than Permission 异常抛出throw 异常的捕获 提醒声明throws try-catch捕获处理 finally的作用 四.自定义异常类 一.异…...
【jvm】虚拟机之堆
目录 一、堆的核心概述二、堆的内存细分(按分代收集理论设计)2.1 java7及以前2.2 java8及以后 三、堆内存大小3.1 说明3.2 参数设置3.3 默认大小3.4 手动设置3.5 jps3.6 jstat3.7 OutOfMemory举例 四、年轻代与老年代4.1 说明 五、对象分配过程5.1 说明5…...
二百零五、Flume——数据流监控工具Ganglia单机版安装以及使用Ganglia监控Flume任务的数据流(附流程截图)
一、目的 Flume采集Kafka的数据流需要实时监控,这时就需要用到监控工具Ganglia 二、Ganglia简介 Ganglia 由 gmond、gmetad 和 gweb 三部分组成。 (一)第一部分:gmond gmond(Ganglia Monitoring Daemon)…...
解决Resolving Android Dependencies问题
无论是谷歌的Admob,还是Unity的Level play, 在windows(win10, win11)下,都出现了resolving android dependencies 报错并且卡住的问题,如图: 主要错误,是找不到这个gradlew.bat文件。 在指定位置…...
深度学习技术前沿:探索与挑战
深度学习技术前沿:探索与挑战 一、引言 近年来,深度学习作为人工智能领域的重要分支,取得了令人瞩目的成就。它凭借强大的学习能力和出色的性能,在图像识别、语音识别、自然语言处理等众多任务中展现出巨大潜力。本文将深入探讨深…...
2023-11-24--oracle--实验--[Merge 语句]
oracle--实验---Merge语句 1.认知Merge 语句 • merge 语句是 sql 语句的一种。在 SQL server 、 Oracle 数据库中可用, MySQL 中不可用。 • merge 用来合并 update 和 insert 语句。目的:通过 merge 语句,根据一张表( 原数据表…...
2023亚太杯C题30页高质量word成品论文+五小问py代码+数据集+运行结果图
迈向绿色未来:中国新能源电动汽车综合分析 摘要 (完整版获取在文末!!!) 这项深入研究探讨了中国新能源电动汽车 (NEEV) 的新兴领域,涵盖从市场动态到生 态影响等广泛方面。问题一深入探讨新能…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
