驱动开发:内核读写内存多级偏移

让我们继续在《内核读写内存浮点数》的基础之上做一个简单的延申,如何实现多级偏移读写,其实很简单,读写函数无需改变,只是在读写之前提前做好计算工作,以此来得到一个内存偏移值,并通过调用内存写入原函数实现写出数据的目的。

以读取偏移内存为例,如下代码同样来源于本人的LyMemory读写驱动项目,其中核心函数为WIN10_ReadDeviationIntMemory()该函数的主要作用是通过用户传入的基地址与偏移值,动态计算出当前的动态地址。

函数首先将基地址指向要读取的变量,并将其转换为LPCVOID类型的指针。然后将指向变量值的缓冲区转换为LPVOID类型的指针。接下来,函数使用PsLookupProcessByProcessId函数查找目标进程并返回其PEPROCESS结构体。随后,函数从偏移地址数组的最后一个元素开始迭代,每次循环都从目标进程中读取4字节整数型数据,并将其存储在Value变量中。然后,函数将基地址指向Value和偏移地址的和,以便在下一次循环中读取更深层次的变量。最后,函数将基地址指向最终变量的地址,读取变量的值,并返回。

如下案例所示,用户传入进程基址以及offset偏移值时,只需要动态计算出该偏移地址,并与基址相加即可得到动态地址。

#include <ntifs.h>
#include <ntintsafe.h>
#include <windef.h>

