• 内存操作相关内核 API 的使用


    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 
            指向调用者提供的内存块的指针相对于Source1的内存块。
    Fill

            待比较内存的长度,单位为字节。

    返回值

         返回两块内存相等的字节数,并且如果一致就返回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 ")); 

    KdPrint(("Allocate size :%d ",size)); 

    return ExAllocatePool(PagedPool,size); 

    2、delete

    作用:重载delete,也就是用来释放内存。所以这个函数里面要用到 ExFreePool API函数,让其达到重载 delete 这个函数不用直接调用 ExFreePool 这个API函数也能释放内存的目的。

    void __cdecl operator delete(void* pointer) {
    KdPrint(("Global delete operator "));

     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
    ")); 
        KdPrint(("Allocate size :%d
    ", size));
        return ExAllocatePool(PagedPool, size);  //分配内存
    } 
    
    
    //重载delete  
    void __cdecl operator delete(void* pointer) {
        KdPrint(("Global delete operator
    "));
        ExFreePool(pointer);//释放指针 
    }  
    
    
    
    #pragma INITCODE
    VOID MemoryOpe() {    
        VOID UNALIGNED *d;  //有关于WIN64的定义,无符号 
        VOID UNALIGNED *s;
        SIZE_T Length = 8; //无符号类型  
        ULONG ulRet; 
        char *buffer = new (PagedPool)  char[111]; //分配111字节指针
        delete buffer;  
        //为s指针分配大小为字节的内核内存  
        s=ExAllocatePool(PagedPool,Length);
        KdPrint(("s=%x 
    ",(int*)s));
        //  _asm int 3 db 
        //为d指针分配大小为字节的内核内存
        d=ExAllocatePool(PagedPool,Length);
        //  __asm int 3 db 
        KdPrint(("d=%x 
    ", (int*)d));
        //用来填充s指针指向的内存填充长度为Length=8
        RtlFillMemory(s,Length,'s');
        //  __asm int 3 db  
        KdPrint(("RtlFillMemory 1 
    "));
        //复制S指针指向的内容到D地址复制长度为Length=8
        RtlCopyMemory(d,s,Length); //memcpy
        //  __asm int 3 
        KdPrint(("RtlCopyMemory s to d 
    "));
        //复制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 内存块相同.
    "));
        }
        else{
            KdPrint(("111 D和S 内存块不相同
    "));
        }
    
    
        //清空S指针指向地址
        RtlZeroBytes(s,Length);  
        ulRet = RtlCompareMemory(d, s, Length);
        if (ulRet == Length){  //如果返回值    
            KdPrint(("222 D和S 内存块相同.
    "));
        }
        else{
            KdPrint(("222 D和S 内存块不相同
    "));
        } 
        ExFreePool(s);
        return;  
    }

    建议在驱动入口函数 DriverEntry 函数中的设备加载过程执行后,再调用此内存操作过程。

    在虚拟机下执行过程, 首先是填充了S和D相同的数据所以相同, 然后由于清空S所以S和D就不相同了。

    最后将尽量用DDK的RtlCompareMemory函数可移植性比较好.

  • 相关阅读:
    Java 面向对象_继承
    Java 面向对象
    使用 pykafka 进行消费
    oracle 的分页、截断查询
    Day03
    Day02 计算机的组成与编程语言
    Day01 MarkDown的使用
    Java方法的重点
    Scanner的小细节
    Java包机制和Javadoc的使用
  • 原文地址:https://www.cnblogs.com/lfls128/p/5020282.html
Copyright © 2020-2023  润新知