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

转载请注明出处:http://blog.csdn.net/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,//normal
0x71, 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,//caps
0x51, 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,//shift
0x51, 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 + shift
0x71, 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;
//用于打印实际按键字符的函数 
//2011/11/10
void _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_DATA
PUCHAR 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!");
}
}


//卸载函数
//2011/11/19
VOID 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值