Windows驅動內存操作

內存複製

內存複製分兩種情況,非重疊和可重疊

如圖:當複製A~C到B~D段內存b-c段內存重疊

RtlCopyMemory爲非重疊複製,即不能使用RtlCopyMemory操作上圖中的內存段,RtlMoveMemory爲可重疊複製,此函數對內存是否重疊進行判斷。

void RtlCopyMemory(
   Destination,   //表示要複製內存的目的地址
   Source,        //表示要複製內存的源地址
   Length         //表示複製內存長度,單位是字節
);
void RtlMoveMemory(
   Destination,    //表示要複製內存目的地址
   Source,         //表示要複製內存的源地址
   Length          //表示要複製內存的長度,單位是字節
);

與RtlCopyMemory相似函數RtlcopyBytes,這個函數參數一樣,功能完全一樣。RtlCopyMemory函數的內部實現方法是依靠memcpy函數實現的,C99定義,memcpy沒有考慮重疊部分,因此它不能保障重疊部分是否被複制。

RtlMoveMemory內部實現爲memmove,爲了保證重疊部分正確複製,C99規定memmove函數完成,這個函數對兩個內存是否重疊進行了判斷,但影響到速度,如果能確保複製的內存沒有重疊,使用memcpy函數。爲了保證可移植性,DDK用宏對memmove進行了封裝,即RtlMoveMemory。

內存填充

固定字節填充:RtlFillMemory

//依靠memset實現
#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length))
//函數定義
void RtlFillMemory(
   Destination,         //目的地址
   Length,               //長度    
   Fill               // 需要填充的字節
);

內存填零:RtlZeroMemory

#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
//定義
void RtlZeroMemory(
   Destination,        //目的地址
   Length              //長度
);

內存比較

RtlCompareMemory比較兩塊內存是否一致。

RtlCompareMemory(
    _In_ const VOID* Source1,    //比較第一個內存地址
    _In_ const VOID* Source2,    //比較第二個內存地址
    _In_ SIZE_T Length           //比較長度,單位爲字節
    );
//返回值:相等的字節數

如果RtlCompareMemory返回值與指定的Length相等兩個內存完全一致

同時,RtlEqualMemory直接判斷兩段內存是否一致,當兩段內存一致返回非零值,不一致返回零值。

#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length)))

內存操作示例:

VOID RtlTestMemory() {
	PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE);
	//用零填充內存
	RtlZeroMemory(pBuffer,BUFFER_SIZE);
	PUCHAR pBuffer2 = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE);
	//用固定字節填充內存  (用AA填充)
	RtlFillMemory(pBuffer2,BUFFER_SIZE,0xAA);
	//內存複製
	RtlCopyMemory(pBuffer,pBuffer2,BUFFER_SIZE);
	//判斷內存是否一致
	ULONG uRet = RtlCompareMemory(pBuffer,pBuffer2,BUFFER_SIZE);
	if (uRet == BUFFER_SIZE) {
		KdPrint(("The two blocks are same.\n"));
	}
	//宏判斷內存是否一致
	ULONG uRet=RtlEqualMemory(pBuffer,pBuffer2,BUFFER_SIZE);
	if (uRet != 0) {
		KdPrint(("The two blocks are same.\n"));
	}
} 

使用Lookaside提高申請內存效率

頻繁向系統申請內存會導致內存空洞,即使用內存中有大量可用內存,也會導致申請失敗,在系統空閒時候,系統會整理內存中

空洞,將內存中空洞進行合併。

內存空洞實際是連續申請內存時,內存是連續的,期間有內存回收後再次申請比回收的大是就無法申請成功,導致內存空洞。如圖:

在操作系統空閒時,系統會整理內存空洞,將內存中的空洞進行合併。

使用Lookaside時,它會事先向windows申請一塊比較大的內存,程序員申請內存時是向Lookaside對象申請內存。Lookaside會避免內存空洞。當Lookaside內存不夠用會繼續向windows申請更多內存。當有大量未使用的內存時,會自動讓windows回收。Lookaisde類似於自動的內存分配容器。使用Lookaside效率高於直接向windows申請內存。

Lookaside使用場景

  1. 每次申請固定大小的內存
  2. 申請和回收內存操作頻繁

Lookaside對象使用工程:初始化-->申請內存-->內存回收-->刪除Lookaside對象。

Lookaside對象非分頁與分頁初始化:

//非分頁初始化
VOID ExInitializeNPagedLookasideList (
    _Out_ PNPAGED_LOOKASIDE_LIST Lookaside,
    _In_opt_ PALLOCATE_FUNCTION Allocate,
    _In_opt_ PFREE_FUNCTION Free,
    _In_ ULONG Flags,
    _In_ SIZE_T Size,
    _In_ ULONG Tag,
    _In_ USHORT Depth
    );
//分頁初始化
VOID ExInitializePagedLookasideList (
    _Out_ PPAGED_LOOKASIDE_LIST Lookaside,
    _In_opt_ PALLOCATE_FUNCTION Allocate,
    _In_opt_ PFREE_FUNCTION Free,
    _In_ ULONG Flags,
    _In_ SIZE_T Size,
    _In_ ULONG Tag,
    _In_ USHORT Depth
    );

Lookaside對象非分頁與分頁申請內存:

//非分頁申請
PVOID ExAllocateFromNPagedLookasideList (
    _Inout_ PNPAGED_LOOKASIDE_LIST Lookaside
    )
//分頁申請
PVOID ExAllocateFromPagedLookasideList (
    _Inout_ PPAGED_LOOKASIDE_LIST Lookaside
    )

Lookaside對象非分頁與分頁內存回收:

//非分頁內存回收
VOID ExFreeToNPagedLookasideList (
    _Inout_ PNPAGED_LOOKASIDE_LIST Lookaside,
    _In_ __drv_freesMem(Mem) PVOID Entry
    )
//分頁內存回收
VOID ExFreeToPagedLookasideList (
    _Inout_ PPAGED_LOOKASIDE_LIST Lookaside,
    _In_ __drv_freesMem(Mem) PVOID Entry
    )

刪除Lookaside對象:

//非分頁刪除Lookaside對象
VOID ExDeleteNPagedLookasideList (
    _Inout_ PNPAGED_LOOKASIDE_LIST Lookaside
    );
//分頁刪除Lookaside對象
VOID ExDeletePagedLookasideList (
    _Inout_ PPAGED_LOOKASIDE_LIST Lookaside
    );

Lookaside對象使用實例:

#define ARRAY_NUMBER 50

typedef struct _MYDATASTRUCT {
	LIST_ENTRY ListEntry;
	ULONG x;
	ULONG y;
}MYDATASTRUCT,*PMYDATASTRUCT;

//LookasideTest函數實現Lookaside操作

VOID LookasideTest() {
	//初始化Lookaside對象
	PAGED_LOOKASIDE_LIST pageList;
	ExInitializePagedLookasideList(&pageList,NULL,NULL,0,sizeof(MYDATASTRUCT),'1234',0);
	PMYDATASTRUCT MyObjectarry[ARRAY_NUMBER];
	//頻繁申請內存
	for (int i = 0; i < ARRAY_NUMBER; i++) {
		MyObjectarry[i] = (PMYDATASTRUCT)ExAllocateFromPagedLookasideList(&pageList);
	}
	//頻繁回收內存
	for (int i = 0; i386 < ARRAY_NUMBER; i++)
	{
		ExFreeToPagedLookasideList(&pageList,MyObjectarry[i]);
		MyObjectarry[i] = NULL;
	}
	//刪除Lookaside對象
	ExDeletePagedLookasideList(&pageList);
}

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章