FileDisk其实说到底也就是对磁盘的一些操作,其原理也相对简单,不像文件过滤驱动那么复杂,FileDisk也只用到了一套接口IRP_MJ_CREATE等,相对来说结构是比较简单的,下面是我对filedisk代码的一些注释,其实还有二个问题没搞太懂,还有一些小细节,不太清楚有些变量是用来搞什么的,还有几个小函数没弄太清楚,把问题放到最后再说。
#include
#include
#include
#include
//
// We include some stuff from newer DDK:s here so that one
// version of the driver for all versions of Windows can
// be compiled with the Windows NT 4.0 DDK.
//
#if (VER_PRODUCTBUILD < 2195)
#define FILE_DEVICE_MASS_STORAGE 0x0000002d
#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
#endif
#if (VER_PRODUCTBUILD < 2600)
#define IOCTL_DISK_GET_PARTITION_INFO_EX CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)
typedef enum _PARTITION_STYLE {
PARTITION_STYLE_MBR,
PARTITION_STYLE_GPT
} PARTITION_STYLE;
typedef unsigned __int64 ULONG64, *PULONG64;
typedef struct _PARTITION_INFORMATION_MBR {
UCHAR PartitionType;
BOOLEAN BootIndicator;
BOOLEAN RecognizedPartition;
ULONG HiddenSectors;
} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR;
typedef struct _PARTITION_INFORMATION_GPT {
GUID PartitionType;
GUID PartitionId;
ULONG64 Attributes;
WCHAR Name[36];
} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT;
typedef struct _PARTITION_INFORMATION_EX {
PARTITION_STYLE PartitionStyle;
LARGE_INTEGER StartingOffset;
LARGE_INTEGER PartitionLength;
ULONG PartitionNumber;
BOOLEAN RewritePartition;
union {
PARTITION_INFORMATION_MBR Mbr;
PARTITION_INFORMATION_GPT Gpt;
};
} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX;
typedef struct _GET_LENGTH_INFORMATION {
LARGE_INTEGER Length;
} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION;
#endif // (VER_PRODUCTBUILD < 2600)
//
// We include some stuff from ntifs.h here so that
// the driver can be compiled with only the DDK.
//
#define TOKEN_SOURCE_LENGTH 8
typedef enum _TOKEN_TYPE {
TokenPrimary = 1,
TokenImpersonation
} TOKEN_TYPE;
typedef struct _TOKEN_SOURCE {
CCHAR SourceName[TOKEN_SOURCE_LENGTH];
LUID SourceIdentifier;
} TOKEN_SOURCE, *PTOKEN_SOURCE;
typedef struct _TOKEN_CONTROL {
LUID TokenId;
LUID AuthenticationId;
LUID ModifiedId;
TOKEN_SOURCE TokenSource;
} TOKEN_CONTROL, *PTOKEN_CONTROL;
typedef struct _SECURITY_CLIENT_CONTEXT {
SECURITY_QUALITY_OF_SERVICE SecurityQos;
PACCESS_TOKEN ClientToken;
BOOLEAN DirectlyAccessClientToken;
BOOLEAN DirectAccessEffectiveOnly;
BOOLEAN ServerIsRemote;
TOKEN_CONTROL ClientTokenControl;
} SECURITY_CLIENT_CONTEXT, *PSECURITY_CLIENT_CONTEXT;
#define PsDereferenceImpersonationToken(T) \
{if (ARGUMENT_PRESENT(T)) { \
(ObDereferenceObject((T))); \
} else { \
; \
} \
}
#define PsDereferencePrimaryToken(T) (ObDereferenceObject((T)))
NTKERNELAPI
VOID
PsRevertToSelf (
VOID
);
NTKERNELAPI
NTSTATUS
SeCreateClientSecurity (
IN PETHREAD Thread,
IN PSECURITY_QUALITY_OF_SERVICE QualityOfService,
IN BOOLEAN RemoteClient,
OUT PSECURITY_CLIENT_CONTEXT ClientContext
);
#define SeDeleteClientSecurity(C) { \
if (SeTokenType((C)->ClientToken) == TokenPrimary) { \
PsDereferencePrimaryToken( (C)->ClientToken ); \
} else { \
PsDereferenceImpersonationToken( (C)->ClientToken ); \
} \
}
NTKERNELAPI
VOID
SeImpersonateClient (
IN PSECURITY_CLIENT_CONTEXT ClientContext,
IN PETHREAD ServerThread OPTIONAL
);
NTKERNELAPI
TOKEN_TYPE
SeTokenType (
IN PACCESS_TOKEN Token
);
#ifndef SE_IMPERSONATE_PRIVILEGE
#define SE_IMPERSONATE_PRIVILEGE (29L)
#endif
#define TOKEN_ASSIGN_PRIMARY (0x0001)
#define TOKEN_DUPLICATE (0x0002)
#define TOKEN_IMPERSONATE (0x0004)
#define TOKEN_QUERY (0x0008)
#define TOKEN_QUERY_SOURCE (0x0010)
#define TOKEN_ADJUST_PRIVILEGES (0x0020)
#define TOKEN_ADJUST_GROUPS (0x0040)
#define TOKEN_ADJUST_DEFAULT (0x0080)
#define TOKEN_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED |\
TOKEN_ASSIGN_PRIMARY |\
TOKEN_DUPLICATE |\
TOKEN_IMPERSONATE |\
TOKEN_QUERY |\
TOKEN_QUERY_SOURCE |\
TOKEN_ADJUST_PRIVILEGES |\
TOKEN_ADJUST_GROUPS |\
TOKEN_ADJUST_DEFAULT)
typedef struct _TOKEN_PRIVILEGES {
ULONG PrivilegeCount;
LUID_AND_ATTRIBUTES Privileges[1];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
NTSYSAPI
NTSTATUS
NTAPI
ZwOpenProcessToken (
IN HANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
OUT PHANDLE TokenHandle
);
NTSYSAPI
NTSTATUS
NTAPI
NtAdjustPrivilegesToken (
IN HANDLE TokenHandle,
IN BOOLEAN DisableAllPrivileges,
IN PTOKEN_PRIVILEGES NewState,
IN ULONG BufferLength,
OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
OUT PULONG ReturnLength
);
//
// For backward compatibility with Windows NT 4.0 by Bruce Engle.
//
#ifndef MmGetSystemAddressForMdlSafe
#define MmGetSystemAddressForMdlSafe(MDL, PRIORITY) MmGetSystemAddressForMdlPrettySafe(MDL)
PVOID
MmGetSystemAddressForMdlPrettySafe (
PMDL Mdl
)
{
CSHORT MdlMappingCanFail;
PVOID MappedSystemVa;
MdlMappingCanFail = Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL;
Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
MappedSystemVa = MmGetSystemAddressForMdl(Mdl);
if (MdlMappingCanFail == 0)
{
Mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL;
}
return MappedSystemVa;
}
#endif
#include "filedisk.h"
#define NUMBEROFDEVICES_VALUE L"NumberOfDevices"
#define DEFAULT_NUMBEROFDEVICES 4
#define SECTOR_SIZE 512
#define TOC_DATA_TRACK 0x04
HANDLE dir_handle;
typedef struct _DEVICE_EXTENSION {
//media_in_device是指这个设备是否已经指定了一个文件作为存储媒质。
//这是一个用文件来虚拟磁盘的驱动。那么一个磁盘应该对应一个实际存在的文件。
//读写这个磁盘的请求最终转变为对文件的读写。
//如果一个磁盘设备对象还没有指定文件,那么这个内容是FALSE。
BOOLEAN media_in_device;
//file_handle是文件句柄。也就是这个虚拟磁盘所对应的文件。
HANDLE file_handle;
//file_information是这个文件的一些信息。
ANSI_STRING file_name;
LARGE_INTEGER file_size;
//read_only是否只读
BOOLEAN read_only;
//访问文件的时候需要使用的一个线程客户安全性上下文
PSECURITY_CLIENT_CONTEXT security_client_context;
//是一个链表头。一部分irp(windows发来的请求包)被放入这个链表中。
//我们为每个磁盘对象开启一个系统线程(处理线程),专门用来处理这些请求。
LIST_ENTRY list_head;
//是为了保证链表读写同步的锁
KSPIN_LOCK list_lock;
//是一个事件。当链表中没有请求的时候,处理请求的系统线程并不做任何事情,
//而只等待这个事件。当有请求到来,我们把请求放入链表,然后设置这个事件。
//处理线程就会开始处理这些请求。
KEVENT request_event;
//是线程的指针,用来最后等待这个线程的结束。
PVOID thread_pointer;
//是一个标志。如果设置为TRUE,处理线程执行的时候检测到这个,就会把自己终止掉。
BOOLEAN terminate_thread;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
FileDiskCreateDevice (
IN PDRIVER_OBJECT DriverObject,
IN ULONG Number,
IN DEVICE_TYPE DeviceType
);
VOID
FileDiskUnload (
IN PDRIVER_OBJECT DriverObject
);
PDEVICE_OBJECT
FileDiskDeleteDevice (
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
FileDiskCreateClose (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
FileDiskReadWrite (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
FileDiskDeviceControl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
VOID
FileDiskThread (
IN PVOID Context
);
NTSTATUS
FileDiskOpenFile (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
FileDiskCloseFile (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
FileDiskAdjustPrivilege (
IN ULONG Privilege,
IN BOOLEAN Enable
);
int swprintf(wchar_t *, const wchar_t *, ...);
#pragma code_seg("INIT")
// 驱动程序入口
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
//放驱动参数的路径
UNICODE_STRING parameter_path;
ULONG
n_devices;
NTSTATUS
status;
UNICODE_STRING
device_dir_name;
OBJECT_ATTRIBUTES
object_attributes;
ULONG
n;
USHORT
n_created_devices;
parameter_path.Length = 0;
// 注册表路径的长度
//这参数用途在哪里,这个长度用在下一个函数,申请存放路径buffer的长度;
parameter_path.MaximumLength = RegistryPath->Length + sizeof(PARAMETER_KEY);
//这里是用来存放注册表路径的Buffer,用到刚刚求出的长度,
parameter_path.Buffer = (PWSTR) ExAllocatePool(PagedPool, parameter_path.MaximumLength);
if (parameter_path.Buffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
// copies a source string to a destination string
//在这里就把驱动注册表的路径放到我们申请的Buffer中了,同时还有长度,因为parameter_path是
//UNICODE_STRING类型结构体;
RtlCopyUnicodeString(¶meter_path, RegistryPath);
//concatenates the supplied Unicode string to a buffered
//现在parameter_path就是驱动参数的完整路径
//这个函数把PARAMETER_KEY加在了注册表路径buffer的后面,这里组成了一个完整的路径;
RtlAppendUnicodeToString
(¶meter_path, PARAMETER_KEY);
//把query_table[0]的内容全置空
RtlZeroMemory(&query_table[0], sizeof(query_table));
query_table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
//驱动注册表健值的名字NumberOfDevices;
query_table[0].Name = NUMBEROFDEVICES_VALUE; // L"NumberOfDevices"
query_table[0].EntryContext = &n_devices;
//#define RTL_REGISTRY_ABSOLUTE
0
// Path is a full path
//allows the caller to query several values from the registry subtree with a single call.
//这个函数查询注册表里的数据
status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
parameter_path.Buffer,
&query_table[0],
NULL,
NULL
);
ExFreePool(parameter_path.Buffer);
if (!NT_SUCCESS(status))
{
KdPrint(("FileDisk: Query registry failed, using default values.\n"));
n_devices = DEFAULT_NUMBEROFDEVICES;
}
//#define DEVICE_DIR_NAME
_T("
\\Device")
DEVICE_BASE_NAME
RtlInitUnicodeString(&device_dir_name, DEVICE_DIR_NAME);
InitializeObjectAttribut
es(
&object_attributes,
&device_dir_name,
OBJ_PERMANENT,
NULL,
NULL
);
//创建一个目录名为"
\\Device";
status = ZwCreateDirectoryObject(
&dir_handle,
DIRECTORY_ALL_ACCESS,
&object_attributes
);
if (!NT_SUCCESS(status))
{
return status;
}
//changes the attributes of an object to make it temporary(暂时的)
ZwMakeTemporaryObject(dir_handle);
for (n = 0, n_created_devices = 0; n < n_devices; n++)
{
//#define FILE_DEVICE_DISK
0x00000007
//生成一个磁盘设备对象
status = FileDiskCreateDevice(DriverObject, n, FILE_DEVICE_DISK);
if (NT_SUCCESS(status))
{
n_created_devices++;
}
}
for (n = 0; n < n_devices; n++)
{
//#define FILE_DEVICE_CD_ROM
0x00000002
//生成一个磁盘设备对象
status = FileDiskCreateDevice(DriverObject, n, FILE_DEVICE_CD_ROM);
if (NT_SUCCESS(status))
{
n_created_devices++;
}
}
//通过DeviceTree 可以看到上面二个FOR循环生成了8个设备,n_devices = 4;
if (n_created_devices == 0)
{
ZwClose(dir_handle);
return status;
}
DriverObject->MajorFunction[IRP_MJ_CREATE]
= FileDiskCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE]
= FileDiskCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ]
= FileDiskReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE]
= FileDiskReadWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FileDiskDeviceControl;
DriverObject->DriverUnload = FileDiskUnload;
return STATUS_SUCCESS;
}
//生成一个磁盘设备对象
//可以通过DeviceTree可以看到;
NTSTATUS
FileDiskCreateDevice (
IN PDRIVER_OBJECT
DriverObject,
IN ULONG
Number,
IN DEVICE_TYPE
DeviceType
)
{
//存放设备对象名子的数组
WCHAR
device_name_buffer[MAXIMUM_FILENAME_LENGTH];
UNICODE_STRING
device_name;
NTSTATUS
status;
PDEVICE_OBJECT
device_object;
PDEVICE_EXTENSION
device_extension;
HANDLE
thread_handle;
ASSERT(DriverObject != NULL);
if (DeviceType == FILE_DEVICE_CD_ROM)
{
swprintf(
device_name_buffer,
DEVICE_NAME_PREFIX L"Cd" L"%u",
Number
);
}
else
{
swprintf(
device_name_buffer,
DEVICE_NAME_PREFIX L"%u",
Number
);
}
RtlInitUnicodeString(&device_name, device_name_buffer);
status = IoCreateDevice(
DriverObject,
sizeof(DEVICE_EXTENSION),
&device_name,
DeviceType,
0,
FALSE,
&device_object
);
if (!NT_SUCCESS(status))
{
return status;
}
device_object->Flags |= DO_DIRECT_IO;
device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;
device_extension->media_in_device = FALSE;
if (DeviceType == FILE_DEVICE_CD_ROM)
{
device_object->Characteristics |= FILE_READ_ONLY_DEVICE;
device_extension->read_only = TRUE;
}
InitializeListHead(&device_extension->list_head);
KeInitializeSpinLock(&device_extension->list_lock);
KeInitializeEvent(
&device_extension->request_event,
SynchronizationEvent,
FALSE
);
device_extension->terminate_thread = FALSE;
//生成一个系统线程
//前面说到为每一个磁盘设备对象生成了一个系统线程,用来处理Irp。
//系统线程的生成用以下的调用:
status = PsCreateSystemThread(
&thread_handle,
(ACCESS_MASK) 0L,
NULL,
NULL,
NULL,
FileDiskThread,
device_object
);
if (!NT_SUCCESS(status))
{
IoDeleteDevice(device_object);
return status;
}
//device_object是我所生成的磁盘设备对象。作为线程上下文传入。
//便于我们在线程中得到设备对象指针,然后得到设备扩展。
//稍后我们要把线程对象的指针保留下来存到设备扩展中。这使用
status = ObReferenceObjectByHandl
e(
thread_handle,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&device_extension->thread_pointer,
NULL
);
if (!NT_SUCCESS(status))
{
ZwClose(thread_handle);
device_extension->terminate_thread = TRUE;
KeSetEvent(
&device_extension->request_event,
(KPRIORITY) 0,
FALSE
);
IoDeleteDevice(device_object);
return status;
}
ZwClose(thread_handle);
return STATUS_SUCCESS;
}
#pragma code_seg("PAGE")
VOID
FileDiskUnload (
IN PDRIVER_OBJECT DriverObject
)
{
PDEVICE_OBJECT device_object;
PAGED_CODE();
device_object = DriverObject->DeviceObject;
while (device_object)
{
device_object = FileDiskDeleteDevice(device_object);
}
ZwClose(dir_handle);
}
PDEVICE_OBJECT
FileDiskDeleteDevice (
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION
device_extension;
PDEVICE_OBJECT
next_device_object;
PAGED_CODE();
ASSERT(DeviceObject != NULL);
device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
device_extension->terminate_thread = TRUE;
//sets an event object to a signaled state if the event was not already signaled,
//and returns the previous state of the event object.
KeSetEvent(
&device_extension->request_event,
(KPRIORITY) 0,
FALSE
);
KeWaitForSingleObject(
device_extension->thread_pointer,
Executive,
KernelMode,
FALSE,
NULL
);
ObDereferenceObject(device_extension->thread_pointer);
if (device_extension->security_client_context != NULL)
{
SeDeleteClientSecurity(device_extension->security_client_context);
ExFreePool(device_extension->security_client_context);
}
next_device_object = DeviceObject->NextDevice;
IoDeleteDevice(DeviceObject);
return next_device_object;
}
//这里需要Create和Close是为了通信。让应用程序可以打开这些磁盘设备来设置一些信息。
//打开关闭非常简单,都是对irp无条件返回成功:
NTSTATUS
FileDiskCreateClose (
IN PDEVICE_OBJECT
DeviceObject,
IN PIRP
Irp
)
{
//PAGED_CODE()是一个调试用的宏。如果一个函数被定义在可分页交换的段中,
//那么它执行时的中断级别必须满足一定的要求。PAGED_CODE()用来检测是否符合。
//如果不行,调试版本中这里会出现失败。这个宏仅仅在调试版本下有效。
PAGED_CODE();
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = FILE_OPENED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
#pragma code_seg()
//DDK里有一个例子disk,它的读写非常复杂。而本方案的读写是对文件的读写。
//所以相对简单一些。基本的过程如下:
//1.得到设备扩展。
//2.检查是否已经打开了文件。如果没有,直接返回失败。
//3.对于长度为0的读写,直接返回成功。
//4.把请求加入设备扩展中的请求队列中,设置事件让处理线程运行处理。
//5.返回等待。
//你固然可以在读写例程中直接读写文件。
//但是这不符合惯例。读写文件需要消耗的时间比较长,
//应该让系统尽快得到答复以便可以干其他的事情。
//此外这个函数很容易重入,我们希望把读写请求的完成序列化,
//为此我们并不在这里直接读写文件。而是把请求放入队列中。
//为每个磁盘设备对象生成一个系统线程,来依次处理这些请求。
NTSTATUS
FileDiskReadWrite (
IN PDEVICE_OBJECT
DeviceObject,
IN PIRP
Irp
)
{
PDEVICE_EXTENSION
device_extension;
PIO_STACK_LOCATION
io_stack;
//得到设备扩展;
device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
//上面得到了设备扩展,那么我检查这个磁盘是否已经有物理媒质(也就是一个文件用来模拟磁盘空间)。
如果没有打开过文件,就返回失败
if (!device_extension->media_in_device)
{
Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NO_MEDIA_IN_DEVICE;
}
//想得到要读多长的时候要得到Irp的当前栈空间:
//irp当前栈空间里有具体的要读写的长度,以及别的重要信息;
io_stack = IoGetCurrentIrpStackLoca
tion(Irp);
// 读0长的时候立刻成功
if (io_stack->Parameters.Read.Length == 0)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//然后就可以把Irp放到队列里去等待完成了:
// 标志pending
IoMarkIrpPending(Irp);
// 把请求写入链表
ExInterlockedInsertTailL
ist(
&device_extension->list_head,
&Irp->Tail.Overlay.ListEntry,
&device_extension->list_lock
);
// 设置事件。让线程循环运行。
KeSetEvent(
&device_extension->request_event,
(KPRIORITY) 0,
FALSE
);
return STATUS_PENDING;
//到此读写例程完成。至于真正的读写完成在处理线程中。
}
//设备控制(Device Control)是除了读、写之外最重要的操作之一。
//对磁盘来说,windows通过发送设备控制请求来询问磁盘的一些信息。
//收到设备控制请求之后,应该首先得到控制功能号,然后根据不同的控制功能号进行不同的处理.
//这些功能号有些是windows固有的,有些是由自己定义的。
NTSTATUS
FileDiskDeviceControl (
IN PDEVICE_OBJECT
DeviceObject,
IN PIRP
Irp
)
{
PDEVICE_EXTENSION
device_extension;
PIO_STACK_LOCATION
io_stack;
NTSTATUS
status;
//得到设备扩展
device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
//得到当前设备栈
io_stack = IoGetCurrentIrpStackLoca
tion(Irp);
// 判断如果是还没有加载物理媒质就返回失败。但是
// IOCTL_FILE_DISK_OPEN_FILE是自定义的功能号,专
// 用来加载物理媒质的,所以排除在外
if (!device_extension->media_in_device &&
io_stack->Parameters.DeviceIoControl.IoControlCode !=
IOCTL_FILE_DISK_OPEN_FILE)
{
Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NO_MEDIA_IN_DEVICE;
}
//有很多的设备控制码要处理。这些请求都有参数,从输入空间得到参数后,
//把返回结果写到输出空间。无论什么请求,
//其输入和输出空间都是Irp->AssociatedIrp.SystemBuffer,
//但是每种请求的参数和返回都有自己的格式,需要参考相应的文档。
switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
{
//根据不同的功能号处理不同的操作;
case IOCTL_FILE_DISK_OPEN_FILE:
{
SECURITY_QUALITY_OF_SERVICE security_quality_of_service;
if (device_extension->media_in_device)
{
KdPrint(("FileDisk: IOCTL_FILE_DISK_OPEN_FILE: Media already opened\n"));
status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
break;
}
if (io_stack->Parameters.DeviceIoControl.InputBufferLength <<BR>
sizeof(OPEN_FILE_INFORMATION))
{
status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
if (io_stack->Parameters.DeviceIoControl.InputBufferLength <<BR>
sizeof(OPEN_FILE_INFORMATION) +
((POPEN_FILE_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->FileNameLength -
sizeof(UCHAR))
{
status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
if (device_extension->security_client_context != NULL)
{
SeDeleteClientSecurity(device_extension->security_client_context);
}
else
{
device_extension->security_client_context =
ExAllocatePool(NonPagedPool, sizeof(SECURITY_CLIENT_CONTEXT));
}
RtlZeroMemory(&security_quality_of_service, sizeof(SECURITY_QUALITY_OF_SERVICE));
security_quality_of_service.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
security_quality_of_service.ImpersonationLevel = SecurityImpersonation;
security_quality_of_service.ContextTrackingMode = SECURITY_STATIC_TRACKING;
security_quality_of_service.EffectiveOnly = FALSE;
SeCreateClientSecurity(
PsGetCurrentThread(),
&security_quality_of_service,
FALSE,
device_extension->security_client_context
);
IoMarkIrpPending(Irp);
ExInterlockedInsertTailL
ist(
&device_extension->list_head,
&Irp->Tail.Overlay.ListEntry,
&device_extension->list_lock
);
KeSetEvent(
&device_extension->request_event,
(KPRIORITY) 0,
FALSE
);
status = STATUS_PENDING;
break;
}
case IOCTL_FILE_DISK_CLOSE_FILE:
{
IoMarkIrpPending(Irp);
ExInterlockedInsertTailL
ist(
&device_extension->list_head,
&Irp->Tail.Overlay.ListEntry,
&device_extension->list_lock
);
KeSetEvent(
&device_extension->request_event,
(KPRIORITY) 0,
FALSE
);
status = STATUS_PENDING;
break;
}
case IOCTL_FILE_DISK_QUERY_FILE:
{
POPEN_FILE_INFORMATION open_file_information;
if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>
sizeof(OPEN_FILE_INFORMATION) + device_extension->file_name.Length - sizeof(UCHAR))
{
status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
open_file_information = (POPEN_FILE_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
open_file_information->FileSize.QuadPart = device_extension->file_size.QuadPart;
open_file_information->ReadOnly = device_extension->read_only;
open_file_information->FileNameLength = device_extension->file_name.Length;
RtlCopyMemory(
open_file_information->FileName,
device_extension->file_name.Buffer,
device_extension->file_name.Length
);
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(OPEN_FILE_INFORMATION) +
open_file_information->FileNameLength - sizeof(UCHAR);
break;
}
//下面的4个功能号检查磁盘的有效性。现在一律返回有效,这个请求简单,不带参数。
case IOCTL_DISK_CHECK_VERIFY:
case IOCTL_CDROM_CHECK_VERIFY:
case IOCTL_STORAGE_CHECK_VERIFY:
case IOCTL_STORAGE_CHECK_VERIFY2:
{
status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
}
//下面这个请求获得磁盘的物理属性:
//请注意你要把结果写入到一个DISK_GEOMETRY结构中并把这个结构返回到
//Irp->AssociatedIrp.SystemBuffer中。这个结构的定义如下:
//typedef struct _DISK_GEOMETRY
//{LARGE_INTEGER Cylinders;
磁柱个数
//MEDIA_TYPE MediaType;
媒质类型
//ULONG TracksPerCylinder;
每个磁柱上的磁道数
//ULONG SectorsPerTrack;
每个磁道上的扇区数
//ULONG BytesPerSector;
每个扇区上的字节数
//} DISK_GEOMETRY, *PDISK_GEOMETRY;
//以上这个结构说明来自ddk文档。你必须"如实"的返回这些数据。
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
{
PDISK_GEOMETRY
disk_geometry;
ULONGLONG
length;
if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>
sizeof(DISK_GEOMETRY))
{
status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
disk_geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
length = device_extension->file_size.QuadPart;
disk_geometry->Cylinders.QuadPart = length / SECTOR_SIZE / 32 / 2;
disk_geometry->MediaType = FixedMedia;
disk_geometry->TracksPerCylinder = 2;
disk_geometry->SectorsPerTrack = 32;
disk_geometry->BytesPerSector = SECTOR_SIZE;
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
break;
}
case IOCTL_DISK_GET_LENGTH_INFO:
{
PGET_LENGTH_INFORMATION get_length_information;
if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>
sizeof(GET_LENGTH_INFORMATION))
{
status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
get_length_information = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
get_length_information->Length.QuadPart = device_extension->file_size.QuadPart;
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
break;
}
//此外比较重要的是获取分区信息,获取分区信息有两个功能号
//IOCTL_DISK_GET_PARTITION_INFO和IOCTL_DISK_GET_PARTITION_INFO_EX,
//其处理过程是类似的,只是返回结果的结构不同
case IOCTL_DISK_GET_PARTITION_INFO:
{
PPARTITION_INFORMATION
partition_information;
ULONGLONG
length;
if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>
sizeof(PARTITION_INFORMATION))
{
status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
partition_information = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
length = device_extension->file_size.QuadPart;
partition_information->StartingOffset.QuadPart = 0;
partition_information->PartitionLength.QuadPart = length;
partition_information->HiddenSectors = 1;
partition_information->PartitionNumber = 0;
partition_information->PartitionType = 0;
partition_information->BootIndicator = FALSE;
partition_information->RecognizedPartition = FALSE;
partition_information->RewritePartition = FALSE;
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
break;
}
case IOCTL_DISK_GET_PARTITION_INFO_EX:
{
PPARTITION_INFORMATION_EX
partition_information_ex;
ULONGLONG
length;
if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>
sizeof(PARTITION_INFORMATION_EX))
{
status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
partition_information_ex = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;
length = device_extension->file_size.QuadPart;
partition_information_ex->PartitionStyle = PARTITION_STYLE_MBR;
partition_information_ex->StartingOffset.QuadPart = 0;
partition_information_ex->PartitionLength.QuadPart = length;
partition_information_ex->PartitionNumber = 0;
partition_information_ex->RewritePartition = FALSE;
partition_information_ex->Mbr.PartitionType = 0;
partition_information_ex->Mbr.BootIndicator = FALSE;
partition_information_ex->Mbr.RecognizedPartition = FALSE;
partition_information_ex->Mbr.HiddenSectors = 1;
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
break;
}
case IOCTL_DISK_IS_WRITABLE:
{
if (!device_extension->read_only)
{
status = STATUS_SUCCESS;
}
else
{
status = STATUS_MEDIA_WRITE_PROTECTED;
}
Irp->IoStatus.Information = 0;
break;
}
case IOCTL_DISK_MEDIA_REMOVAL:
case IOCTL_STORAGE_MEDIA_REMOVAL:
{
status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
}
case IOCTL_CDROM_READ_TOC:
{
PCDROM_TOC cdrom_toc;
if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <<BR>
sizeof(CDROM_TOC))
{
status = STATUS_BUFFER_TOO_SMALL;
Irp->IoStatus.Information = 0;
break;
}
cdrom_toc = (PCDROM_TOC) Irp->AssociatedIrp.SystemBuffer;
RtlZeroMemory(cdrom_toc, sizeof(CDROM_TOC));
cdrom_toc->FirstTrack = 1;
cdrom_toc->LastTrack = 1;
cdrom_toc->TrackData[0].Control = TOC_DATA_TRACK;
status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(CDROM_TOC);
break;
}
case IOCTL_DISK_SET_PARTITION_INFO:
{
if (device_extension->read_only)
{
status = STATUS_MEDIA_WRITE_PROTECTED;
Irp->IoStatus.Information = 0;
break;
}
if (io_stack->Parameters.DeviceIoControl.InputBufferLength <<BR>
sizeof(SET_PARTITION_INFORMATION))
{
status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
}
case IOCTL_DISK_VERIFY:
{
PVERIFY_INFORMATION verify_information;
if (io_stack->Parameters.DeviceIoControl.InputBufferLength <<BR>
sizeof(VERIFY_INFORMATION))
{
status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
verify_information = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
status = STATUS_SUCCESS;
Irp->IoStatus.Information = verify_information->Length;
break;
}
default:
{
KdPrint((
"FileDisk: Unknown IoControlCode %#x\n",
io_stack->Parameters.DeviceIoControl.IoControlCode
));
status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
}
}
if (status != STATUS_PENDING)
{
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return status;
}
//线程的启动函数是FileDiskThread。它实现了以下的功能:
//1.获得设备扩展
//2.设置线程优先级。
//3.进入死循环。首先等待事件的发生(device_extension->request_event),避免空循环消耗资源。
//4.检查终止标志(device_extension->terminate_thread)。如果外部要求终止,就使用
//PsTerminateSystemThread(STATUS_SUCCESS)终止它。
//5.检查请求链表(device_extension->list_head),若有请求,则完成他们。
VOID
FileDiskThread (
IN PVOID Context
)
{
PDEVICE_OBJECT
device_object;
PDEVICE_EXTENSION
device_extension;
PLIST_ENTRY
request;
PIRP
irp;
PIO_STACK_LOCATION
io_stack;
PUCHAR
system_buffer;
PUCHAR
buffer;
ASSERT(Context != NULL);
device_object = (PDEVICE_OBJECT) Context;
device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;
KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
FileDiskAdjustPrivilege(SE_IMPERSONATE_PRIVILEGE, TRUE);
for (;;)
{
KeWaitForSingleObject(
&device_extension->request_event,
Executive,
KernelMode,
FALSE,
NULL
);
if (device_extension->terminate_thread)
{
PsTerminateSystemThread(STATUS_SUCCESS);
}
while (request = ExInterlockedRemoveHeadL
ist(
&device_extension->list_head,
&device_extension->list_lock
))
{
irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);
io_stack = IoGetCurrentIrpStackLoca
tion(irp);
//IRP请求放到栈中,判断请求类型是靠io_stack->MajorFunction要分别的;
switch (io_stack->MajorFunction)
{
case IRP_MJ_READ:
system_buffer = (PUCHAR) MmGetSystemAddressForMdl
Safe(irp->MdlAddress, NormalPagePriority);
if (system_buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
buffer = (PUCHAR) ExAllocatePool(PagedPool, io_stack->Parameters.Read.Length);
if (buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
ZwReadFile(
device_extension->file_handle,
NULL,
NULL,
NULL,
&irp->IoStatus,
buffer,
io_stack->Parameters.Read.Length,
&io_stack->Parameters.Read.ByteOffset,
NULL
);
RtlCopyMemory(system_buffer, buffer, io_stack->Parameters.Read.Length);
ExFreePool(buffer);
break;
case IRP_MJ_WRITE:
if ((io_stack->Parameters.Write.ByteOffset.QuadPart +
io_stack->Parameters.Write.Length) >
device_extension->file_size.QuadPart)
{
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
irp->IoStatus.Information = 0;
}
ZwWriteFile(
device_extension->file_handle,
NULL,
NULL,
NULL,
&irp->IoStatus,
MmGetSystemAddressForMdl
Safe(irp->MdlAddress, NormalPagePriority),
io_stack->Parameters.Write.Length,
&io_stack->Parameters.Write.ByteOffset,
NULL
);
break;
case IRP_MJ_DEVICE_CONTROL:
switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_FILE_DISK_OPEN_FILE:
SeImpersonateClient(device_extension->security_client_context, NULL);
irp->IoStatus.Status = FileDiskOpenFile(device_object, irp);
PsRevertToSelf();
break;
case IOCTL_FILE_DISK_CLOSE_FILE:
irp->IoStatus.Status = FileDiskCloseFile(device_object, irp);
break;
default:
irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
}
break;
default:
irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
}
//最后都用IoCompleteRequest完成这些请求
IoCompleteRequest(
irp,
(CCHAR) (NT_SUCCESS(irp->IoStatus.Status) ?
IO_DISK_INCREMENT : IO_NO_INCREMENT)
);
}
}
}
#pragma code_seg("PAGE")
NTSTATUS
FileDiskOpenFile (
IN PDEVICE_OBJECT
DeviceObject,
IN PIRP
Irp
)
{
PDEVICE_EXTENSION
device_extension;
POPEN_FILE_INFORMATION
open_file_information;
UNICODE_STRING
ufile_name;
NTSTATUS
status;
OBJECT_ATTRIBUTES
object_attributes;
FILE_END_OF_FILE_INFORMATION
file_eof;
FILE_BASIC_INFORMATION
file_basic;
FILE_STANDARD_INFORMATION
file_standard;
FILE_ALIGNMENT_INFORMATION
file_alignment;
PAGED_CODE();
ASSERT(DeviceObject != NULL);
ASSERT(Irp != NULL);
device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
open_file_information = (POPEN_FILE_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
if (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)
{
device_extension->read_only = open_file_information->ReadOnly;
}
device_extension->file_name.Length = open_file_information->FileNameLength;
device_extension->file_name.MaximumLength = open_file_information->FileNameLength;
device_extension->file_name.Buffer = ExAllocatePool(NonPagedPool, open_file_information->FileNameLength);
RtlCopyMemory(
device_extension->file_name.Buffer,
open_file_information->FileName,
open_file_information->FileNameLength
);
status = RtlAnsiStringToUnicodeSt
ring(
&ufile_name,
&device_extension->file_name,
TRUE
);
if (!NT_SUCCESS(status))
{
ExFreePool(device_extension->file_name.Buffer);
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
return status;
}
InitializeObjectAttribut
es(
&object_attributes,
&ufile_name,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
status = ZwCreateFile(
&device_extension->file_handle,
device_extension->read_only ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
&object_attributes,
&Irp->IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
device_extension->read_only ? FILE_SHARE_READ : 0,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE |
FILE_RANDOM_ACCESS |
FILE_NO_INTERMEDIATE_BUFFERING |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_NO_SUCH_FILE)
{
if (device_extension->read_only || open_file_information->FileSize.QuadPart == 0)
{
ExFreePool(device_extension->file_name.Buffer);
RtlFreeUnicodeString(&ufile_name);
Irp->IoStatus.Status = STATUS_NO_SUCH_FILE;
Irp->IoStatus.Information = 0;
return STATUS_NO_SUCH_FILE;
}
else
{
status = ZwCreateFile(
&device_extension->file_handle,
GENERIC_READ | GENERIC_WRITE,
&object_attributes,
&Irp->IoStatus,
&open_file_information->FileSize,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN_IF,
FILE_NON_DIRECTORY_FILE |
FILE_RANDOM_ACCESS |
FILE_NO_INTERMEDIATE_BUFFERING |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(status))
{
ExFreePool(device_extension->file_name.Buffer);
RtlFreeUnicodeString(&ufile_name);
return status;
}
if (Irp->IoStatus.Information == FILE_CREATED)
{
file_eof.EndOfFile.QuadPart = open_file_information->FileSize.QuadPart;
status = ZwSetInformationFile(
device_extension->file_handle,
&Irp->IoStatus,
&file_eof,
sizeof(FILE_END_OF_FILE_INFORMATION),
FileEndOfFileInformation
);
if (!NT_SUCCESS(status))
{
ExFreePool(device_extension->file_name.Buffer);
RtlFreeUnicodeString(&ufile_name);
ZwClose(device_extension->file_handle);
return status;
}
}
}
}
else if (!NT_SUCCESS(status))
{
ExFreePool(device_extension->file_name.Buffer);
RtlFreeUnicodeString(&ufile_name);
return status;
}
RtlFreeUnicodeString(&ufile_name);
status = ZwQueryInformationFile(
device_extension->file_handle,
&Irp->IoStatus,
&file_basic,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation
);
if (!NT_SUCCESS(status))
{
ExFreePool(device_extension->file_name.Buffer);
ZwClose(device_extension->file_handle);
return status;
}
status = ZwQueryInformationFile(
device_extension->file_handle,
&Irp->IoStatus,
&file_standard,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation
);
if (!NT_SUCCESS(status))
{
ExFreePool(device_extension->file_name.Buffer);
ZwClose(device_extension->file_handle);
return status;
}
device_extension->file_size.QuadPart = file_standard.EndOfFile.QuadPart;
status = ZwQueryInformationFile(
device_extension->file_handle,
&Irp->IoStatus,
&file_alignment,
sizeof(FILE_ALIGNMENT_INFORMATION),
FileAlignmentInformation
);
if (!NT_SUCCESS(status))
{
ExFreePool(device_extension->file_name.Buffer);
ZwClose(device_extension->file_handle);
return status;
}
DeviceObject->AlignmentRequirement = file_alignment.AlignmentRequirement;
if (device_extension->read_only)
{
DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
}
else
{
DeviceObject->Characteristics &= ~FILE_READ_ONLY_DEVICE;
}
device_extension->media_in_device = TRUE;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
return STATUS_SUCCESS;
}
NTSTATUS
FileDiskCloseFile (
IN PDEVICE_OBJECT
DeviceObject,
IN PIRP
Irp
)
{
PDEVICE_EXTENSION device_extension;
PAGED_CODE();
ASSERT(DeviceObject != NULL);
ASSERT(Irp != NULL);
device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
ExFreePool(device_extension->file_name.Buffer);
ZwClose(device_extension->file_handle);
device_extension->media_in_device = FALSE;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
return STATUS_SUCCESS;
}
NTSTATUS
FileDiskAdjustPrivilege (
IN ULONG
Privilege,
IN BOOLEAN
Enable
)
{
NTSTATUS
status;
HANDLE
token_handle;
TOKEN_PRIVILEGES
token_privileges;
PAGED_CODE();
status = ZwOpenProcessToken(
NtCurrentProcess(),
TOKEN_ALL_ACCESS,
&token_handle
);
if (!NT_SUCCESS(status))
{
return status;
}
token_privileges.PrivilegeCount = 1;
token_privileges.Privileges[0].Luid = RtlConvertUlongToLuid(Privilege);
token_privileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
//
// Normaly one would use ZwAdjustPrivilegesToken but it is only available
// on Windows 2000 and later versions, however since we are in a system
// thread does ExGetPreviousMode always return KernelMode and therefore
// can NtAdjustPrivilegesToken be used directly.
//
status = NtAdjustPrivilegesToken(
token_handle,
FALSE,
&token_privileges,
sizeof(token_privileges),
NULL,
NULL
);
ZwClose(token_handle);
return status;
}
第一个问题就是设备是怎么通知线程去处理IRP请求的?
第二个问题是挂载出现一个磁盘是怎么实现的,原理是什么?
接下来的任务就是解决这二个问题,同时解决一些变量,和几个函数等相关细节问题,
以前一个朋友对我说过,一个人功底怎么样,要看细节。