抑郁症健康,内容丰富有趣,生活中的好帮手!
抑郁症健康 > 寒江独钓学习笔记 -- 第四章 Hook分发函数 过滤键盘输入

寒江独钓学习笔记 -- 第四章 Hook分发函数 过滤键盘输入

时间:2020-07-13 19:35:47

相关推荐

转载请注明出处:/lup7in/article/details/7015497

最近在学习windows内核编程,下面是《寒江独钓》第四章hook分发函数过滤键盘输入的源代码,书上没有提供完整的代码,经过调试完成了这部分代码,下面把代码分享出来,有不对的地方,希望大牛指教。

#include <ntddk.h> #include <ntddkbd.h>#define NTSTRSAFE_LIB#include <Ntstrsafe.h>extern POBJECT_TYPE IoDriverObjectType;#define KBD_DRIVER_NAME L"\\Driver\\Kbdclass"//用于延时的宏定义#define DELAY_ONE_MICROSECOND (-10)#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND * 1000)#define DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND * 1000)//表示几个特殊键的宏#define S_SHIFT 0x01//shift键#define S_CAPS 0x02//大写锁定键#define S_NUM 0x04//数字锁定键ULONG gC2pKeyCount = 0;unsigned char asciiTbl[]={0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,//normal0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x5B, 0x5D, 0x0D, 0x00, 0x61, 0x73,0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B, 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,0x32, 0x33, 0x30, 0x2E,0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09,//caps0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0x5B, 0x5D, 0x0D, 0x00, 0x41, 0x53,0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3B, 0x27, 0x60, 0x00, 0x5C, 0x5A, 0x58, 0x43, 0x56,0x42, 0x4E, 0x4D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,0x32, 0x33, 0x30, 0x2E,0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x09,//shift0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0x7B, 0x7D, 0x0D, 0x00, 0x41, 0x53,0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A, 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,0x32, 0x33, 0x30, 0x2E,0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x09,//caps + shift0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x7B, 0x7D, 0x0D, 0x00, 0x61, 0x73,0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3A, 0x22, 0x7E, 0x00, 0x7C, 0x7A, 0x78, 0x63, 0x76,0x62, 0x6E, 0x6D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,0x32, 0x33, 0x30, 0x2E};//储存旧的分发函数的数组PDRIVER_DISPATCH OldMajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1];//用于根据驱动名称打开驱动对象 这个函数文档没公布 所以要声明一下NTSTATUS ObReferenceObjectByName(PUNICODE_STRING ObjectName,ULONG Attributes,PACCESS_STATE AccessState,ACCESS_MASK DesiredAccess,POBJECT_TYPE ObjectType,KPROCESSOR_MODE AccessMode,PVOID ParseContext,PVOID *Object);PDRIVER_OBJECT pKbdDriverObject = NULL;UNICODE_STRING uniNtNameString;//打开驱动对象的函数NTSTATUS OpenKbdDriver(){NTSTATUS status;RtlInitUnicodeString(&uniNtNameString,KBD_DRIVER_NAME);status = ObReferenceObjectByName(&uniNtNameString,OBJ_CASE_INSENSITIVE,NULL,0,IoDriverObjectType,KernelMode,NULL,&pKbdDriverObject);if(NT_SUCCESS(status)){ObDereferenceObject(pKbdDriverObject);DbgPrint("open the kbd driver success!");}else{DbgPrint("open the kbd driver fail!");}return status;}static int kb_status = S_NUM;//用于打印实际按键字符的函数 ///11/10void _stdcall print_keystroke(UCHAR sch,USHORT Flags){UCHAR ch = 0;int off = 0;//kb_status = S_NUM;//DbgPrint("%x\n",sch);//按下if(Flags == KEY_MAKE/*(sch & 0x80) == 0*/){switch(sch){case 0x3A:kb_status ^= S_CAPS;break;case 0x2A:case 0x36:kb_status |= S_SHIFT;break;case 0x45:kb_status ^= S_NUM;break;}}else if(Flags == KEY_BREAK) //弹起{if(sch == 0x2A || sch == 0x36)kb_status &= ~S_SHIFT;}if(kb_status & S_CAPS){off = 84 * 1;}if(kb_status & S_SHIFT){off = 84 * 2;}if((kb_status & S_SHIFT) && (kb_status & S_CAPS)){off = 84 * 3;}//DbgPrint("%d\n",off);if((sch < 0x47) || ((sch >= 0x47 && sch < 0x54) && (kb_status & S_NUM))){ch = asciiTbl[off + sch];}if(Flags == KEY_MAKE){if(ch >= 0x20 && ch < 0x7F){DbgPrint("%C\n",ch);}}}NTSTATUS c2pReadComplete(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID Context){PIO_STACK_LOCATION IrpSp;ULONG buf_len = 0;//systembuffer 的数据结构形式 是一个结构体 KEYBOARD_INPUT_DATAPUCHAR buf = NULL;size_t i;ULONG numKeys = 0;PKEYBOARD_INPUT_DATA KeyData = NULL;IrpSp = IoGetCurrentIrpStackLocation(Irp);//如果成功if(NT_SUCCESS(Irp->IoStatus.Status)){//获取读请求完成后的输出缓冲区buf = Irp->AssociatedIrp.SystemBuffer;KeyData = (PKEYBOARD_INPUT_DATA)buf;//获得缓冲区长度buf_len = Irp->IoStatus.Information;numKeys = buf_len / sizeof(KEYBOARD_INPUT_DATA);for(i = 0;i < numKeys;i++){//打印出一些按键信息//DbgPrint("numKeys:%d",numKeys);//DbgPrint("ScanCode:%x",KeyData->MakeCode);//DbgPrint("%s\n",KeyData->Flags ? "UP" : "DOWN");print_keystroke((UCHAR)KeyData->MakeCode,KeyData->Flags);//这里是一个小实验 当用户按下ctrl键时 //把其扫描码改成大写锁定键CAPS_LOCK的扫描码//当按下ctrl键时就会启动大写锁定//这说明按键是可以被截获并且人为修改的//if(KeyData->MakeCode == LCONTROL)//{// KeyData->MakeCode = CAPS_LOCK;//}}//这里可以做其他事情//打印按键的扫描码//for(i = 0;i < buf_len;i++)//{// DbgPrint("ctrl2cap:%2x\r\n",buf[i]);//}}gC2pKeyCount--;//DbgPrint("count:%d",gC2pKeyCount);if(Irp->PendingReturned){IoMarkIrpPending(Irp);}return Irp->IoStatus.Status;}//自己写的分发函数 NTSTATUS MyDispatchFunction (IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp){PUCHAR buf = NULL;ULONG buf_len = 0;ULONG i;PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);//如果是读请求 就hook之if(irpsp->MajorFunction == IRP_MJ_READ){irpsp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;//保留原来的完成函数,如果有的话irpsp->Context = irpsp->CompletionRoutine;irpsp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)c2pReadComplete; //DbgPrint("已设置回调函数.../n");gC2pKeyCount++;//DbgPrint("count:%d",gC2pKeyCount);//调用原来的分发函数,完成应该有的内容return OldMajorFunction[irpsp->MajorFunction](DeviceObject,Irp);}else{return OldMajorFunction[irpsp->MajorFunction](DeviceObject,Irp);}}//替换分发函数指针的函数VOID ReplaceDispatch(){ULONG i;for(i = 0;i < IRP_MJ_MAXIMUM_FUNCTION + 1;i++){//保存分发函数指针OldMajorFunction[i] = pKbdDriverObject->MajorFunction[i];//把分发函数指针设置成我们自己写的分发函数 这个函数替换指针是原子操作 防止替换时被打断InterlockedExchangePointer(&pKbdDriverObject->MajorFunction[i],MyDispatchFunction);DbgPrint("replace successful!");}}//恢复分发函数指针的函数VOID ReSetDispatchFunction(){ULONG i;for(i = 0;i < IRP_MJ_MAXIMUM_FUNCTION + 1;i++){InterlockedExchangePointer(&pKbdDriverObject->MajorFunction[i],OldMajorFunction[i]);DbgPrint("reset dispatch function success!");}}//卸载函数///11/19VOID HookDispatchUnload(IN PDRIVER_OBJECT DriverObject){PDEVICE_OBJECT DeviceObject;PRKTHREAD pCurrentThread;LARGE_INTEGER lDelay;lDelay = RtlConvertLongToLargeInteger(100 * DELAY_ONE_MILLISECOND);pCurrentThread = KeGetCurrentThread();//把线程设置成低实时模式 减少对其他程序的影响KeSetPriorityThread(pCurrentThread,LOW_REALTIME_PRIORITY);UNREFERENCED_PARAMETER(DriverObject);KdPrint(("DriverEntry unLoading...\n"));//恢复分发函数指针ReSetDispatchFunction();while(gC2pKeyCount){KeDelayExecutionThread(KernelMode,FALSE,&lDelay);}KdPrint(("DriverEntry unLoad OK!\n"));}//入口函数NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath ){NTSTATUS status;DriverObject->DriverUnload = HookDispatchUnload;//打开键盘内核对象status = OpenKbdDriver();if(NT_SUCCESS(status)){//替换分发函数ReplaceDispatch();}return status;}

如果觉得《寒江独钓学习笔记 -- 第四章 Hook分发函数 过滤键盘输入》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。