겸손한 개발을 위한 자양분

IRP Major Function Codes

MSDN2008. 4. 25. 18:12

Windows Driver Kit: Kernel-Mode Driver Architecture

IRP Major Function Codes

Each driver-specific I/O stack location (IO_STACK_LOCATION) for every IRP contains a major function code (IRP_MJ_XXX), which tells the driver what operation it or the underlying device driver should carry out to satisfy the I/O request. Each kernel-mode driver must provide dispatch routines for the major function codes that it must support.

The specific operations a driver carries out for a given IRP_MJ_XXX code depend somewhat on the underlying device, particularly for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL requests. For example, the requests sent to a keyboard driver are necessarily somewhat different from those sent to a disk driver. However, the I/O manager defines the parameters and I/O stack location contents for each system-defined major function code.

Every higher-level driver must set up the appropriate I/O stack location in IRPs for the next-lower-level driver and call IoCallDriver, either with each input IRP, or with a driver-created IRP (if the higher-level driver holds on to the input IRP). Consequently, every intermediate driver must supply a dispatch routine for each major function code that the underlying device driver handles. Otherwise, a new intermediate driver will "break the chain" whenever an application or still higher-level driver attempts to send an I/O request down to the underlying device driver.

File system drivers also handle a required subset of system-defined IRP_MJ_XXX function codes, some with subordinate IRP_MN_XXX function codes.

Drivers handle IRPs set with some or all of the following major function codes:

IRP_MJ_CREATE

IRP_MJ_PNP

IRP_MJ_POWER

IRP_MJ_READ

IRP_MJ_WRITE

IRP_MJ_FLUSH_BUFFERS

IRP_MJ_QUERY_INFORMATION

IRP_MJ_SET_INFORMATION

IRP_MJ_DEVICE_CONTROL

IRP_MJ_INTERNAL_DEVICE_CONTROL

IRP_MJ_SYSTEM_CONTROL

IRP_MJ_CLEANUP

IRP_MJ_CLOSE

IRP_MJ_SHUTDOWN

The input and output parameters described in this section are the function-specific parameters in the IRP.


IRP_MJ_CREATE

Every kernel-mode driver must handle IRP_MJ_CREATE requests in a DispatchCreate or DispatchCreateClose routine.

When Sent

The operating system sends an IRP_MJ_CREATE request to open a handle to a file object or device object. For example, when a driver calls ZwCreateFile, the operating system sends an IRP_MJ_CREATE request to perform the actual open operation.

Input Parameters

The Parameters.Create.SecurityContext member points to an IO_SECURITY_CONTEXT structure that describes the security context for the request.

The Parameters.Create.Options member is a ULONG value that describes the options that are used when opening the handle. The high 8 bits correspond to the value of the CreateDisposition parameter of ZwCreateFile, and the low 24 bits correspond to the value of the CreateOptions parameter of ZwCreateFile.

The Parameters.Create.ShareAccess member is a USHORT value that describes the type of share access. This value corresponds to the value of the ShareAccess parameter of ZwCreateFile.

The Parameters.Create.FileAttributes and Parameters.Create.EaLength members are reserved for use by file systems and file system filter drivers. For more information, see the IRP_MJ_CREATE topic in the Installable File System (IFS) documentation.

Output Parameters

None

Operation

Most device and intermediate drivers set STATUS_SUCESS in the I/O status block of the IRP and complete the create request, but drivers can optionally use their DispatchCreate routine to reserve resources for any subsequent I/O requests for that handle. For example, the system serial driver maps its paged-out code and allocates any resources that are necessary to handle subsequent I/O requests for the user-mode thread that is attempting to open the device for input and output.


IRP_MJ_PNP

All drivers must be prepared to service IRP_MJ_PNP requests in a DispatchPnP routine.

When Sent

The PnP manager sends IRP_MJ_PNP requests during enumeration, resource rebalancing, and any other time Plug and Play activity occurs on the system. Drivers can also send certain IRP_MJ_PNP requests, depending on the minor function code.

Input Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP. Every IRP_MJ_PNP request specifies a minor function code that identifies the requested PnP action.

Output Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP.

Operation

See Plug and Play Minor IRPs for detailed information about IRP_MJ_PNP requests.


IRP_MJ_POWER

All drivers must be prepared to service IRP_MJ_POWER requests in a DispatchPower routine.

When Sent

