VC编程实现内核方法实现进程保护

来源:互联网 发布:视频会议网络传输协议 编辑:程序博客网 时间:2024/06/04 18:42

《Windows Rootkit开发初步》这篇文章大致讲地是Rootkit实现进程隐藏,当时我受益匪浅。后来看到这期另外一篇文章名为《木马编程DIY之线程守护》这篇文章,提到了一个双进程实现进程守护的方法。不过他的引言里提到了Icesword的一种HOOK系统底层函数的方法,但是没有细讲。然后我查询很多资料加上自己的研究,试验成功了这个方法。代码原理和Rootkit文章的原理类似,不过我稍加改进更简洁明了,希望对大家学习驱动开发能有一定的帮助。

原理分析
 大家知道,如果想要结束一个进程,需要获得当前进程的访问权限,方法是先调用系统API函数OpenProcess打开进程。

HANDLE OpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
);

其中设置第一个参数为值PROCESS_ALL_ACCESS。而实际上OpenProcess这个API对应了内核的NtOpenProcess函数。这个我们可以用IceSword查看到,如图1所示,它个系统的SSDT表。我们更改NtOpenProcess的默认地址,就可以实现对NtOpenProcess函数的过滤了(这个原理和HOOK API原理类似)。当调用NtOpenProcess时,我们先判断是否为我们指定要保护的进程,如果不是,则不管它,如果是,则直接返回。这时调用OpenProcess的程序(因为程序调用的是OpenProcess在Kernel32.dll上的导出函数到ntdll.dll的NtOpenProcess函数,最后到内核的NtOpenProcess,具体信息可以查阅一些内核方面的资料)没有获得到正确的访问权限,当调用TerminateProcess结束进程的时候就会出错。

图1

步骤整理
 第一步:修改SSDT表来实现对NtOpenProcess的挂钩。
  第二步:通过自定义的NtOpenProcess函数过滤传递进来的PID(进程ID,用于标识进程,PID不会有重复值,一个进程一个,可能不连续)。
  
开发准备
 首先我们需要DDK。我用的是Windows 2003的DDK,也有Windows XP/2000的DDK,不过Windows 2003的在Windows XP下一样可以使用。安装好后,在开始菜单里就找到相应的内容,如图2所示。选择后会出现一个控制台,进入到代码的目录后,使用Build命令就可以编译相应的文件了(选择Windows XP Free Build Environment 则可以生成发布版,也就是说给别人用的,Checked版本是调试版本,对方没有DDK则无法运行,这里随便选都可以,似乎没有影响),如图3所示。

图2

图3
驱动编译和一般的编译方法不太一样,需要一个source和一个makefile两个文件(都没有扩展名),两个文件指示了哪些文件是需要编译的文件以及编译后的一些信息。
makefile内容如下:

!INCLUDE $(NTMAKEENV)\makefile.def

source内容如下
TARGETNAME=Protect
TARGETPATH=.\sys
TARGETTYPE=DRIVER
SOURCES=Protect.c

其中Protect.c是源文件。

代码分析
 下面我们就开始编写代码。先建立一个设备,这样就可以通过程序动态的控制要保护的PID,否则每次PID都会变,我们的程序就没有实际价值了。

#include "ntddk.h"

#define NT_DEVICE_NAME      L"\\Device\\ProtectProcess"
#define DOS_DEVICE_NAME     L"\\DosDevices\\ProtectProcess"

#define IOCTL_PROTECT_CONTROL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

NTSTATUS DispatchDeviceControl(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp);
VOID OnUnload(IN PDRIVER_OBJECT DriverObject);

VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
//卸载时会调用
UNICODE_STRING DeviceLinkString;
PDEVICE_OBJECT DeviceObjectTemp1=NULL;
PDEVICE_OBJECT DeviceObjectTemp2=NULL;

DbgPrint("驱动程序卸载...\n");

RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&DeviceLinkString);
if(DriverObject)
{
DeviceObjectTemp1=DriverObject->DeviceObject;
while(DeviceObjectTemp1)
{
DeviceObjectTemp2=DeviceObjectTemp1;
DeviceObjectTemp1=DeviceObjectTemp1->NextDevice;
IoDeleteDevice(DeviceObjectTemp2);
}

DbgPrint("设备已经卸载\n");
DbgPrint("驱动卸载完毕.\n");
}

