HOOK分发函数实现截获键盘输入

来源:互联网 发布:英语单词测试软件 编辑:程序博客网 时间:2024/03/29 19:41

关心我的同志们可能又要说了,哈哈,这个菜鸟又要发话了,嘿嘿,我菜鸟我荣幸。

最近的编程走向白热化,因为刚开学,所以时间比较多,所以经常泡图书馆。下决心这学期一定搞定内核级编程,大话放出去了,实现与否还得看造化了。

刚刚迈入驱动程序设计的老高的门槛,发现原来困难重重,内核程序设计不同于一般的用户层的接口程序设计,有大量的帮助资料,网上的,MSDN,论坛里的,各种各样,连绵不绝。到了内核态,帮助资料也少了,论坛的回复也少了,错误也比以前更难调试了,所以一下子不知道咋办,手足无措,一连一个星期下来,除了在内核态打印的“Hello World”这句话通过了意外,其他的程序一律蓝屏。驱动程序设计的错误不同于用户态的程序设计,他更加接近底层的东西,所以一旦有逻辑上的或者说是编译器无法检查出来的非语法错误,就会导致系统的严重错误,直至蓝屏。一时间不知道该咋办。但是根据我多年的经验来看,学习一门编程语言最重要的是不能放弃,只有在不断的错不断的该,不断的练的情况下你才能获得一种居高临下的感觉,才能使你编写程序,而不是程序编写你。

终于,黄天不负有心人,我的第二个不算太2的程序调试成功了,是一个HOOK键盘驱动的分发函数,实现截获键盘输入的例子,虽然网上有不少现成的,但是入门的程序设计菜鸟重在自己动手做,这个过程是痛苦的,我写了好久,查阅了好多资料,调试了无数遍,经历了无数次蓝屏,终于在dbgview上看到了我的键盘输入,那时候自己好开心。

下面就是我的hook的代码,虽然没有检测其稳定性,也就是在替换分发函数的指针的时候有IRP发过来的情况,但是我测试过是可以运行的,还有就是我没有写驱动的卸载模块,也就是说,这个hook一旦开始,除非关闭电脑,不可能使其停下。毕竟我是菜鸟嘛,就用一些简单的功能聊以自慰。

代码如下:


#include "wdm.h"
#include <ntddk.h>

#define KBD_DRIVER_NAME L"//Driver//kbdclass"

ULONG gC2pKeyCount=0;           //全局变量记录IRP个数
extern POBJECT_TYPE IoDriverObjectType;//声明这个函数
PDRIVER_DISPATCH OldDispatchRead;//原IRP_MJ_READ函数的入口地址

 

NTSTATUS OnReadCompletion(IN PDRIVER_OBJECT DriverObject,
                         IN PIRP Irp,
                         IN PVOID Context
       )   //完成函数
{
   PIO_STACK_LOCATION IrpSp;
   ULONG buf_len=0;
   PUCHAR buf=NULL;
   size_t i;
  
   IrpSp=IoGetCurrentIrpStackLocation(Irp);
   if(NT_SUCCESS(Irp->IoStatus.Status))
   {
      buf=Irp->AssociatedIrp.SystemBuffer;
      buf_len=Irp->IoStatus.Information;
      for(i=0;i<=buf_len;++i)
      {
          DbgPrint("%2x/r/n",buf[i]);
      }
   }
   gC2pKeyCount--;
   if(Irp->PendingReturned)
   {
      IoMarkIrpPending(Irp);
   }
   return Irp->IoStatus.Status;
}


NTSTATUS NewDispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP Irp)     //新的分发函数
{
    PIO_STACK_LOCATION irpSp;                                          //以下的内容都是新分发函数的新增内容
    irpSp = IoGetCurrentIrpStackLocation(Irp);

    irpSp->Control = SL_INVOKE_ON_SUCCESS|SL_INVOKE_ON_ERROR|SL_INVOKE_ON_CANCEL;

    //保留原来的完成函数,如果有的话
    irpSp->Context = irpSp->CompletionRoutine;
    irpSp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)OnReadCompletion;
    DbgPrint("已设置回调函数.../n");
    gC2pKeyCount++;
   return OldDispatchRead(pDeviceObject,Irp);                //调用原来的分发函数,完成应该有的内容
}

 

VOID DriverUnload(PDRIVER_OBJECT DriverObject)                //卸载函数,应该更完善
{
   DbgPrint("successful!");
}


NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath) //入口函数
{

PDRIVER_OBJECT kbdDriverObject;
UNICODE_STRING uniNtNameString;
NTSTATUS status=NULL;
NTSTATUS ObReferenceObjectByName(PUNICODE_STRING ObjectName,                          //先声明
         ULONG Attributes,
         PACCESS_STATE AccessState,
         ACCESS_MASK DesiredAccess,
         POBJECT_TYPE ObjectType,
         KPROCESSOR_MODE AccessMode,
         PVOID ParseContext,
         PVOID *Object);

RtlInitUnicodeString(&uniNtNameString,KBD_DRIVER_NAME);                       //初始化为0
status=ObReferenceObjectByName(                                            //得到并打开设备
       &uniNtNameString,
       OBJ_CASE_INSENSITIVE,
       NULL,
       0,
       IoDriverObjectType,
       KernelMode,
       NULL,
       &kbdDriverObject);
if(!NT_SUCCESS(status))
{
    DbgPrint("cannot get the kbd object/n");
    return STATUS_UNSUCCESSFUL;
}
else
{
   ULONG i;
   //PDRIVER_DISPATCH OldDispatchFunctions[IRP_MJ_MAXIMUM_FUNCTION+1];
   OldDispatchRead = kbdDriverObject->MajorFunction[IRP_MJ_READ];//保存原IRP_MJ_READ函数的入口地址
   InterlockedExchangePointer(&kbdDriverObject->MajorFunction[IRP_MJ_READ],NewDispatchRead);//替换为自定义的新分发函数的地址
   ObDereferenceObject(kbdDriverObject);                //不要忘记解除调用
}


DriverObject->DriverUnload=DriverUnload;
return STATUS_SUCCESS;
}

 

 


原创粉丝点击