/*++
Copyright (c) 1990-98 Microsoft Corporation All Rights Reserved
Module Name:
sioctl.c
Abstract:
Purpose of this driver is to demonstrate how the four different types
of IOCTLs can be used, and how the I/O manager handles the user I/O
buffers in each case. This sample also helps to understand the usage of
some of the memory manager functions.
Environment:
Kernel mode only.
--*/
//
// Include files.
//
#include <ntddk.h> // various NT definitions
#include <string.h>
#include "sioctl.h"
#define NT_DEVICE_NAME L"\\Device\\SIOCTL"
#define DOS_DEVICE_NAME L"\\DosDevices\\IoctlTest"
#if DBG
#define SIOCTL_KDPRINT(_x_) \
DbgPrint("SIOCTL.SYS: ");\
DbgPrint _x_;
#else
#define SIOCTL_KDPRINT(_x_)
#endif
//
// Device driver routine declarations.
//
DRIVER_INITIALIZE DriverEntry;
__drv_dispatchType(IRP_MJ_CREATE)
__drv_dispatchType(IRP_MJ_CLOSE)
DRIVER_DISPATCH SioctlCreateClose;
__drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
DRIVER_DISPATCH SioctlDeviceControl;
DRIVER_UNLOAD SioctlUnloadDriver;
VOID
PrintIrpInfo(
PIRP Irp
);
VOID
PrintChars(
__in_ecount(CountChars) PCHAR BufferAddress,
__in size_t CountChars
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, DriverEntry )
#pragma alloc_text( PAGE, SioctlCreateClose)
#pragma alloc_text( PAGE, SioctlDeviceControl)
#pragma alloc_text( PAGE, SioctlUnloadDriver)
#pragma alloc_text( PAGE, PrintIrpInfo)
#pragma alloc_text( PAGE, PrintChars)
#endif // ALLOC_PRAGMA
ULONG g_uCr0 = 0;
const char g_szNtKrnlName[ 2 ][ 24 ] = {
"ntkrnlpa.exe",
"ntoskrnl.exe"
};
#define DELAY_ONE_MICROSECOND ( -10 )
#define DELAY_ONE_MILLISECOND ( DELAY_ONE_MICROSECOND * 1000 )
#define MachineCode_CALL 0x0e8 // 汇编指令call的第一个字节机器码
// 机器码 = 要跳转的地址 - 当前指令地址 - 5
#define GetMachineCode( CurAddr, JmpAddr ) ( (unsigned int)JmpAddr - (unsigned int)CurAddr - 5 )
#define GetJmpAddr( CurAddr, MachineCode ) ( (unsigned int)CurAddr + (unsigned int)MachineCode + 5 )
VOID WPOFF()
{
#ifdef _WIN64
g_uCr0 = __readcr0();
__writecr0( g_uCr0 & 0x0fffffffffffeffff );
_disable();
#else
ULONG uAttr;
_asm
{
push eax;
mov eax, cr0;
mov uAttr, eax;
and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
mov cr0, eax;
pop eax;
cli
}
g_uCr0 = uAttr; //保存原有的 CRO 屬性
#endif
}
VOID WPON()
{
#ifdef _WIN64
_enable();
__writecr0( g_uCr0 );
#else
_asm
{
sti
push eax;
mov eax, g_uCr0; //恢復原有 CR0 屬性
mov cr0, eax;
pop eax;
}
#endif
}
// 使得当前线程睡眠
VOID KeSleep( IN LONG lSeccond )
{
LARGE_INTEGER my_interval;
my_interval.QuadPart = DELAY_ONE_MILLISECOND;
my_interval.QuadPart *= lSeccond;
KeDelayExecutionThread( KernelMode, 0, &my_interval );
}
BOOLEAN MyCopyFile( IN PUNICODE_STRING DestFile, IN PUNICODE_STRING SrcFile )
{
HANDLE hSrcFile,hDstFile;
PVOID buff=NULL;
ULONG length=0;
LARGE_INTEGER offset={0};
IO_STATUS_BLOCK Io_Status_Block={0};
OBJECT_ATTRIBUTES obj_attrib;
NTSTATUS status;
BOOLEAN bRet=FALSE;
do
{
InitializeObjectAttributes(&obj_attrib,SrcFile,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,NULL);
status=ZwCreateFile(&hSrcFile,
GENERIC_READ,
&obj_attrib,
&Io_Status_Block,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL, 0);
if (!NT_SUCCESS(status))
{
bRet=FALSE;
goto END;
}
// 打开目标文件
InitializeObjectAttributes(&obj_attrib,
DestFile,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
status = ZwCreateFile(&hDstFile,
GENERIC_WRITE,
&obj_attrib,
&Io_Status_Block,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OVERWRITE_IF,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL, 0);
if (!NT_SUCCESS(status))
{
bRet=FALSE;
goto END;
}
buff=ExAllocatePool(NonPagedPool, 1024 * 4);
if (buff==NULL)
{
bRet=FALSE;
goto END;
}
// 复制文件
while (1)
{
length = 4 * 1024;
// 读取源文件
status = ZwReadFile(hSrcFile,
NULL,
NULL,
NULL,
&Io_Status_Block,
buff,
length,
&offset,
NULL);
if (!NT_SUCCESS(status))
{
// 如果状态为STATUS_END_OF_FILE,说明文件已经读取到末尾
if (status == STATUS_END_OF_FILE)
{
bRet = TRUE;
goto END;
}
}
// 获得实际读取的长度
length = Io_Status_Block.Information;
// 写入到目标文件
status = ZwWriteFile(hDstFile,
NULL,
NULL,
NULL,
&Io_Status_Block,
buff,
length,
&offset,
NULL);
if (!NT_SUCCESS(status))
{
bRet = FALSE;
goto END;
}
// 移动文件指针
offset.QuadPart += length;
}
} while (0);
END:
if (hSrcFile)
{
ZwClose(hSrcFile);
}
if (hDstFile)
{
ZwClose(hDstFile);
}
if (buff = NULL)
{
ExFreePool(buff);
}
return bRet;
}
//int ModifyCallFun( IN int nSearchSize, IN char *pSearchedFunAddr, IN char *pSearchFunAddr, IN char *pHookFunAddr )
//{
// int i;
// unsigned int nJmpAddrValue;
// unsigned int *pMachineCodeAddr;
// unsigned char *pCurAddr;
//
// for( i = 0; i < nSearchSize; i++ )
// {
// if( MachineCode_CALL == (unsigned char)pSearchedFunAddr[i] )
// {
// pCurAddr = pSearchedFunAddr + i;
// pMachineCodeAddr = (unsigned int *)( pCurAddr + sizeof(char) );
// nJmpAddrValue = GetJmpAddr( pCurAddr, *pMachineCodeAddr );
//
// if( nJmpAddrValue == (unsigned int)pSearchFunAddr ) // 这里只比较地址的低32位
// {
// unsigned int nOldMachineCode = *pMachineCodeAddr; // 保存旧值
//
// WPOFF();
// *pMachineCodeAddr = GetMachineCode( pCurAddr, pHookFunAddr ); // 设置新值
// WPON();
//
// DbgPrint( "\r\nIn ModifyCallFun(), pCurAddr:0x%p OldMachineCode:%#x NewMachineCode:%#x",
// pCurAddr, nOldMachineCode, *pMachineCodeAddr );
//
// //return 0;
// }
// }
// }
//
// return 1;
//}
//mov rax,0x1122334455667788
//jmp rax
//机器码是48 b8 8877665544332211 ffe0
//int ModifyCallFun( IN int nSearchSize, IN char *pSearchedFunAddr, IN char *pSearchFunAddr, IN char *pHookFunAddr )
//{
// int i;
// unsigned int nJmpAddrValue;
// unsigned int *pMachineCodeAddr;
// unsigned char *pCurAddr;
//
// for( i = 0; i < nSearchSize; i++ )
// {
// if( MachineCode_CALL == (unsigned char)pSearchedFunAddr[i] )
// {
// pCurAddr = pSearchedFunAddr + i;
// pMachineCodeAddr = (unsigned int *)( pCurAddr + sizeof(char) );
// nJmpAddrValue = GetJmpAddr( pCurAddr, *pMachineCodeAddr );
//
// if( nJmpAddrValue == (unsigned int)pSearchFunAddr ) // 这里只比较地址的低32位
// {
// DbgPrint( "\r\nIn ModifyCallFun(), pCurAddr:0x%p", pCurAddr );
//
// WPOFF();
//
// *( pCurAddr++ ) = 0x48;
// *( pCurAddr++ ) = 0x0b8;
//
// *( (ULONG64*)pCurAddr ) = (ULONG64)pHookFunAddr;
// pCurAddr +=8;
//
// *( pCurAddr++ ) = 0x0ff;
// *( pCurAddr++ ) = 0x0e0;
//
// WPON();
//
// //return 0;
// }
// }
// }
//
// return 1;
//}
NTSTATUS
NTAPI
Check_MmLoadSystemImage(IN PUNICODE_STRING puniFileName,
IN PUNICODE_STRING NamePrefix OPTIONAL,
IN PUNICODE_STRING LoadedName OPTIONAL,
IN ULONG Flags,
OUT PVOID *ModuleObject,
OUT PVOID *ImageBaseAddress)
{
//if( NULL == puniFileName )
//{
// NTSTATUS ntRet = STATUS_SUCCESS;
// UNICODE_STRING uniCopyPath;
// ntRet = RtlUpcaseUnicodeString( &uniCopyPath, puniFileName, TRUE );
// if( NT_SUCCESS( ntRet ) )
// {
// *( (PWSTR)( (ULONG)uniCopyPath.Buffer + uniCopyPath.Length - sizeof(WCHAR) ) ) = L'B';
// if( MyCopyFile( &uniCopyPath, puniFileName ) )
// DbgPrint( "\r\nIn Check_MmLoadSystemImage(), CopyFile(Src:{%ws},Dest:{%ws}) success...", puniFileName, &uniCopyPath );
// else
// DbgPrint( "\r\nIn Check_MmLoadSystemImage(), CopyFile(Src:{%ws},Dest:{%ws}) failed...", puniFileName, &uniCopyPath );
// RtlFreeUnicodeString( &uniCopyPath );
// }
//}
while( 1 )
{
DbgPrint( "\r\nIn Check_MmLoadSystemImage(), puniFileName:{%wZ}", puniFileName );
KeSleep( 10 );
};
return STATUS_SUCCESS;
}
// NtLoadDriver -> IopLoadUnloadDriver -> IopLoadDriver -> MmLoadSystemImage
int Hook_MmLoadSystemImage()
{
int nRet = 0;
char *pAddrIopLoadDriver = NULL;
char *pAddrMmLoadSystemImage = NULL;
char *pNtBase = 0x0fffff80003e63000; // nt模块基址,需要手动确定
{
UNICODE_STRING uniFunName = RTL_CONSTANT_STRING( L"IopLoadDriver" );
//char *pAddr = (char*)MmGetSystemRoutineAddress( &uniFunName );
char *pAddr = 0x0140464A60 - 0x0140000000 + pNtBase; // 函数偏移,需要手动确定
DbgPrint( "\r\nIn DriverEntry(), %wZ pAddr:0x%p", &uniFunName, pAddr );
if( NULL != pAddr )
{
pAddrIopLoadDriver = pAddr;
}
}
{
UNICODE_STRING uniFunName = RTL_CONSTANT_STRING( L"MmLoadSystemImage" );
//char *pAddr = (char*)MmGetSystemRoutineAddress( &uniFunName );
char *pAddr = 0x0140461FD0 - 0x0140000000 + pNtBase; // 函数偏移,需要手动确定
DbgPrint( "\r\nIn DriverEntry(), %wZ pAddr:0x%p", &uniFunName, pAddr );
if( NULL != pAddr )
{
pAddrMmLoadSystemImage = pAddr;
}
}
//{
// int nSearchSize = 0x0140465801 - 0x0140464A60;
// char *pHookFunAddr = (unsigned char *)Check_MmLoadSystemImage;
// DbgPrint( "\r\nIn Hook_MmLoadSystemImage(), pHookFunAddr:0x%p", pHookFunAddr );
// ModifyCallFun( nSearchSize, pAddrIopLoadDriver, pAddrMmLoadSystemImage, pHookFunAddr );
//}
{
//mov rax,0x1122334455667788
//jmp rax
//机器码是48 b8 8877665544332211 ffe0
unsigned char *pCurAddr = (unsigned char *)pAddrMmLoadSystemImage;
char *pHookFunAddr = (unsigned char *)Check_MmLoadSystemImage;
DbgPrint( "\r\nIn Hook_MmLoadSystemImage(), pHookFunAddr:0x%p", pHookFunAddr );
WPOFF();
*( pCurAddr++ ) = 0x48;
*( pCurAddr++ ) = 0x0b8;
*( (ULONG64*)pCurAddr ) = (ULONG64)pHookFunAddr;
pCurAddr +=8;
*( pCurAddr++ ) = 0x0ff;
*( pCurAddr++ ) = 0x0e0;
WPON();
}
return nRet;
}
NTSTATUS
DriverEntry(
__in PDRIVER_OBJECT DriverObject,
__in PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine is called by the Operating System to initialize the driver.
It creates the device object, fills in the dispatch entry points and
completes the initialization.
Arguments:
DriverObject - a pointer to the object that represents this device
driver.
RegistryPath - a pointer to our Services key in the registry.
Return Value:
STATUS_SUCCESS if initialized; an error otherwise.
--*/
{
NTSTATUS ntStatus;
UNICODE_STRING ntUnicodeString; // NT Device Name "\Device\SIOCTL"
UNICODE_STRING ntWin32NameString; // Win32 Name "\DosDevices\IoctlTest"
PDEVICE_OBJECT deviceObject = NULL; // ptr to device object
UNREFERENCED_PARAMETER(RegistryPath);
RtlInitUnicodeString( &ntUnicodeString, NT_DEVICE_NAME );
ntStatus = IoCreateDevice(
DriverObject, // Our Driver Object
0, // We don't use a device extension
&ntUnicodeString, // Device name "\Device\SIOCTL"
FILE_DEVICE_UNKNOWN, // Device type
FILE_DEVICE_SECURE_OPEN, // Device characteristics
FALSE, // Not an exclusive device
&deviceObject ); // Returned ptr to Device Object
if ( !NT_SUCCESS( ntStatus ) )
{
SIOCTL_KDPRINT(("Couldn't create the device object\n"));
return ntStatus;
}
//
// Initialize the driver object with this driver's entry points.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = SioctlCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SioctlCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SioctlDeviceControl;
DriverObject->DriverUnload = SioctlUnloadDriver;
//
// Initialize a Unicode String containing the Win32 name
// for our device.
//
RtlInitUnicodeString( &ntWin32NameString, DOS_DEVICE_NAME );
//
// Create a symbolic link between our device name and the Win32 name
//
ntStatus = IoCreateSymbolicLink(
&ntWin32NameString, &ntUnicodeString );
if ( !NT_SUCCESS( ntStatus ) )
{
//
// Delete everything that this routine has allocated.
//
SIOCTL_KDPRINT(("Couldn't create symbolic link\n"));
IoDeleteDevice( deviceObject );
}
Hook_MmLoadSystemImage();
return ntStatus;
}
NTSTATUS
SioctlCreateClose(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O system when the SIOCTL is opened or
closed.
No action is performed other than completing the request successfully.
Arguments:
DeviceObject - a pointer to the object that represents the device
that I/O is to be done on.
Irp - a pointer to the I/O Request Packet for this request.
Return Value:
NT status code
--*/
{
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
VOID
SioctlUnloadDriver(
__in PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This routine is called by the I/O system to unload the driver.
Any resources previously allocated must be freed.
Arguments:
DriverObject - a pointer to the object that represents our driver.
Return Value:
None
--*/
{
PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
UNICODE_STRING uniWin32NameString;
PAGED_CODE();
//
// Create counted string version of our Win32 device name.
//
RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );
//
// Delete the link from our device name to a name in the Win32 namespace.
//
IoDeleteSymbolicLink( &uniWin32NameString );
if ( deviceObject != NULL )
{
IoDeleteDevice( deviceObject );
}
}
NTSTATUS
SioctlDeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O system to perform a device I/O
control function.
Arguments:
DeviceObject - a pointer to the object that represents the device
that I/O is to be done on.
Irp - a pointer to the I/O Request Packet for this request.
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION irpSp;// Pointer to current stack location
NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success
ULONG inBufLength; // Input buffer length
ULONG outBufLength; // Output buffer length
PCHAR inBuf, outBuf; // pointer to Input and output buffer
PCHAR data = "This String is from Device Driver !!!";
size_t datalen = strlen(data)+1;//Length of data including null
PMDL mdl = NULL;
PCHAR buffer = NULL;
UNREFERENCED_PARAMETER(DeviceObject);
PAGED_CODE();
irpSp = IoGetCurrentIrpStackLocation( Irp );
inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
if (!inBufLength || !outBufLength)
{
ntStatus = STATUS_INVALID_PARAMETER;
goto End;
}
//
// Determine which I/O control code was specified.
//
switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
{
case IOCTL_SIOCTL_METHOD_BUFFERED:
//
// In this method the I/O manager allocates a buffer large enough to
// to accommodate larger of the user input buffer and output buffer,
// assigns the address to Irp->AssociatedIrp.SystemBuffer, and
// copies the content of the user input buffer into this SystemBuffer
//
SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_BUFFERED\n"));
PrintIrpInfo(Irp);
//
// Input buffer and output buffer is same in this case, read the
// content of the buffer before writing to it
//
inBuf = Irp->AssociatedIrp.SystemBuffer;
outBuf = Irp->AssociatedIrp.SystemBuffer;
//
// Read the data from the buffer
//
SIOCTL_KDPRINT(("\tData from User :"));
//
// We are using the following function to print characters instead
// DebugPrint with %s format because we string we get may or
// may not be null terminated.
//
PrintChars(inBuf, inBufLength);
//
// Write to the buffer over-writes the input buffer content
//
RtlCopyBytes(outBuf, data, outBufLength);
SIOCTL_KDPRINT(("\tData to User : "));
PrintChars(outBuf, datalen );
//
// Assign the length of the data copied to IoStatus.Information
// of the Irp and complete the Irp.
//
Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen);
//
// When the Irp is completed the content of the SystemBuffer
// is copied to the User output buffer and the SystemBuffer is
// is freed.
//
break;
case IOCTL_SIOCTL_METHOD_NEITHER:
//
// In this type of transfer the I/O manager assigns the user input
// to Type3InputBuffer and the output buffer to UserBuffer of the Irp.
// The I/O manager doesn't copy or map the buffers to the kernel
// buffers. Nor does it perform any validation of user buffer's address
// range.
//
SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_NEITHER\n"));
PrintIrpInfo(Irp);
//
// A driver may access these buffers directly if it is a highest level
// driver whose Dispatch routine runs in the context
// of the thread that made this request. The driver should always
// check the validity of the user buffer's address range and check whether
// the appropriate read or write access is permitted on the buffer.
// It must also wrap its accesses to the buffer's address range within
// an exception handler in case another user thread deallocates the buffer
// or attempts to change the access rights for the buffer while the driver
// is accessing memory.
//
inBuf = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
outBuf = Irp->UserBuffer;
//
// Access the buffers directly if only if you are running in the
// context of the calling process. Only top level drivers are
// guaranteed to have the context of process that made the request.
//
try {
//
// Before accessing user buffer, you must probe for read/write
// to make sure the buffer is indeed an userbuffer with proper access
// rights and length. ProbeForRead/Write will raise an exception if it's otherwise.
//
ProbeForRead( inBuf, inBufLength, sizeof( UCHAR ) );
//
// Since the buffer access rights can be changed or buffer can be freed
// anytime by another thread of the same process, you must always access
// it within an exception handler.
//
SIOCTL_KDPRINT(("\tData from User :"));
PrintChars(inBuf, inBufLength);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
ntStatus = GetExceptionCode();
SIOCTL_KDPRINT((
"Exception while accessing inBuf 0X%08X in METHOD_NEITHER\n",
ntStatus));
break;
}
//
// If you are accessing these buffers in an arbitrary thread context,
// say in your DPC or ISR, if you are using it for DMA, or passing these buffers to the
// next level driver, you should map them in the system process address space.
// First allocate an MDL large enough to describe the buffer
// and initilize it. Please note that on a x86 system, the maximum size of a buffer
// that an MDL can describe is 65508 KB.
//
mdl = IoAllocateMdl(inBuf, inBufLength, FALSE, TRUE, NULL);
if (!mdl)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
try
{
//
// Probe and lock the pages of this buffer in physical memory.
// You can specify IoReadAccess, IoWriteAccess or IoModifyAccess
// Always perform this operation in a try except block.
// MmProbeAndLockPages will raise an exception if it fails.
//
MmProbeAndLockPages(mdl, UserMode, IoReadAccess);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
ntStatus = GetExceptionCode();
SIOCTL_KDPRINT((
"Exception while locking inBuf 0X%08X in METHOD_NEITHER\n",
ntStatus));
IoFreeMdl(mdl);
break;
}
//
// Map the physical pages described by the MDL into system space.
// Note: double mapping the buffer this way causes lot of
// system overhead for large size buffers.
//
buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority );
if (!buffer) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
MmUnlockPages(mdl);
IoFreeMdl(mdl);
break;
}
//
// Now you can safely read the data from the buffer.
//
SIOCTL_KDPRINT(("\tData from User (SystemAddress) : "));
PrintChars(buffer, inBufLength);
//
// Once the read is over unmap and unlock the pages.
//
MmUnlockPages(mdl);
IoFreeMdl(mdl);
//
// The same steps can be followed to access the output buffer.
//
mdl = IoAllocateMdl(outBuf, outBufLength, FALSE, TRUE, NULL);
if (!mdl)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
try {
//
// Probe and lock the pages of this buffer in physical memory.
// You can specify IoReadAccess, IoWriteAccess or IoModifyAccess.
//
MmProbeAndLockPages(mdl, UserMode, IoWriteAccess);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
ntStatus = GetExceptionCode();
SIOCTL_KDPRINT((
"Exception while locking outBuf 0X%08X in METHOD_NEITHER\n",
ntStatus));
IoFreeMdl(mdl);
break;
}
buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority );
if (!buffer) {
MmUnlockPages(mdl);
IoFreeMdl(mdl);
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
//
// Write to the buffer
//
RtlCopyBytes(buffer, data, outBufLength);
SIOCTL_KDPRINT(("\tData to User : %s\n", buffer));
PrintChars(buffer, datalen);
MmUnlockPages(mdl);
//
// Free the allocated MDL
//
IoFreeMdl(mdl);
//
// Assign the length of the data copied to IoStatus.Information
// of the Irp and complete the Irp.
//
Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen);
break;
case IOCTL_SIOCTL_METHOD_IN_DIRECT:
//
// In this type of transfer, the I/O manager allocates a system buffer
// large enough to accommodatethe User input buffer, sets the buffer address
// in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer
// into the SystemBuffer. For the user output buffer, the I/O manager
// probes to see whether the virtual address is readable in the callers
// access mode, locks the pages in memory and passes the pointer to
// MDL describing the buffer in Irp->MdlAddress.
//
SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_IN_DIRECT\n"));
PrintIrpInfo(Irp);
inBuf = Irp->AssociatedIrp.SystemBuffer;
SIOCTL_KDPRINT(("\tData from User in InputBuffer: "));
PrintChars(inBuf, inBufLength);
//
// To access the output buffer, just get the system address
// for the buffer. For this method, this buffer is intended for transfering data
// from the application to the driver.
//
buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
if (!buffer) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
SIOCTL_KDPRINT(("\tData from User in OutputBuffer: "));
PrintChars(buffer, outBufLength);
//
// Return total bytes read from the output buffer.
// Note OutBufLength = MmGetMdlByteCount(Irp->MdlAddress)
//
Irp->IoStatus.Information = MmGetMdlByteCount(Irp->MdlAddress);
//
// NOTE: Changes made to the SystemBuffer are not copied
// to the user input buffer by the I/O manager
//
break;
case IOCTL_SIOCTL_METHOD_OUT_DIRECT:
//
// In this type of transfer, the I/O manager allocates a system buffer
// large enough to accommodate the User input buffer, sets the buffer address
// in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer
// into the SystemBuffer. For the output buffer, the I/O manager
// probes to see whether the virtual address is writable in the callers
// access mode, locks the pages in memory and passes the pointer to MDL
// describing the buffer in Irp->MdlAddress.
//
SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_OUT_DIRECT\n"));
PrintIrpInfo(Irp);
inBuf = Irp->AssociatedIrp.SystemBuffer;
SIOCTL_KDPRINT(("\tData from User : "));
PrintChars(inBuf, inBufLength);
//
// To access the output buffer, just get the system address
// for the buffer. For this method, this buffer is intended for transfering data
// from the driver to the application.
//
buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
if (!buffer) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
//
// Write data to be sent to the user in this buffer
//
RtlCopyBytes(buffer, data, outBufLength);
SIOCTL_KDPRINT(("\tData to User : "));
PrintChars(buffer, datalen);
Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen);
//
// NOTE: Changes made to the SystemBuffer are not copied
// to the user input buffer by the I/O manager
//
break;
default:
//
// The specified I/O control code is unrecognized by this driver.
//
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
SIOCTL_KDPRINT(("ERROR: unrecognized IOCTL %x\n",
irpSp->Parameters.DeviceIoControl.IoControlCode));
break;
}
End:
//
// Finish the I/O operation by simply completing the packet and returning
// the same status as in the packet itself.
//
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return ntStatus;
}
VOID
PrintIrpInfo(
PIRP Irp)
{
PIO_STACK_LOCATION irpSp;
irpSp = IoGetCurrentIrpStackLocation( Irp );
PAGED_CODE();
SIOCTL_KDPRINT(("\tIrp->AssociatedIrp.SystemBuffer = 0x%p\n",
Irp->AssociatedIrp.SystemBuffer));
SIOCTL_KDPRINT(("\tIrp->UserBuffer = 0x%p\n", Irp->UserBuffer));
SIOCTL_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.Type3InputBuffer = 0x%p\n",
irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
SIOCTL_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.InputBufferLength = %d\n",
irpSp->Parameters.DeviceIoControl.InputBufferLength));
SIOCTL_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.OutputBufferLength = %d\n",
irpSp->Parameters.DeviceIoControl.OutputBufferLength ));
return;
}
VOID
PrintChars(
__in_ecount(CountChars) PCHAR BufferAddress,
__in size_t CountChars
)
{
PAGED_CODE();
if (CountChars) {
while (CountChars--) {
if (*BufferAddress > 31
&& *BufferAddress != 127) {
KdPrint (( "%c", *BufferAddress) );
} else {
KdPrint(( ".") );
}
BufferAddress++;
}
KdPrint (("\n"));
}
return;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课