3.1 Windows驱动开发:内核远程堆分配与销毁
在开始学习内核内存读写篇之前,我们先来实现一个简单的内存分配销毁堆的功能,在内核空间内用户依然可以动态的申请与销毁一段可控的堆空间,一般而言内核中提供了ZwAllocateVirtualMemory这个函数用于专门分配虚拟空间,而与之相对应的则是ZwFreeVirtualMemory此函数则用于销毁堆内存,当我们需要分配内核空间时往往需要切换到对端进程栈上再进行操作,接下来LyShark将从API开始介绍如何运用这两个函数实现内存分配与使用,并以此来作为驱动读写篇的入门知识。
首先以内存分配为例ZwAllocateVirtualMemory()函数,该系列函数在ntifs.h头文件内,且如果需要使用则最好提前在程序头部进行声明,该函数的微软官方定义如下所示;
NTSYSAPI NTSTATUS ZwAllocateVirtualMemory([in] HANDLE ProcessHandle, // 进程句柄[in, out] PVOID *BaseAddress, // 指向将接收已分配页面区域基址的变量的指针[in] ULONG_PTR ZeroBits, // 节视图基址中必须为零的高顺序地址位数[in, out] PSIZE_T RegionSize, // 指向将接收已分配页面区域的实际大小[in] ULONG AllocationType, // 包含指定要执行的分配类型的标志的位掩码[in] ULONG Protect // 包含页面保护标志的位掩码
);
参数ProcessHandle用于传入一个进程句柄此处我们可以通过NtCurrentProcess()获取到当前自身进程的句柄。
参数BaseAddress则用于接收分配堆地址的首地址,此处指向将接收已分配页面区域基址的变量的指针。
参数RegionSize则用于指定需要分配的内存空间大小,此参数的初始值指定区域的大小(以字节为单位)并向上舍入到下一个主机页大小边界。
参数AllocationType用于指定分配内存的属性,通常我们会用到的只有两种MEM_COMMIT指定为提交类型,MEM_PHYSICAL则用于分配物理内存,此标志仅用于地址窗口扩展AWE内存。 如果设置了MEM_PHYSICAL则还必须设置MEM_RESERVE不能设置其他标志,并且必须将保护设置为PAGE_READWRITE。
参数Protect用于设置当前分批堆的保护属性,通常当我们需要分配一段可执行指令的内存空间时会使用PAGE_EXECUTE_READWRITE,如果无执行需求则推荐使用PAGE_READWRITE属性。
在对特定进程分配堆时第一步就是要切入到该进程的进程栈中,此时可通过KeStackAttachProcess()切换到进程栈,于此对应的是KeUnstackDetachProcess()脱离进程栈,这两个函数的具体定义如下;
// 附加到进程栈
void KeStackAttachProcess(PRKPROCESS PROCESS, // 传入EProcess结构[out] PRKAPC_STATE ApcState // 指向KAPC_STATE结构的不透明指针
);
// 接触附加
void KeUnstackDetachProcess([in] PRKAPC_STATE ApcState // 指向KAPC_STATE结构的不透明指针
);
此处如果需要附加进程栈则必须提供该进程的PRKPROCESS也就是EProcess结构,此结构可通过PsLookupProcessByProcessId()获取到,该函数接收一个进程PID并将此PID转为EProcess结构,函数定义如下;
NTSTATUS PsLookupProcessByProcessId([in] HANDLE ProcessId, // 进程PID[out] PEPROCESS *Process // 输出EP结构
);
基本的函数介绍完了,那么这段代码应该不难理解了,如下代码中需要注意一点,参数OUT PVOID Buffer用于输出堆地址而不是输入地址。
#include <ntifs.h>
#include <windef.h>// 定义声明
NTSTATUS ZwAllocateVirtualMemory(__in HANDLE ProcessHandle,__inout PVOID *BaseAddress,__in ULONG_PTR ZeroBits,__inout PSIZE_T RegionSize,__in ULONG AllocationType,__in ULONG Protect
);// 分配内存空间
NTSTATUS AllocMemory(IN ULONG ProcessPid, IN SIZE_T Length, OUT PVOID Buffer)
{NTSTATUS Status = STATUS_SUCCESS;PEPROCESS pEProcess = NULL;KAPC_STATE ApcState = { 0 };PVOID BaseAddress = NULL;// 通过进程PID得到进程EProcessStatus = PsLookupProcessByProcessId((HANDLE)ProcessPid, &pEProcess);if (!NT_SUCCESS(Status) && !MmIsAddressValid(pEProcess)){return STATUS_UNSUCCESSFUL;}// 验证内存可读if (!MmIsAddressValid(pEProcess)){return STATUS_UNSUCCESSFUL;}__try{// 附加到进程栈KeStackAttachProcess(pEProcess, &ApcState);// 分配内存Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &BaseAddress, 0, &Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);RtlZeroMemory(BaseAddress, Length);// 返回内存地址*(PVOID*)Buffer = BaseAddress;// 脱离进程栈KeUnstackDetachProcess(&ApcState);}__except (EXCEPTION_EXECUTE_HANDLER){KeUnstackDetachProcess(&ApcState);Status = STATUS_UNSUCCESSFUL;}ObDereferenceObject(pEProcess);return Status;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint(("hello lyshark \n"));DWORD process_id = 4160;DWORD create_size = 1024;DWORD64 ref_address = 0;NTSTATUS Status = AllocMemory(process_id, create_size, &ref_address);DbgPrint("对端进程: %d \n", process_id);DbgPrint("分配长度: %d \n", create_size);DbgPrint("分配的内核堆基址: %p \n", ref_address);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
运行如上代码片段,则会在进程PID=4160中开辟一段堆空间,输出效果如下;

与创建堆相对ZwFreeVirtualMemory()则用于销毁一个堆,其微软定义如下所示;
NTSYSAPI NTSTATUS ZwFreeVirtualMemory([in] HANDLE ProcessHandle, // 进程句柄[in, out] PVOID *BaseAddress, // 堆基址[in, out] PSIZE_T RegionSize, // 销毁长度[in] ULONG FreeType // 释放类型
);
相对于创建来说,销毁堆则必须传入堆空间BaseAddress基址,以及堆空间的RegionSize长度,需要格外注意FreeType参数,这是一个位掩码,其中包含描述ZwFreeVirtualMemory将为页面指定区域执行的任意操作类型。如果传入MEM_DECOMMIT则将取消提交页面的指定区域,页面进入保留状态。而如果设置为MEM_RELEASE则堆地址将被立即释放。
销毁堆空间FreeMemory()的完整代码如下所示,销毁是我们使用MEM_RELEASE参数即立即销毁。
#include <ntifs.h>
#include <windef.h>// 申请堆
NTSTATUS ZwAllocateVirtualMemory(__in HANDLE ProcessHandle,__inout PVOID *BaseAddress,__in ULONG_PTR ZeroBits,__inout PSIZE_T RegionSize,__in ULONG AllocationType,__in ULONG Protect
);// 销毁堆
NTSYSAPI NTSTATUS ZwFreeVirtualMemory(__in HANDLE ProcessHandle,__inout PVOID *BaseAddress,__inout PSIZE_T RegionSize,__in ULONG FreeType
);// 分配内存空间
NTSTATUS AllocMemory(IN ULONG ProcessPid, IN SIZE_T Length, OUT PVOID Buffer)
{NTSTATUS Status = STATUS_SUCCESS;PEPROCESS pEProcess = NULL;KAPC_STATE ApcState = { 0 };PVOID BaseAddress = NULL;// 通过进程PID得到进程EProcessStatus = PsLookupProcessByProcessId((HANDLE)ProcessPid, &pEProcess);if (!NT_SUCCESS(Status) && !MmIsAddressValid(pEProcess)){return STATUS_UNSUCCESSFUL;}// 验证内存可读if (!MmIsAddressValid(pEProcess)){return STATUS_UNSUCCESSFUL;}__try{// 附加到进程栈KeStackAttachProcess(pEProcess, &ApcState);// 分配内存Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &BaseAddress, 0, &Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);RtlZeroMemory(BaseAddress, Length);// 返回内存地址*(PVOID*)Buffer = BaseAddress;// 脱离进程栈KeUnstackDetachProcess(&ApcState);}__except (EXCEPTION_EXECUTE_HANDLER){KeUnstackDetachProcess(&ApcState);Status = STATUS_UNSUCCESSFUL;}ObDereferenceObject(pEProcess);return Status;
}// 注销内存空间
NTSTATUS FreeMemory(IN ULONG ProcessPid, IN SIZE_T Length, IN PVOID BaseAddress)
{NTSTATUS Status = STATUS_SUCCESS;PEPROCESS pEProcess = NULL;KAPC_STATE ApcState = { 0 };Status = PsLookupProcessByProcessId((HANDLE)ProcessPid, &pEProcess);if (!NT_SUCCESS(Status) && !MmIsAddressValid(pEProcess)){return STATUS_UNSUCCESSFUL;}if (!MmIsAddressValid(pEProcess)){return STATUS_UNSUCCESSFUL;}__try{// 附加到进程栈KeStackAttachProcess(pEProcess, &ApcState);// 释放内存Status = ZwFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &Length, MEM_RELEASE);// 脱离进程栈KeUnstackDetachProcess(&ApcState);}__except (EXCEPTION_EXECUTE_HANDLER){KeUnstackDetachProcess(&ApcState);Status = STATUS_UNSUCCESSFUL;}ObDereferenceObject(pEProcess);return Status;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint(("hello lyshark \n"));DWORD process_id = 4160;DWORD create_size = 1024;DWORD64 ref_address = 0;NTSTATUS Status = AllocMemory(process_id, create_size, &ref_address);DbgPrint("对端进程: %d \n", process_id);DbgPrint("分配长度: %d \n", create_size);DbgPrint("分配的内核堆基址: %p \n", ref_address);Status = FreeMemory(process_id, create_size, ref_address);DbgPrint("销毁堆地址: %p \n", ref_address);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}
编译并运行如上这段代码,代码会首先调用AllocMemory()函数实现分配堆,然后调用FreeMemory()函数销毁堆,并输出销毁地址,如下图所示;

相关文章:
3.1 Windows驱动开发:内核远程堆分配与销毁
在开始学习内核内存读写篇之前,我们先来实现一个简单的内存分配销毁堆的功能,在内核空间内用户依然可以动态的申请与销毁一段可控的堆空间,一般而言内核中提供了ZwAllocateVirtualMemory这个函数用于专门分配虚拟空间,而与之相对应…...
C++: 模板初阶
文章目录 一. 泛型编程二. 函数模板函数模板的原理函数模板的实例化隐式实例化: 让编译器根据实参推演模板参数的实际类型显示实例化: 在函数名后的<>中制定模板参数的世纪类型 模板参数的匹配原则 三. 类模板类模板的定义格式类模板的实例化 一. 泛型编程 如何实现一个…...
人工智能基础_机器学习036_多项式回归升维实战3_使用线性回归模型_对天猫双十一销量数据进行预测_拟合---人工智能工作笔记0076
首先我们拿到双十一从2009年到2018年的数据 可以看到上面是代码,我们自己去写一下 首先导包,和准备数据 from sklearn.linear_model import SGDRegressor import numpy as np import matplotlib.pyplot as plt X=np.arange(2009.2020)#左闭右开,2009到2019 获取从2009到202…...
【算法挨揍日记】day29——139. 单词拆分、467. 环绕字符串中唯一的子字符串
139. 单词拆分 139. 单词拆分 题目描述: 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 解题思路&am…...
YOLOv8-Seg改进:轻量级Backbone改进 | VanillaNet极简神经网络模型 | 华为诺亚2023
🚀🚀🚀本文改进:一种极简的神经网络模型 VanillaNet,支持vanillanet_5, vanillanet_6, vanillanet_7, vanillanet_8, vanillanet_9, vanillanet_10, vanillanet_11等版本,相比较yolov8-seg各个版本如下: layersparametersgradientsGFLOPsvanillanet_521230017523...
解决Requests中使用httpbin服务器问题:自定义URL的实现与验证
问题背景 在使用Python的Requests模块进行单元测试时,可能会遇到无法使用本地运行的httpbin服务器进行测试的问题。这是因为测试脚本允许通过环境变量HTTPBIN_URL指定用于测试的本地httpbin实例,但在某些测试用例中,URL是硬编码为httpbin.or…...
软考-高级-系统架构设计师教程(清华第2版)【第17章 通信系统架构设计理论与实践(P614~646)-思维导图】
软考-高级-系统架构设计师教程(清华第2版)【第17章 通信系统架构设计理论与实践(P614~646)-思维导图】 课本里章节里所有蓝色字体的思维导图...
【MATLAB源码-第82期】基于matlab的OFDM系统载波频移偏差(CFO)估计,对比三种不同的方法。
操作环境: MATLAB 2013b 1、算法描述 正交频分复用(OFDM)系统中的载波频率偏移(CFO)估计是一项关键技术,用于确保数据传输的准确性和效率。CFO通常由于振荡器频率不匹配和多普勒频移引起。不同的CFO估计…...
Docker Swarm: 容器编排的力量和优势深度解析
文章目录 Docker Swarm的核心概念1. 节点(Node)2. 服务(Service)3. 栈(Stack) 使用Docker Swarm1. 初始化Swarm2. 加入节点3. 创建服务4. 扩展和缩减服务5. 管理栈6. 管理服务更新 Docker Swarm的优势深度解…...
调整Windows键盘上只能看到拼音而无法看到实际的文本以及关闭输入法悬浮窗方法
一、输入法设置 如果您在键盘上只能看到拼音而无法看到实际的文本,这可能是因为您的输入法设置为中文拼音输入法或其他仅显示拼音的输入法。 要解决这个问题,您可以尝试以下方法: 1. 切换输入法:按下 Shift Alt 组合键或 Wind…...
【微软技术栈】C#.NET 中的管道操作
C#.NET 管道为进程间通信提供了平台。 管道分为两种类型: 匿名管道。 匿名管道在本地计算机上提供进程间通信。 与命名管道相比,虽然匿名管道需要的开销更少,但提供的服务有限。 匿名管道是单向的,不能通过网络使用。 仅支持一个服…...
Python学习笔记--进程
进程 Python 中的多线程其实并不是真正的多线程,如果想要充分地使用多核 CPU 的资源,在 Python 中大部分情况需要使用多进程。 Python 提供了非常好用的多进程包 multiprocessing,只需要定义一个函数,Python 会完成其他所有事情。 借助这个包,可以轻松完成从单进程到并…...
比亚迪刀片电池与特斯拉4680电池比较
1 电池材料 比亚迪刀片电池采用的磷酸铁锂LFP(LiFePO4),特斯拉的4680电池采用的三元锂。 磷酸铁锂:循环寿命长,安全性能好,价格低廉,但是能量密度低,导电性能差,低温表现…...
在写windows C++代码的时候,从代码安全角度考虑,我们应该注意什么?
在写windows C代码的时候,从代码安全角度考虑,我们应该注意什么?分别是:输入验证、内存管理、错误处理、并发和线程安全、使用安全的API、避免使用不安全的函数、最小权限原则。 一、输入验证 1. 用户输入验证 #include <io…...
【草料】uni-app ts vue 小程序 如何如何通过草料生成对应的模块化二维码
一、查看uni-app项目 1、找到路径 可以看到项目从 src-race-pages-group 这个使我们目标的查询页面 下面我们将这个路径copy到草料内 2、找到进入页面入参 一般我们都会选择 onload() 函数下的入参 这里我们参数的是 id 二、草料 建议看完这里的教程文档 十分清晰!…...
CMS与FullGC
JVM中的CMS(Concurrent Mark Sweep)GC和Full GC(Full Garbage Collection)是两种不同的垃圾回收算法。 CMS GC:CMS GC是一种并发的垃圾回收算法,它在运行期间与应用程序线程并发工作,尽可能减少…...
一款.NET开源的小巧、智能、免费的Windows内存清理工具 - WinMemoryCleaner
前言 我们在使用Windows系统的时候经常会遇到一些程序不会释放已分配的内存,从而导致电脑变得缓慢。今天给大家推荐一款.NET开源的小巧、智能、免费的Windows内存清理工具:WinMemoryCleaner。 使用Windows内存清理工具来优化内存,这样不必浪…...
iptables详解:链、表、表链关系、规则的基本使用
目录 防火墙基本概念 什么是防火墙? Netfilter与iptables的关系 链的概念 表的概念 表链关系 规则的概念 查询规则 添加规则 删除iptables中的记录 修改规则 更详细的命令(5链4表) 防火墙基本概念 什么是防火墙? 在…...
安全管理中心(设备和技术注解)
网络安全等级保护相关标准参考《GB/T 22239-2019 网络安全等级保护基本要求》和《GB/T 28448-2019 网络安全等级保护测评要求》 密码应用安全性相关标准参考《GB/T 39786-2021 信息系统密码应用基本要求》和《GM/T 0115-2021 信息系统密码应用测评要求》 1系统管理 1.1对系统管…...
Failed to execute org.scala-tools:maven-scala-plugin:2.15.2解决
原因也不是很清楚,查看一个博主文章(net.alchim31.maven:scala-maven-plugin:maven依赖无法下载或无法编译)得到的解决方案: 在idea的terminal执行以下语句即可实现maven对scala代码的编译: mvn clean scala:compile compile pac…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
