内核驱动修改内存

news2024/11/15 9:24:15

概述

在这里插入图片描述

本文会利用内核驱动进行读写取第三方应用内存。

内核实现会使用内联汇编 所以对于内核数据结构每个windwos版本不一样需要判断,本文使用19041所写代码。

命令行:winver 即可查看你当前的版本,如下图19042.631 就是构建版本号

或者调用对应内核API.

BOOLEAN PsGetVersion(
  [out, optional] PULONG          MajorVersion,
  [out, optional] PULONG          MinorVersion,
  [out, optional] PULONG          BuildNumber,
  [out, optional] PUNICODE_STRING CSDVersion
);

PsGetVersion 文档

或者链接windbg的时候查看如下图所示。 19041便是构建号。
在这里插入图片描述

获取内核进程信息

在内核中IoGetCurrentProcess可以获取到当前进程对应的结构体

如下图所示

// ntddk.h
PEPROCESS IoGetCurrentProcess();

typedef struct _EPROCESS *PEPROCESS;

IoGetCurrentProcess

_EPROCESS 结构体因构建版本不同而有所差异
可以在windbg 输入如下命令查看

dt nt!_EPROCESS

19041构建版本的核心输出:

nt!_EPROCESS
   +0x000 Pcb                : _KPROCESS
   +...   ....    	         :  ....
   +0x0e4 UniqueProcessId    : Ptr32 Void
   +0x0e8 ActiveProcessLinks : _LIST_ENTRY
   +...   ....    	         :  ....
   +0x1ac ImageFileName      : [15] UChar
   +...   ....    	         :  ....

Pcb: 进程控制块,包含很多核心信息比如分页表分段表信息等
UniqueProcessId : 进程id
ActiveProcessLinks: 所有进程的双向链表循环,可以通过这个遍历所有进程
ImageFileName : 进程名

_LIST_ENTRY 数据结构

nt!_LIST_ENTRY
   +0x000 Flink            : Ptr32 _LIST_ENTRY
   +0x004 Blink            : Ptr32 _LIST_ENTRY

Flink指向上个进程的_EPROCESS对象的ActiveProcessLinks地址
Blink指向下个进程的_EPROCESS对象的ActiveProcessLinks地址

在这里插入图片描述

Pcb 是一个非常重要的数据结构这里贴出我们关心的数据结构:


nt!_KPROCESS
   +...   ...                : ....
   
   +0x018 DirectoryTableBase : Uint4B
   +...   ...                : ....


DirectoryTableBase 指向的就是cr3中保存的物理地址.注意是物理地址非虚拟地址。我们知道现代操作系统都在弱化段内存强化分页内存,因此我们需要获取其他进程的分页内存进而直接读取内存数据,这样可以无视任何检测。

我们现在创建一个函数传入一个进程pid然后返回对应的分页物理地址:

