首页
社区
课程
招聘
个人备份,win7 64位下卡住MmLoadSystemImage,防止驱动加载后删除驱动文件
发表于: 2018-8-12 11:59 6330

个人备份,win7 64位下卡住MmLoadSystemImage,防止驱动加载后删除驱动文件

2018-8-12 11:59
6330
/*++

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直播授课

上传的附件:
收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 914
活跃值: (2463)
能力值: ( LV5,RANK:68 )
在线值:
发帖
回帖
粉丝
2
楼主头像让人忍不住双击
2018-8-13 11:30
0
雪    币: 37
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
哈哈会玩噢
2018-10-19 17:58
0
雪    币: 6507
活跃值: (2382)
能力值: ( LV12,RANK:320 )
在线值:
发帖
回帖
粉丝
4
好帖,帮顶!
2019-7-30 16:36
0
游客
登录 | 注册 方可回帖
返回
//