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

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

以读取偏移内存为例,如下代码同样来源于本人的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;elsereturn 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;elsereturn 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;elsereturn 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实际地址,实现效果图如下所示;

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot的日志

SpringBoot的日志 &#x1f50e;日志是什么&#x1f50e;日志的作用&#x1f50e;日志级别日志级别的作用日志级别的分类日志级别的设置 &#x1f50e;打印日志打印日志具体内容划分 &#x1f50e;常用的日志框架为什么这样设计对比System.out.ptintln()与日志框架 &#x1f50…

Observability:如何把 Elastic Agent 采集的数据输入到 Logstash 并最终写入到 Elasticsearch

在之前的文章 “安装独立的 Elastic Agents 并采集数据 - Elastic Stack 8.0”&#xff0c;我们详述了如何使用 No Fleet Server 来把数据写入到 Elasticsearch 中。在今天的文章中&#xff0c;我们来详述如下使用 Elastic Agents 在独立&#xff08;standalone&#xff09;模式…

《诸神之眼:Nmap网络安全审计技术揭秘》读书笔记

《诸神之眼&#xff1a;Nmap网络安全审计技术揭秘》读书笔记 作者&#xff1a;李华峰 ◆ 前言 NSE是Nmap中革命性的创新。通过Nmap强大的脚本引擎&#xff08;NSE&#xff09;&#xff0c;每一个用户都可以向Nmap中添加自己编写的代码&#xff0c;从而将Nmap打造成用户自由定制…

fusionpbx简介

概述 fusionpbx是以freeswitch作为底层框架开发而成的开源PBX&#xff0c;在freeswitch的基础上&#xff0c;优化了GUI的易用性。 fusionpbx可用作高可用性的单租户或基于域的多租户 PBX、运营商级交换机、呼叫中心服务器、传真服务器、voip服务器、语音邮件服务器、会议服务…

深入理解深度学习——BERT派生模型:T5(Text to Text Transfer Transformer)

分类目录&#xff1a;《深入理解深度学习》总目录 T5的全称为Text to Text Transfer Transformer&#xff0c;是谷歌提出的预训练语言模型领域的通用模型&#xff0c;该模型将所有自然语言问题都转化成文本到文本的形式&#xff0c;并用一个统一的模型解决。为了得到大一统的高…

hexo stellar设置笔记页面

stellar主题的作者在其文档介绍了如何进行笔记页面的简单设置&#xff0c;但是我看了以后还是有点云里雾里&#xff0c;在一顿查阅资料以后&#xff0c;我终于找到了解决办法。 参考下面这个博主的文章。写得很详细&#xff0c;这里就不再赘述啦。 Stellar主题自定义侧边栏教…

C#,保持亮度的动态直方图均衡化(Brightness Preserving Dynamic Histogram Equalization:BPDHE)源代码

图像增强的主要目的是显示隐藏的图像细节&#xff0c;或者用新的动态范围增加图像对比度。直方图均衡&#xff08;HE&#xff09;是用于图像对比度增强的最流行的技术之一&#xff0c;因为HE在计算上快速且易于实现。HE通过基于输入灰度级的概率分布重新映射图像的灰度级来执行…

微服务远程调用openFeign整合

✅作者简介&#xff1a;大家好&#xff0c;我是Cisyam&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Cisyam-Shark的博客 &#x1f49e;当前专栏&#xff1a; 微服务探索之旅 ✨特色专…

聚类分析(文末送书)

目录 聚类分析是什么 一、 定义和数据类型 聚类应用 聚类分析方法的性能指标 聚类分析中常用数据结构有数据矩阵和相异度矩阵 聚类分析方法分类 二、K-means聚类算法 划分聚类方法对数据集进行聚类时包含三个要点 K-Means算法流程: K-means聚类算法的特点 三、k-med…

【数据挖掘】时间序列模型处理指南(二)

一、说明 本文是一个系列文章的第二部分&#xff0c;本文将用股票数据进行时间序列分析为例&#xff0c;对时间分析的方法、过程&#xff0c;进行详细阐述。 二、前文章节 在文章第一部分种&#xff1a;【数据挖掘】时间序列模型处理&#xff08;一&#xff09;_无水先生的博客…

C++ 文件和流

我们已经使用了 iostream 标准库&#xff0c;它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。 本教程介绍如何从文件读取流和向文件写入流。这就需要用到 C 中另一个标准库 fstream&#xff0c;它定义了三个新的数据类型&#xff1a; 数据类型描述of…

Java之Javac、JIT、AOT之间的关系

Javac&#xff1a;javac 是java语言编程编译器。全称java compiler。但这时候还是不能直接执行的&#xff0c;因为机器只能读懂汇编&#xff0c;也就是二进制&#xff0c;因此还需要进一步把.class文件编译成二进制文件。 Java的执行过程 详细流程 结论&#xff1a;javac编译后…