//从hookport.sys学到的hook方法,主要是KiFastCallEntry地址的获取及hook的地方思路 //DRIVER.CPP #include "Driver.h" #define MAX_POOL_EXA 0x1000 /************************************************************************ 全局结构变量 *************************************************************************/ #define FUNCINDEX 0xDB extern "C" typedef struct _SERVICE_DESCRIPTOR_TABLE { PVOID ServiceTableBase; PULONG ServiceCounterTableBase; ULONG NumberOfService; ULONG ParamTableBase; }SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE; extern "C" PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable; #define Unprotect() / __asm cli / __asm mov eax,cr0 / __asm and eax,0x0FFFEFFFF / __asm mov cr0,eax #define Protect() / __asm mov eax,cr0 / __asm or eax, not 0FFFEFFFFh / __asm mov cr0,eax / __asm sti ULONG g_OldServiceAddress=0; ULONG g_hookkifasthandle=0x680286449; PVOID g_pJmpBuff=NULL; ULONG g_KiFaseCallEntryEntryAddress=0; ULONG g_OldKiFastCallEntryAddress=0; CHAR TagsToHookKiFastCallEntry[]={0x2b,0xe1,0xc1,0xe9,0x02}; CHAR g_jmp[]={0xe9,0x90,0x90,0x90,0x90}; /************************************************************************ 函数声明 *************************************************************************/ extern "C" NTSTATUS ZwSetEvent( __in HANDLE EventHandle, __out_opt PLONG PreviousState ); /************************************************************************ * 函数名称:MySleep * 功能描述:传入时间,暂停指定时间 * 参数列表: * 返回 值:无 *************************************************************************/ VOID MySleep(ULONG dwMilliseconds) { KTIMER Timer; LARGE_INTEGER DueTime; DueTime.QuadPart=dwMilliseconds*(-1000); KeInitializeTimerEx(&Timer, SynchronizationTimer); KeSetTimer(&Timer,DueTime,0); KeWaitForSingleObject(&Timer,UserRequest,0,TRUE,0); } /************************************************************************ * 函数名称:RealKiFastCallEntry * 功能描述:这里添加各种过滤规则,暂未添加规则,只是简单打印 * 参数列表:这3个参数暂且不知道什么意思,需要看wrk * 返回 值:NTSTATUS *************************************************************************/ ULONG RealKiFastCallEntry(ULONG arg1,ULONG arg2,ULONG arg3) { KdPrint(("i'am running in kifastcallentry,%.8X,%.8X,%.8X",arg1,arg2,arg3)); return arg1; } /************************************************************************ * 函数名称:MyZwSetEvent * 功能描述:挂钩ZwSetEvent的挂钩函数 * 参数列表: * 返回 值:NTSTATUS *************************************************************************/ __declspec(naked) __stdcall MyKiFastCallEntry() { __asm { mov edi,edi push ebp pushfd pushad push edi push edx push eax call RealKiFastCallEntry mov [esp+10],eax popad popfd pop ebp //KiFastCallEntry原处的指令 sub esp,ecx shr ecx,2 // push [g_OldKiFastCallEntryAddress] retn } } /************************************************************************ * 函数名称:MyZwSetEvent * 功能描述:挂钩ZwSetEvent的挂钩函数,在这里面得到kIfastcallentry地址并inine hook * 参数列表:EventHandle PreviousState都是原ZwSetEvent的参数 * 返回 值:NTSTATUS *************************************************************************/ NTSTATUS MyZwSetEvent( __in HANDLE EventHandle, __out_opt PLONG PreviousState ) { BOOLEAN bFlags=FALSE; KSPIN_LOCK Spinlock; KIRQL Irql; NTSTATUS Status=STATUS_SUCCESS; ULONG MyJmpAddress=(ULONG)MyKiFastCallEntry; //获取KFastCallEntry地址 if (EventHandle==(HANDLE)g_hookkifasthandle) { if (ExGetPreviousMode()==0)//先前模式是内核的才行 { g_pJmpBuff=ExAllocatePoolWithTag(NonPagedPool,5,'jmp'); if (g_pJmpBuff==NULL) { // goto Retu; } else { //开始获取地址并hook __asm { push eax push ebx mov eax,g_pJmpBuff//构造好buffer,形成jmp XXXXXXXX mov byte ptr [eax],0xe9 //这个jmp XxxXXXX是跳到我们上面的MyKiFastCallEntry的 mov ebx,MyJmpAddress sub ebx,eax sub ebx,5 mov dword ptr [eax+1],ebx pop ebx pop eax } KeAcquireSpinLock(&Spinlock,&Irql); Unprotect(); //取ebp+4 __asm { mov eax,[ebp+4]///*********************关键点 mov edx,eax mov g_KiFaseCallEntryEntryAddress,eax agains: mov edi,eax lea esi,TagsToHookKiFastCallEntry mov ecx,5 repe cmpsb push eax setz al test al,al pop eax jnz Find dec eax //从后往前找 push edx sub edx,eax cmp edx,64h pop edx ja ReadyExit jmp agains //循环,找到改写的地址 Find: add eax,5 mov g_OldKiFastCallEntryAddress,eax//g_ OldKiFastCallEntryAddress在MyKiFastCallEntry调回的 mov edx,g_pJmpBuff //在这里填入的JMp sub edx,eax //是jmp XXXXX到上面分配的buffer中的 lea eax,g_jmp mov [eax+1],edx mov edi,g_OldKiFastCallEntryAddress sub edi,5 //开始hook的地方 lea esi,g_jmp mov ecx,5 rep movsb } ReadyExit: Protect(); KeReleaseSpinLock(&Spinlock,Irql); } } } //调用原来的 __asm { pushad mov eax,EventHandle mov ebx,PreviousState; push ebx push eax call g_OldServiceAddress mov Status,eax popad } Retu: return Status; } /************************************************************************ * 函数名称:HookTableFunc * 功能描述:传入要hook的某个表的地址和表中的函数索引,和函数地址 * 参数列表: * 返回 值:无 *************************************************************************/ VOID HookTableFunc(ULONG TableAddress,ULONG Index,ULONG MyFuncAddress) { KSPIN_LOCK Spinlock; KIRQL Irql; ULONG HookAddress=TableAddress+Index*4; KdPrint(("HookAddress=%.8X/n",HookAddress)); g_OldServiceAddress=*(ULONG *)HookAddress; KeInitializeSpinLock(&Spinlock); KeAcquireSpinLock(&Spinlock,&Irql); Unprotect(); // *(ULONG *)HookAddress=MyFuncAddress; InterlockedExchange((volatile LONG *)HookAddress,MyFuncAddress); Protect(); KeReleaseSpinLock(&Spinlock,Irql); } /************************************************************************ * 函数名称:HookSdtFunc * 功能描述:传入要unhook的某个表的地址和表中的函数索引,和填入函数地址 * 参数列表: * 返回 值:无 *************************************************************************/ VOID UnHookTableFunc(ULONG TableAddress,ULONG Index,ULONG OldFuncAddress) { KSPIN_LOCK Spinlock; KIRQL Irql; ULONG HookAddress=TableAddress+Index*4; KdPrint(("HookAddress=%.8X/n",HookAddress)); KeInitializeSpinLock(&Spinlock); KeAcquireSpinLock(&Spinlock,&Irql); Unprotect(); // *(ULONG *)HookAddress=MyFuncAddress; InterlockedExchange((volatile LONG *)HookAddress,OldFuncAddress); Protect(); KeReleaseSpinLock(&Spinlock,Irql); } /************************************************************************ * 函数名称:DriverEntry * 功能描述:驱动入口 * 参数列表: * 返回 值:NTSTATUS *************************************************************************/ #pragma INITCODE extern "C" NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) { NTSTATUS status; KdPrint(("Enter DriverEntry/n")); //注册其他驱动调用函数入口 pDriverObject->DriverUnload = HelloDDKUnload; pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine; //创建驱动设备对象 status = CreateDevice(pDriverObject); //hook zwsetevent HookTableFunc((ULONG) KeServiceDescriptorTable->ServiceTableBase,FUNCINDEX,(ULONG)MyZwSetEvent); //调用zwSetevent ZwSetEvent((HANDLE)g_hookkifasthandle,0); //取消hook UnHookTableFunc((ULONG) KeServiceDescriptorTable->ServiceTableBase,FUNCINDEX,(ULONG)g_OldServiceAddress); KdPrint(("DriverEntry end/n")); return status; } /************************************************************************ * 函数名称:CreateDevice * 功能描述:初始化设备对象 * 参数列表: pDriverObject:从I/O管理器中传进来的驱动对象 * 返回 值:返回初始化状态 *************************************************************************/ #pragma INITCODE NTSTATUS CreateDevice ( IN PDRIVER_OBJECT pDriverObject) { NTSTATUS status; PDEVICE_OBJECT pDevObj; PDEVICE_EXTENSION pDevExt; //创建设备名称 UNICODE_STRING devName; RtlInitUnicodeString(&devName,L"//Device//MyRookit"); //创建设备 status = IoCreateDevice( pDriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj ); if (!NT_SUCCESS(status)) return status; pDevObj->Flags |= DO_BUFFERED_IO; pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; pDevExt->pDevice = pDevObj; pDevExt->ustrDeviceName = devName; //创建符号链接 UNICODE_STRING symLinkName; RtlInitUnicodeString(&symLinkName,L"//??//MyRookit"); pDevExt->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink( &symLinkName,&devName ); if (!NT_SUCCESS(status)) { IoDeleteDevice( pDevObj ); return status; } return STATUS_SUCCESS; } /************************************************************************ * 函数名称:HelloDDKUnload * 功能描述:负责驱动程序的卸载操作 * 参数列表: pDriverObject:驱动对象 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) { PDEVICE_OBJECT pNextObj; KdPrint(("Enter DriverUnload/n")); pNextObj = pDriverObject->DeviceObject; while (pNextObj != NULL) { PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pNextObj->DeviceExtension; //删除符号链接 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName; IoDeleteSymbolicLink(&pLinkName); pNextObj = pNextObj->NextDevice; IoDeleteDevice( pDevExt->pDevice ); } } #pragma PAGEDCODE NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("Enter HelloDDKDispatchRoutine/n")); NTSTATUS status = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDispatchRoutine/n")); return status; } //Driver.h #pragma once #ifdef __cplusplus extern "C" { #endif #include <NTDDK.h> #ifdef __cplusplus } #endif #define PAGEDCODE code_seg("PAGE") #define LOCKEDCODE code_seg() #define INITCODE code_seg("INIT") #define PAGEDDATA data_seg("PAGE") #define LOCKEDDATA data_seg() #define INITDATA data_seg("INIT") #define arraysize(p) (sizeof(p)/sizeof((p)[0])) typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT pDevice; UNICODE_STRING ustrDeviceName; //设备名称 UNICODE_STRING ustrSymLinkName; //符号链接名 } DEVICE_EXTENSION, *PDEVICE_EXTENSION; // 函数声明 NTSTATUS CreateDevice (IN PDRIVER_OBJECT pDriverObject); VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject); NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp); 只是个框架,并未实现什么,简单的打印了下字符,并且未作卸载驱动hook的恢复(几句搞定)