NTSTATUS DispatchDeviceControl(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp)
{
//IRP_MJ_DEVICE_CONTROL的响应函数
NTSTATUS nStatus = STATUS_SUCCESS;
ULONG IoControlCode = 0;
PIO_STACK_LOCATION IrpStack = NULL;
long* inBuf = NULL;
char* outBuf = NULL;
ULONG inSize = 0;
ULONG outSize = 0;
PCHAR buffer = NULL;
PMDL mdl = NULL;

Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IrpStack = IoGetCurrentIrpStackLocation(Irp);

switch(IrpStack->MajorFunction)
{
case IRP_MJ_CREATE:
DbgPrint("IRP_MJ_CREATE 被调用\n");
break;
case IRP_MJ_CLOSE:
DbgPrint("IRP_MJ_CLOSE 被调用\n");
break;
case IRP_MJ_DEVICE_CONTROL:
DbgPrint("IRP_MJ_DEVICE_CONTROL 被调用\n");
IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch(IoControlCode)
{
case IOCTL_PROTECT_CONTROL:
inSize = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
outSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
inBuf = (long*)Irp->AssociatedIrp.SystemBuffer;

DbgPrint("===========================\n");
DbgPrint("IOCTL_PROTECT_CONTROL 被调用,通讯成功!\n");
DbgPrint("输入缓冲区大小: %d\n",inSize);
DbgPrint("输出缓冲区大小: %d\n",outSize);
DbgPrint("输入缓冲区内容: %ld\n",*inBuf);
DbgPrint("当前保护进程ID: %ld\n",pid);
DbgPrint("===========================\n"); 

strcpy(Irp->UserBuffer,"OK!\n");
break;
default:
break;
}
break;
default:
DbgPrint("未知请求包被调用\n");
break;
}
nStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return nStatus;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING theRegistryPath)
{//驱动入口函数
NTSTATUS        ntStatus = STATUS_SUCCESS;
UNICODE_STRING  ntDeviceName;
UNICODE_STRING  DeviceLinkString;
PDEVICE_OBJECT  deviceObject = NULL;
DbgPrint("驱动程序加载...\n");
RtlInitUnicodeString( &ntDeviceName, NT_DEVICE_NAME );
ntStatus = IoCreateDevice(
DriverObject,
0,
&ntDeviceName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject );

if ( !NT_SUCCESS( ntStatus ) )
{
DbgPrint("无法创建驱动设备");
return ntStatus;
}

RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
ntStatus=IoCreateSymbolicLink(&DeviceLinkString,&ntDeviceName);

if(!NT_SUCCESS(ntStatus))
{
DbgPrint("无法创建驱动设备");
return ntStatus;
}

DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
DriverObject->DriverUnload = OnUnload;

DbgPrint("驱动程序已经启动\n");
DbgPrint("驱动程序加载完毕.\n");
return STATUS_SUCCESS;
}

以上就是一个标准的设备驱动的代码。这个代码定义了一个通讯命令 IOCTL_PROTECT_CONTROL,我们定义这个命令的作用就是传递进PID。下面我们修改部分代码,来实现SSDT的挂钩和进程保护。

#include "ntddk.h"

#define NT_DEVICE_NAME      L"\\Device\\ProtectProcess"
#define DOS_DEVICE_NAME     L"\\DosDevices\\ProtectProcess"

#define IOCTL_PROTECT_CONTROL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

NTSTATUS DispatchDeviceControl(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp);
VOID OnUnload(IN PDRIVER_OBJECT DriverObject);

#pragma pack(1) //SSDT表的结构
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //Used only in checked build
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
}ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; //变量名是不能变的,因为是从外部导入
//这个是查询某个函数的地址的一个宏
#define SYSTEMSERVICE(_function)  KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]

NTSYSAPI NTSTATUS NTAPI ZwOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL);
typedef NTSTATUS (*ZWOPENPROCESS)(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL);

ZWOPENPROCESS OldZwOpenProcess;
long pid = 0;

NTSTATUS NewZwOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL)
{//用来替换的新函数
NTSTATUS nStatus = STATUS_SUCCESS;
if((long)ClientId->UniqueProcess == pid)
{
DbgPrint("保护进程 PID:%ld\n",pid);
return STATUS_ACCESS_DENIED;
}

//剩下的交给我们的原函数
nStatus = OldZwOpenProcess(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId);
return STATUS_SUCCESS;
}

VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
//卸载时会调用
UNICODE_STRING DeviceLinkString;
PDEVICE_OBJECT DeviceObjectTemp1=NULL;
PDEVICE_OBJECT DeviceObjectTemp2=NULL;
DbgPrint("驱动程序卸载...\n");
RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&DeviceLinkString);
if(DriverObject)
{
DeviceObjectTemp1=DriverObject->DeviceObject;
while(DeviceObjectTemp1)
{
DeviceObjectTemp2=DeviceObjectTemp1;
DeviceObjectTemp1=DeviceObjectTemp1->NextDevice;
IoDeleteDevice(DeviceObjectTemp2);
}

DbgPrint("设备已经卸载\n");
DbgPrint("修复SSDT表\n");
(ZWOPENPROCESS)(SYSTEMSERVICE(ZwOpenProcess)) = OldZwOpenProcess;
DbgPrint("驱动卸载完毕.\n");
}

NTSTATUS DispatchDeviceControl(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp)
{//IRP_MJ_DEVICE_CONTROL的响应函数
NTSTATUS nStatus = STATUS_SUCCESS;
ULONG IoControlCode = 0;
PIO_STACK_LOCATION IrpStack = NULL;

long* inBuf = NULL;
char* outBuf = NULL;
ULONG inSize = 0;
ULONG outSize = 0;
PCHAR buffer = NULL;
PMDL mdl = NULL;

Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;

IrpStack = IoGetCurrentIrpStackLocation(Irp);
switch(IrpStack->MajorFunction)
{
case IRP_MJ_CREATE:
DbgPrint("IRP_MJ_CREATE 被调用\n");
break;
case IRP_MJ_CLOSE:
DbgPrint("IRP_MJ_CLOSE 被调用\n");
break;
case IRP_MJ_DEVICE_CONTROL:
DbgPrint("IRP_MJ_DEVICE_CONTROL 被调用\n");
IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch(IoControlCode)
{
case IOCTL_PROTECT_CONTROL:
inSize = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
outSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
inBuf = (long*)Irp->AssociatedIrp.SystemBuffer;

pid = *inBuf;
DbgPrint("===========================\n");
DbgPrint("IOCTL_PROTECT_CONTROL 被调用,通讯成功!\n");
DbgPrint("输入缓冲区大小: %d\n",inSize);
DbgPrint("输出缓冲区大小: %d\n",outSize);
DbgPrint("输入缓冲区内容: %ld\n",*inBuf);
DbgPrint("当前保护进程ID: %ld\n",pid);
DbgPrint("===========================\n"); 

strcpy(Irp->UserBuffer,"OK!\n");
break;
default:
break;
}
break;
default:
DbgPrint("未知请求包被调用\n");
break;
}
nStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return nStatus;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING theRegistryPath)
{//驱动入口函数
NTSTATUS        ntStatus = STATUS_SUCCESS;
UNICODE_STRING  ntDeviceName;
UNICODE_STRING  DeviceLinkString;
PDEVICE_OBJECT  deviceObject = NULL;
DbgPrint("驱动程序加载...\n");
RtlInitUnicodeString( &ntDeviceName, NT_DEVICE_NAME );
ntStatus = IoCreateDevice(
DriverObject,
0,
&ntDeviceName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject );

if ( !NT_SUCCESS( ntStatus ) )
{
DbgPrint("无法创建驱动设备");
return ntStatus;
}
RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
ntStatus=IoCreateSymbolicLink(&DeviceLinkString,&ntDeviceName);
if(!NT_SUCCESS(ntStatus))
{
return ntStatus;
}

DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
DriverObject->DriverUnload = OnUnload;

DbgPrint("驱动程序已经启动\n");
DbgPrint("修改SSDT表...\n");

//修改 ZwOpenProcess 函数地址
OldZwOpenProcess =(ZWOPENPROCESS)(SYSTEMSERVICE(ZwOpenProcess));
(ZWOPENPROCESS)(SYSTEMSERVICE(ZwOpenProcess)) = NewZwOpenProcess;
DbgPrint("驱动程序加载完毕.\n");
return STATUS_SUCCESS;
}

以上斜体部分就是我们新添加的代码,不是很多吧?但是却实现了好几个功能,我们一步一步分析。

