1,驱动框架常见数据结构有 驱动对象结构, 设备对象结构等。
A)驱动对象结构 (DRIVER_OBJECT)
每个驱动对象代表一个已加载的内核驱动程序,指向驱动对象结构的指针常常作为DriverEntry,AddDevice,Unload等函数的参数。驱动对象结构式半透明的。其中公开的域包括DeviceObject,DriverExtension,HardwareDatabase ,FastIoDispath,DriverInit,DriverStartIo,DriverUnload以及MajorFunction。
驱动对象的数据结构如下:
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
//
// The following links all of the devices created by a single driver
// together on a list, and the Flags word provides an extensible flag
// location for driver objects.
//
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
//
// The following section describes where the driver is loaded. The count
// field is used to count the number of times the driver has had its
// registered reinitialization routine invoked.
//
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
//
// The driver name field is used by the error log thread
// determine the name of the driver that an I/O request is/was bound.
//
UNICODE_STRING DriverName;
//
// The following section is for registry support. Thise is a pointer
// to the path to the hardware information in the registry
//
PUNICODE_STRING HardwareDatabase;
//
// The following section contains the optional pointer to an array of
// alternate entry points to a driver for "fast I/O" support. Fast I/O
// is performed by invoking the driver routine directly with separate
// parameters, rather than using the standard IRP call mechanism. Note
// that these functions may only be used for synchronous I/O, and when
// the file is cached.
//
PFAST_IO_DISPATCH FastIoDispatch;
//
// The following section describes the entry points to this particular
// driver. Note that the major function dispatch table must be the last
// field in the object so that it remains extensible.
//
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
typedef struct _DRIVER_OBJECT *PDRIVER_OBJECT; // ntndis
其中DeviceObject域指向由此驱动创建的设备对象:FastIoDispath域指向快速I/O 入口。DriverInit指向驱动入口点地址(DriverEntry):DriverUnload 指向驱动卸载程序:MajorFunction 是一张函数分发表,数组的所引致与IRP_MJ_Xxx相对应。
自己重新对上面的结构体认识了下,省略了部分,主要了解下面的:
typedef struct _DRIVER_OBJECT{
//结构的类型和大小
CSHORT Type;
CSHORT Size;
//设备对象,这里实际上是一个设备对象的链表的开始。因为 DeviceObject 中有相关链表信息。
PDEVICE_OBJECT DeviceObject;
•••
//这个内核模块在内核空间中的开始地址和大小
PVOID DriverStart;
ULONG DriverSize;
•••
//驱动的名字
UNICODE_STRING DriverName;
•••
//快速IO分发函数
PFAST_IO_DISPATCH FastIoDispatch;
•••
//驱动的卸载函数
PDRIVER_UNLOAD.DriverUnload;
//普通分发函数
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
}DRIVER_OBJECT;
这样看起来是不是 少了很多呢, 上面做了注释的是 主要需要了解的。
-------------------------------------------------------------------------------------------------------
B)设备驱动程序(DEVICE_OBJECT)
系统使用设备对象来描述一个设备对象,数据结构如下:
typedef struct _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;
struct _DRIVER_OBJECT *DriverObject;
struct _DEVICE_OBJECT *NextDevice;
struct _DEVICE_OBJECT *AttachedDevice;
struct _IRP *CurrentIrp;
PIO_TIMER Timer;
ULONG Flags;
ULONG Characteristics;
__volatile PVPB Vpb;
PVOID DeviceExtension;
DEVICE_TYPE DeviceType;
CCHAR StackSize;
union {
LIST_ENTRY ListEntry;
WAIT_CONTEXT_BLOCK Wcb;
} Queue;
ULONG AlignmentRequirement;
KDEVICE_QUEUE DeviceQueue;
KDPC Dpc;
ULONG ActiveThreadCount;
PSECURITY_DESCRIPTOR SecurityDescriptor;
KEVENT DeviceLock;
USHORT SectorSize;
USHORT Spare1;
struct _DEVOBJ_EXTENSION * DeviceObjectExtension;
PVOID Reserved;
} DEVICE_OBJECT, *PDEVICE_OBJECT;
其中,DriverObject 域指向创建次设备对象的驱动程序对象:NextDevice 域指向一个驱动程序创建的下一个设备对象:AttachedDevice 域指向绑定到此设备对象上的设备对象;Flags域指定了设备对象的标记,如该谁被是缓冲读写方式(DO_BUFFERED_IO)还是直接读写方式(DO_DIRECT_IO);Vpb 域指向此设备对象相关的卷参数块;DeviceExtension 域指向设备扩展,设备扩展中的内容由程序设计者自定义,往往用来记录域设备相关的一些信息。
这个结构体也很复杂,我自己总结了下,如下:
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)
_DEVICE_OBJECT{
//结构的类型和大小
CSHORT Type;
CSHORT Size;
//引用计数
ULONG ReferenceCount;
//这个设备所属的驱动对象
struct _DRIVER_OBJECT *DriverObject;
//下一个设备对象,在一个驱动对象中有N个设备,这些设备用这个指针连接起来作为一个单向的链表
struct _DRIVER_OBJECT *NextDevice;
//设备类型
DEVICE_TYPE DeviceType;
•••
//IRP栈大小
HAR StackSize;
••••••
}DEVICE_OBJECT;
这样一来,就清晰很多啦
----------------------------------------------------------------------------------------------------------------------------
2,进程域线程数据结构
A)执行体进程块(EXPROCESS)
执行体进程块是一个不透明的数据结构,用来描述一个进程对象。驱动程序可以用PsGetCurrentProcess函数获取指向当前进程的执行体进程进程块指针。
由于其数据结构不是透明的,想了好多办法,还是找到了啦:
typedef struct _EPROCESS
{
KPROCESS Pcb;
EX_PUSH_LOCK ProcessLock;
LARGE_INTEGER CreateTime;
LARGE_INTEGER ExitTime;
EX_RUNDOWN_REF RundownProtect;
HANDLE UniqueProcessId;
LIST_ENTRY ActiveProcessLinks;
SIZE_T QuotaUsage[PsQuotaTypes];
SIZE_T QuotaPeak[PsQuotaTypes];
SIZE_T CommitCharge;
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
LIST_ENTRY SessionProcessLinks;
PVOID DebugPort;
PVOID ExceptionPort;
PHANDLE_TABLE ObjectTable;
EX_FAST_REF Token;
PFN_NUMBER WorkingSetPage;
KGUARDED_MUTEX AddressCreationLock;
KSPIN_LOCK HyperSpaceLock;
struct _ETHREAD *ForkInProgress;
ULONG_PTR HardwareTrigger;
PMM_AVL_TABLE PhysicalVadRoot;
PVOID CloneRoot;
PFN_NUMBER NumberOfPrivatePages;
PFN_NUMBER NumberOfLockedPages;
PVOID Win32Process;
struct _EJOB *Job;
PVOID SectionObject;
PVOID SectionBaseAddress;
PEPROCESS_QUOTA_BLOCK QuotaBlock;
PPAGEFAULT_HISTORY WorkingSetWatch;
HANDLE Win32WindowStation;
HANDLE InheritedFromUniqueProcessId;
PVOID LdtInformation;
PVOID VadFreeHint;
PVOID VdmObjects;
PVOID DeviceMap;
PVOID Spare0[3];
union
{
HARDWARE_PTE PageDirectoryPte;
ULONGLONG Filler;
};
PVOID Session;
UCHAR ImageFileName[ 16 ];
LIST_ENTRY JobLinks;
PVOID LockedPagesList;
LIST_ENTRY ThreadListHead;
PVOID SecurityPort;
PVOID PaeTop;
ULONG ActiveThreads;
ACCESS_MASK GrantedAccess;
ULONG DefaultHardErrorProcessing;
NTSTATUS LastThreadExitStatus;
PPEB Peb;
EX_FAST_REF PrefetchTrace;
LARGE_INTEGER ReadOperationCount;
LARGE_INTEGER WriteOperationCount;
LARGE_INTEGER OtherOperationCount;
LARGE_INTEGER ReadTransferCount;
LARGE_INTEGER WriteTransferCount;
LARGE_INTEGER OtherTransferCount;
SIZE_T CommitChargeLimit;
SIZE_T CommitChargePeak;
PVOID AweInfo;
SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo;
MMSUPPORT Vm;
LIST_ENTRY MmProcessLinks;
ULONG ModifiedPageCount;
ULONG JobStatus;
union
{
ULONG Flags;
struct {
ULONG CreateReported : 1;
ULONG NoDebugInherit : 1;
ULONG ProcessExiting : 1;
ULONG ProcessDelete : 1;
ULONG Wow64SplitPages : 1;
ULONG VmDeleted : 1;
ULONG OutswapEnabled : 1;
ULONG Outswapped : 1;
ULONG ForkFailed : 1;
ULONG Wow64VaSpace4Gb : 1;
ULONG AddressSpaceInitialized : 2;
ULONG SetTimerResolution : 1;
ULONG BreakOnTermination : 1;
ULONG SessionCreationUnderway : 1;
ULONG WriteWatch : 1;
ULONG ProcessInSession : 1;
ULONG OverrideAddressSpace : 1;
ULONG HasAddressSpace : 1;
ULONG LaunchPrefetched : 1;
ULONG InjectInpageErrors : 1;
ULONG VmTopDown : 1;
ULONG ImageNotifyDone : 1;
ULONG PdeUpdateNeeded : 1; // NT32 only
ULONG VdmAllowed : 1;
ULONG SmapAllowed : 1;
ULONG CreateFailed : 1;
ULONG DefaultIoPriority : 3;
ULONG Spare1 : 1;
ULONG Spare2 : 1;
};
};
NTSTATUS ExitStatus;
USHORT NextPageColor;
union
{
struct
{
UCHAR SubSystemMinorVersion;
UCHAR SubSystemMajorVersion;
};
USHORT SubSystemVersion;
};
UCHAR PriorityClass;
MM_AVL_TABLE VadRoot;
ULONG Cookie;
} EPROCESS, *PEPROCESS;
又是一大堆这么多复杂的代码。 这里 有详情解释。
B)内核进程块(KPROCESS)
执行进程块的第一个域Pcb描述了内核进程块,
typedef struct _KPROCESS
{
DISPATCHER_HEADER Header;
LIST_ENTRY ProfileListHead;
ULONG DirectoryTableBase;
ULONG Unused0;
KGDTENTRY LdtDescriptor;
KIDTENTRY Int21Descriptor;
WORD IopmOffset;
UCHAR Iopl;
UCHAR Unused;
ULONG ActiveProcessors;
ULONG KernelTime;
ULONG UserTime;
LIST_ENTRY ReadyListHead;
SINGLE_LIST_ENTRY SwapListEntry;
PVOID VdmTrapcHandler;
LIST_ENTRY ThreadListHead;
ULONG ProcessLock;
ULONG Affinity;
union
{
ULONG AutoAlignment: 1;
ULONG DisableBoost: 1;
ULONG DisableQuantum: 1;
ULONG ReservedFlags: 29;
LONG ProcessFlags;
};
CHAR BasePriority;
CHAR QuantumReset;
UCHAR State;
UCHAR ThreadSeed;
UCHAR PowerState;
UCHAR IdealNode;
UCHAR Visited;
union
{
KEXECUTE_OPTIONS Flags;
UCHAR ExecuteOptions;
};
ULONG StackCount;
LIST_ENTRY ProcessListEntry;
UINT64 CycleTime;
} KPROCESS, *PKPROCESS;
内核进程快主要是记录和处理器调度相关的一些信息。
C)执行体进程块(ETHREAD)
Executive Thread block( ETHREAD)与 EPROCESS 结构的情形类似,用来描述 thread 的相关信息的结构:另一个 thread 相关的结构是 Thread Environment Block(TEB)结构,它存在于用户进程空间。
D)内核线程块(KTHREAD)
执行进程结构的第一个域是Tcb描述了内核线程块,该模块也是不透明的。结构如下:
kd> dt -r _kthread
nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x000 Type : UChar
+0x001 Absolute : UChar
+0x002 Size : UChar
+0x003 Inserted : UChar
+0x004 SignalState : Int4B
+0x008 WaitListHead : _LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
+0x010 MutantListHead : _LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
+0x018 InitialStack : Ptr32 Void
+0x01c StackLimit : Ptr32 Void
+0x020 Teb : Ptr32 Void
+0x024 TlsArray : Ptr32 Void
+0x028 KernelStack : Ptr32 Void
+0x02c DebugActive : UChar
+0x02d State : UChar
+0x02e Alerted : [2] UChar
+0x030 Iopl : UChar
+0x031 NpxState : UChar
+0x032 Saturation : Char
+0x033 Priority : Char
+0x034 ApcState : _KAPC_STATE
+0x000 ApcListHead : [2] _LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
+0x010 Process : Ptr32 _KPROCESS
其实Header 域保存了一个分发器头,表明线程对象(ETHREAD结构)也是基于分发器头的同步对象:InitialStack和StackLimit分别记录线程栈基址和栈边界地址;Teb保存了一个指向线程环境块的指针。
3 ,存储系统数据结构
A)参数模块(VPB)
详细如下:
1: kd> ?? fastfat!FatData
struct _FAT_DATA
+0x000 NodeTypeCode : 0x500
+0x002 NodeByteSize : 304
+0x008 LazyWriteThread : 0xfffffa80`037151a0
+0x010 VcbQueue : _LIST_ENTRY [ 0xfffffa80`0384fa18 – 0xfffffa80`0384fa18 ]
……
1: kd> !list "-t nt!_LIST_ENTRY.Flink -e -x \"dd @$extret l4; dt fastfat!_VCB @$extret-0x58\" 0xfffffa80`0384fa18"
dd @$extret l4; dt fastfat!_VCB @$extret-0x58
fffffa80`0384fa18 070e34d0 fffff880 070e34d0 fffff880
+0x000 VolumeFileHeader : _FSRTL_ADVANCED_FCB_HEADER
+0x058 VcbLinks : _LIST_ENTRY [ 0xfffff880`070e34d0 – 0xfffff880`070e34d0 ]
+0x068 TargetDeviceObject : 0xfffffa80`053c7040 _DEVICE_OBJECT
+0x070 Vpb : 0xfffffa80`05b54a00 _VPB
+0x078 VcbState : 0x101002
+0x07c VcbCondition : 1 ( VcbGood )
……
+0x410 SwapVpb : 0xfffffa80`056f19e0 _VPB
+0x418 AsyncCloseList : _LIST_ENTRY [ 0xfffffa80`0384fdd8 – 0xfffffa80`0384fdd8 ]
+0x428 DelayedCloseList : _LIST_ENTRY [ 0xfffff8a0`170d3880 – 0xfffff8a0`170d3880 ]
+0x438 AdvancedFcbHeaderMutex : _FAST_MUTEX
+0x470 CloseContext : 0xfffff8a0`0af0eef0 CLOSE_CONTEXT
+0x478 CloseContextCount : 2
1: kd> dt _VPB 0xfffffa80`05b54a00
nt!_VPB
+0x000 Type : 10
+0x002 Size : 96
+0x004 Flags : 1
+0x006 VolumeLabelLength : 0x10
+0x008 DeviceObject : 0xfffffa80`0384f820 _DEVICE_OBJECT
+0x010 RealDevice : 0xfffffa80`05bab060 _DEVICE_OBJECT
+0x018 SerialNumber : 0x51e712c6
+0x01c ReferenceCount : 9
+0x020 VolumeLabel : [32] "CANON_DC"
1: kd> dt _VPB 0xfffffa80`056f19e0
nt!_VPB
+0x000 Type : 0
+0x002 Size : 0
+0x004 Flags : 0
+0x006 VolumeLabelLength : 0
+0x008 DeviceObject : (null)
+0x010 RealDevice : (null)
+0x018 SerialNumber : 0
+0x01c ReferenceCount : 0
+0x020 VolumeLabel : [32] ""
1: kd> !devobj 0xfffffa80`05bab060
Device object (fffffa8005bab060) is for:
HarddiskVolume18 \Driver\volmgr DriverObject fffffa8004086e70
Current Irp 00000000 RefCount 9 Type 00000007 Flags 00003050
Vpb fffffa8005b54a00 Dacl fffff9a1171d06c0 DevExt fffffa8005bab1b0 DevObjExt fffffa8005bab318 Dope fffffa8004fa7fa0 DevNode fffffa80055d9d90
ExtensionFlags (0000000000)
AttachedDevice (Upper) fffffa8005b4a040 \Driver\fvevol
Device queue is not busy.
1: kd> dt _DEVICE_OBJECT 0xfffffa80`05bab060
nt!_DEVICE_OBJECT
+0x000 Type : 3
+0x002 Size : 0x2b8
+0x004 ReferenceCount : 9
+0x008 DriverObject : 0xfffffa80`04086e70 _DRIVER_OBJECT
+0x010 NextDevice : 0xfffffa80`045ed440 _DEVICE_OBJECT
+0x018 AttachedDevice : 0xfffffa80`05b4a040 _DEVICE_OBJECT
+0x020 CurrentIrp : (null)
+0x028 Timer : (null)
+0x030 Flags : 0x3050
+0x034 Characteristics : 1
+0x038 Vpb : 0xfffffa80`05b54a00 _VPB
+0x040 DeviceExtension : 0xfffffa80`05bab1b0
+0x048 DeviceType : 7
+0x04c StackSize : 9 ”
+0x050 Queue :
+0x098 AlignmentRequirement : 0
+0x0a0 DeviceQueue : _KDEVICE_QUEUE
+0x0c8 Dpc : _KDPC
+0x108 ActiveThreadCount : 0
+0x110 SecurityDescriptor : 0xfffff8a0`170b0620
+0x118 DeviceLock : _KEVENT
+0x130 SectorSize : 0x200
+0x132 Spare1 : 1
+0x138 DeviceObjectExtension : 0xfffffa80`05bab318 _DEVOBJ_EXTENSION
+0x140 Reserved : (null)
又是一板的代码、、 唉。。 这个就不细说啦。 这哥们总结的非常好!
B) 文件对象(File_Object)
文件对象就是一个文件,设备,目录等对象的打开实例。在任何时候,针对一个共享文件可以有多个文件对象,即共享文件可以被多次打开,但是每一个文件对象只对应一个句柄。文件对象的数据结构如下所示:
typedef struct _FILE_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
PVPB Vpb;
PVOID FsContext;
PVOID FsContext2;
PSECTION_OBJECT_POINTERS SectionObjectPointer;
PVOID PrivateCacheMap;
NTSTATUS FinalStatus;
struct _FILE_OBJECT *RelatedFileObject;
BOOLEAN LockOperation;
BOOLEAN DeletePending;
BOOLEAN ReadAccess;
BOOLEAN WriteAccess;
BOOLEAN DeleteAccess;
BOOLEAN SharedRead;
BOOLEAN SharedWrite;
BOOLEAN SharedDelete;
ULONG Flags;
UNICODE_STRING FileName;
LARGE_INTEGER CurrentByteOffset;
__volatile ULONG Waiters;
__volatile ULONG Busy;
PVOID LastLock;
KEVENT Lock;
KEVENT Event;
__volatile PIO_COMPLETION_CONTEXT CompletionContext;
KSPIN_LOCK IrpListLock;
LIST_ENTRY IrpList;
__volatile PVOID FileObjectExtension;
} FILE_OBJECT, *PFILE_OBJECT;
其中,
DeviceObject域记录域所打开文件相关联的设备。Vpb记录参数块;
FsContext及
FsContext2域是自定义指针;
SectionObjectPointer 是一个内存区对象指针,指向数据控制区域或者映像控制区域;
FileName记录文件名。
C) SCSI请求块(SRB)
SCSI请求块结构用来在存储类驱动和存储端口驱动间传输I/O请求。然后端口驱动再将SRB转发给小端口驱动。SRB的结构如下:
typedef struct _SCSI_REQUEST_BLOCK {
USHORT Length;
UCHAR Function;
UCHAR SrbStatus;
UCHAR ScsiStatus;
UCHAR PathId;
UCHAR TargetId;
UCHAR Lun;
UCHAR QueueTag;
UCHAR QueueAction;
UCHAR CdbLength;
UCHAR SenseInfoBufferLength;
ULONG SrbFlags;
ULONG DataTransferLength;
ULONG TimeOutValue;
PVOID DataBuffer;
PVOID SenseInfoBuffer;
struct _SCSI_REQUEST_BLOCK *NextSrb;
PVOID OriginalRequest;
PVOID SrbExtension;
union {
ULONG InternalStatus;
ULONG QueueSortKey;
ULONG LinkTimeoutValue;
};
#ifdef _WIN64
ULONG Reserved;
#endif
UCHAR Cdb[16];
} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;
Length 记录此数据结构的长度;
Function记录执行的操作,
SrbStatus记录请求完成时的状态,
ScsiStatus记录
HBA 或者目标设备返回的
SCSI 状态,
PathId 标识请求的
SISC端口或者总线;
TargetId 标识目标i控制器或总线上的设备;
Lun标识设备的逻辑单元号;
CdbLength记录SCSI-2或者命令秒速块的大小;
DataBuffer指向数据缓冲区;
OriginalRequest指向原始的IRP 请求;
SrbExtension指向Srb的扩展部分;
Cdb指定要发送给目标设备的 SCSI-2或者命令描述符块。