The power manager or a driver can send IRP_MJ_POWER requests at any time the operating system is running.

Input Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP. Every IRP_MJ_POWER request specifies a minor function code that identifies the requested power action.

Output Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP.

Operation

See Power Management Minor IRPs for detailed information about IRP_MJ_POWER requests.


IRP_MJ_READ

Every device driver that transfers data from its device to the system must handle read requests in a DispatchRead or DispatchReadWrite routine, as must any higher-level driver layered over such a device driver.

When Sent

Any time following the successful completion of a create request.

Possibly, a user-mode application or Win32 component with a handle for the file object representing the target device object has requested a data transfer from the device. Possibly, a higher-level driver has created and set up the read IRP.

Input Parameters

The driver's I/O stack location in the IRP indicates how many bytes to transfer at Parameters.Read.Length.

Some drivers use the value at Parameters.Read.Key to sort incoming read requests into a driver-determined order in the device queue or in a driver-managed internal queue of IRPs. Certain types of drivers also use the value at Parameters.Read.ByteOffset, which indicates the starting offset for the transfer operation.

Output Parameters

Depending on whether the underlying device driver sets up the target device object's Flags with DO_BUFFERED_IO or with DO_DIRECT_IO, data is transferred into one of the following:

  • The buffer at Irp->AssociatedIrp.SystemBuffer if the driver uses buffered I/O
  • The buffer described by the MDL at Irp->MdlAddress if the underlying device driver uses direct I/O (DMA or PIO)

Operation

On receipt of a read request, a higher-level driver sets up the I/O stack location in the IRP for the next-lower driver, or it creates and sets up additional IRPs for one or more lower drivers. It can set up its IoCompletion routine, which is optional for the input IRP but required for driver-created IRPs, by calling IoSetCompletionRoutine. Then, the driver passes the request on to the next-lower driver with IoCallDriver.

On receipt of a read request, a device driver transfers data from its device to system memory. The device driver sets the Information field of the I/O status block to the number of bytes transferred when it completes the IRP.


IRP_MJ_WRITE

Every device driver that transfers data from the system to its device must handle write requests in a DispatchWrite or DispatchReadWrite routine, as must any higher-level driver layered over such a device driver.

When Sent

Any time following the successful completion of a create request.

Possibly, a user-mode application or Win32 component with a handle for the file object representing the target device object has requested a data transfer to the device. Possibly, a higher-level driver has created and set up the write IRP.

Input Parameters

The driver's I/O stack location in the IRP indicates how many bytes to transfer at Parameters.Write.Length.

Some drivers use the value at Parameters.Write.Key to sort incoming write requests into a driver-determined order in the device queue or in a driver-managed internal queue of IRPs. Certain types of drivers also use the value at Parameters.Write.ByteOffset, which indicates the starting offset for the transfer operation.

Depending on whether the underlying device driver sets up the target device object's Flags with DO_BUFFERED_IO or with DO_DIRECT_IO, data is transferred from one of the following:

  • The buffer at Irp->AssociatedIrp.SystemBuffer, if the driver uses buffered I/O
  • The buffer described by the MDL at Irp->MdlAddress, if the underlying device driver uses direct I/O (DMA or PIO)

Output Parameters

None

Operation

On receipt of a write request, a higher-level driver sets up the I/O stack location in the IRP for the next-lower driver, or it creates and sets up additional IRPs for one or more lower drivers. It can set up its IoCompletion routine, which is optional for the input IRP but required for driver-created IRPs, by calling IoSetCompletionRoutine. Then, the driver passes the request on to the next-lower driver with IoCallDriver.

On receipt of a write request, a device driver transfers data from system memory to its device. The device driver sets the Information field of the I/O status block to the number of bytes transferred when it completes the IRP.


IRP_MJ_FLUSH_BUFFERS

Drivers of devices with internal caches for data and drivers that maintain internal buffers for data must handle this request in a DispatchFlushBuffers routine.

When Sent

Receipt of a flush request indicates that the driver should flush the device's cache or its internal buffer, or, possibly, should discard the data in its internal buffer.

Input Parameters

None

Output Parameters

None

Operation

The driver transfers any data currently cached in the device or held in the driver's internal buffers before completing the flush request. The driver of an input-only device that buffers data internally might simply discard the currently buffered device data before completing the flush IRP, depending on the nature of its device.


IRP_MJ_QUERY_INFORMATION

