内核模式下的字符串操作
KdPrint(); // 类似于C中的printf();
字符串结构体
typedef struct _STRING
{
USHORT Length; // 字符的长度
USHORT MaximumLength; // 整个字符缓冲区的最大长度
PCHAR Buffer; // 缓冲区的指针
}STRING;
typedef STRING ANSI_STRING;
typedef PSTRING PANSI_STRING;
typedef STRING OEM_STRING;
typedef PSTRING POEM_STRING;
typedef struct _UNICODE_STRING
{
USHORT Length; // 单位是字节, 如果是N个字符, 则长度为2N
USHORT MaximumLength; // 单位也是字节
PWSTR Buffer; // 缓冲区指针
}UNICODE_STRING;
VOID RtlInitAnsiString(
IN OUT PANSI_STRING DestinationString, // 要初始化的ANSI_STRING字符串
IN PCSZ SourceString // 字符串内容
);
例如:
方法1:
ANSI_STRING AnsiString1;
CHAR *string1 = "hello";
RtlinitAnsiString(&AnsiString1, string1);
KdPrint(("AnsiString1:%z\n", &AnsiString1)); // 打印hello
// 改变string1
string[0] = 'H';
// 改变string1, AnsiString1同样会导致变化
KdPrint(("%Z\n", &AnsiString1)); // 打印Hello
方法2:
#define BUFFER_SIZE 1024
UNICODE_STRING UnicodeString1 = {0};
// 设置缓冲区大小
UnicodeString1.MaximumLength = BUFFER_SIZE;
// 分配内存
UnicodeString1.Buffer = (PWSTR)ExAllocatePool(PagedPool,
BUFFER_SIZE);
WCHAR *wideString = L"hello";
//设置字符长度, 因为是宽字符, 所以是字符长度的2倍
UnicodeString1.Length = 2 * wcslen(wideString);
// 保证缓冲区足够大, 否则程序终止
ASSERT(UnicodeString1.MaximumLength >= UnicodeString1.Length);
// 内存复制
RtlCopyMemory(UnicodeString1.Buffer,
wideString,
UnicodeString1.Length);
KdPrint(("UnicodeString:%wZ\n", &UnicodeString1));
// 清理内存
ExFreePool(UnicodeString1.Buffer);
UnicodeString.Buffer = NULL;
UnicodeString1.Length = UnicodeString1.MaximumLength = 0;
字符串复制
VOID RtlCopyString(
IN OUT PSTRING DestinationString, // 目的字符串
IN PSTRING SourceString OPTIONAL // 源字符串
);
VOID RtlCopyUnicodeString
IN OUT PUNICODE_STRING DestinationString,
IN PUNCIDE_STRING SourceString
);
例子:
// 初始化UnicodeString1
UNICODE_STRING UnicodeString1;
RtlInitUnicodeString(&UnicodeString1, L"Hello World");
// 初始化UnicodeString2
UNICODE_STRING UnicodeString2 = {0};
UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagePool,
BUFFER_SIZE);
// 将UnicodeString1复制到UnicodeString2
RtlCopyUnicodeString(&UnicodeString2, UnicodeString1);
// 分别显示
KdPrint(("UnicodeString1:%wZ\n", &UnicodeString1));
KdPrint(("UnicodeString2:%wZ\n", &UnicodeString2));
// 销毁UnicodeString2
// 注意! UnicodeString1不用销毁
RtlFreeUnicodeString(&UnicodeString2);
字符串比较
LONG RtlCompareSring(
IN PSTRING String1,
in PSTRING String2,
BOOLEAN CaseInSensitve // 是否对大小写敏感
);
返回值:如果返回0, 表示两个字符串相等, 如果小于0, 则表示第一个
字符串小于第二个字符串. 反之, 如果大于0, 则代表第一个字符串
大于第二个字符串.
LONG RtlCompareUnicodeString(
IN PUNICODE_STRING String1,
IN PUNICODE_STRING String2,
IN BOOLEAN CaseInSensitive;
);
LONG RtlEqualString(
IN PSTRING String1,
in PSTRING String2,
BOOLEAN CaseInSensitve // 是否对大小写敏感
);
返回值:非0代表相等, 零代表不相等.
LONG RtlEqualUnicodeString(
IN PUNICODE_STRING String1,
IN PUNICODE_STRING String2,
IN BOOLEAN CaseInSensitive;
);
字符串转换成大小
VOID RtlUpperString(
IN OUT PSTRING DestinationString, // 目的字符串
IN PSTRING SourceString // 源字符串
);
NTSTATUS RtlUpcaseUnicodeString(
IN OUT PUNICODE_STRING DestinationString OPTIONAL,
IN PCUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString // 是否为目的字符串分配NEC
);
返回值:转换是否成功.
字符串与整型数字相互转换
NTSTATUS RtlUnicodeStringToInteger(
IN PUNICODE_STRING String, // 需要转换的字符串
IN ULONG Base OPTIONAL, // 转换的进制(2, 8, 10, 16)
OUT PULONG Value // 需要转的数字
);
返回值:指明是否转换成功
ANSI - UNICODE
NTSTATUS RtlUnicodeStringToAnsiString(
IN OUT PANSI_STRING DestinationString,
IN PUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
);
NTSTATUS RtlAnsiStringToUnicodeString(
IN OUT PUNCODE_STRING DestinationString,
IN PANSI_STRING SourceString,
IN BOOLEAN AllocateDestinationString,
NTSTATUS ZwCreateFile(
__out PHANDLE FileHandle, // 返回打开文件的句柄
__in ACCESS_MASK DesiredAccess, // 对打开文件的操作描述, 一般指定为GENERIC_READ或GENERIC_WRITE
__in POBJECT_ATTRIBUTES ObjectAttributes, // OBJECT_ATTRIBUTES结构地址, 该结构包含要打开的文件名
__out PIO_STATUS_BLOCK IoStatusBlock, // IO_STATUS_BLOCK结构地址, 该结构接收ZwVCreateFile操作的结果状态
__in_opt PLARGE_INTEGER AllocationSize, // 指向一个64位整数, 该数指定文件初始分配时的大小,
// 该参数仅关系到创建或重写文件操作, 如果忽略它, 那么文件长度将
// 从0开始, 并随着写入而增长
__in ULONG FileAttributes, // 0或FILE_ATTRIBUTE_NORMAL, 指定新创建文件的属性.
__in ULONG ShareAccess, // FILE_SHARE_READ或0, 指定文件的共享方式. 如果仅为读数据而打开
// 文件, 则可以与其他线程同时读取该文件. 如果为写数据而打开, 可
// 能不希望其他线程访问该文件.
__in ULONG CreateDisposition, // FILE_OPEN或FILE_OVERWRITE_IF, 表明当指定文件存在或不存在时
// 应如何处理.
__in ULONG CreateOptions, // FILE_SYNCHRONOUS_IO_NONALERT, 指定控制打开操作和句柄使用附加
// 标志
__in_opt PVOID EaBuffer, // 一个指针, 指向可选的扩展属性区.
__in ULONG EaLength // 扩展属性区的长度
);
// 设置过滤钩子
NTSTATUS IoAttachDevice(
IN PDEVICE_OBJECT SourceDevice, // 源设备对象
IN PUNICODE_STRING TargetDevice, // 目标设备对象
OUT PDEVICE_OBJECT *AttachedDevice // Attach上的设备对象
);
// 卸载过滤钩子
VOID IoDetachDevice(
IN OUT PDEVICE_OBJECT TargetDevice // 为IoAttachDevice函数的第三个参数
);
// 指定的内存清零
VOID RtlZeroMemory(
IN VOID UNALIGNED *Destination,
IN SIZE_T Length
);
分配内核内存
//
PVOID ExAllocatePool(IN POOL_TYPE poolType,
IN SIZE_T NumberOfBytes
);
//
PVOID ExAllocatePoolWithTag(IN POOL_TYE PoolType,
IN SIZE_T NumberOfBytes,
IN ULONG Tag
);
//
PVOID ExAllocatePoolWithQuota(IN POOL_TYPE PoolTye,
IN SIZE_T NumberOfByts
);
//
PVOID ExAllocatePoolWithQuotaTag(IN POOL_TYPE PoolType,
IN SIZE_T NumberOfBytes,
IN ULONG Tag
);
参数:
PoolType
是个枚举变量, 如果此值为NonPagedPool, 则分配非分页内存.
如果此值为PagePool, 则分配内存为分页内存.
NumberOfBytes
是分配内存大小, 注意最好是4的倍数.
返回值:
返回分配的内存地址, 一定是内核模式地址. 如果返回0, 则代表
分配失败.
以上四个函数功能类似, 函数以WithQuota结尾的代表分配的是按
配额分配. 函数以WithTag结尾的函数, 和ExAllocatePool功能类似, 唯
一不同的是多了一个Tag参数, 系统在要求的内存外又额外地多分配了4
个字节的标签. 在调试的时候, 可以找出是否有标有这个标签的内存没
有被释放.
以上4个函数都需要指定PoolType, 分别可以指定如下几种:
1.NonPagedPool:指定要求分配非分页内存.
2.PagedPool:指定要求分配分页内存.
3.NnPagedPoolMustSucceed:指定分配非分页内存, 必须成功.
4.DontUseThisType:未指定.
5.NonPagedPoolCacheAligned:指定要求分配非分页内存, 而且必须内存对齐.
6.PagedPoolCatcheAligned:指定分配分页内存, 而且必须内存对齐.
7.NonPagedPoolCacheAlignedMustS:指定分配非分页内存, 而且必须内存对齐,
且必须成功.
将分配的内存, 进行回收的函数是ExFreePool和ExFreePoolWithTag, 它们的
原型是:
//
VOID ExFreePool(IN PVOID P);
//
NTKERENLAPI(VOID ExFreePoolWithTag(IN PVOID P,
IN ULONG Tag
);
重要函数学习:IoBuildDeviceIoControlRequest 收藏
重要函数学习:IoBuildDeviceIoControlRequest
这个函数主要用来构造一个用于设备i/o控制请求的irp包,该irp包将被同步处理,其原型如下:
参数解释:
IoControlCode
提供i/o控制请求所需的i/o控制码。这个i/o控制码可以在msdn中查询到。
DeviceObject
指向下层驱动的设备对象的指针。这个就是构造的irp要被发向的目标对象。
InputBuffer
指向输入缓冲区的指针,这个缓冲区中的内容是给下层驱动使用的。此指针可为NULL。
InputBufferLength
输入缓冲区的长度,按字节计算。如果InputBuffer为NULL,则此参数必须为0。
OutputBuffer
指向输出缓冲区的指针,这个缓冲区是用于给下层驱动返回数据用的。此指针可为NULL。
OutputBufferLength
输出缓冲区的长度,按字节计算。如果OutputBuffer为NULL,则此参数必须为0。
InternalDeviceIoControl
如果此参数为TRUE,这个函数设置所构造的irp的主函数码(major function code)为IRP_MJ_INTERNAL_DEVICE_CONTROL,否则这个函数设置所构造的irp的主函数码(major function code)为IRP_MJ _DEVICE_CONTROL。
Event
提供一个指向事件对象的指针,该事件对象由调用者分配并初始化。当下层驱动程序完成这个irp请求时i/o管理器将此事件对象设置为通知状态(signaled)。当调用IoCallDriver后,调用者可以等待这个事件对象成为通知状态。
IoStatusBlock
调用者指定一个i/o状态块,当这个irp完成时,下层驱动会把相应信息填入这个i/o状态块。
关于返回:
当这个函数调用成功时,将返回一个指向所构造的irp的指针并且下一层驱动的i/o堆栈会根据调用此函数提供的参数设置好,若调用失败,将返回NULL。
注意事项:
1、 此函数构造的irp包将被同步处理。当构造好irp包后,调用者调用IoCallDriver将这个irp发送给目标对象,如果IoCallDriver返回STATUS_PENDING,调用者必须调用KeWaitForSingleObject等待调用IoBuildDeviceIoControlRequest时所提供的那个Event。对于大多数的驱动程序我们不用给该irp设置完成函数。
2、 由IoBuildDeviceIoControlRequest构造的irp必须由某个驱动调用IoCompleteRequest来完成,并且注意调用IoBuildDeviceIoControlRequest的驱动程序不能调用IoFreeIrp来释放这些构造的irp,因为i/o管理器会在IoCompleteRequest被调用后自动释放这些irp。
3、 IoBuildDeviceIoControlRequest将把它构造的irp放在当前线程特有的一个irp队列上,如果当前线程退出,则i/o管理器将取消这些irp。
4、 InputBuffer和OutputBuffer这两个参数如何存放在所构造的irp中将取决于IoControlCode的TransferType,具体可查相关资料。
5、 IoBuildDeviceIoControlRequest的调用者必须运行在IRQL <= APC_LEVEL。
6、 这个函数并不初始化所构造irp中的FileObject指针,因此如果你在写和文件系统相关的驱动,你必须自己初始化这个指针。
7、 使用IoBuildDeviceIoControlRequest构造的irp其主函数代码只能是IRP_MJ_DEVICE_CONTROL 或IRP_MJ_INTERNAL_DEVICE_CONTROL。
KdPrint使用方法类似printf,注意KdPrint((" ", ));使用的是双括号。
用KdPrint(())来代替printf 输出信息。这些信息可以在DbgView 中看到。KdPrint(())自身是一个宏,
为了完整传入参数所以使用了两重括弧。这个比DbgPrint 调用要稍好。因为在free 版不被编译。
DebugPrint格式说明符
格式说明符 类型
%c ANSI字符 char
%C 宽字符 wchar_t
%d,%i 十进制有符号整数 int
%D 十进制__int64 __int64
%I IRP主功能代码和次功能代码 PIRP
%l 十六进制的__int64 __int64
%L 十六进制的LARGE_INTEGER LARGE_INTEGER
%s NULL终止的ANSI字符串 char *
%S NULL终止的宽字符串 wchar_t *
%T UNICODE_STRING PUNICODE_STRING
%wZ UNICODE_STRING PUNICODE_STRING
%u 十进制的ULONG ULONG
%x 十六进制的ULONG ULONG
DDK常用函数列表
(A)
ASSERT
ASSERTMSG
(C)
CM_FULL_RESOURCE_DESCRIPTOR
CM_PARTIAL_RESOURCE_DESCRIPTOR
CM_PARTIAL_RESOURCE_LIST
CM_RESOURCE_LIST
CONFIGURATION_INFORMATION
CONTAINING_RECORD
CONTROLLER_OBJECT
(D)
DbgBreakPoint
DbgPrint
DEVICE_DESCRIPTION
DEVICE_OBJECT
DriverEntry
DRIVER_OBJECT
(E)
ExAcquireFastMutex
ExAcquireFastMutexUnsafe
ExAcquireResourceExclusiveLite
ExAcquireResourceSharedLite
ExAcquireSharedStarveExclusive
ExAcquireSharedWaitForExclusive
ExAllocateFromNPagedLookasideList
ExAllocateFromPagedLookasideList
ExAllocatePool
ExAllocatePoolWithQuota
ExAllocatePoolWithQuotaTag
ExAllocatePoolWithTag
ExConvertExclusiveToSharedLite
ExDeleteNPagedLookasideList
ExDeletePagedLookasideList
ExDeleteResourceLite
ExFreePool
ExFreeToNPagedLookasideList
ExFreeToPagedLookasideList
ExGetCurrentResourceThread
ExInitializeFastMutex
ExInitializeNPagedLookasideList
ExInitializePagedLookasideList
ExInitializeResourceLite
ExInitializeWorkItem
ExInterlockedInsertHeadList
ExInterlockedInsertTailList
ExInterlockedRemoveHeadList
ExIsResourceAcquiredExclusiveLite
ExIsResourceAcquiredSharedLite
ExQueueWorkItem
ExReleaseFastMutex
ExReleaseFastMutexUnsafe
ExReleaseResourceForThreadLite
ExTryToAcquireFastMutex
ExTryToAcquireResourceExclusiveLite
(H)
HalAssignSlotResources
HalGetAdapter
HalGetBusData
HalGetBusDataByOffset
HalGetInterruptVector
HalSetBusData
HalSetBusDataByOffset
HalTranslateBusAddress
HKEY_LOCAL_MACHINE
(I)
InitializeListHead
InitializeObjectAttributes
InsertHeadList
InsertTailList
INTERFACE_TYPE
InterlockedDecrement
InterlockedExchange
InterlockedExchangeAdd
InterlockedIncrement
IoAcquireCancelSpinLock
IoAllocateAdapterChannel
IoAllocateController
IoAllocateErrorLogEntry
IoAllocateIrp
IoAllocateMdl
IoAssignResources
IoAttachDevice
IoAttachDeviceToDeviceStack
IoBuildAsynchronousFsdRequest
IoBuildDeviceIoControlRequest
IoBuildPartialMdl
IoBuildSynchronousFSDRequest
IoCallDriver
IoCancelIrp
IoCompleteRequest
IoConnectInterrupt
IoCopyCurrentIrpStackLocationToNext
IoCreateController
IoCreateDevice
IoCreateNotificationEvent
IoCreateSymbolicLink
IoCreateSynchronizationEvent
IoDeleteController
IoDeleteDevice
IoDeleteSymbolicLink
IoDetachDevice
IoDisconnectInterrupt
IO_ERROR_LOG_PACKET
IoFlushAdapterBuffers
IoFreeAdapterChannel
IoFreeController
IoFreeIrp
IoFreeMapRegisters
IoFreeMdl
IoGetConfiguationInformation
IoGetCurrentIrpStackLocation
IoGetCurrentProcess
IoGetDeviceObjectPointer
IoGetNextIrpStackLocation
IoInitializeDpcRequest
IoInitializeIrp
IoInitializeTimer
IoMakeAssociatedIrp
IoMapTransfer
IoMarkIrpPending
IoRegisterShutdownNotification
IoReleaseCancelSpinLock
IoRequestDpc
IO_RESOURCE_DESCRIPTOR
IO_RESOURCE_LIST
IO_RESOURCE_REQUIREMENTS_LIST
IoSetCancelRoutine
IoSetCompletionRoutine
IoSetNextIrpStackLocation
IoSizeOfIrp
IoSkipCurrentIrpStackLocation
IO_STACK_LOCATION
IoStartNextPacket
IoStartNextPacketByKey
IoStartPacket
IoStartTimer
IO_STATUS_BLOCK
IoStopTimer
IoUnregisterShutdownNotification
IoWriteErrorLogEntry
IsListEmpty
IRP
(K)
KdPrint
KeAcquireSpinLock
KeAcquireSpinLockAtDpcLevel
KeBugCheck
KeBugCheckEx
KeCancelTimer
KeClearEvent
KeDelayExecutionThread
KeDeregisterBugCheckCallback
KeFlushIoBuffers
KeGetCurrentIrql
KeGetCurrentProcessorNumber
KeGetDcacheFillSize
KeInitializeCallbackRecord
KeInitializeDeviceQueue
KeInitializeDpc
KeInitializeEvent
KeInitializeMutex
KeInitializeSemaphore
KeInitializeSpinLock
KeInitializeTimer
KeInitializeTimerEx
KeInsertByKeyDeviceQueue
KeInsertDeviceQueue
KeInsertQueueDpc
KeLowerIrql
KeNumberProcessors
KeQueryPerformanceCounter
KeQuerySystemTime
KeQueryTickCount
KeQueryTimeIncrement
KeRaiseIrql
KeReadStateEvent
KeReadStateMutex
KeReadStateSemaphore
KeReadStateTimer
KeRegisterBugCheckCallback
KeReleaseMutex
KeReleaseSemaphore
KeReleaseSpinLock
KeReleaseSpinLockFromDpcLevel
KeRemoveByKeyDeviceQueue
KeRemoveDeviceQueue
KeRemoveEntryDeviceQueue
KeRemoveQueueDpc
KeResetEvent
KeSetEvent
KeSetPriorityThread
KeSetTimer
KeSetTimerEx
KeStallExecutionProcessor
KeSynchronizeExecution
KeWaitForMultipleObjects
KeWaitForMutexObject
KeWaitForSingleObject
KEY_BASIC_INFORMATION
KEY_FULL_INFORMATION
KEY_NODE_INFORMATION
KEY_VALUE_BASIC_INFORMATION
KEY_VALUE_FULL_INFORMATION
KEY_VALUE_PARTIAL_INFORMATION
KIRQL
KSYNCHRONIZE_ROUTINE
(L)
LARGE_INTEGER
(M)
MmAllocateContiguousMemory
MmAllocateNonCachedMemory
MmCreateMdl
MmFreeContiguousMemory
MmFreeNonCachedMemory
MmGetMdlByteCount
MmGetMdlByteOffset
MmGetMdlVirtualAddress
MmGetPhysicalAddress
MmGetSystemAddressForMdl
MmInitializeMdl
MmIsAddressValid
MmMapIoSpace
MmMapLockedPages
MmPrepareMdlForReuse
MmProbeAndLockPages
MmQuerySystemSize
MmSizeOfMdl
MmUnlockPages
MmUnlockPagableImageSection
MmUnmapIoSpace
MmUnmapLockedPages
(N)
NTSTATUS
(O)
ObDereferenceObject
ObReferenceObjectByHandle
ObReferenceObjectByPointer
(P)
PCI_COMMON_CONFIG
PCI_SLOT_NUMBER
PDRIVER_CONTROL
PIO_DPC_ROUTINE
PIO_TIMER_ROUTINE
PKDEFERRED_ROUTINE
PKSTART_ROUTINE
PsCreateSystemThread
PsGetCurrentProcess
PsGetCurrentThread
PsTerminateSystemThread
(R)
READ_PORT_BUFFER_type
READ_PORT_type
READ_REGISTER_BUFFER_type
READ_REGISTER_type
RemoveEntryList
RemoveHeadList
RemoveTailList
RtlInitUnicodeString
RtlMoveMemory
RTL_QUERY_REGISTRY_ROUTINE
RTL_QUERY_REGISTRY_TABLE
RtlQueryRegistryValues
RtlUnicodeStringToAnsiString
RtlZeroMemory
(U)
UNICODE_STRING
_URB_CONTROL_DESCRIPTOR_REQUEST
_URB_HEADER
UsbBuildGetDescriptorRequest
(W)
WRITE_PORT_BUFFER_type
WRITE_PORT_type
WRITE_REGISTER_BUFFER_type
WRITE_REGISTER_type
(Z)
ZwClose
ZwCreateFile
ZwCreateKey
ZwDeleteKey
ZwEnumerateKey
ZwEnumerateValueKey
ZwFlushKey
ZwMapViewOfSection
ZwOpenKey
ZwOpenSection
ZwQueryKey
ZwQueryValueKey
ZwSetInformationThread
ZwSetValueKey
ZwUnmapViewOfSection
// 内存间复制(非重叠)
VOID RtlCopyMmeory(
IN VOID UNALIGNED *Destination, // 复制内存的目的地址
IN CONST VOID UNALIGNED *Source, // 复制内存的源地址
IN SIZE_T Length // 表示要复制的字节数
);
// 内存间复制(可重叠)
VOID RtlMoveMemory(
IN VOID UNALIGNED *Destination,
IN CONST VOID UNALIGNED *Source,
IN SIZE_T Length
);
// 填充内存
VOID RtlFillMemory(
IN VOID UNALIGNED *Destination, // 目的地址
IN SIZE_T Length, // 长度
IN UCHAR Fill // 需要填充的字节
);
// 填充0字节
VOID RtlZeroMemory(
IN VOID UNALIGNED *Destination,
IN SIZE_T Length
);
// 内存比较
UNLONG RtlEqualMemory(
CONST VOID *Source1, // 比较的第1个内存地址
const void *Sourcd2, // 比较的第2个内存地址
SIZE_T Length // 比较的长度, 单位为字节
);
返回值:相等的字节数
// 判断内存是否可读
VOID ProbeForRead(
IN CONST VOID *Address, // 被检查内存地址
IN SIZE_T Length, // 需要被检查的内存的字节数
IN ULONG Alignment // 描述该段内存是以多少字节对齐的
);
// 判断内存是否可写
VOID ProbeForWrite(
IN CONST VOID *Address,
IN SIZE_T Length,
IN ULONG Alignment
);
这两个函数不是返回该段内存是否可读写, 而是当不可读写是, 引
发一个异常(Excetpiton).
异常处理
__try
{
}
__except(filter_value)
{
}
filter_value的数值有三种可能:
(1)EXCEPTION_EXECUTE_HANDLER, 该数值为1. 进入到__except进行错误
处理, 处理完后不再回到__try{}块中, 转而继续执行.
(2)EXCEPTION_CONTINUE_SEARCH, 该数值为0. 不使用__excep块中的异常
处理, 转而向上一层回卷. 如果已经是最外层, 则向操作系统请求异常
处理函数.
(3)EXCEPTION_CONTINUE_EXECUTION, 该数值为-1. 重复先前错误的指令,
这个在驱动程序中很少用到.
ProbeForRead和ProbeForWrite函数可以和try_except块配合, 用来检查
某段内存是否可读写.
例如:
VOID ProbeTest()
{
PVOID badPointer = NULL;
KdPrint(("Enter ProbeTest\n"));
__try
{
KdPritn(("Enter __try block\n"));
// 判断空指针是否可读, 显然会导致异常
ProbeForWrite(badPointer, 100, 4);
// 由于上面引发异常, 所以下面这句不会被执行
KdPrint(("Leave __try block\n"));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("Catch the exception\n"));
KdPrint(("The program will keep going\n"));
}
KdPrint(("Leave ProbeTest\n"));
}
触发异常函数
ExRaiseStatus // 用指定状态代码触发异常
ExRaiseAccessViolation // 触发STATUS_ACCESS_VIOLATION异常
ExRaiseDatatypeMisalignment // 触发STATUS_DATATYPE_MISALIGNMENT异常
__try
{
}
__finally
{
}
断言
NTSTATUS Foo(PCHAR *str)
{
ASSERT(str != NULL);
}
NTSTATUS IoCreateDevice(
IN PDRIVER_OBJECT DriverObject, // 本驱动的驱动对象
IN ULONG DeviceExtensionSize, // 设备扩展, 简单传入0
IN PUNICODE_STRING DeviceName OPTIONAL, // 设备名, 过滤设备一般不需要名称, 所以传入NULL即可.
IN DEVICE_TYPE DeviceType, // 设备类型, 保持和被绑定设备类型一致即可.
IN ULONG DeviceCharacteristics, // 设备特征, 填0
IN BOOLEAN Exclusive, // 是否排斥, 一般FALSE
OUT PDEVICE_OBJECT *DeviceObject // 返回的过滤设备
);
NTSTATUS IoAttachDevice(
IN PDEVICE_OBJECT SourceDevice, // 过滤设备
IN PUNICODE_STRING TargetDevice, // 要绑定的目标设备的名称
OUT PDEVICE_OBJECT *AttachedDevice // 被绑定的设备指针被返回到这个地址
);
NTSTATUS IoAttachDeviceToDeviceStackSafe(
IN PDEVICE_OBJECT SourceDevice, // 过滤设备
IN PDEVICE_OBJECT TargetDevice, // 要绑定的目标设备的名称
IN OUT PDEVICE_OBJECT *AttachedToDeviceObject // 返回最终被绑定的设备
);
// 在win2000下
PDEVICE_OBJECT IoAttachDeviceToDeviceStack(
IN PDEVICE_OBJECT SourceDevice, // 过滤设备
IN PDEVICE_OBJECT TargetDevice // 要绑定的目标设备的名称
);
返回值:返回最终被绑定的设备, NULL表示绑定失败.
NTSTATUS IoCallDriver(
IN PDEVICE_OBJECT DeviceObject, // 设备对象
IN OUT PIRP Irp // 设备对象相应的IRP
);
在这之前先调用
IoSkipCurrentIrpStackLocation(irp);
PIRP TdiBuildInternalDeviceControlIrp(
IN CCHAR IrpSubFunction, //
IN PDEVICE_OBJECT DeviceObject, // 指向被过滤设备绑定的那个设备
IN PFILE_OBJECT FileObject,
IN PKEVENT Event,
IN PIO_STATUS_BLOCK IoStatusBlock
);
返回值:一块分配的IRP堆栈空间