PVOID GetDirectoryTableBase(HANDLE  hProcess) {
	
	PEPROCESS Process = NULL;



	__try {
		//DbgBreakPoint();
		Process = IoGetCurrentProcess();
		//IoGetCurrentProcess内核实现其实非常简单如下所示,可以使用windbg : u IoGetCurrentProcess 查看反编译
			//__asm {
	//	//fs 指向 _kpcr 的结构
	//	//fs  0x120指向_KPRCB
	//	//_KPRCB偏移0x4指向 _KTHREAD 
	//	//也就是fs : [00000124h]指向一个_KTHREAD结构、、 _ETHTREAD(PsGetCurrentThread函数就是eax, dword ptr fs : [00000124h] 实现的)
	//	//
	//	mov     eax, dword ptr fs : [00000124h]
	//	mov     eax, dword ptr[eax + 80h]
	//	mov		Process,eax
	//}
		PEPROCESS Head = Process;
		//遍历双向链表
		while (Process)
		{
			//校验内存是否在物理页映射了( 是否分页结构体p标志位有效)
			if (MmIsAddressValid(Process)) {
			    //相关偏移
				int pidOffset = 0x0e4;
				int imageFileNameOffset = 0x1ac;
				int DirectoryTableBaseOffset = 0x018;
				int activeProcessLinksOffset = 0x0e8;
				if (MmIsAddressValid((char*)Process + pidOffset)) {
					// _EPROCESS --->>+0x0e4 UniqueProcessId  : Ptr32 Void
					//获取进程pid
					HANDLE ProcessID = *(HANDLE*)((char*)Process + pidOffset);
					if (MmIsAddressValid((char*)Process + imageFileNameOffset)) {
						//_EPROCESS --->>  +0x1ac ImageFileName    : [15] UChar
						//获取进程名称
						UCHAR* ImageFileName = (UCHAR *)((char*)Process + imageFileNameOffset);
						if (MmIsAddressValid((char*)Process + DirectoryTableBaseOffset)) {
							//_EPROCESS --->> +0x000 Pcb              : _KPROCESS
							//_KPROCESS --->>    +0x018 DirectoryTableBase : Uint4B
							//分页地址
							PVOID DirectoryTableBase = *(PVOID*)((char*)Process + DirectoryTableBaseOffset);
							//如果当前进程pid和寻找pid相同直接返回分页地址
							if (ProcessID == hProcess)
							{
								DbgPrint("pid %d ImageFileName :%s DirectoryTableBase:%p\n", ProcessID, ImageFileName, DirectoryTableBase);

								return DirectoryTableBase;
							}
							else {
								DbgPrint("[My learning] find next \r\n", __FUNCTION__);
							}
			
							if (MmIsAddressValid((char*)Process + activeProcessLinksOffset)) {
								//   _EPROCESS --->>  +0x0e8 ActiveProcessLinks : _LIST_ENTRY
								//遍历双向链表,寻找下一个
								PLIST_ENTRY Entry = (PLIST_ENTRY)((char*)Process + activeProcessLinksOffset);
								Process = (PEPROCESS)((char *)Entry->Flink - activeProcessLinksOffset);
								//兜底双向链表全部搜寻不到
								if (Process == Head)
								{
									DbgPrint("[My learning] Process == Head \r\n ", __FUNCTION__);
									break;
								}
							}
						}
					}
				}
			}
		}
	}
	__except (1) {
		Process = NULL;
		DbgPrint("[My learning] %s __exception\r\n", __FUNCTION__);
	}

	return NULL;
}

读取内存信息


PVOID pOldDirectoryTableBase;
//hProcess目标进程
//lpBaseAddress读取的进程内存地址
//lpBuffer读取到哪 必须内核地址
//nSize 读取字节
NTSTATUS MyReadProcessMemory(
	HANDLE  hProcess,
	PVOID lpBaseAddress,
	PVOID  lpBuffer,
	SIZE_T  nSize) {



	__try {
		//获取目标进程的页表
		PVOID pDirectoryTableBase = GetDirectoryTableBase((HANDLE)hProcess);
		if (pDirectoryTableBase == NULL)
		{
			return STATUS_UNSUCCESSFUL;
		}
		__asm {
			//防止当前进程被切换出去
			cli
			//保存环境
			pushad
			pushf

			//保存旧的CR3
			mov eax, cr3
			mov pOldDirectoryTableBase, eax

			//修改CR3
			mov eax, pDirectoryTableBase
			mov cr3, eax
		}
		if (MmIsAddressValid(lpBaseAddress))
		{
			ProbeForRead(lpBaseAddress, nSize, 4);
			RtlCopyMemory(lpBuffer, lpBaseAddress, nSize);
			DbgPrint("[My learning] MmIsAddressValid is Ok\r\n", __FUNCTION__);
		}


		__asm {
			//恢复环境
			mov eax, pOldDirectoryTableBase
			mov pOldDirectoryTableBase, eax
			popf
			popad
			//恢复
			sti
		}

		DbgPrint("[My learning] STATUS_SUCCESS\r\n", __FUNCTION__);

		return STATUS_SUCCESS;
	}
	__except (1) {
		DbgPrint("[My learning] %s __exception\r\n", __FUNCTION__);
		__asm {
			//恢复环境
			mov eax, pOldDirectoryTableBase
			mov pOldDirectoryTableBase, eax
			popf
			popad
			//恢复
			sti
		}
	}

	DbgPrint("[My learning] STATUS_UNSUCCESSFUL\r\n", __FUNCTION__);

	return STATUS_UNSUCCESSFUL;
}

核心思想:把目标进程的页目录置换到自己的内核进程中,那么你读取内存信息操作系统通过MMU等来自己算出结果。

__asm {
			//略....

			//保存旧的CR3
			mov eax, cr3
			mov pOldDirectoryTableBase, eax

			//修改CR3
			mov eax, pDirectoryTableBase
			mov cr3, eax
}

当我们读出结果的时候需要把cr3换回来

__asm {
			//恢复环境
			mov eax, pOldDirectoryTableBase
			mov pOldDirectoryTableBase, eax
}