Drivers can optionally handle an IRP_MJ_QUERY_INFORMATION request.

When Sent

The operating system sends an IRP_MJ_QUERY_INFORMATION request to obtain metadata about a file or file handle. For example, when a driver calls ZwQueryInformationFile, the operating system sends an IRP_MJ_QUERY_INFORMATION request.

Input Parameters

The Parameters.QueryFile.FileInformationClass member is a FILE_INFORMATION_CLASS constant that specifies the type of metadata to provide. For more information about the types of metadata, see the FileInformationClass parameter of the ZwQueryInformationFile routine.

The Parameters.QueryFile.Length member specifies the length of the buffer that the AssociatedIrp.SystemBuffer member points to.

Output Parameters

The AssociatedIrp.SystemBuffer member points to the buffer where the driver supplies the requested information. The value of Parameters.QueryFile.FileInformationClass determines the format of the metadata (a FILE_XXX_INFORMATION structure) to return. For more information about the formats of metadata, see the FileInformation parameter of ZwQueryInformationFile.

Operation

Drivers are not required to handle this request, and drivers that do are not required to handle every possible value of Parameters.QueryFile.FileInformationClass. The driver's dispatch routine should return an error code such as STATUS_INVALID_DEVICE_REQUEST for any values that it does not handle.

Not all of the possible values of FILE_INFORMATION_CLASS can occur. For a complete list of the possible values, see the IRP_MJ_QUERY_INFORMATION topic in the Installable File System (IFS) documentation.


IRP_MJ_SET_INFORMATION

Device drivers can optionally handle an IRP_MJ_SET_INFORMATION request.

When Sent

The operating system sends an IRP_MJ_SET_INFORMATION request to set metadata about a file or file handle. For example, when a driver calls ZwSetInformationFile, the operating system sends an IRP_MJ_SET_INFORMATION request.

Input Parameters

The Parameters.SetFile.FileInformationClass member is a FILE_INFORMATION_CLASS constant that specifies the type of metadata to set. For more information about the types of metadata, see the FileInformationClass parameter of ZwSetInformationFile.

The Parameters.SetFile.Length member specifies the length of the buffer that the AssociatedIrp.SystemBuffer member points to.

AssociatedIrp.SystemBuffer points to the buffer that contains the new information setting. The value of Parameters.SetFile.FileInformationClass determines the format of the data (a FILE_XXX_INFORMATION structure) to return. For more information about the formats of metadata, see the FileInformation parameter of ZwSetInformationFile.

Output Parameters

None

Operation

Drivers are not required to handle this request, and drivers that do are not required to handle every possible value of Parameters.SetFile.FileInformationClass. The driver's dispatch routine should return an error code such as STATUS_INVALID_DEVICE_REQUEST for any values that it does not handle.

Not all of the possible values of FILE_INFORMATION_CLASS can occur. For a complete list of the possible values, see the IRP_MJ_SET_INFORMATION topic in the Installable File System (IFS) documentation.


IRP_MJ_DEVICE_CONTROL

Every driver whose device objects belong to a particular device type (see Specifying Device Types) is required to support this request in a DispatchDeviceControl routine, if a set of system-defined I/O control codes (IOCTLs) exists for the type.

Higher-level drivers usually pass these requests on to an underlying device driver. Each device driver in a driver stack is assumed to support this request, along with a set of device type-specific, public or private IOCTLs. For more information about IOCTLs for specific device types, see device type-specific documentation in the Microsoft Windows Driver Kit (WDK).

When Sent

Any time following the successful completion of a create request.

Input Parameters

The I/O control code is contained at Parameters.DeviceIoControl.IoControlCode in the driver's I/O stack location of the IRP.

Other input parameters depend on the I/O control code's value. For more information, see Buffer Descriptions for I/O Control Codes.

Output Parameters

Output parameters depend on the I/O control code's value. For more information, see Buffer Descriptions for I/O Control Codes.

Operation

A driver receives this I/O control code because user-mode thread has called the Microsoft Win32 DeviceIoControl function, or a higher-level kernel-mode driver has set up the request. Possibly, a user-mode driver has called DeviceIoControl, passing in a driver-defined (also called private) I/O control code, to request device- or driver-specific support from a closely coupled, kernel-mode device driver.

