码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 驱动开发:内核读写内存多级偏移


    合集 - Windows 内核安全编程技术实践(97)
    1.驱动开发:运用VAD隐藏R3内存思路2021-07-162.驱动开发:应用DeviceIoContro模板精讲06-293.驱动开发:取进程模块的函数地址06-28
    4.驱动开发:内核读写内存多级偏移06-27
    5.驱动开发:内核物理内存寻址读写06-266.驱动开发:内核远程线程实现DLL注入06-257.驱动开发:摘除InlineHook内核钩子06-248.驱动开发:内核中进程与句柄互转06-239.驱动开发:内核注册表增删改查06-2110.驱动开发:基于事件同步的反向通信06-2011.驱动开发:文件微过滤驱动入门06-1912.驱动开发:内核RIP劫持实现DLL注入06-1613.驱动开发:内核解锁与强删文件06-1514.驱动开发:内核ShellCode线程注入06-1415.驱动开发:内核LoadLibrary实现DLL注入06-1316.驱动开发:内核遍历文件或目录06-1217.驱动开发:内核文件读写系列函数06-0918.驱动开发:内核封装WFP防火墙入门06-0819.驱动开发:PE导出函数与RVA转换06-0720.驱动开发:内核扫描SSDT挂钩状态06-0621.驱动开发:内核实现SSDT挂钩与摘钩06-0522.驱动开发:内核PE结构VA与FOA转换06-0223.驱动开发:内核解析PE结构节表06-0124.驱动开发:内核解析PE结构导出表05-3125.驱动开发:内核读写内存浮点数05-3026.驱动开发:内核解析内存四级页表05-2927.驱动开发:内核实现进程汇编与反汇编05-2328.驱动开发:通过应用堆实现多次通信05-1929.驱动开发:内核远程堆分配与销毁05-1530.驱动开发:通过MDL映射实现多次通信04-2931.驱动开发:内核使用IO/DPC定时器04-0432.驱动开发:探索DRIVER_OBJECT驱动对象04-0333.驱动开发:配置Visual Studio驱动开发环境03-1334.驱动开发:内核封装TDI网络通信接口2022-11-0335.驱动开发:内核封装WSK网络通信接口2022-11-0336.驱动开发:内核层InlineHook挂钩函数2022-10-3137.驱动开发:内核LDE64引擎计算汇编长度2022-10-3138.驱动开发:内核强制结束进程运行2022-10-2939.驱动开发:内核监控FileObject文件回调2022-10-2840.驱动开发:内核监控Register注册表回调2022-10-2741.驱动开发:内核运用LoadImage屏蔽驱动2022-10-2642.驱动开发:内核监视LoadImage映像回调2022-10-2543.驱动开发:内核无痕隐藏自身分析2022-10-2444.驱动开发:内核注册并监控对象回调2022-10-2445.驱动开发:内核监控进程与线程回调2022-10-2346.驱动开发:内核测试模式过DSE签名2022-10-2247.驱动开发:内核枚举进程与线程ObCall回调2022-10-2248.驱动开发:内核枚举Registry注册表回调2022-10-2149.驱动开发:内核枚举LoadImage映像回调2022-10-2050.驱动开发:内核枚举ShadowSSDT基址2022-10-2051.驱动开发:Win10枚举完整SSDT地址表2022-10-1952.驱动开发:Win10内核枚举SSDT表基址2022-10-1953.驱动开发:内核特征码扫描PE代码段2022-10-1854.驱动开发:内核枚举Minifilter微过滤驱动2022-10-1855.驱动开发:内核特征码搜索函数封装2022-10-1756.驱动开发:内核枚举驱动内线程(答疑篇)2022-10-1657.驱动开发:内核枚举PspCidTable句柄表2022-10-1658.驱动开发:内核枚举DpcTimer定时器2022-10-1659.驱动开发:如何枚举所有SSDT表地址2022-10-1460.驱动开发:内核枚举IoTimer定时器2022-10-1461.驱动开发:内核遍历进程VAD结构体2022-10-1362.驱动开发:内核中实现Dump进程转储2022-10-1163.驱动开发:内核R3与R0内存映射拷贝2022-10-1164.驱动开发:内核通过PEB得到进程参数2022-10-1065.驱动开发:内核取应用层模块基地址2022-10-0966.驱动开发:内核取ntoskrnl模块基地址2022-10-0967.驱动开发:判断自身是否加载成功2022-10-0868.驱动开发:应用DeviceIoContro开发模板2022-10-0369.驱动开发:通过Async反向与内核通信2022-10-0370.驱动开发:通过PIPE管道与内核层通信2022-10-0171.驱动通信:通过PIPE管道与内核层通信2022-10-0172.驱动开发:通过ReadFile与内核层通信2022-09-3073.驱动开发:内核字符串拷贝与比较2022-09-2974.驱动开发:内核字符串转换方法2022-09-2875.驱动开发:内核中的自旋锁结构2022-09-2876.驱动开发:内核CR3切换读写内存2022-09-2577.驱动开发:内核中的链表与结构体2022-09-2378.驱动开发:摘链DKOM进程隐藏2022-08-3179.驱动开发:WinDBG 枚举SSDT以及SSSDT地址2022-04-2880.驱动开发:实现驱动加载卸载工具2021-07-1681.驱动开发:断链隐藏驱动程序自身2021-07-1682.驱动开发:通过内存拷贝读写内存2021-07-1283.驱动开发:内核MDL读写进程内存2021-07-0584.驱动开发:内核监控进程与线程创建2021-05-0685.驱动开发:监控进程与线程对象操作2020-06-1486.驱动开发:WinDBG 常用调试命令总结2020-06-1087.驱动开发:通过SystemBuf与内核层通信2020-04-1388.驱动开发:对象回调监控文件访问2019-11-0189.驱动开发:内核中枚举进线程与模块2019-10-2190.驱动开发:DKOM 实现进程隐藏2019-10-1191.驱动开发:内核读取SSDT表基址2019-10-0992.驱动开发:驱动与应用的简单通信2019-09-2393.驱动开发:恢复SSDT内核钩子2019-09-2194.驱动开发:挂接SSDT内核钩子2019-09-2095.驱动开发:WinDBG 配置内核双机调试2019-09-1996.VS2013+WDK8.1 驱动开发环境配置2019-09-1897.驱动开发:派遣函数与设备对象2019-09-14
    收起

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

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

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

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

    #include 
    #include 
    #include 
    
    // 普通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=4884的PBase的动态地址中的数据,如下图所示;

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

    #include 
    #include 
    #include 
    
    // 普通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 
    #include 
    #include 
    
    // 普通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实际地址,实现效果图如下所示;

  • 相关阅读:
    【云原生Kubernetes系列第六篇】Kubernetes的认证和授权
    表单提交是
    Linux 基础-查看进程命令 ps 和 top
    世界数字工厂的发展现状究竟如何?仅10%公司实施完成!
    领域驱动模型DDD(四)——Eventuate Tram Saga源码讲解
    Flink原理与实现:数据交换策略
    C# Onnx Yolov8 Detect 涉黄检测
    多台的UPS该如何实现系统化的集中监控呢?
    Ajax的基础知识
    UNet pytorch 胎教级介绍 使用DRIVE眼底血管分割数据集进行入门实战
  • 原文地址:https://www.cnblogs.com/LyShark/p/17507776.html
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号