IRP 乱杂谈[转]

作者: JIURL
IRP 是 I/O request packet 的缩写,即 I/O 请求包。驱动与驱动之间通过 IRP 进行通信。而使用驱动的应用层调用的 CreatFile,ReadFile,WriteFile,DeviceIoControl 等函数,说到底也是使用 IRP 和驱动进行通信。
一个 IRP 由两部分组成。首先是头部或者叫包的固定部分,是一个 IRP 结构。紧跟在这个头部之后的是 I/O stack locations ,这是一个 IO_STACK_LOCATION 结构的数组,这个数组中元素的个数是根据情况而定的,由 IoAllocateIrp( IN CCHAR StackSize , IN BOOLEAN ChargeQuota ) 时的参数 StackSize 决定。而 StackSize 通常由 IRP 发往的目标 DEVICE_OBJECT 的 +30 char StackSize 决定。而这个 StackSize 是由设备对象连入所在的设备栈时,根据在设备栈中位置决定的。我们先看看 IRP 结构和 IO_STACK_LOCATION 结构的定义。
IRP 结构定义如下
struct _IRP (sizeof=112)
+00 int16 Type
+02 uint16 Size
+04 struct _MDL *MdlAddress
+08 uint32 Flags
+0c union __unnamed14 AssociatedIrp
+0c struct _IRP *MasterIrp
+0c int32 IrpCount
+0c void *SystemBuffer
+10 struct _LIST_ENTRY ThreadListEntry
+10 struct _LIST_ENTRY *Flink
+14 struct _LIST_ENTRY *Blink
+18 struct _IO_STATUS_BLOCK IoStatus
+18 int32 Status
+18 void *Pointer
+1c uint32 Information
+20 char RequestorMode
+21 byte PendingReturned
+22 char StackCount
+23 char CurrentLocation
+24 byte Cancel
+25 byte CancelIrql
+26 char ApcEnvironment
+27 byte AllocationFlags
+28 struct _IO_STATUS_BLOCK *UserIosb
+2c struct _KEVENT *UserEvent
+30 union __unnamed15 Overlay
+30 struct __unnamed16 AsynchronousParameters
+30 function *UserApcRoutine
+34 void *UserApcContext
+30 union _LARGE_INTEGER AllocationSize
+30 uint32 LowPart
+34 int32 HighPart
+30 struct __unnamed3 u
+30 uint32 LowPart
+34 int32 HighPart
+30 int64 QuadPart
+38 function *CancelRoutine
+3c void *UserBuffer
+40 union __unnamed17 Tail
+40 struct __unnamed18 Overlay
+40 struct _KDEVICE_QUEUE_ENTRY DeviceQueueEntry
+40 struct _LIST_ENTRY DeviceListEntry
+40 struct _LIST_ENTRY *Flink
+44 struct _LIST_ENTRY *Blink
+48 uint32 SortKey
+4c byte Inserted
+40 void *DriverContext[4]
+50 struct _ETHREAD *Thread
+54 char *AuxiliaryBuffer
+58 struct _LIST_ENTRY ListEntry
+58 struct _LIST_ENTRY *Flink
+5c struct _LIST_ENTRY *Blink
+60 struct _IO_STACK_LOCATION *CurrentStackLocation
+60 uint32 PacketType
+64 struct _FILE_OBJECT *OriginalFileObject
+40 struct _KAPC Apc
+40 int16 Type
+42 int16 Size
+44 uint32 Spare0
+48 struct _KTHREAD *Thread
+4c struct _LIST_ENTRY ApcListEntry
+4c struct _LIST_ENTRY *Flink
+50 struct _LIST_ENTRY *Blink
+54 function *KernelRoutine
+58 function *RundownRoutine
+5c function *NormalRoutine
+60 void *NormalContext
+64 void *SystemArgument1
+68 void *SystemArgument2
+6c char ApcStateIndex
+6d char ApcMode
+6e byte Inserted
+40 void *CompletionKey
IO_STACK_LOCATION 结构定义如下
struct _IO_STACK_LOCATION (sizeof=36)
+00 byte MajorFunction
+01 byte MinorFunction
+02 byte Flags
+03 byte Control
+04 union __unnamed19 Parameters
+04 struct __unnamed20 Create
+04 struct _IO_SECURITY_CONTEXT *SecurityContext
+08 uint32 Options
+0c uint16 FileAttributes
+0e uint16 ShareAccess
+10 uint32 EaLength
+04 struct __unnamed21 CreatePipe
+04 struct _IO_SECURITY_CONTEXT *SecurityContext
+08 uint32 Options
+0c uint16 Reserved
+0e uint16 ShareAccess
+10 struct _NAMED_PIPE_CREATE_PARAMETERS *Parameters
+04 struct __unnamed22 CreateMailslot
+04 struct _IO_SECURITY_CONTEXT *SecurityContext
+08 uint32 Options
+0c uint16 Reserved
+0e uint16 ShareAccess
+10 struct _MAILSLOT_CREATE_PARAMETERS *Parameters
+04 struct __unnamed23 Read
+04 uint32 Length
+08 uint32 Key
+0c union _LARGE_INTEGER ByteOffset
+0c uint32 LowPart
+10 int32 HighPart
+0c struct __unnamed3 u
+0c uint32 LowPart
+10 int32 HighPart
+0c int64 QuadPart
+04 struct __unnamed23 Write
+04 uint32 Length
+08 uint32 Key
+0c union _LARGE_INTEGER ByteOffset
+0c uint32 LowPart
+10 int32 HighPart
+0c struct __unnamed3 u
+0c uint32 LowPart
+10 int32 HighPart
+0c int64 QuadPart
+04 struct __unnamed24 QueryDirectory
+04 uint32 Length
+08 struct _STRING *FileName
+0c int32 FileInformationClass
+10 uint32 FileIndex
+04 struct __unnamed25 NotifyDirectory
+04 uint32 Length
+08 uint32 CompletionFilter
+04 struct __unnamed26 QueryFile
+04 uint32 Length
+08 int32 FileInformationClass
+04 struct __unnamed27 SetFile
+04 uint32 Length
+0c struct _FILE_OBJECT *FileObject
+10 byte ReplaceIfExists
+11 byte AdvanceOnly
+10 uint32 ClusterCount
+10 void *DeleteHandle
+04 struct __unnamed28 QueryEa
+04 uint32 Length
+08 void *EaList
+0c uint32 EaListLength
+10 uint32 EaIndex
+04 struct __unnamed29 SetEa
+04 uint32 Length
+04 struct __unnamed30 QueryVolume
+04 uint32 Length
+08 int32 FsInformationClass
+04 struct __unnamed30 SetVolume
+04 uint32 Length
+08 int32 FsInformationClass
+04 struct __unnamed31 FileSystemControl
+04 uint32 OutputBufferLength
+08 uint32 InputBufferLength
+0c uint32 FsControlCode
+10 void *Type3InputBuffer
+04 struct __unnamed32 LockControl
+04 union _LARGE_INTEGER *Length
+08 uint32 Key
+0c union _LARGE_INTEGER ByteOffset
+0c uint32 LowPart
+10 int32 HighPart
+0c struct __unnamed3 u
+0c uint32 LowPart
+10 int32 HighPart
+0c int64 QuadPart
+04 struct __unnamed33 DeviceIoControl
+04 uint32 OutputBufferLength
+08 uint32 InputBufferLength
+0c uint32 IoControlCode
+10 void *Type3InputBuffer
+04 struct __unnamed34 QuerySecurity
+04 uint32 SecurityInformation
+08 uint32 Length
+04 struct __unnamed35 SetSecurity
+04 uint32 SecurityInformation
+08 void *SecurityDes criptor
+04 struct __unnamed36 MountVolume
+04 struct _VPB *Vpb
+08 struct _DEVICE_OBJECT *DeviceObject
+04 struct __unnamed36 VerifyVolume
+04 struct _VPB *Vpb
+08 struct _DEVICE_OBJECT *DeviceObject
+04 struct __unnamed37 Scsi
+04 *Srb
+04 struct __unnamed38 QueryQuota
+04 uint32 Length
+08 void *StartSid
+0c struct _FILE_GET_QUOTA_INFORMATION *SidList
+10 uint32 SidListLength
+04 struct __unnamed29 SetQuota
+04 uint32 Length
+04 struct __unnamed39 QueryDeviceRelations
+04 int32 Type
+04 struct __unnamed40 QueryInterface
+04 struct _GUID *InterfaceType
+08 uint16 Size
+0a uint16 Version
+0c struct _INTERFACE *Interface
+10 void *InterfaceSpecificData
+04 struct __unnamed41 DeviceCapabilities
+04 struct _DEVICE_CAPABILITIES *Capabilities
+04 struct __unnamed42 FilterResourceRequirements
+04 struct _IO_RESOURCE_REQUIREMENTS_LIST *IoResourceRequirementList
+04 struct __unnamed51 ReadWriteConfig
+04 uint32 WhichSpace
+08 void *Buffer
+0c uint32 Offset
+10 uint32 Length
+04 struct __unnamed52 SetLock
+04 byte Lock
+04 struct __unnamed53 QueryId
+04 int32 IdType
+04 struct __unnamed54 QueryDeviceText
+04 int32 DeviceTextType
+08 uint32 LocaleId
+04 struct __unnamed55 UsageNotification
+04 byte InPath
+05 byte Reserved[3]
+08 int32 Type
+04 struct __unnamed56 WaitWake
+04 int32 PowerState
+04 struct __unnamed57 PowerSequence
+04 struct _POWER_SEQUENCE *PowerSequence
+04 struct __unnamed58 Power
+04 uint32 SystemContext
+08 int32 Type
+0c union _POWER_STATE State
+0c int32 SystemState
+0c int32 DeviceState
+10 int32 ShutdownType
+04 struct __unnamed59 StartDevice
+04 struct _CM_RESOURCE_LIST *AllocatedResources
+08 struct _CM_RESOURCE_LIST *AllocatedResourcesTranslated
+04 struct __unnamed60 WMI
+04 uint32 ProviderId
+08 void *DataPath
+0c uint32 BufferSize
+10 void *Buffer
+04 struct __unnamed61 Others
+04 void *Argument1
+08 void *Argument2
+0c void *Argument3
+10 void *Argument4
+14 struct _DEVICE_OBJECT *DeviceObject
+18 struct _FILE_OBJECT *FileObject
+1c function *CompletionRoutine
+20 void *Context
IO_STACK_LOCATION 结构的大小是固定的,+04 到 +14 之间的16个字节是个公用体。
我们大略的看一个例子,或许能让你对 IO_STACK_LOCATION 有点概念
一个驱动程序的应用层程序,调用 DeviceIoControl ,让驱动程序完成一个任务。DeviceIoControl 中会申请一个Irp,初始化它,然后用这个 Irp,调用 IoCallDriver 发往设备栈的最高层。
IoCallDriver 会根据Irp中的当前 IO_STACK_LOCATION 中的 +00 byte MajorFunction,调用发往设备对象所属驱动中的相应函数。
我们看看被传入到设备栈最高层的 irp,
kd> !irp fe403968
Irp is active with 6 stacks 6 is current (= 0xfe403a8c)
No Mdl System buffer = fe3d6068 Thread fe427960: Irp stack trace.
cmd flg cl Device File Completion-Context
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
>[ e, 0] 0 0 fe4f5df0 fe426688 00000000-00000000
/Driver/Kbdclass
Args: 00000000 00000004 000b0008 00000000
WinDbg 的 !irp 命令,会显示一个 Irp 的 IO_STACK_LOCATION 数组的一些格式化信息
可以看到传入的这个 Irp,它的最后一个 IO_STACK_LOCATION 是当前的 IO_STACK_LOCATION,里面有传入的一些参数。
>[ e, 0] 0 0 fe4f5df0 fe426688 00000000-00000000
/Driver/Kbdclass
Args: 00000000 00000004 000b0008 00000000
kd> !strct io_stack_location fe403a8c
struct _IO_STACK_LOCATION (sizeof=36)
+00 byte MajorFunction = 0e .
+01 byte MinorFunction = 00 .
+02 byte Flags = 00 .
+03 byte Control = 00 .
+04 union __unnamed19 Parameters
+04 struct __unnamed33 DeviceIoControl
+04 uint32 OutputBufferLength = 00000000
+08 uint32 InputBufferLength = 00000004
+0c uint32 IoControlCode = 000b0008
+10 void *Type3InputBuffer = 00000000
+14 struct _DEVICE_OBJECT *DeviceObject = FE4F5DF0
+18 struct _FILE_OBJECT *FileObject = FE426688
这样减 0x24 就等于把 +60 struct _IO_STACK_LOCATION *CurrentStackLocation 指向了前一个 IO_STACK_LOCATION。然后将新的 CurrentStackLocation 的 +14 struct _DEVICE_OBJECT *DeviceObject 赋值为传入的参数 DeviceObject 。从传入的参数 DeviceObject 中获得该 DeviceObject 的 DriverObject,调用该 DriverObject 的新的 CurrentStackLocation 的 +00 byte MajorFunction 相
+1c function *CompletionRoutine = 00000000
+20 void *Context = 00000000
这些就是当前 IO_STACK_LOCATION,里面有参数什么的,这样本层驱动就可以根据 IRP 和当前的 IO_STACK_LOCATION 中的内容,知道该干些什么。本例中,本层驱动根据这个 Irp 做了些处理,发现还需要下层驱动做更多处理,就设置了下一层驱动要使用的 IO_STACK_LOCATION ,然后调用 IoCallDriver ,把这个 Irp 发到了下一层。
在下一层的处理程序中,我们看看收到的 Irp
kd> !irp fe403968
Irp is active with 6 stacks 5 is current (= 0xfe403a68)
No Mdl System buffer = fe3d6068 Thread fe427960: Irp stack trace.
cmd flg cl Device File Completion-Context
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
>[ f, 0] 0 0 fe4f5020 fe426688 00000000-00000000
/Driver/i8042prt
Args: 00000000 00000004 000b0008 00000000
[ e, 0] 0 0 fe4f5df0 fe426688 00000000-00000000
/Driver/Kbdclass
Args: 00000000 00000004 000b0008 00000000
我们看到了 Irp 的当前 IO_STACK_LOCATION 变成了倒数第二个 IO_STACK_LOCATION ,里面是上一层驱动中设置的参数,告诉这一层驱动要干什么。本例中,本层驱动读写端口,操作硬件,完成了相应的功能。
IoCallDriver
首先我们看看对了解 IRP 最重要的一个函数,也是使用 IRP 进行驱动间通信所使用的函数,IoCallDriver。这个函数并不大,也不复杂,我们将详细的看看它的汇编代码。
NTSTATUS
IoCallDriver(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
Irp 是发往设备对象的。参数 DeviceObject 指明设备目标设备对象。
nt!IoCallDriver:
80421417 8b542408 mov edx,[esp+0x8]
/* [esp+0x8] 为 IN OUT PIRP Irp */
8042141b 8b4c2404 mov ecx,[esp+0x4]
/* [esp+0x4] 为 IN PDEVICE_OBJECT DeviceObject */
8042141f e82ae1ffff call nt!IofCallDriver (8041f54e)
80421424 c20800 ret 0x8
nt!IofCallDriver:
8041f54e ff25d01a4780 jmp dword ptr [nt!pIofCallDriver (80471ad0)]
nt!IopfCallDriver:
8041f516 56 push esi
8041f517 8bf2 mov esi,edx
/* edx 为 IN OUT PIRP Irp */
8041f519 57 push edi
8041f51a 8bf9 mov edi,ecx
/* ecx 为 IN PDEVICE_OBJECT DeviceObject */
8041f51c fe4e23 dec byte ptr [esi+0x23]
/* esi 为 IN OUT PIRP Irp */
/* struct _IRP (sizeof=112) */
/* +23 char CurrentLocation */
8041f51f 8a4623 mov al,[esi+0x23]
8041f522 33c9 xor ecx,ecx
8041f524 3ac1 cmp al,cl
8041f526 7f0b jg nt!IopfCallDriver+0x1d (8041f533)
/* 如果 Irp->CurrentLocation 大于0,就跳 */
8041f528 51 push ecx
8041f529 51 push ecx
8041f52a 51 push ecx
8041f52b 56 push esi
8041f52c 6a35 push 0x35
8041f52e e8e1c90000 call nt!KeBugCheckEx (8042bf14)
8041f533 8b4660 mov eax,[esi+0x60]
/* esi 为 IN OUT PIRP Irp */
/* struct _IRP (sizeof=112) */
/* +60 struct _IO_STACK_LOCATION *CurrentStackLocation */
8041f536 56 push esi
/* esi 为 IN OUT PIRP Irp */
8041f537 83e824 sub eax,0x24
/* eax 为 Irp->CurrentStackLocation */
/* 0x24 为 sizeof(IO_STACK_LOCATION) */
8041f53a 57 push edi
/* edi 为 IN PDEVICE_OBJECT DeviceObject */
8041f53b 894660 mov [esi+0x60],eax
/* [esi+0x60] 为 Irp->CurrentStackLocation */
8041f53e 897814 mov [eax+0x14],edi
/* eax 为新的当前 IO_STACK_LOCATION */
/* struct _IO_STACK_LOCATION (sizeof=36) */
/* +14 struct _DEVICE_OBJECT *DeviceObject */
/* edi 为 IN PDEVICE_OBJECT DeviceObject */
8041f541 8b4f08 mov ecx,[edi+0x8]
/* edi 为 IN PDEVICE_OBJECT DeviceObject */
/* struct _DEVICE_OBJECT (sizeof=184) */
/* +08 struct _DRIVER_OBJECT *DriverObject */
8041f544 0fb600 movzx eax,byte ptr [eax]
/* eax 为新的当前 IO_STACK_LOCATION */
/* struct _IO_STACK_LOCATION (sizeof=36) */
/* +00 byte MajorFunction */
8041f547 ff548138 call dword ptr [ecx+eax*4+0x38]
/* ecx 为 DeviceObject->DriverObject */
/* struct _DRIVER_OBJECT (sizeof=168) */
/* +38 function *MajorFunction[28] */
/* eax 为 Irp->CurrentStackLocation->MajorFunction */
/* [ecx+eax*4+0x38] 为 */
/* DeviceObject->DriverObject.MajorFunction[Irp->CurrentStackLocation->MajorFunction] */
8041f54b 5f pop edi
8041f54c 5e pop esi
8041f54d c3 ret
IoCallDriver 将参数 Irp 的 +23 char CurrentLocation 减1,然后检查这时的 CurrentLocation 是否大于0。如果不大于0,将蓝屏。接着将参数 Irp 的 +60 struct _IO_STACK_LOCATION *CurrentStackLocation 减 0x24 。这里原来是一个 IO_STACK_LOCATION 的地址,0x24是一个 IO_STACK_LOCATION 结构的大小
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值