On receipt of a device I/O control request, a higher-level driver usually passes the IRP on to the next-lower driver. However, there are some exceptions to this practice. For example, a class driver that has stored configuration information obtained from the underlying port driver might complete certain IOCTL_XXX requests without passing the IRP down to the corresponding port driver.

On receipt of a device I/O control request, a device driver examines the I/O control code to determine how to satisfy the request. For most public I/O control codes, device drivers transfer a small amount of data to or from the buffer at Irp->AssociatedIrp.SystemBuffer.

For general information about I/O control codes for IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL requests, see Using I/O Control Codes. See also Device Type-specific I/O Requests.


IRP_MJ_INTERNAL_DEVICE_CONTROL

In general, any replacement for an existing driver that supports internal device control requests should handle this request in a DispatchInternalDeviceControl routine. Such a driver must support at least the same set of internal I/O control codes as the driver it replaces. Otherwise, existing higher-level drivers might not work with the new driver.

Drivers that replace certain lower-level system drivers are required to handle this request. For example, a replacement for the system parallel port driver must continue to support existing parallel class drivers. Note that certain system drivers that handle this request cannot be replaced, in particular, the system-supplied SCSI and video port drivers.

When Sent

Any time after the successful completion of a create request.

Input Parameters

The I/O control code is contained at Parameters.DeviceIoControl.IoControlCode in the I/O stack location of the IRP.

Other input parameters depend on the I/O control code's value. For more information, see Buffer Descriptions for I/O Control Codes.

Output Parameters

Output parameters depend on the I/O control code's value. For more information, see Buffer Descriptions for I/O Control Codes.

Operation

Drivers receive IRP_MJ_INTERNAL_DEVICE_CONTROL requests when another driver calls either IoBuildDeviceIoControlRequest or IoAllocateIrp to create a request.

This I/O control code has been defined for communication between paired and layered kernel-mode drivers, such as one or more class drivers layered over a port driver. The higher-level driver sets up IRPs with device- or driver-specific I/O control codes, requesting support from the next-lower driver.

The requested operation is device- or driver-specific.

For general information about I/O control codes for IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL requests, see Using I/O Control Codes. See also Device Type-specific I/O Requests.


IRP_MJ_SYSTEM_CONTROL

All drivers must provide a DispatchSystemControl routine that handles IRP_MJ_SYSTEM_CONTROL requests, which are sent by the kernel-mode component of Windows Management Instrumentation (WMI).

When Sent

The WMI kernel-mode component can send an IRP_MJ_SYSTEM_CONTROL request any time following a driver's successful registration as a supplier of WMI data. WMI IRPs typically are sent when a user-mode data consumer has requested WMI data.

Input Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP. Every IRP_MJ_SYSTEM_CONTROL request specifies a minor function code that identifies the requested WMI action.

Output Parameters

Depends on the value at MinorFunction in the current I/O stack location of the IRP.

Operation

All drivers must support IRP_MJ_SYSTEM_CONTROL requests by supplying a DispatchSystemControl routine.

Drivers that support Windows Management Instrumentation (WMI) must handle IRP_MJ_SYSTEM_CONTROL requests by processing the minor function codes associated with this major function code. For information about the WMI minor function codes, see WMI Minor IRPs.

Drivers that do not support WMI by registering as a WMI data provider must pass IRP_MJ_SYSTEM_CONTROL requests to the next lower driver.


IRP_MJ_CLEANUP

Drivers that maintain process-specific context information must handle cleanup requests in DispatchCleanup routines.

When Sent

Receipt of this request indicates that the last handle for a file object that is associated with the target device object has been closed (but, due to outstanding I/O requests, might not have been released).

Input Parameters

None

Output Parameters

None

Operation

This IRP is sent in the context of the process that closed the file object handle. Therefore, the driver should release process-specific resources, such as user memory, that the driver previously locked or mapped.

If the driver's device objects were set up as exclusive, so that only a single thread can use the device at a time, the driver must complete every IRP that is currently queued to the target device object and set STATUS_CANCELLED in each IRP's I/O status block.

