|
#include<ntddk.h>
#define BUFF_SIZE 256
static KEVENT S_event;//初始化一个事件对象
#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
void Unload(PDRIVER_OBJECT drivdr_object)//卸载驱动例程
{
KdPrint(("卸载成功1"));
}
void MySleep(LONG Msec)//定义一个线程睡眠例程
{
LARGE_INTEGER My_int;// LARGE_INTEGER表示一个64位有符号整数,实际上是一个联合,如果你的编译器具有内置64位整数,
//使用成员QuadPart成员,可以使存储64位整数,否则,使用LowPart和HighPart成员的存储的64位整数。
My_int.QuadPart=-10*1000;//将10*100付给成员变量
My_int.QuadPart*=Msec;//乘以MySleep传递进来的
//函数将当前的线程置于指定的时间间隔,(暂停),可报警或不可报警的等待状态
//参数1是指定等待的模式,可以使内核模式或者用户模式,较低级别的驱动应该指定为内核模式
//参数2,如果等待是可警报的则指定为true,较低级别的驱动程序应该指定为false
//参数3,是我们需要等待的时间可以使绝对的时间也可以是相对时间,负值表示相对时间,
KeDelayExecutionThread(KernelMode,0,&My_int);//
KdPrint(("睡眠结束!"));
}
void MyThread(IN PVOID pContext )//线程的回调函数
{
//PEPROCESS 结构,在调用IoGetCurrentProcess函数,该函数返回一个指向当前进程的指针,那么我们需要有一个该结构的成员
//变量来接受
PEPROCESS EPROCESSPROTECT=IoGetCurrentProcess();//获取当前进程的指针,该函数没有参数,并且返回指向当前进程的指针
//接收到该进程对的地址是我们需要加上该进程的偏移量才能得到该进程的名称加上0x174即可得到,进程的名字
PTSTR ProcessName=(PTSTR)((ULONG)EPROCESSPROTECT+0x174);//这里加上0x174就得到了该进程的名字,然后转为ULONG在转为
//PTSTR然后赋给ProcessName
KdPrint((" This Thread Run IN %s Process\n",ProcessName));//打印出获取到的进程名称
MySleep(1000*5);//调用刚刚写的线程睡眠函数
KdPrint(("Create Thread Success"));//输出函数调用成功
//设置事件对象信号,
//参数1指向调用方为其提供存储的舒适化事件对象指针(也可以使地址)该事件对象我们在开头的时候初始化了
//参数2 指定设置事件满足等待时要应用的优先级 ,这里写默认
//参数3 这里我们信号设置为真
KeSetEvent(&S_event,0,TRUE);//将时间设置为真 这样在后面的KeWaitForSingleObject(&S_event,Executive,KernelMode,0,0);就会
//知道 我们的线程完成了
PsTerminateSystemThread(0);//退出线程
}
/*
在进入DriverEntry函数之前会调用iopinvalid_deruver_object地址填满真个majorfuntion数组,该数组是在AEriver_object的函数指针数组它里面的每一个地址对应着相应的irp我们可以通过简单的设置这个数组,
将IRP与相应的派遣函数关联起来
*/
NTSTATUS DriverEntry(PDRIVER_OBJECT pdriver_object,PUNICODE_STRING punicode_string)
{
//------------------------------------------------------------------------------
HANDLE hMyThread;//定义了一个通用句柄handle的成员变量
OBJECT_ATTRIBUTES pObject_Attributes;
//参数1是初始化的事件成员,该成员我们在头部定义了在这里初始化,
//参数2是初始化的类型是同步类型还是通知类型,ynchronizationEvent为同步类型-NotificationEvent为通知事件类型
//参数3是事件对象的初始化状态,这里我们为false,表示状态为激活,
//如果创建的是通知事件,当事件变为激活状态时,需要程序员手动将其改为为激活状态,
//如果为同步事件是,当事件为激发状态时,遇到KeWaitForxxx内核函数是事件对象则自动的变回会激活状态
KeInitializeEvent(&S_event,SynchronizationEvent,FALSE);
//PsCreateSystemThread(&hMyThread,0,NULL,NULL,NULL,MyThread,NULL);
PsCreateSystemThread(
&hMyThread,//参数1是需要一个句柄,这个通用句柄我们在HANDLE hMyThread;定义了一个
0,//指向所需要的的访问权限 一般写0即可
0,//指向OBJECT_ATTRIBUTES pObject_Attributes; 的指针但是这里传递进去后会导致 线程无线等待 目前还不知道原因
NULL,//指定在其地址空间中运行线程的那个进程句柄,可以获取当前的进程句柄NtCurrentProcess宏,来指定当前进程,也可以为空
NULL,//线程的标识,这里我们不关心可以为空
MyThread,//线程的回调函数(开始例程)这个参数指向我们创建的那个线程实例
NULL);//当该函数开始执行时, 提供一个单独的参数传递给我们创建的那个线程,这个参数应该是传递给线程的参数
//这里的第三个参数不能为指向OBJECT_ATTRIBUTES结构的参数,不然加载了驱动会无线等待,具体原因还不清楚
KdPrint(("等待结束之前!\n"));
//等待线程的函数 参数1是指向调用方为其提供的初始化调度程序事件对象
//参数2是等待的原因,驱动程序应将此值设置为Executive,假如为用户工作,并在用户线程的上下文中运行,这种情况下应该讲此
//值设置为UserRequest
//参数3是指定调用方是在内核模式还是用户模式这里我们设置为内核模式 ,因为我们是在内核模式调用
//参数4 是等待的事件是 可报警则为true 否则Wiefalse 这里我们设置为空
//参数5是指定等待的事件,0表示立刻返回
KeWaitForSingleObject(&S_event,Executive,KernelMode,0,0);
KdPrint(("等待结束之后"));
//------------------------------------------------------------------------------
pdriver_object->DriverUnload=Unload;// 指向驱动的卸载回调函数,每一个驱动框架都有一个该函数 可以为空 但是一定要写否则驱动无法下载
return STATUS_SUCCESS;//返回执行状态
//NTSTATUS 是一个32位无符号长整型,在驱动开发中经常用其来返回状态,
//NTSTATUS是一个非常有用的宏定义 通常我们用NT-siuccess来检测返回的状态是否正确
}
|
上一篇: WinInet发送或接收函数超时的Bug & 解决办法下一篇: 蓝屏(BSOD)转储设置,看本文就够了!
|