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

这篇具有很好参考价值的文章主要介绍了驱动开发:内核读写内存多级偏移。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

驱动开发:内核读写内存多级偏移文章来源地址https://www.toymoban.com/news/detail-501882.html

到了这里,关于驱动开发:内核读写内存多级偏移的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 驱动开发:内核解析内存四级页表

    当今操作系统普遍采用64位架构,CPU最大寻址能力虽然达到了64位,但其实仅仅只是用到了48位进行寻址,其内存管理采用了 9-9-9-9-12 的分页模式, 9-9-9-9-12 分页表示物理地址拥有四级页表,微软将这四级依次命名为PXE、PPE、PDE、PTE这四项。 关于内存管理和分页模式,不同的操

    2024年02月06日
    浏览(55)
  • 字符设备驱动(内核态用户态内存交互)

    内核驱动:运行在内核态的动态模块,遵循内核模块框架接口,更倾向于插件。 应用程序:运行在用户态的进程。 应用程序与内核驱动交互通过既定接口,内核态和用户态访问依然遵循内核既定接口。 系统:openEuler-20.03-LTS-SP3 char_module.c Makefile 驱动构建 驱动信息确认 应用程

    2024年02月11日
    浏览(44)
  • 【嵌入式环境下linux内核及驱动学习笔记-(10-内核内存管理)】

    对于包含MMU(内存管理单元)的处理器而言,linux系统以虚拟内存的方式为每个进程分配最大4GB的内存。这真的4GB的内存空间被分为两个部分–用户空间 与 内核空间。用户空间地地址分布为0~3GB,剩下的3 ~ 4GB 为内核空间。如下图。 用户进程通常只能访问用户空间的虚拟地址

    2024年02月11日
    浏览(58)
  • Linux内核驱动开发(一)

    linux操作系统历史 开发模式 git 分布式管理 git clone 获取 git push 提交 git pull 更新 邮件组 mailing list patch 内核代码组成 Makfile arch 体系系统架构相关 block 块设备 crypto 加密算法 drivers 驱动(85%) atm 通信 bluetooth 蓝牙 firmware:外设 fs 文件系统 include 头文件 init 启动代码 ipc 进程通

    2023年04月11日
    浏览(47)
  • Linux驱动开发——内核模块

    目录 内核模块的由来 第一个内核模块程序  内核模块工具  将多个源文件编译生成一个内核模块  内核模块参数 内核模块依赖 关于内核模块的进一步讨论  习题 最近一直在玩那些其它的技术,眼看快暑假了,我决定夯实一下我的驱动方面的技能,迎接我的实习,找了一本

    2024年02月04日
    浏览(83)
  • linux内核网络驱动框架(linux驱动开发篇)

    网络驱动的核心: 1、就是初始化 net_device 结构体中的各个成员变量, 2、然后将初始化完成以后的 net_device 注册到 Linux 内核中 1、网络设备(用net_device结构体) 2、网络设备的操作集( net_device_ops结构体 ) 3、sk_buff结构体 网络是分层的,对于应用层而言不用关系具体的底层是

    2023年04月08日
    浏览(80)
  • 驱动开发:内核遍历文件或目录

    在笔者前一篇文章 《驱动开发:内核文件读写系列函数》 简单的介绍了内核中如何对文件进行基本的读写操作,本章我们将实现内核下遍历文件或目录这一功能,该功能的实现需要依赖于 ZwQueryDirectoryFile 这个内核API函数来实现,该函数可返回给定文件句柄指定的目录中文件

    2024年02月08日
    浏览(82)
  • 驱动开发:内核ShellCode线程注入

    还记得 《驱动开发:内核LoadLibrary实现DLL注入》 中所使用的注入技术吗,我们通过 RtlCreateUserThread 函数调用实现了注入DLL到应用层并执行,本章将继续探索一个简单的问题,如何注入 ShellCode 代码实现反弹Shell,这里需要注意一般情况下 RtlCreateUserThread 需要传入两个最重要的

    2024年02月08日
    浏览(51)
  • 驱动开发:摘除InlineHook内核钩子

    在笔者上一篇文章 《驱动开发:内核层InlineHook挂钩函数》 中介绍了通过替换 函数 头部代码的方式实现 Hook 挂钩,对于ARK工具来说实现扫描与摘除 InlineHook 钩子也是最基本的功能,此类功能的实现一般可在应用层进行,而驱动层只需要保留一个 读写字节 的函数即可,将复杂

    2024年02月10日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包