DbgPrint("修改SSDT表...\n");
//修改 ZwOpenProcess 函数地址
OldZwOpenProcess =(ZWOPENPROCESS)(SYSTEMSERVICE(ZwOpenProcess));
(ZWOPENPROCESS)(SYSTEMSERVICE(ZwOpenProcess)) = NewZwOpenProcess;

这段代码先是将ZwOpenProcess(实际就是NtOpenProcess)的地址保存在OldZwOpenProcess里,然后将新函数的地址替换掉SSDT表中的ZwOpenProcess(NtOpenProcess)。当驱动接收到控制命令以后,我们将传入缓冲区的内容保存在变量pid里,然后当调用到NtOpenProcess时,调用新函数里我们做相应过滤。

NTSTATUS NewZwOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId OPTIONAL)
{
//用来替换的新函数
NTSTATUS nStatus = STATUS_SUCCESS;
if((long)ClientId->UniqueProcess == pid)
{
DbgPrint("保护进程 PID:%ld\n",pid);
return STATUS_ACCESS_DENIED;
}
//剩下的交给我们的原函数
nStatus = OldZwOpenProcess(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId);
return STATUS_SUCCESS;
}

到此,我们的驱动程序就编写完了。然后如图3所示的方法编译驱动,我们就会在sys/i386目录下产生一个名为Protect.sys的驱动文件。

驱动安装
我们直接生成的是SYS驱动文件,无法直接双击运行,怎么办呢?常规方法是安装一个系统服务。当然,这里的服务安装后在服务管理器里是看不到的。我写了一个简单的控制台程序,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>

#define BUF_SIZE 4096

int main(int argc,char* argv[])
{
char path[BUF_SIZE];
char base[BUF_SIZE];
char sername[BUF_SIZE];
char disname[BUF_SIZE];
memset(path,0,BUF_SIZE);
memset(base,0,BUF_SIZE);
memset(sername,0,BUF_SIZE);
memset(disname,0,BUF_SIZE);
 
SC_HANDLE rh = NULL;
SC_HANDLE sh = NULL;
if (argc == 1)
{
printf("use: install/start/uninstall\n");
exit(0);
}
 
::GetModuleFileName(0,base,BUF_SIZE);
int p = strlen(base);
while(base[p] != '\\'){p--;}
strncpy(path,base,p+1);
memset(base,0,BUF_SIZE);
sprintf(base,"%sInstall.ini",path);
memset(path,0,BUF_SIZE);
::GetPrivateProfileString("Config","Path","",path,BUF_SIZE,base);
::GetPrivateProfileString("Config","ServiceName","",sername,BUF_SIZE,base);
::GetPrivateProfileString("Config","DisplayName","",disname,BUF_SIZE,base);

printf("[*]Service Name:%s\n",sername);
printf("[*]Display Name:%s\n",disname);
printf("[*]Driver  Path:%s\n",path);
sh = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

if (!sh){
printf("[-]Error OpenSCManger.\n");
exit(0);
}

if (argc == 2 && !strcmp(argv[1],"install"))
{
if (!strcmp(path,""))
{
printf("[-]error read Install.ini\n");
exit(0);
}

rh = CreateService(sh,sername,disname,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
//{
//SERVICE_SYSTEM_START,
SERVICE_DEMAND_START,
//}
SERVICE_ERROR_NORMAL,
path,
NULL,NULL,NULL,NULL,NULL);

if (!rh){
printf("[-]error CreateService.\n");
exit(0);
}

printf("[-]Install Service Complete...\n");
}else if (argc == 2 && !strcmp(argv[1],"start"))
{
rh = OpenService(sh,sername,SERVICE_ALL_ACCESS);
if (!rh){
printf("error OpenService.\n");
exit(0);
}
StartService(rh,NULL,NULL);
printf("[-]Start Service Complete...\n");
}else if (argc == 2 && !strcmp(argv[1],"uninstall"))
{
rh = OpenService(sh,sername,SERVICE_ALL_ACCESS);
if (!rh){
printf("error OpenService.\n");
exit(0);
}

SERVICE_STATUS ss;
ControlService(rh,SERVICE_CONTROL_STOP,&ss);
printf("[-]Stop Service Complete...\n");
DeleteService(rh);
printf("[-]Delete Service Complete...\n");
}
CloseServiceHandle(rh);
CloseServiceHandle(sh);
return 1;
}