cli指令的作用是用于不响应中断,那么会导致操作变为原子执行,直到调用sti才能恢复。这里是为了防止内核进程,当前运行此代码的线程被切走运行当前进程的其他代码,但是此时cr3已经变成了目标进程的页目录,切换线程不会更新cr3会导致可能读写到目标进程数据的风险。

另外注意cli会导致__try{}__except 不能捕获异常(无法响应中断的后果,所以上面的代码存在逻辑问题)

在这里插入图片描述

tip:

  1. CR3存放当前进程的页目录物理地址
  2. CR3切换线程不会改变
  3. windbg 的!process 0 0 命令可以查看所有进程信息

写内存信息

我们知道页表中有读写属性,如果我们写入的是具有只读的内存那么回抛出错误,我们可以通过简单修改CR0.WP为0来关闭这个保护。

cr0寄存器如下:
在这里插入图片描述


NTSTATUS MyWriteProcessMemory(
	HANDLE  hProcess,
	PVOID lpBaseAddress,
	PVOID  lpBuffer,
	SIZE_T  nSize) {




	NTSTATUS Status = STATUS_SUCCESS;

	PVOID pDirectoryTableBase = GetDirectoryTableBase((HANDLE)hProcess);
	
	if (pDirectoryTableBase == NULL)
	{
		DbgPrint("[My learning] pDirectoryTableBase ==null %s\r\n", __FUNCTION__);
		return STATUS_UNSUCCESSFUL;
	}
	KdBreakPoint();
	__asm {
		//防止当前进程被切换出去
		cli

		//保存环境
		//pushad
		//pushf
		//保存旧的CR3
		mov eax, cr3
		mov pOldDirectoryTableBase, eax

		//修改CR3
		mov eax, pDirectoryTableBase
		mov cr3, eax

		//关闭写保护
		mov eax,cr0
		and eax,not 10000h
		mov cr0,eax

		

		
	}

	if (MmIsAddressValid(lpBaseAddress))
	{
		RtlCopyMemory(lpBaseAddress, lpBuffer, nSize);
		DbgPrint("[My learning] MmIsAddressValid is %s \r\n", __FUNCTION__);
	}
	else {
		DbgPrint("[My learning] MmIsAddressinValid is %s \r\n", __FUNCTION__);
	}

	__asm {
		//恢复环境
		mov eax, pOldDirectoryTableBase
		mov cr3, eax
		//popfd
		//popad
	

		//关闭写保护
		mov eax, cr0
		or eax,  10000h
		mov cr0, eax

		//恢复
		sti
	}


	return Status;
}

源码

https://github.com/fanmingyi/winkernel_read_mm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/99178.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

痞子衡嵌入式:低功耗高性能边缘人工智能应用的新答案 - MCXN947

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是恩智浦MCX系列MCU的新品MCXN947。 自 2015 年恩智浦和飞思卡尔合并成新恩智浦之后,关于它们各自的 Arm Cortex-M 内核通用微控制器代表作系列 LPC 和 Kinetis 接下来怎么发展…

数据结构 | 链式二叉树【递归的终极奥义】

递归——这就是俄罗斯套娃吗😮🌳链式二叉树的结构及其声明🌳链式二叉树的四种遍历方式📕先序遍历(先根遍历)递归算法图解📕中序遍历(中根遍历)📕后序遍历&…

TIA PORTAL 导出导入数据块

1.导出:选择要导出的数据块鼠标右键-->从块生成源-->仅所选块或包含所有关联块-->最后选择数据块的存储路径保存 2.导入:选外部源文件-->添加新的外部文件-->选择要导入的数据块文件-->单击文件鼠标右键-->从源生成块,最…

Vue3——ref(),reactive(),watch(),computed()的使用

都需要先引入才能使用 ref()函数 作用:创建一个响应式变量,使得某个变量在发生改变时可以同步发生在页面上 模板语句中使用这个变量时可以直接使用变量名来调用,在setup内部调用时则需要在变量明后面加上一个.value获取它的值,原…

记录一次使用卷积神经网络进行图片二分类的实战

写在前面 笔者目前就读的专业是软件工程,并非人工智能专业,但是由于对人工智能有兴趣,于是课下进行了一些自学。正巧最近有些闲暇时间,就想着使用自学的内容做个小型的实战。这篇文章的主要目的也就是从一个入门者的角度&#xf…

【C++】list

本期就来讲讲list的使用技巧 文章目录list的介绍及使用list的介绍list迭代器失效list的模拟实现list与vector的对比我们前面知道迭代器是一个像指针一样的东西,但是在C里面,出来string和vector,其他类都不能 将迭代器当成指针使用&#xff0c…

二叉树的非递归与相关oj

🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸 文章目录一、二叉树相关oj①二叉搜索树与双向链表②前序遍历和中序遍历构造二叉树二、二叉树的非递归①前序遍历非递归②中序遍历非递归③后序遍历非…

简单的算法思想 - 利用快慢指针解决问题 - 寻找链表中的中间节点,回文序列,倒数第k个节点 - 详解

文章目录1. 寻找链表中倒数第K个节点1.1. 思路分析1.2 代码实现2. 寻找链表中的中间结点2.1 思路概述2.2 代码实现3. 链表的回文结构3.1 思路分析3.2 代码实现总结✨✨✨学习的道路很枯燥,希望我们能并肩走下来! 本文通过寻找链表中的中间节点&#xff0…

汽车托运网址

开发工具(eclipse/idea/vscode等): 数据库(sqlite/mysql/sqlserver等): 功能模块(请用文字描述,至少200字): 基于Web的汽车托运网站的设计与实现 网站前台:关于我们、联系我们、公告信息、卡车类型、卡车信息、运输评论…

【语音处理】一种增强的隐写及其在IP语音隐写中的应用(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

Effective Objective-C 2.0学习记录(一)

48.多用块枚举,少用for循环for循环快速枚举(快速遍历)基于块的遍历方式在编程中经常需要用到列举collection(NSArray、NSDictionary、NSSet等)中的元素,当前的Objective-C语言有多种办法实现此功能&#xf…

【专栏】核心篇09| 怎么保证缓存与DB的数据一致性

计算机类PDF整理:【详细!!】计算机类PDF整理 Redis专栏合集 【专栏】01| Redis夜的第一章 【专栏】基础篇02| Redis 旁路缓存的价值 【专栏】基础篇03| Redis 花样的数据结构 【专栏】基础篇04| Redis 该怎么保证数据不丢失(上…

Python -- 模块和包

目录 1.Python中的模块 1.1 import 1.3 from...import * 1.4 as别名 2.常见的系统模块和使用 2.1 OS模块 2.2 sys模块 2.3 math模块 2.4 random模块 2.5 datetime模块 2.6 time模块 2.7 calendar模块 2.8 hashlib模块 2.9 hmac模块 2.10 copy模块 3.pip命令的使…

【机器学习---01】机器学习

文章目录1. 什么是机器学习?2. 机器学习分类2.1 基本分类2.2 按模型分类2.3 其他分类(不重要)3. 机器学习三要素4. 监督学习的应用(分类、标注、回归问题)1. 什么是机器学习? 定义:给定训练集D,让计算机从一个函数集合F {f1(x)&…

虚拟机打不开,提示“此主机不支持虚拟化实际模式”的详细解决方法

虚拟机打不开,提示“此主机不支持虚拟机实际模式”的解决方法 一、第一种情况安装/启动虚拟机失败, 在VMWare软件中,安装/启动虚拟机时,如果出以类似以下的错误提示: 出现该提示是由于电脑不支持虚拟化技术或是相关功…

IDEA报错:类文件具有错误的版本 61.0,应为52.0

springboot项目启动报错: 类文件具有错误的版本 61.0,应为52.0 请删除该文件或确保该文件位于正确的类路径子目录中 查阅了网上的很多资料,普遍原因说是springboot版本过高,高于3.0 需要在pom文件中降低版本 也有说是idea的maven配置java版…

网购商城网站

开发工具(eclipse/idea/vscode等): 数据库(sqlite/mysql/sqlserver等): 功能模块(请用文字描述,至少200字):

【Python机器学习】层次聚类AGNES、二分K-Means算法的讲解及实战演示(图文解释 附源码)

需要源码和数据集请点赞关注收藏后评论区留言私信~~~ 层次聚类 在聚类算法中,有一类研究执行过程的算法,它们以其他聚类算法为基础,通过不同的运用方式试图达到提高效率,避免局部最优等目的,这类算法主要有网格聚类和…

easypoi导入excel空指针异常

问题描述 前端页面停留在导入页面,通过后端返回的接口,确认后端已经抛出异常查看系统调用错误日志为 java.lang.NullPointerException: nullat org.apache.poi.xssf.usermodel.XSSFClientAnchor.setCol2(XSSFClientAnchor.java:231)at org.apache.poi.…

基于EKF的四旋翼无人机姿态估计matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 卡尔曼滤波是一种高效率的递归滤波器(自回归滤波器),它能够从一系列的不完全包含噪声的测量中,估计动态系统的状态。这种滤波方法以它的发明者鲁道夫E卡尔曼(R…