Otherwise, the driver must cancel and complete only the currently queued IRPs that are associated with the file object handle that is being released. (A pointer to the file object is located in the FileObject member of the driver's IO_STACK_LOCATION of the IRP.) After canceling these queued IRPs, the driver completes the cleanup IRP and sets STATUS_SUCCESS in its I/O status block.

For more information about handling this request, see DispatchCleanup Routines.


IRP_MJ_CLOSE

Every driver must handle close requests in a DispatchClose routine, with the possible exception of a driver whose device cannot be disabled or removed from the machine without bringing down the system. A disk driver whose device holds the system page file is an example of such a driver. Note that the driver of such a device also cannot be unloaded dynamically.

When Sent

Receipt of this request indicates that the last handle of the file object that is associated with the target device object has been closed and released. All outstanding I/O requests have been completed or canceled.

Input Parameters

None

Output Parameters

None

Operation

Many device and intermediate drivers merely set STATUS_SUCCESS in the I/O status block of the IRP and complete the close request. However, what a given driver does on receipt of a close request depends on the driver's design. In general, a driver should undo whatever actions it takes on receipt of the IRP_MJ_CREATE request. Device drivers whose device objects are exclusive, such as a serial driver, also can reset the hardware on receipt of a close request.

The IRP_MJ_CLOSE request is not necessarily sent in the context of the process that closed the file object handle. If the driver must release process-specific resources, such as user memory, that the driver previously locked or mapped, it must do so in response to an IRP_MJ_CLEANUP request.

The IRP_MJ_CLOSE request will always be sent at PASSIVE_LEVEL.


IRP_MJ_SHUTDOWN

Drivers of mass-storage devices that have internal caches for data must handle this request in a DispatchShutdown routine. Drivers of mass-storage devices and intermediate drivers layered over them also must handle this request if an underlying driver maintains internal buffers for data.

When Sent

Receipt of a shutdown request indicates that a file system driver is sending notice that the system is being shut down.

One or more file system drivers can send such a lower-level driver more than one shutdown request when a user logs off or when the system is being shut down for some other reason.

Input Parameters

None

Output Parameters

None

Operation

The driver must complete the transfer of any data currently cached in the device or held in the driver's internal buffers before completing the shutdown request.

A driver does not receive an IRP_MJ_SHUTDOWN request for a device object unless it registers to do so with either IoRegisterShutdownNotification or IoRegisterLastChanceShutdownNotification.

~ System Process 가 가진 ObjectTable 을 찾아본다.
~ System Process 의 PID가 4이므로, 4번 PID 의 EPROCESS 확인

0: kd> !process 4 0
Searching for Process with Cid == 4
PROCESS 867b5830  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 06e40020  ObjectTable: e1003ea8  HandleCount: 1321.
    Image: System

~ 디버거에서 ObjectTable 을 반환하지만
~ EPROCESS 구조체에서 직접 확인
0: kd> dt nt!_EPROCESS 867b5830
   +0x000 Pcb              : _KPROCESS
   +0x06c ProcessLock      : _EX_PUSH_LOCK
   +0x070 CreateTime       : _LARGE_INTEGER 0x0
   +0x078 ExitTime         : _LARGE_INTEGER 0x0
   +0x080 RundownProtect   : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId  : 0x00000004
   +0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x86476558 - 0x805627b8 ]
   +0x090 QuotaUsage       : [3] 0
   +0x09c QuotaPeak        : [3] 0
   +0x0a8 CommitCharge     : 7
   +0x0ac PeakVirtualSize  : 0x537000
   +0x0b0 VirtualSize      : 0x1e4000
   +0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x0bc DebugPort        : (null)
   +0x0c0 ExceptionPort    : (null)
   +0x0c4 ObjectTable      : 0xe1003ea8 _HANDLE_TABLE
   +0x0c8 Token            : _EX_FAST_REF
   +0x0cc WorkingSetLock   : _FAST_MUTEX
...

~ HandleTable 값 확인
0: kd> dt _HANDLE_TABLE 0xe1003ea8
nt!_HANDLE_TABLE
   +0x000 TableCode        : 0xe18b3001
   +0x004 QuotaProcess     : (null)
   +0x008 UniqueProcessId  : 0x00000004
   +0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
   +0x01c HandleTableList  : _LIST_ENTRY [ 0xe1010f84 - 0x80563aa8 ]
   +0x024 HandleContentionEvent : _EX_PUSH_LOCK
   +0x028 DebugInfo        : (null)
   +0x02c ExtraInfoPages   : 0
   +0x030 FirstFree        : 0x1740
   +0x034 LastFree         : 0
   +0x038 NextHandleNeedingPool : 0x1800
   +0x03c HandleCount      : 1321
   +0x040 Flags            : 0
   +0x040 StrictFIFO       : 0y0

