深度剖析WinPcap之(三)――所涉及的Windows驱动基础知识(3)

1.1.6      内核的内存操作

    Windows 驱动程序使用的内存资源非常珍贵,分配内存时要尽量节约。和应用程序一样,局部变量是存放在栈 ( Stack) 空间中的。但栈空间不会像应用程序那么大,所以驱动程序不适台递归调用或者局部变量是大型结构体。如果需要大型结构体,请在堆 ( Heap) 中申请。
    堆中申请内存的函数有以下几个,原型如下:
PVOID   
ExAllocatePool(
IN POOL_TYPE  PoolType,
IN SIZE_T  NumberOfBytes
 );
PVOID   
ExAllocatePoolWithTag(
IN POOL_TYPE  PoolType,
IN SIZE_T  NumberOfBytes,
IN ULONG  Tag
 );
PVOID   
ExAllocatePoolWithQuota(
IN POOL_TYPE  PoolType,
IN SIZE_T  NumberOfBytes
 );
PVOID   
ExAllocatePoolWithQuotaTag(
IN POOL_TYPE  PoolType,
IN SIZE_T  NumberOfBytes,
IN ULONG  Tag 
);
参数 PooIType 是个枚举变量,如果此值为 NonPagedPool ,则分配非分页内存。如果此值为 PagedPool ,则分配内存为分页内存。 Windows 规定有些虚拟内存页面是可以交换到文件中的,这类内存被称为分页内存。而有些虚拟内存页永远不会交换到文件中,这些内存被称为非分页内存。
参数 NumbelofBytes 是分配内存的大小,注意最好是 4 的倍数。
函数返回分配的内存地址,一定是内核模式地址。如果返回 NULL ,则代表分配失败。
    以上四个函数功能类似,函数以 WithQuota 结尾的代表分配的时候按配额分配。函数以 WithTag 结尾的函数,和 ExAllocatePool 功能类似,唯一不同的是多了一个 Tag 参数,系统在要求的内存外又额外地多分配了 4 个字节的标签。在调试的时候,可以找出是否有标有这个标签的内存没有被释放。
将分配的内存,进行回收的函数是 ExFreePool ExFreePoolWithTag ,它们的原型是:
VOID
ExFreePool(
 IN PVOID  P
 );
VOID
ExFreePoolWithTag(
IN PVOID  P,
IN ULONG  Tag
); 
参数 P 就是要释放的地址。
下面的代码为WinPcap中使用内核内存操作的实例:
PWCHAR getAdaptersList(void)
{
   
    PWCHAR DeviceNames = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen,
 '0PWA');
ExFreePool(DeviceNames);
}
 

1.1.7       内存操作的运行时函数

运行时函数是程序运行时必不可少的,由编译器提供。针对不同的操作系统,运行时函数的实现方法不同,但接口基本保持一致。例如, malloc 函数就是典型的运行时函数,所有编译器厂商都必须提供这个函数,但在不同操作系统上的实现方法就不尽相同了。

1.1.7.1     内存间复制(非重叠的情况)

在驱动程序开发中,经常用到内存的复制。 DDK 为程序员提供了 RtlCopyMemory 函数。
VOID
RtlCopyMemory(
    IN VOID UNALIGNED  *Destination,
    IN CONST VOID UNALIGNED  *Source,
    IN SIZE_T  Length
);
参数 Destination 表示要复制内存的目标地址。参数 Source 表示要复制内存的源地址。参数 Length 表示要复制的内存的长度,单位是字节。

1.1.7.2    内存间复制(可重叠的情况)

RtICopyMemory 可以复制内存,但其内部没有考虑目标内存与源内存重叠的情况。对可重叠的情况 DDK 提供了 RtIMoveMemory 函数。
VOID
RtlMoveMemory(
    IN VOID UNALIGNED  *Destination,
    IN CONST VOID UNALIGNED  *Source,
    IN SIZE_T  Length
);
参数 Destination 表示要复制内存的目标地址。参数 Source 表示要复制内存的源地址。参数 Length 表示要复制的内存的长度,单位是字节。

1.1.7.3    填充内存

驱动程序开发中,迹经常用到对某段内存区域用固定字节填充。 DDK 为程序员提供了 RtIFillMemory 函数。
VOID
RtlFillMemory(
    IN VOID UNALIGNED  *Destination,
    IN SIZE_T  Length,
    IN UCHAR  Fill
);
参数 Destination 为目标内存的地址。参数 Length 为待填的长度。参数 Fill 为需要填充的字节。
在驱动程序开发中,还经常要对某段内存填零, DDK 提供了 RtlZeroMemory 函数。
VOID
RtlZeroMemory(
           IN VOID UNALIGNED  *Destination,
            IN SIZE_T  Length
    );
参数 Destination 为目标内存的地址。参数 Length 为待填的长度。

1.1.7.4   内存比较

驱动程序开发中,还会用到比较两块内存是否一致,可采用 RtICompareMemory 函数。
SIZE_T
RtlCompareMemory(
    IN CONST VOID  *Source1,
    IN CONST VOID  *Source2,
    IN SIZE_T  Length
);
参数 Sourcel 为比较的第一个内存地址。参数 Sou:rce2 为比较的第二个内存地址。参数 Length 为比较的长度,单位为字节。
函数返回相等的字节数。
函数 RtIEquaIMemory 通过判断返回值和 Length 是否相等,来判断两块内存是否完全一致。同时 DDK 还提供了 RtlEqualMemory 函数,直接判断两块内存是否一致。
LOGICAL
RtlEqualMemory(
    CONST VOID  *Source1,
    CONST VOID  *Source2,
    SIZE_T  Length
);
函数 RtlEquaIMemory 在两块内存一致的情况下返回非零值,在不一致的情况下返回零。

你可能感兴趣的:(windows,基础,深度,知识,winpcap)