在开始学习内核内存读写篇之前,我们先来实现一个简单的内存分配销毁堆的功能,在内核空间内用户依然可以动态的申请与销毁一段可控的堆空间,一般而言内核中提供了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
属性。
在对特定进程分配堆时第一步就是要切入到该进程的进程栈中&