上一篇说到内核里面用户态这边差不多的函数, 比如ZwCreateFile, ZwReadFile什么之类的,
内核里面其实还有些更加暴力的东西存在的, 比如说用户态这边打开设备只有一个句柄, 但是内核里面是可以直接触摸到指针的,
用户态那边只可以调用几个固定的函数来发送Irp. 那么内核里面可以自定义Irp的发送, 非常的暴力, 好用!
首先我们也不用去调用什么ZwCreateFile了, 直接用这个IoGetDeviceObjectPointer函数, 这个函数可以通过设备名获得文件对象指针, 和设备对象指针, 指针啊, 不是句柄了..和ZwCreateFile一样, 末尾记得调用ObDereferenceObject函数, 来解引用.
打开以后就是发送Irp消息了, 基本上有很多的选择, 看下面代码就知道了, 有同步的又异步的, 非常的暴力好用, 看自己喜欢了. 其实看下面代码就知道了, 同步的和异步的其实区别不是很大, 无论如何还是需要一个同步事件来同步的. 只是放在了不同的地方了. 稍微搞一下就明白了, 这个很简单的嘛.
重点说说这个, ObReferenceObjectByName这号函数是未公开的函数, 一般未公开的函数就是暴力啊, 其可以获得各类对象的指针, 而不是和IoGetDeviceObjectPointer这样只能够获取设备对象的指针, ObReferenceObjectByName可以获取各种对象的指针, 非常好用了. ObReferenceObjectByName只是引用下对象的指针, 并没有打开操作, 但是IoGetDeviceObjectPointer内部是有打开操作的. 也就是相当于向设备发送了Irp_Mj_Create的Irp. 明白了他们之间的区别, 那么我们就可以适时的在二者中选择某个函数来做一些事情了.
后面还有一个模拟IoGetDeviceObjectPointer内核函数的实现, 首先要打开设备对象, 获得设备对象的句柄,然后ObReferenceObjectByHandle内核函数将设备对象的句柄, 转换设备对象相关的文件对象的指针. 然后再调用IoGetBaseFileSystemDeviceObject函数, 可以将文件对象指针得到设备对象针! 有点晕了. 主要要把握住, 设备, 文件, 句柄. 这是关键字!
下面就上代码, 测试驱动已经在上一篇中说到了, 那么这边看看代码的情况:
/*
Windows 内核下驱动程序通过设备指针调用其他驱动程序 调用驱动程序
编译方法参见makefile. TAB = 8
*/
#include <ntddk.h>
//===========================================================================
#define SYSLINK_NAME L"\\??\\SysLinkTestDriver"
#define MAX_PATH 260
#ifdef __cplusplus
extern "C"
{
#endif
#include <NTDDK.h>
NTKERNELAPI
NTSTATUS
ObReferenceObjectByName(
IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN PACCESS_STATE PassedAccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess OPTIONAL,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext OPTIONAL,
OUT PVOID *Object
);
NTKERNELAPI
PDEVICE_OBJECT
NTAPI
IoGetBaseFileSystemDeviceObject (
IN PFILE_OBJECT FileObject
);
extern POBJECT_TYPE IoDeviceObjectType;
#ifdef __cplusplus
}
#endif
//===========================================================================
//模拟系统内部IoGetDeviceObjectPointer实现
//===========================================================================
_IoGetDeviceObjectPointer( PUNICODE_STRING pObjName, ACCESS_MASK DesiredAccess,
PFILE_OBJECT* ppFileObj, PDEVICE_OBJECT* ppDeviceObj ) {
HANDLE hDevice = NULL;
NTSTATUS Status;
PFILE_OBJECT pFileObj = NULL;
OBJECT_ATTRIBUTES ObjAttr;
IO_STATUS_BLOCK Status_block;
//初始化要打开的设备名称
InitializeObjectAttributes( &ObjAttr, pObjName, OBJ_KERNEL_HANDLE, NULL, NULL );
//打开设备 对象
Status = ZwOpenFile( &hDevice, DesiredAccess, &ObjAttr, &Status_block,
0, FILE_NON_DIRECTORY_FILE );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
//通过设备对象句柄得到设备对象指针
Status = ObReferenceObjectByHandle( hDevice, 0, *IoFileObjectType,
KernelMode, &pFileObj, NULL );
if ( !NT_SUCCESS( Status ) ) {
return Status;
}
*ppFileObj = pFileObj;
//通过设备相关文件对象指针得到设备对象指针
*ppDeviceObj = IoGetBaseFileSystemDeviceObject( pFileObj );
if ( hDevice ) {
ZwClose(hDevice);
}
return STATUS_SUCCESS;
}
//===========================================================================
//打开设备
//===========================================================================
NTSTATUS OpenDevice() {
NTSTATUS Status;
HANDLE hSysLink;
HANDLE hDevice = NULL;
ULONG ulStrLen, i;
UCHAR ucBuf[10];
KEVENT Event;
PIRP pNewIrp = NULL;
OBJECT_ATTRIBUTES ObjAttr;
UNICODE_STRING USzDeviceName = {0};
PIO_STACK_LOCATION pStack = NULL;
IO_STATUS_BLOCK Status_Block;
LARGE_INTEGER liOffset;
PDEVICE_OBJECT pDevice = NULL;
PFILE_OBJECT pFileObj = NULL;
UNICODE_STRING USzDeviceLinkName = RTL_CONSTANT_STRING( SYSLINK_NAME );
do {
//这边是内核的对象, 加了个内核属性
InitializeObjectAttributes( &ObjAttr, &USzDeviceLinkName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL );
//获取符号链接句柄
Status = ZwOpenSymbolicLinkObject( &hSysLink, FILE_ALL_ACCESS, &ObjAttr );
if ( !NT_SUCCESS( Status ) ) {
KdPrint( ( "打开符号链接失败!\n" ) );
break;
}
USzDeviceName.Buffer = ExAllocatePool( PagedPool, MAX_PATH );
USzDeviceName.MaximumLength = MAX_PATH;
ASSERT( USzDeviceName.Buffer );
//通过符号名称得到设备名称
Status = ZwQuerySymbolicLinkObject( hSysLink, &USzDeviceName, &ulStrLen );
if ( !NT_SUCCESS( Status ) ) {
KdPrint( ( "符号名称转换成链接名称失败!\n" ) );
break;
}
KdPrint( ( "设备名称%wZ\n", &USzDeviceName ) );
//这个打开设备比ZwCreateFile好多了, 参数简单,
//还可以直接获取到文件对象指针, 设备对象指针
//这边还模拟了一个系统这个部分的实现.
Status = _IoGetDeviceObjectPointer( &USzDeviceName, FILE_ALL_ACCESS,
&pFileObj, &pDevice );
if ( !NT_SUCCESS( Status ) ) {
KdPrint( ( "设备名转文件对象指针失败!\n" ) );
break;
}
//---------------------------------------------------------------------------
//创建同步IRP写入请求, 这里的话, 其实同步和异步差不多
//---------------------------------------------------------------------------
liOffset.QuadPart = 0i64;
KeInitializeEvent( &Event, NotificationEvent, FALSE );
RtlFillMemory( ucBuf, sizeof( ucBuf ), ‘a‘ );
//创建同步IRP请求
pNewIrp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE, pDevice, &ucBuf[0],
sizeof( ucBuf ), &liOffset,
&Event, &Status_Block );
//得到下一层的I/O堆栈(如果驱动不是只有一层, 应该怎么做呢?)
pStack = IoGetNextIrpStackLocation( pNewIrp );
//设置I/O堆栈的文件对象指针
pStack->FileObject = pFileObj;
//调用下一层驱动
Status = IoCallDriver( pDevice, pNewIrp );
if ( !NT_SUCCESS( Status ) ) {
KdPrint( ( "调用驱动失败!\n" ) );
break;
}
if ( Status == STATUS_PENDING ) {
KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
Status = Status_Block.Status;
if ( NT_SUCCESS( Status_Block.Status ) ) {
KdPrint( ( "写入设备成功, 总共写入了%d字节!\n",
Status_Block.Information ) );
} else {
KdPrint( ( "写入设备失败!\n" ) );
break;
}
}
//---------------------------------------------------------------------------
//创建异步Irp读取请求,
//---------------------------------------------------------------------------
pNewIrp = NULL;
pStack = NULL;
KeResetEvent( &Event );
liOffset.QuadPart = 0i64;
RtlZeroBytes( &ucBuf[0], sizeof( ucBuf ) );
//创建异步Irp
pNewIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ, pDevice, &ucBuf[0],
sizeof( ucBuf ), &liOffset, &Status_Block );
//Irp完成后会通过这里通知这边
pNewIrp->UserEvent = &Event;
//获取下一层I/O堆栈
pStack = IoGetNextIrpStackLocation( pNewIrp );
pStack->FileObject = pFileObj;
Status = IoCallDriver( pDevice, pNewIrp );
if ( !NT_SUCCESS( Status ) ) {
KdPrint( ( "读取设备请求失败!" ) );
break;
}
if ( Status == STATUS_PENDING ) {
KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
Status = Status_Block.Status;
if ( NT_SUCCESS( Status_Block.Status ) ) {
KdPrint( ( "读取设备成功!\n" ) );
for( i = 0; i < Status_Block.Information; i++ ) {
KdPrint( ( "%c\t", ucBuf[i] ) );
}
KdPrint( ( "\n" ) );
} else {
KdPrint( ( "读取设备失败!\n" ) );
break;
}
}
//---------------------------------------------------------------------------
//手工创建Irp
//---------------------------------------------------------------------------
pNewIrp = NULL;
pStack = NULL;
KeResetEvent( &Event );
liOffset.QuadPart = 0i64;
RtlZeroBytes( &ucBuf[0], sizeof( ucBuf ) );
//这个创建出来的是最原始的IRP
pNewIrp = IoAllocateIrp( pDevice->StackSize, FALSE );
//设置同步事件
pNewIrp->UserEvent = &Event;
pNewIrp->UserIosb = &Status_Block;
//填写新Irp的线程号
pNewIrp->Tail.Overlay.Thread = PsGetCurrentThread();
//填写缓冲区
pNewIrp->AssociatedIrp.SystemBuffer = ucBuf;
//获取下一层堆栈
pStack = IoGetNextIrpStackLocation( pNewIrp );
//填写功能号
pStack->MajorFunction = IRP_MJ_READ;
pStack->MinorFunction = IRP_MN_NORMAL;
//填写文件对象
pStack->FileObject = pFileObj;
//填写缓冲区长度和偏移
pStack->Parameters.Read.Length = sizeof( ucBuf );
pStack->Parameters.Read.ByteOffset = liOffset;
Status = IoCallDriver( pDevice, pNewIrp );
if ( !NT_SUCCESS( Status ) ) {
KdPrint( ( "Irp发送失败!\n" ) );
break;
}
if ( Status == STATUS_PENDING ) {
KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
Status = Status_Block.Status;
if ( NT_SUCCESS( Status_Block.Status ) ) {
KdPrint( ( "读取设备成功!\n" ) );
for( i = 0; i < Status_Block.Information; i++ ) {
KdPrint( ( "%c\t", ucBuf[i] ) );
}
KdPrint( ( "\n" ) );
} else {
KdPrint( ( "读取设备失败!\n" ) );
break;
}
}
} while ( FALSE );
//---------------------------------------------------------------------------
if ( USzDeviceName.Buffer ) {
ExFreePool( USzDeviceName.Buffer );
}
if ( hSysLink ) {
ZwClose( hSysLink );
}
if ( pFileObj ) {
ObDereferenceObject( pFileObj );
}
return Status;
}
//===========================================================================
//驱动入口
//===========================================================================
NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) {
NTSTATUS Status;
PDEVICE_OBJECT pDevice = NULL;
PFILE_OBJECT pFileObj = NULL;
UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( SYSLINK_NAME );
//这号函数可以通过名字获取设备指针, 可以获取各种对象的指针(事件, 互斥量等)
Status = ObReferenceObjectByName( &USzDeviceName, OBJ_CASE_INSENSITIVE,
NULL, FILE_ALL_ACCESS, IoDeviceObjectType,
KernelMode, NULL, &pDevice );
if ( !NT_SUCCESS( Status ) ) {
KdPrint( ( "通过名称获取对象指针失败!\n" ) );
return Status;
} else {
KdPrint( ( "通过名称获取对象指针成功!\n" ) );
}
if ( pDevice ) {
ObDereferenceObject( pDevice );
pDevice = NULL;
}
Status = OpenDevice();
if ( !NT_SUCCESS( Status ) ) {
KdPrint( ( "操作设备失败!\n" ) );
return Status;
} else {
KdPrint( ( "操作设备成功!\n" ) );
}
return STATUS_UNSUCCESSFUL;
}原文地址:http://www.cnblogs.com/adylee/p/3714295.html