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…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
spring Security对RBAC及其ABAC的支持使用
RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型,它将权限分配给角色,再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...