~ TableCode 값이 Handle Table Entries (최종엔트리) 인지 확인
~ 0x03 과 & 연산에서 0 인경우 최종엔트리
0: kd> ? e18b3001 & 0x3
Evaluate expression: 1 = 00000001

~ 최종 엔트리가 아닌경우
~ 포인터 테이블의 주소값 연산
0: kd> ? e18b3001 & 0xfffffffc
Evaluate expression: -510971904 = e18b3000

~ ObjectTable Pointer 값 확인
0: kd> dd e18b3000
e18b3000  e1004000 e18b4000 e1a3e000 00000000
e18b3010  00000000 00000000 00000000 00000000
e18b3020  00000000 00000000 00000000 00000000
e18b3030  00000000 00000000 00000000 00000000
e18b3040  00000000 00000000 00000000 00000000
e18b3050  00000000 00000000 00000000 00000000
e18b3060  00000000 00000000 00000000 00000000
e18b3070  00000000 00000000 00000000 00000000

~ 다시 최종 엔트리인지 확인
0: kd> ? e1004000 & 0x03
Evaluate expression: 0 = 00000000

~ 최종 ObjectTable(HandleTableEntries) 확인
0: kd> dd e1004000
e1004000  00000000 fffffffe 867b5819 001f0fff
e1004010  867b4009 00000000 e14e3469 000f003f
e1004020  e1011459 00000000 e14ea419 00020019
e1004030  e14f1419 00020019 e1023441 0002001f
e1004040  e14e9129 00020019 e14e2151 00020019
e1004050  e14f6441 00020019 e14f2419 0002001f
e1004060  e14ff441 00020019 867e8239 001f0003
e1004070  8634ae89 0012019f 86366cd1 0012019f
0: kd> dd e18b4000
...
0: kd> dd e1a3e000
...

~ ENTRY 구조는 다음과 같이
  4바이트 오브젝트(_OBJECT_HEADER), 4바이트 GrantAccess 구조이다
0: kd> dt nt!_HANDLE_TABLE_ENTRY
   +0x000 Object           : Ptr32 Void
   +0x000 ObAttributes     : Uint4B
   +0x000 InfoTable        : Ptr32 _HANDLE_TABLE_ENTRY_INFO
   +0x000 Value            : Uint4B
   +0x004 GrantedAccess    : Uint4B
   +0x004 GrantedAccessIndex : Uint2B
   +0x006 CreatorBackTraceIndex : Uint2B
   +0x004 NextFreeTableEntry : Int4B
