内存的分配和链表

实现效果

本例最终实现了,启动驱动后会捕获所有打开的应用程序信息,并且在debugview里面打印出应程序的执行名称,和ID号,
在驱动卸载后会打印出所有应用程序的信息,应用程序是保存在链表里面的。

内存分配

查找内存泄露的工具 PoolMonX.exe
在这里插入图片描述

//-----------------内存分配---------------
	PVOID tempbuffer = ExAllocatePoolWithTag(NonPagedPool,0x1000,'xxaa');

在这里插入图片描述

链表

知识点

链表初始化

先定义一个结构 ,和链表头

/// <summary>
/// 自定义的结构体
/// </summary>
typedef struct _Mystruct
{
    
    
	LIST_ENTRY list;//链表的指针,有前后两个指针

	HANDLE pid;

	PEPROCESS peprocessobj;

	BYTE processname[16];
}Mystruct,*PMyStruct;

LIST_ENTRY listhead = {
    
     0 };//链表头

初始化函数

	InitializeListHead(&listhead);//初始化链表头
	DbgPrint("--%p--%p--%p--\n",&listhead,listhead.Flink,listhead.Blink);

运行效果,链表,链表前指针,和后指针都一样
在这里插入图片描述

定义一个回调函数,获取电脑打开软件的信息,就是进程ID

/// <summary>
/// 进程信息的回调函数
/// </summary>
/// <param name="pid">操作系统传入父进程ID</param>
/// <param name="pid2">操作系统传入本进程ID</param>
/// <param name="bcareaf">操作系统传入TRUE表示创建进程 faste 表示结束进程</param>
VOID ProcessNotifyFun(HANDLE pid, HANDLE pid2, BOOLEAN bcareaf)
{
    
    
	//链表测试函数
	if (bcareaf)
	{
    
    
		DbgPrint("process carete,PID id %d", pid2);//打印进程创建信息,和本进程ID

		PEPROCESS tempep =NULL;

		PsLookupProcessByProcessId(pid2, &tempep);

		if (!tempep)
		{
    
    
			return;
		}

	/*  下面的语句需要放到引用文件之后, 
		NTKERNELAPI UCHAR * PsGetProcessImageFileName(__in PEPROCESS Process);		*/
		PCHAR processname = PsGetProcessImageFileName(tempep);

		DbgPrint("Process name is %s", processname);// 打印进程的名字
	}


	return;
}

启用这个回调函数,可以放在入口函数执行

	//创建一个进程通知,当进程发生变化创建或结束的时候,操作系统就自动调用我们自己写的函数ProcessNotifyFun
	//并且把一些相关的信息通过参数的形式传给我们,
	//传回的参数1是父进程ID
	//传回的参数2是自己进程ID
	//传回的参数3如果是真就是Create ,如果是假就是Close,也就是说如果是真就是进程创建,如果是假就是进程结束
	PsSetCreateProcessNotifyRoutine(ProcessNotifyFun,FALSE);

驱动卸载的同时也要卸载这个回调函数的调用

// 加在 VOID DrvUnload(PDRIVER_OBJECT pdriver) 函数里面
PsSetCreateProcessNotifyRoutine(ProcessNotifyFun,TRUE);//移除回调,参数2 TRUE就是移除的意思

执行效果:

打开程序后会显示程序的名字和ID
在这里插入图片描述

把打开的进程信息写入链表

把每次打开的应用程序信息写入 链表结构,本例中 ptempptr 就是用来存放链表结构的
/// <summary>
/// 进程信息的回调函数
/// </summary>
/// <param name="pid">操作系统传入父进程ID</param>
/// <param name="pid2">操作系统传入本进程ID</param>
/// <param name="bcareaf">操作系统传入TRUE表示创建进程 faste 表示结束进程</param>
VOID ProcessNotifyFun(HANDLE pid, HANDLE pid2, BOOLEAN bcareaf)
{
    
    
	//链表测试函数
	if (bcareaf)
	{
    
    
		DbgPrint("process carete,PID id %d", pid2);//打印进程创建信息,和本进程ID

		PEPROCESS tempep = NULL;

		PsLookupProcessByProcessId(pid2, &tempep);

		if (!tempep)
		{
    
    
			return;
		}

		ObDereferenceObject(tempep);//节引用

		PCHAR processname = PsGetProcessImageFileName(tempep);

		DbgPrint("Process name is %s", processname);// 打印进程的名字

		PMyStruct ptempptr = ExAllocatePool(NonPagedPool, sizeof(Mystruct));//申请一个链表结构的内存空间

		if (ptempptr)
		{
    
    
			KIRQL oldirql = 0;

			// 避免多核CPU同时创建进程时,都把打开软件的进程信息同时写到这个链表,这里用自旋锁让他们排队写入
			KeAcquireSpinLock(&spinlock, &oldirql); //上锁,只让一个程序来访问

			PLIST_ENTRY templist = NULL;

			RtlZeroMemory(ptempptr, sizeof(Mystruct));

			//成员赋值
			ptempptr->peprocessobj = tempep;

			ptempptr->pid = pid2;

			RtlCopyMemory(ptempptr->processname, processname, strlen(processname));


			// ptempptr 结构的指针
			//Mystruct 结构的类型
			//list  在参数2结构里面的链表指针的别名
			//templist = CONTAINING_RECORD(ptempptr, Mystruct, list);

			//&listhead 链表头
			InsertTailList(&listhead,&(ptempptr->list));

			KeReleaseSpinLock(&spinlock, oldirql); // 解锁

		}
	}


	return;
}
打印出链表信息,循环链表打印出来,这个打印信息我是写在卸载函数里面的

这里是用到了移除以前的链表,避免了内存泄露

	//遍历链表,打印出链表,本例中就是打印出驱动启动后捕获到所有打开的应用程序的信息
	PLIST_ENTRY temlist = NULL;

	PMyStruct tempptr = NULL;

	while (listhead.Blink !=&listhead)
	{
    
    
		temlist = RemoveTailList(&listhead);//移出链表头,保存到临时指针

		tempptr = CONTAINING_RECORD(temlist,Mystruct,list);

		DbgPrint("--%d--%p--%s", tempptr->pid,tempptr->peprocessobj,tempptr->processname);
		
		ExFreePool(tempptr);//释放掉这个临时保存链表信息的指针

	}

下图的方法是没有用移除链表 ,只用FOR循环遍历链表,打印出链表信息
在这里插入图片描述

执行效果:卸载驱动后会打印出驱动启动和卸载直间打开的所有应用程序的信息

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lygl35/article/details/112884230