剖析一个典型的Keyboard_Hook
//本人巨菜,纯粹的学习笔记
//高手飘过就可以了
//不当之处还请指出,谢谢了.
//先mark下,回头再弄,笔记本没电了...
1.键盘过滤
2.深入native application
3.进程与线程 EPROCESS 分析
//关于I/O堆栈
1.当前设备堆栈不对IRP做任何处理.
//给出一个通用的DispatchCommon函数
NTSTATUS DispatchCommon(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
IoSkipCurrentIrpStackLocation(pIrp);
status=IoCallDriver(pdx->TargetDevice,pIrp);
}
2.当前IRP也需要参与操作 ,需要将当前的I/0堆栈的参数复制到下一层.
NTSTATUS Dispatch_Other(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
// PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(pIrp);
// PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(pIrp);
// *nextIrpStack = *currentIrpStack;
IoCopyCurrentIrpStackLocationToNext(pIrp);
// IoSetCompletionRoutine(pIrp, OnOtherCompletion, pDeviceObject, TRUE, TRUE, TRUE);
status=IoCallDriver(pdx->TargetDevice,pIrp);
}
//关于完成例程IoSetCompletionRoutine
//一旦底层驱动讲IRP完成后,IRP的完成例程立刻被触发
VOID
IoSetCompletionRoutine(
IN PIRP Irp,
IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
IN PVOID Context OPTIONAL,
IN BOOLEAN InvokeOnSuccess,
IN BOOLEAN InvokeOnError,
IN BOOLEAN InvokeOnCancel
);
// in the CompletionRoutine ,you should call IoMarkPending(),
//关于新创建的Keyboard Device
//调用IoCreateDevice,传入的Device_Type是FILE_DEVICE_KEYBOARD
//新创建的设备相关标记 应该设置与底层键盘设备相同.可以使用DeviceTree工具查看
//一般而言:
pKeyboardDeviceObject->Flags = pKeyboardDeviceObject->Flags | (DO_BUFFERED_IO | DO_POWER_PAGABLE);
pKeyboardDeviceObject->Flags = pKeyboardDeviceObject->Flags & ~DO_DEVICE_INITIALIZING;
//关于IoAttachDevice
NTSTATUS
IoAttachDevice(
IN PDEVICE_OBJECT SourceDevice,
IN PUNICODE_STRING TargetDevice,
OUT PDEVICE_OBJECT *AttachedDevice
);
//关于PsCreateSystemThread
//The PsCreateSystemThread routine creates a system thread that executes in kernel mode and returns a handle for the thread.
NTSTATUS
PsCreateSystemThread(
OUT PHANDLE ThreadHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle OPTIONAL,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PKSTART_ROUTINE StartRoutine,
IN PVOID StartContext
);
//补充下最后两个参数的说明,其他的参考wdk或者ddk
//
// StartRoutine
// Is the entry point for a driver thread.
// Supplies a single argument that is passed to the thread when it begins execution.
//关于CONTAINING_RECORD
The CONTAINING_RECORD macro returns the base address of an instance of a structure given the type of the structure and the address of a field within the containing structure.
PCHAR
CONTAINING_RECORD(
IN PCHAR Address,
IN TYPE Type,
IN PCHAR Field
);
//最后随便扯点思路
//主要是分层驱动程序过滤,Hook键盘的话,主要是捕获IRP_MJ_READ 信息
//1.首先Hook IRP_MJ_READ的分发函数,通过IoSetCompletionRoutine设置一个完成例程OnReadCompletionRoutine;
//2.通过IoCreateDevice创建一个新的键盘设备,然后调用IoAttachDevice(),将该设备挂上old设备栈上
// 通过上面两步,过滤驱动安装好.然后是对所捕获的键盘消息的处理
//3.在Klog的src所实现的是,通过PsCreateSystemThread创建一个工作线程来实现对键盘消息的处理.
//4.在该工作线程中,讲所记录的键盘码,写入klog.txt 文件中.
//总结下,思路很简单,但是code起来,细节很多...很多地方需要注意.同步,线程的创建和释放,对KEYBOARD_INPUT_DATA的处理
//还有如何将扫描码转换成真正的键盘码.ConvertScanCodeToKeyCode...