typedef struct _HANDLE_TABLE_ENTRY {
 union {
  PVOID Object;
  ULONG ObAttributes;
 };
 union {
  union {
   ACCESS_MASK GrantedAccess;
   struct {
    USHORT GrantedAccessIndex;
    USHORT CreatorBackTraceIndex;
   };
  };
 LONG NextFreeTableEntry;
 };
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;

~ 단, 8바이트 오브젝트 포인터의 마지막 비트가 Lock Bit 이므로
~ 사용할때 & ~1 연산이 필요하다
~ 엔트리중 e1004000 + sizeof(_HANDLE_TABLE_ENTRY).
~ 즉, 첫번째 값을 보면
0: kd> ? 867b5819 & 0xfffffffe
Evaluate expression: -2038736872 = 867b5818
0: kd> dt nt!_OBJECT_HEADER 867b5818
   +0x000 PointerCount     : 89
   +0x004 HandleCount      : 2
   +0x004 NextToFree       : 0x00000002
   +0x008 Type             : 0x867b5e70 _OBJECT_TYPE
   +0x00c NameInfoOffset   : 0 ''
   +0x00d HandleInfoOffset : 0 ''
   +0x00e QuotaInfoOffset  : 0 ''
   +0x00f Flags            : 0x22 '"'
   +0x010 ObjectCreateInfo : 0x80562860 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : 0x80562860
   +0x014 SecurityDescriptor : 0xe1001bd2
   +0x018 Body             : _QUAD
0: kd> dt nt!_OBJECT_TYPE 0x867b5e70
   +0x000 Mutex            : _ERESOURCE
   +0x038 TypeList         : _LIST_ENTRY [ 0x867b5ea8 - 0x867b5ea8 ]
   +0x040 Name             : _UNICODE_STRING "Process"
   +0x048 DefaultObject    : (null)
   +0x04c Index            : 5
   +0x050 TotalNumberOfObjects : 0x1e
   +0x054 TotalNumberOfHandles : 0x79
   +0x058 HighWaterNumberOfObjects : 0x20
   +0x05c HighWaterNumberOfHandles : 0x80
   +0x060 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0ac Key              : 0x636f7250
   +0x0b0 ObjectLocks      : [4] _ERESOURCE

~ Process Type의 Object 이므로
~ Object Header + sizeof(_OBJECT_HEADER) 주소, 즉 Body 주소를 캐스트한다
0: kd> dt nt!_EPROCESS 867b5818+0x18
   +0x000 Pcb              : _KPROCESS
   +0x06c ProcessLock      : _EX_PUSH_LOCK
   +0x070 CreateTime       : _LARGE_INTEGER 0x0
   +0x078 ExitTime         : _LARGE_INTEGER 0x0
   +0x080 RundownProtect   : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId  : 0x00000004
   +0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x86476558 - 0x805627b8 ]
   +0x090 QuotaUsage       : [3] 0
   +0x09c QuotaPeak        : [3] 0
   +0x0a8 CommitCharge     : 7
   +0x0ac PeakVirtualSize  : 0x537000
   +0x0b0 VirtualSize      : 0x1e4000
   +0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x0bc DebugPort        : (null)
   +0x0c0 ExceptionPort    : (null)
   +0x0c4 ObjectTable      : 0xe1003ea8 _HANDLE_TABLE
   +0x0c8 Token            : _EX_FAST_REF
   +0x0cc WorkingSetLock   : _FAST_MUTEX
   +0x0ec WorkingSetPage   : 0x6dc6
   +0x0f0 AddressCreationLock : _FAST_MUTEX
   +0x110 HyperSpaceLock   : 0
   +0x114 ForkInProgress   : (null)
   +0x118 HardwareTrigger  : 0
   +0x11c VadRoot          : 0x867b11e8
   +0x120 VadHint          : 0x867b11e8
   +0x124 CloneRoot        : (null)
   +0x128 NumberOfPrivatePages : 3
   +0x12c NumberOfLockedPages : 0
   +0x130 Win32Process     : (null)
   +0x134 Job              : (null)
   +0x138 SectionObject    : (null)
   +0x13c SectionBaseAddress : (null)
   +0x140 QuotaBlock       : 0x80562860 _EPROCESS_QUOTA_BLOCK
   +0x144 WorkingSetWatch  : (null)
   +0x148 Win32WindowStation : (null)
   +0x14c InheritedFromUniqueProcessId : (null)
   +0x150 LdtInformation   : (null)
   +0x154 VadFreeHint      : (null)
   +0x158 VdmObjects       : (null)
   +0x15c DeviceMap        : 0xe1002170
   +0x160 PhysicalVadList  : _LIST_ENTRY [ 0x867b5990 - 0x867b5990 ]
   +0x168 PageDirectoryPte : _HARDWARE_PTE
   +0x168 Filler           : 0
   +0x170 Session          : (null)
   +0x174 ImageFileName    : [16]  "System"
   +0x184 JobLinks         : _LIST_ENTRY [ 0x0 - 0x0 ]
...


~ "system" process 의 핸들임을 확인할 수 있다.
~ 마찬가지로 다른 핸들테이블엔트리를 확인하여 찾을 수 있다.
~ 끝


[참고]

1. 핸들 테이블 항목의 구조

      0        8        16       24bit

    [ -------- -------- -------- -------- ] // 개체 헤더에 대한 포인터
      L                               AIP

    [ -------- -------- -------- -------- ] // 엑세스 마스크

    총 4B + 4B 의 8바이트로 구성됨.
    L : Lock Bit
    A : Audit Bit
    I : Inherit Bit
    P : Protect Bit

2. Win2K 의 경우
   핸들테이블 -> 핸들테이블포인터 -> 핸들테이블포인터 -> 핸들테이블엔트리리스트
   의 3단계 구조

   WinXP/2k3 의 경우
   1단계~3단계 가능하므로 0x3 Mask 로 확인

3. 핸들 테이블 항목의 최대 개수는
   4KByte(1Page) 에 들어갈 수 있는 최대 개수로 결정되므로
   핸들테이블엔트리사이즈(8Byte) / 4K(1Page) -> 511개 ( 맨 앞단 1개는 사용되지 않음 )