//author:梧桐
//转载请注明出处
------------------------很不华丽的分割线------------------------------------------------------
本文章仅供那些在驱动开发门外徘徊的程序爱好者参考和学习,大牛就绕过吧,
如有错误的地方,还请多多指出,不胜感激。
------------------------很不华丽的分割线------------------------------------------------------
对于Driver 一词儿,我想大家都不陌生,它是工作在ring0下的,正是因为如此,它不不能够快速上手的,更多的时候你要熟悉它的技术资料和接口,还要熟悉底层工作的原理,一不小心搞个BSOD,那是会非常郁闷的。
好了,现在让我们步入正题,首先确认你已经安装好了DDK(学习驱动开发,推荐WINXP DDK 2600、 Windows XP, VS2003),配置好了你的开发环境(DDK Wizard),在VS20003里添加WINDDK路径。
打开VS2003,Tools选项,选取 Options(如下图):
然后,我们找到 Projects(工程),选取VC++ Directories,添加WINDDK路径:
配置好这些环境以后,我们开始与驱动的亲密接触吧。
先来建立一个驱动的工程:
那些默认的选项,全部取消掉:
接着点 Finish ,删除 Header Files、Resource Files,此时,DDK Wizard 已经为我们建立了一套Driver模板了,但细看,是不是感觉非常非常的乱?
OK,我们把它K掉,现在我们自己来打造一个简单的入口点。
#include "ntddk.h" //Unload VOID UnLoad(IN PDRIVER_OBJECT DriverObject) { DbgPrint("UnLoad Driver.\n"); } //EntryPoint. NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { DriverObject->DriverUnload = UnLoad; //TODO return STATUS_SUCCESS; }
要挂钩SSDT,就必须先要由内核到处一个KeServiceDescriptorTable,那么我们还要先定义一个KeServiceDescriptorTable类型的的结构体:
typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; //Used only in checked build unsigned int NumberOfServices; unsigned char *ParamTableBase; } SSDTEntry;
ZwTerminateProcess( IN HANDLE ProcessHandle OPTIONAL, IN NTSTATUS ExitStatus );
typedef NTSTATUS(*_ZwTerminateProcess)( IN HANDLE ProcessHandle OPTIONAL, IN NTSTATUS ExitStatus );
#define GetSystemFunc(FuncName) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)FuncName+1)];
有的网友此刻估计已经明白了。
没错,就是 Memory Descriptor List,简称 MDL。有的同学可能会问了,MDL究竟是个什么东西呢?从字面意思看,不难理解,内存描述符列表。MDL包含了内存区域的起始、拥有者proc、字节数、标记等。OK,我们需要先定义一个MDL的指针。
PMDL MDLSystemCall;
定义了MDL的指针以后,我们要通过MAPPED系列的参数来使内存拥有可写性,然后锁定内存中的MDL,那么我们就要定义一个PVOID的指针,来供MmMap操作。
PVOID *MappedSCT;
MDLSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4); if(!MDLSystemCall) return STATUS_UNSUCCESSFUL;
对的,没错。
MmBuildMdlForNonPagedPool(MDLSystemCall); MDLSystemCall->MdlFlags = MDLSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; //可写 MappedSCT = MmMapLockedPages(MDLSystemCall, KernelMode);
刚才我们已经定义了 ZwTerminateProcess 的结构。
Old_ZwTerminateProcess = (_ZwTerminateProcess)(GetSystemFunc(ZwTerminateProcess));
那么下一步呢,就是干掉他了,替换为我们的函数,那么我们是不是要构造一个自己的函数过程呢,恩,没错。
NTSTATUS NewZwTerminateProcess( IN HANDLE ProcessHandle OPTIONAL, IN NTSTATUS ExitStatus ) { //TODO return STATUS_SUCCESS; }
下面就是替换函数了,修改SSDT中函数地址指向的位置,下面是宏定义:
#define GetIndex(_foo) *(PULONG)((PUCHAR)_foo+1) #define HookOn(_Old,_New) InterlockedExchange((PLONG)&MappedSCT[GetIndex(_Old)] ,(LONG)_New)
MDLSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4); if(!MDLSystemCall) return STATUS_UNSUCCESSFUL; MmBuildMdlForNonPagedPool(MDLSystemCall); MDLSystemCall->MdlFlags = MDLSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; //可写 MappedSCT = MmMapLockedPages(MDLSystemCall, KernelMode); HookOn(ZwTerminateProcess, NewZwTerminateProcess); return STATUS_SUCCESS;
/////////////////////////////////////////////////////////////////////////////// /// /// Copyright (c) 2008 - <company name here> /// /// Original filename: NtHook.c /// Project : NtHook /// Date of creation : 2008-11-20 /// Author(s) : 梧桐 /// /// Purpose : <description> /// /// Revisions: /// 0000 [2008-11-20] Initial revision. /// /////////////////////////////////////////////////////////////////////////////// #include "ntddk.h" #pragma pack(1) typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; //Used only in checked build unsigned int NumberOfServices; unsigned char *ParamTableBase; } SSDTEntry; __declspec(dllimport) SSDTEntry KeServiceDescriptorTable; #pragma pack() NTKERNELAPI NTSTATUS ZwTerminateProcess( IN HANDLE ProcessHandle OPTIONAL, IN NTSTATUS ExitStatus ); typedef NTSTATUS(*_ZwTerminateProcess)( IN HANDLE ProcessHandle OPTIONAL, IN NTSTATUS ExitStatus ); _ZwTerminateProcess Old_ZwTerminateProcess; #define GetSystemFunc(FuncName) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)FuncName+1)] PMDL MDSystemCall; PVOID *MappedSCT; #define GetIndex(_Function) *(PULONG)((PUCHAR)_Function+1) #define HookOn(_Old, _New) \ (PVOID) InterlockedExchange( (PLONG) &MappedSCT[GetIndex(_Old)], (LONG) _New) #define UnHook(_Old, _New) \ InterlockedExchange( (PLONG) &MappedSCT[GetIndex(_Old)], (LONG) _New) NTSTATUS NewZwTerminateProcess( IN HANDLE ProcessHandle OPTIONAL, IN NTSTATUS ExitStatus ) { return STATUS_SUCCESS; } //Unload VOID UnLoad(IN PDRIVER_OBJECT DriverObject) { DbgPrint("UnLoad Driver.\n"); //卸载Hook UnHook( ZwTerminateProcess, Old_ZwTerminateProcess); //解锁、释放MDL if(MDSystemCall) { MmUnmapLockedPages(MappedSCT, MDSystemCall); IoFreeMdl(MDSystemCall); } } //EntryPoint. NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { DriverObject->DriverUnload = UnLoad; //找出旧函数地址并保存 Old_ZwTerminateProcess =(_ZwTerminateProcess)(GetSystemFunc(ZwTerminateProcess)); MDSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4); if(!MDSystemCall) return STATUS_UNSUCCESSFUL; MmBuildMdlForNonPagedPool(MDSystemCall); MDSystemCall->MdlFlags = MDSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; MappedSCT = MmMapLockedPages(MDSystemCall, KernelMode); //安装HOOK HookOn( ZwTerminateProcess, NewZwTerminateProcess); return STATUS_SUCCESS; }