1、RtlCopyMemory 、RtlCopyBytes、RtlMoveMemory;
2、RtlZeroMemory、RtlFillMemory;
3、RtlEqualMemory;
4、ExAllocatePool、ExFreePool;
5、New(重载)、Delete *** 作符
一、内存的复制与移动
1、RtlCopyMemory
作用:把一个缓冲区的内容复制到另一一个缓冲区。
VOID RtlCopyMemory(
IN VOID UNALIGNED *Destination,
IN CONST VOID UNALIGNED *Source,
IN SIZE_T Length
);
- Destination
指针移动的目的地(也就是要粘贴的地方)。
- Source
- 指针指向的要复制的内存 .
- Length
- 指定要复制的字节数。
无
但是如果内存有互相覆盖的情况可能出错,因为源和目的重叠的部分有可能还没读取就被写入了,要用 RtlMoveMemory 进行移除。
2、RtlCopyBytes
作用:复制给定的字节数从一个位置到另一个地方。
VOID RtlCopyBytes(
IN PVOID Destination,
IN CONST VOID *Source,
IN SIZE_T Length
);
- Destination
指向目的地的字节(也就是要粘贴的地方)。
- Source
- 指针指向的复制的内存.
- Length
指定要复制的字节数。
无
推荐驱动应该使用 RtlCopyMemory 进行常规 *** 作,而不是 RtlCopyBytes 。
3、RtlMoveMemory
作用:从指定内存中复制内存至另一内存里.简称:复制内存。
RtlCopyMemory非重叠复制,而RtlMoveMemory是重叠复制
对内存进行要么向前或向后移动,或未对齐,对齐在4字节块,紧随其后的是剩余的字节。
VOID RtlMoveMemory(
IN VOID UNALIGNED *Destination,
IN CONST VOID UNALIGNED *Source,
IN SIZE_T Length
);
- Destination
指针移动的目的地(也就是要移到的地方)。
- Source
- 指针指向的复制的内存.
- Length
指定要复制的字节数。
无
•内存的“copy”和“move” *** 作之间的区别在于可否容忍源和目的相重叠。
move *** 作不管源和目的是否重叠。
而copy *** 作在源和目的有任何重叠时不工作。
•“byte” *** 作和“memory” *** 作的区别是 *** 作的间隔尺寸。
byte *** 作保证按字节为单位执行。
而memory *** 作可以在内部使用更大的块,所有这些块的和等于 指定的字节数。
这个区别会根据平台的不同而改变,在32位Intel计算机上,byte *** 作实际上是对应memory *** 作的宏。
但在Alpha平台 上,RtlCopyBytes与RtlCopyMemory是完全不同的函数。
二、内存的填充
1、RtlZeroMemory
作用:用0来填充一块内存区域。
VOID RtlZeroMemory(
IN VOID UNALIGNED *Destination,
IN SIZE_T Length
);
- Destination
指向一块准备用0来填充的内存区域的开始地址。
(也就是要填充的地方)。
- Length
准备用0来填充的内存区域的大小,按字节来计算
无
2、RtlFillMemory
作用:调用者向提供的缓冲区填满给定的字符。
VOID RtlFillMemory(
IN VOID UNALIGNED *Destination,
IN SIZE_T Length,
IN UCHAR Fill
);
- Destination
指针指向的内存(也就是要填充的地方)。
- Length
- 指定的字节数(要填充多少(大))
- Fill
指定填充内存的值。
无
三、内存的比较
1、RtlEqualMemory
作用:对两个内存块进行比较,以确定指定的字节数是相同的。
LOGICAL RtlEqualMemory(
CONST VOID *Source1,
CONST VOID *Source2,
SIZE_T Length
);
- Source1
指针指向一个调用者提供的要比较的内存块。
- Source2
- Fill
指向调用者提供的内存块的指针相对于Source1的内存块。
待比较内存的长度,单位为字节。
返回两块内存相等的字节数,并且如果一致就返回True,否则返回False。
四、内存的分配和释放
1、ExAllocatePool
作用: ExAllocatePool分配池指定类型和返回一个指针指向的内存分配的块。
另外:ExAllocatePool程序已经过时了,出口仅为现有的二进制文件。
建议使用ExAllocatePoolWithTag代替。
PVOID ExAllocatePool(
IN POOL_TYPE PoolType,
IN SIZE_T NumberOfBytes
);
- PoolType
给要分配的内存池指定类型。
- NumberOfBytes
指定要分配的字节数。
如果没有足够的内存空闲池中满足要求,返回NULL。
否则,程序返回一个指向分配的内存的指针。
2、ExFreePool
作用:释放一块内存池。
VOID ExFreePool(
IN PVOID P
);
- P
指定要被收回的内存块地址池。
无
四、内存的重载 *** 作符
1、New
作用:重载New,也就是用来分配内存。
所以这个函数里面要用到 ExAllocatePool API函数,让其达到重载 New 这个函数不用直接调用 ExAllocatePool 这个API函数也能分配内存的目的。
void * __cdecl operator new(size_t size,POOL_TYPE PoolType=PagedPool)
{
KdPrint(("global operator new\n"));
KdPrint(("Allocate size :%d\n",size));
return ExAllocatePool(PagedPool,size);
}
2、delete
作用:重载delete,也就是用来释放内存。
所以这个函数里面要用到 ExFreePool API函数,让其达到重载 delete 这个函数不用直接调用 ExFreePool 这个API函数也能释放内存的目的。
void __cdecl operator delete(void* pointer) {
KdPrint(("Global delete operator\n"));
ExFreePool(pointer);
}
下面看一段代码
#pragma once
#ifdef _cplusplus
extern "C"
{
#endif
#include <NTDDK.h> //这里包含需要用C方式编译的头文件
//#include <winnt.h> 运行库已包含了,就不需要,如果报错就需要添加此头文件
#ifdef _cplusplus
}
#endif //重载new和delete *** 作符
//重载new
void * _cdecl operator new(size_t size, POOL_TYPE PoolType = PagedPool){ // *** 作符重载,否则报错
KdPrint(("global operator new\n"));
KdPrint(("Allocate size :%d\n", size));
return ExAllocatePool(PagedPool, size); //分配内存
} //重载delete
void __cdecl operator delete(void* pointer) {
KdPrint(("Global delete operator\n"));
ExFreePool(pointer);//释放指针
} #pragma INITCODE
VOID MemoryOpe() {
VOID UNALIGNED *d; //有关于WIN64的定义,无符号
VOID UNALIGNED *s;
SIZE_T Length = ; //无符号类型
ULONG ulRet;
char *buffer = new (PagedPool) char[]; //分配111字节指针
delete buffer;
//为s指针分配大小为字节的内核内存
s=ExAllocatePool(PagedPool,Length);
KdPrint(("s=%x \n",(int*)s));
// _asm int 3 db
//为d指针分配大小为字节的内核内存
d=ExAllocatePool(PagedPool,Length);
// __asm int 3 db
KdPrint(("d=%x \n", (int*)d));
//用来填充s指针指向的内存填充长度为Length=8
RtlFillMemory(s,Length,'s');
// __asm int 3 db
KdPrint(("RtlFillMemory 1 \n"));
//复制S指针指向的内容到D地址复制长度为Length=8
RtlCopyMemory(d,s,Length); //memcpy
// __asm int 3
KdPrint(("RtlCopyMemory s to d \n"));
//复制S指针指向的内容到D地址复制长度为Length=8
RtlCopyBytes(d,s,Length);
//判断内存是否一致
ulRet = RtlCompareMemory(d, s, Length); // 返回为1则相等
//RtlEqualMemory(d,s,Length); 在VS下此句编译错误所以就用DDK进行编译和此函数时请用build
if (ulRet == Length){ //如果返回值
KdPrint(("111 D和S 内存块相同.\n"));
}
else{
KdPrint(("111 D和S 内存块不相同\n"));
} //清空S指针指向地址
RtlZeroBytes(s,Length);
ulRet = RtlCompareMemory(d, s, Length);
if (ulRet == Length){ //如果返回值
KdPrint(("222 D和S 内存块相同.\n"));
}
else{
KdPrint(("222 D和S 内存块不相同\n"));
}
ExFreePool(s);
return;
}
建议在驱动入口函数 DriverEntry 函数中的设备加载过程执行后,再调用此内存 *** 作过程。
在虚拟机下执行过程, 首先是填充了S和D相同的数据所以相同, 然后由于清空S所以S和D就不相同了。
最后将尽量用DDK的RtlCompareMemory函数可移植性比较好.
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)