// 普通Ke内存读取
NTSTATUS KeReadProcessMemory(PEPROCESS Process, PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
	PEPROCESS SourceProcess = Process;
	PEPROCESS TargetProcess = PsGetCurrentProcess();
	SIZE_T Result;
	if (NT_SUCCESS(MmCopyVirtualMemory(SourceProcess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
		return STATUS_SUCCESS;
	else
		return STATUS_ACCESS_DENIED;
}

// 读取整数内存多级偏移
/*
  Pid: 目标进程的进程ID。
  Base: 变量的基地址。
  offset: 相对基地址的多级偏移地址,用于定位变量。
  len: 偏移地址的数量。
*/
INT64 WIN10_ReadDeviationIntMemory(HANDLE Pid, LONG Base, DWORD offset[32], DWORD len)
{
	INT64 Value = 0;
	LPCVOID pbase = (LPCVOID)Base;
	LPVOID rbuffer = (LPVOID)&Value;

	PEPROCESS Process;
	PsLookupProcessByProcessId((HANDLE)Pid, &Process);

	for (int x = len - 1; x >= 0; x--)
	{
		__try
		{
			KeReadProcessMemory(Process, pbase, rbuffer, 4);
			pbase = (LPCVOID)(Value + offset[x]);
		}
		__except (EXCEPTION_EXECUTE_HANDLER)
		{
			return 0;
		}
	}

	__try
	{
		DbgPrint("读取基址:%x \n", pbase);
		KeReadProcessMemory(Process, pbase, rbuffer, 4);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return 0;
	}

	return Value;
}

// 驱动卸载例程
VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("Uninstall Driver \n");
}

// 驱动入口地址
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("Hello LyShark \n");

	DWORD PID = 4884;
	LONG PBase = 0x6566e0;
	LONG Size = 4;
	DWORD Offset[32] = { 0 };

	Offset[0] = 0x18;
	Offset[1] = 0x0;
	Offset[2] = 0x14;
	Offset[3] = 0x0c;

	// 读取内存数据
	INT64 read = WIN10_ReadDeviationIntMemory(PID, PBase, Offset, Size);

	DbgPrint("PID: %d 基址: %p 偏移长度: %d \n", PID, PBase, Size);
	DbgPrint("[+] 1级偏移: %x \n", Offset[0]);
	DbgPrint("[+] 2级偏移: %x \n", Offset[1]);
	DbgPrint("[+] 3级偏移: %x \n", Offset[2]);
	DbgPrint("[+] 4级偏移: %x \n", Offset[3]);

	DbgPrint("[ReadMemory] 读取偏移数据: %d \n", read);

	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

编译并运行如上这段代码,则可获取到PID=4884PBase的动态地址中的数据,如下图所示;

至于如何将数据写出四级偏移的基址上面,则只需要取出pbase里面的基址,并通过原函数WIN10_WriteProcessMemory直接写出数据即可,此出的原函数在《内核MDL读写进程内存》中已经做了详细介绍,实现写出代码如下所示;

#include <ntifs.h>
#include <ntintsafe.h>
#include <windef.h>

// 普通Ke内存读取
NTSTATUS KeReadProcessMemory(PEPROCESS Process, PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
	PEPROCESS SourceProcess = Process;
	PEPROCESS TargetProcess = PsGetCurrentProcess();
	SIZE_T Result;
	if (NT_SUCCESS(MmCopyVirtualMemory(SourceProcess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
		return STATUS_SUCCESS;
	else
		return STATUS_ACCESS_DENIED;
}

// Win10 内存写入函数
BOOLEAN WIN10_WriteProcessMemory(HANDLE Pid, PVOID Address, SIZE_T BYTE_size, PVOID VirtualAddress)
{
	PVOID buff1;
	VOID *buff2;
	int MemoryNumerical = 0;
	KAPC_STATE KAPC = { 0 };

	PEPROCESS Process;
	PsLookupProcessByProcessId((HANDLE)Pid, &Process);

	__try
	{
		//分配内存
		buff1 = ExAllocatePoolWithTag((POOL_TYPE)0, BYTE_size, 1997);
		buff2 = buff1;
		*(int*)buff1 = 1;
		if (MmIsAddressValid((PVOID)VirtualAddress))
		{
			// 复制内存
			memcpy(buff2, VirtualAddress, BYTE_size);
		}
		else
		{
			return FALSE;
		}

		// 附加到要读写的进程
		KeStackAttachProcess((PRKPROCESS)Process, &KAPC);
		if (MmIsAddressValid((PVOID)Address))
		{
			// 判断地址是否可写
			ProbeForWrite(Address, BYTE_size, 1);
			// 复制内存
			memcpy(Address, buff2, BYTE_size);
		}
		else
		{
			return FALSE;
		}
		// 剥离附加的进程
		KeUnstackDetachProcess(&KAPC);
		ExFreePoolWithTag(buff2, 1997);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return FALSE;
	}
	return FALSE;
}

// 写入整数内存多级偏移
INT64 WIN10_WriteDeviationIntMemory(HANDLE Pid, LONG Base, DWORD offset[32], DWORD len, INT64 SetValue)
{
	INT64 Value = 0;
	LPCVOID pbase = (LPCVOID)Base;
	LPVOID rbuffer = (LPVOID)&Value;

	PEPROCESS Process;
	PsLookupProcessByProcessId((HANDLE)Pid, &Process);

	for (int x = len - 1; x >= 0; x--)
	{
		__try
		{
			KeReadProcessMemory(Process, pbase, rbuffer, 4);
			pbase = (LPCVOID)(Value + offset[x]);
		}
		__except (EXCEPTION_EXECUTE_HANDLER)
		{
			return 0;
		}
	}

	__try
	{
		KeReadProcessMemory(Process, pbase, rbuffer, 4);
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		return 0;
	}

	// 使用原函数写入
	BOOLEAN ref = WIN10_WriteProcessMemory(Pid, (void *)pbase, 4, &SetValue);
	if (ref == TRUE)
	{
		DbgPrint("[内核写成功] # 写入地址: %x \n", pbase);
		return 1;
	}
	return 0;
}

// 驱动卸载例程
VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("Uninstall Driver \n");
}

// 驱动入口地址
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("Hello LyShark \n");

	DWORD PID = 4884;
	LONG PBase = 0x6566e0;
	LONG Size = 4;
	INT64 SetValue = 100;

	DWORD Offset[32] = { 0 };

	Offset[0] = 0x18;
	Offset[1] = 0x0;
	Offset[2] = 0x14;
	Offset[3] = 0x0c;

	// 写出内存数据
	INT64 write = WIN10_WriteDeviationIntMemory(PID, PBase, Offset, Size, SetValue);

	DbgPrint("PID: %d 基址: %p 偏移长度: %d \n", PID, PBase, Size);
	DbgPrint("[+] 1级偏移: %x \n", Offset[0]);
	DbgPrint("[+] 2级偏移: %x \n", Offset[1]);
	DbgPrint("[+] 3级偏移: %x \n", Offset[2]);
	DbgPrint("[+] 4级偏移: %x \n", Offset[3]);

	DbgPrint("[WriteMemory] 写出偏移数据: %d \n", SetValue);

	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

运行如上代码将在0x6566e0所在的基址上,将数据替换为100,实现效果图如下所示;

那么如何实现读写内存浮点数,字节集等多级偏移呢?

其实我们可以封装一个WIN10_ReadDeviationMemory函数,让其只计算得出偏移地址,而所需要写出的类型则根据自己的实际需求配合不同的写入函数完成,也就是将两者分离开,如下则是一段实现计算偏移的代码片段,该代码同样来自于本人的LyMemory驱动读写项目;

#include <ntifs.h>
#include <ntintsafe.h>
#include <windef.h>

// 普通Ke内存读取
NTSTATUS KeReadProcessMemory(PEPROCESS Process, PVOID SourceAddress, PVOID TargetAddress, SIZE_T Size)
{
	PEPROCESS SourceProcess = Process;
	PEPROCESS TargetProcess = PsGetCurrentProcess();
	SIZE_T Result;
	if (NT_SUCCESS(MmCopyVirtualMemory(SourceProcess, SourceAddress, TargetProcess, TargetAddress, Size, KernelMode, &Result)))
		return STATUS_SUCCESS;
	else
		return STATUS_ACCESS_DENIED;
}

// 读取多级偏移内存动态地址
DWORD64 WIN10_ReadDeviationMemory(HANDLE Pid, LONG Base, DWORD offset[32], DWORD len)
{
	INT64 Value = 0;
	LPCVOID pbase = (LPCVOID)Base;
	LPVOID rbuffer = (LPVOID)&Value;

	PEPROCESS Process;
	PsLookupProcessByProcessId((HANDLE)Pid, &Process);

	for (int x = len - 1; x >= 0; x--)
	{
		__try
		{
			KeReadProcessMemory(Process, pbase, rbuffer, 4);
			pbase = (LPCVOID)(Value + offset[x]);
		}
		__except (EXCEPTION_EXECUTE_HANDLER)
		{
			return 0;
		}
	}

	return pbase;
}

// 驱动卸载例程
VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("Uninstall Driver \n");
}

// 驱动入口地址
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("Hello LyShark \n");

	DWORD PID = 4884;
	LONG PBase = 0x6566e0;
	LONG Size = 4;

	DWORD Offset[32] = { 0 };

	Offset[0] = 0x18;
	Offset[1] = 0x0;
	Offset[2] = 0x14;
	Offset[3] = 0x0c;

	// 写出内存数据
	DWORD64 offsets = WIN10_ReadDeviationMemory(PID, PBase, Offset, Size);

	DbgPrint("PID: %d 基址: %p 偏移长度: %d \n", PID, PBase, Size);
	DbgPrint("[+] 1级偏移: %x \n", Offset[0]);
	DbgPrint("[+] 2级偏移: %x \n", Offset[1]);
	DbgPrint("[+] 3级偏移: %x \n", Offset[2]);
	DbgPrint("[+] 4级偏移: %x \n", Offset[3]);

	DbgPrint("[CheckMemory] 计算偏移地址: %x \n", offsets);

	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

运行如上代码将动态计算出目前偏移地址的pbase实际地址,实现效果图如下所示;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【RF-SSA-LSTM】随机森林-麻雀优化算法优化时间序列预测研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

JavaScript内存管理和闭包

1 JavaScript内存管理 2 垃圾回收机制算法 3 闭包的概念理解 4 闭包的形成过程 5 闭包的内存泄漏 一个函数只有调用了外部的变量&#xff0c;才算是闭包。函数内和函数外会写成闭包。 深入JS闭包-闭包的访问过程 <!DOCTYPE html> <html lang"en"> &l…

海气相互作用 - 全球水循环过程及其量级

全球水循环过程及其量级 单位&#xff1a;Sv106m3/s&#xff0c;大气/陆地/海洋(103 km3)径流1.3 Sv≈台湾暖流1.1 Sv≈白令海峡0.9-1.1 Sv 从涡度平衡的角度说明为什么大洋强化发生在西边界而非东边界 有且只有在大洋西边界强化&#xff0c;才可以使得摩擦力产生一个正的涡…

pytorch搭建AlexNet网络实现花分类

pytorch搭建AlexNet网络实现花分类 一、AlexNet网络概述分析 二、数据集准备下载划分训练集和测试集 三、代码model.pytrain.pypredict.py 一、AlexNet网络 概述 使用Dropout的方式在网络正向传播过程中随机失活一部分神经元&#xff0c;以减少过拟合 分析 对其中的卷积层、…

Spring Bean的生命周期解读

目录 1. Spring IOC容器 1.1 Spring IOC 容器的设计 1.1.1 BeanFactory 1.1.2 ApplicationContext 1.2 Spring Bean的生命周期 1.2.1 BeanDefinition 1.2.2 InstantiationAwareBeanPostProcessor和BeanPostProcessor 1.2.3 测试生命周期 1. Spring IOC容器 1.1 Spring …

数据库信息速递 DataStax与谷歌合作将向NoSQL AstraDB引入向量搜索技术

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

2023-06-23:redis中什么是缓存击穿?该如何解决?

2023-06-23&#xff1a;redis中什么是缓存击穿&#xff1f;该如何解决&#xff1f; 答案2023-06-23&#xff1a; 缓存击穿是指一个缓存中的热点数据非常频繁地被大量并发请求访问&#xff0c;当该热点数据失效的瞬间&#xff0c;持续的大并发请求无法通过缓存获取到数据&…

数学建模-数据的处理

MATLAB数学建模方法与实践&#xff08;第3版&#xff09;——读书笔记 数据的准备数据获取数据处理缺失值处理噪音过滤数据集成数据归约数据变换标准化离散化 数据统计基本描述性统计分布描述性统计 数据可视化数据降维主成分分析&#xff08;PCA&#xff09;相关系数降维 数据…

【数据结构】排序

插入排序 把当前遍历到的元素前的元素序列是排好序的,把当前元素放到前边的序列中进行排序。 直接插入排序 不带哨兵 void InsertSort(int A[],int n) { int i,j,temp; for(i1;i<n;i) if(A[i]<A[i-1]) { tempA[i]; for(ji-1;j>0 && A[j]>temp;--j) A[j…

网络安全系统教程+学习路线(自学笔记)

一、什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面…

34岁上岸,我终于圆了自己的考研梦

​ 大家好&#xff0c;我是独孤风&#xff0c;一位曾经的港口煤炭工人&#xff0c;目前在某国企任大数据负责人&#xff0c;公众号大数据流动的作者。 ​ 虽然告诉自己要平静&#xff0c;但是当接到EMS录取通知书的那一刻&#xff0c;眼眶还是忍不住有些湿润。今年正好是是东北…

青岛大学_王卓老师【数据结构与算法】Week03_04_线性表的链式表示和实现4_学习笔记

本文是个人笔记&#xff0c;仅用于学习分享&#xff0c;素材来自青岛大学王卓老师的教学视频&#xff0c;如有侵权&#xff0c;请留言作删文处理。 视频链接&#xff1a; 数据结构与算法基础–第3周04–2.5线性表的链式表示和实现4–单链表基本操作2–销毁单链表 &#x1f4…

Linux——进程的概念

task_struct task_struct 是linux下管理进程的结构&#xff0c;称为PCB&#xff0c;进程控制块。linux所有的指令本质上都是一个进程。进程 task_struct 进程的数据、代码、可执行程序&#xff0c;有属性、有内容。 进程是系统的工作单元。系统由多个进程组成&#xff0c;包…

ChatGPT在物流与运输行业的智能场景:智能调度和自动驾驶的前瞻应用

第一章&#xff1a;引言 随着人工智能技术的飞速发展&#xff0c;物流与运输行业正迎来一场革命。传统的调度和运输模式已经无法满足快速增长的物流需求和客户期望。在这一领域&#xff0c;ChatGPT作为一种先进的自然语言处理模型&#xff0c;具有巨大的潜力。本文将探讨ChatG…

第三十五章Java面向对象概念及封装、继承、多态三种特性详解

面向对象简称 OO&#xff08;Object Oriented&#xff09;&#xff0c;20 世纪 80 年代以后&#xff0c;有了面向对象分析&#xff08;OOA&#xff09;、 面向对象设计&#xff08;OOD&#xff09;、面向对象程序设计&#xff08;OOP&#xff09;等新的系统开发方式模型的研究。…

ECC加密算法详解+python实现

一.前言 目前比较受欢迎的加密算法一共存在两种&#xff0c;一种是基于大整数因子分解问题&#xff08;IFP&#xff09;的RSA算法和基于椭圆曲线上离散对数计算问题&#xff08;ECDLP&#xff09;的ECC算法。之前对RSA算法进行过很详细的讲解&#xff0c;但是ECC加密算法还没有…

数据库的操作

前言 在之前的文章中&#xff0c;我们已经了解了什么是数据库&#xff0c;以及为什么有数据库&#xff0c;和数据库有什么作用&#xff0c;有了这些宏观概念之后&#xff0c;本章为大家进一步详细介绍对于数据库在Linux上如何具体操作。 1.创建数据库 1.1创建数据库语法 语法…

第十二章 EfficientNetv2网络详解

系列文章目录 第一章 AlexNet网络详解 第二章 VGG网络详解 第三章 GoogLeNet网络详解 第四章 ResNet网络详解 第五章 ResNeXt网络详解 第六章 MobileNetv1网络详解 第七章 MobileNetv2网络详解 第八章 MobileNetv3网络详解 第九章 ShuffleNetv1网络详解 第十章…

【线程池】史上最全的ThreadPoolExecutor源码详解

目录 一、线程池框架 1.1 第一层结构 1.2 接口简介 1.3 核心实现类 1.4 辅助类 1.5 完成服务 二、ThreadPoolExecutor的成员属性和内部类 2.1 主要成员属性以及工具方法 2.2 五种内部类 2.2.1 拒绝策略内部类&#xff08;Policy&#xff09; 2.2.2 工作线程内部类&a…

HHU云计算期末复习(下)Hadoop、虚拟化技术、openstack

文章目录 第五章 Hadoop分布式文件系统HDFS分离元数据和数据&#xff1a;NameNode和DataNode流水线复制 第七章 虚拟化技术7.1 虚拟化技术简介7.2 虚拟机迁移7.3 网络虚拟化 第八章 openstack8.1 计算服务NovaRabbitMQ 8.2 Swift 第九章 云计算数据中心9.1 云数据中心特征9.2 网…