因为我经常要调试不同的驱动,每次改代码都比较麻烦,所以我采用INI的方式配置驱动的相关参数,INI的内容如下:

[Config]
;驱动的绝对路径
Path=E:\WDM\Protect\sys\i386\Protect.sys
;服务名
ServiceName=Rootkit
;服务显示的名字
DisplayName=RootkitKernel

代码我已做了详细注释,就不再解释了。这个程序有三个命令,Install用来安装驱动,安装后使用start运行驱动;Start用于运行驱动程序;Uninstall用于卸载驱动。
不过安装好程序后还没有完,因为我们的驱动是独立运行的,所以需要再写个程序和它通讯,这个任务就简单了,实现代码如下。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winioctl.h>
#define IOCTL_HELLO_CONTROL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

int main(int argc,char* argv[])
{
long pid = 0;
char ret[4096];
DWORD ReBytes = 0;
HANDLE hDevice=CreateFile("\\\\.\\ProtectProcess",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hDevice==INVALID_HANDLE_VALUE)
{
if (2 == GetLastError())
{
printf("驱动程序未注册\n");
}else
printf("CreateFile() GetLastError reports %d\n",GetLastError());
return FALSE;
}

memset(ret,0,4096);
printf("请输入需要保护的进程PID:");
scanf("%ld",&pid);
DeviceIoControl(hDevice,IOCTL_HELLO_CONTROL,&pid,sizeof(long),ret,4096,&ReBytes,NULL);

printf("Return Value:%s\n",ret);

CloseHandle(hDevice);
return 1;
}

\\ProtectProcess是驱动的设备名,在驱动代码里我写在了代码的开头部分
#define NT_DEVICE_NAME      L"\\Device\\ProtectProcess"
#define DOS_DEVICE_NAME     L"\\DosDevices\\ProtectProcess"

这里的NT_DEVICE_NAME就是设备名了。

运行效果
大功告成,我们来看下效果。首先,我们安装驱动,如4所示。然后我们使用DriverMonitor查看驱动信息(DriverStudio的一个组件,用于查看DbgPrint输出的调试信息),如图5所示。

图4

图5
现在运行我们的控制程序,来保护千千静听(TTPlayer.exe)的进程,PID为1836,如图6所示。注意图中3个画圈的地方,可以看到和驱动通讯成功了,下面我们用任务管理器结束千千静听的进程试试,如图7所示,可以看到拒绝访问,证明我们的进程保护成功了。下面我们卸载掉驱动,卸载完毕后,DriverMonitor会显示驱动的卸载调试信息,如图8所示。至此,驱动就完美地卸载完成了。

图6

图7

图8

小结
1)很多关于Rootkit修改SSDT的文章,修改SSDT的时候都是使用内存描述符表(MDL)的方式来修改的。我采用了一种更简洁的方法直接赋值,根据测试没有什么不足。当然,本人水平有限,也可能有不足而没有发现,还请高手赐教。
2)当驱动卸载的时候,在Unload函数里一定要记得复原SSDT表,否则当驱动卸载后,NtOpenProcess函数的地址就会指向一个不存在的地址,这时会造成系统蓝屏。想当年我初学驱动的时候,蓝屏简直是家常便饭,而我机子又有Tomcat、Mssql,而且还安的卡巴,启动起来暴慢,郁闷得要死。个人经验:学驱动开发机子少装点东西,尤其是杀毒软件,这样启动起来速度快,嘿嘿~~。
3) 设备驱动不用的时候一定要记得卸载,否则根据安装时候的参数决定。CreateService的参数SERVICE_DEMAND_START表示手动启动。如果是参数SERVICE_SYSTEM_START(代码里我注释起来了)则表示自动启动,开机后自动就运行了。
4)关于DriverMonitor。虽然是DriverStudio其中的一个工具,不过好像单独可以下载到,当然你下个DriverStudio更好,里面的很多其他工具也很实用。
5)很多关于驱动开发的书都是说用DriverStudio生成框架,效果是一样的,不过结构性要强一些,但是个人觉得DDK虽然全部手写,但是更简洁明了。当然,这是个人习惯问题。
6)另外,提一个新手比较容易犯的错误,就是代码的路径里一定不要有空格比,如“E:\WDM\RootKit Program”这种是绝对不行的,因为如果有空格就会破坏掉编译时候的参数。

0 0
原创粉丝点击