Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Monitoring NT Debug Services


February 2000/Monitoring NT Debug Services/Listing 1

Listing 1: entrypoi.cpp — Driver entry points and buffer management

#pragma warning( disable : 4201 4514 4060)
#include "DbgTrapProcs.h"

#define NT_DEVICE_NAME      L"\\Device\\DbgTrap"
#define DOS_DEVICE_NAME     L"\\DosDevices\\DbgTrap"

// DRIVER_STATE is used by CleanUp function to determine work
// to be done. As the driver completes it's initialization we
// increment it's state.  If an error occurs during at any time
// Cleanup does all work undoing what we've done up to that point.
typedef enum DRIVER_STATE
{
    STATE_INITIAL,          // We own no resources
    STATE_HASBUFFER,        // We've allocated our event buffer
    STATE_HASDEVICES,       // We've created a device object
    STATE_HASLINK,          // We've created a symbolic link
    STATE_MONITORING        // We're hooked into the debugger service
};

DRIVER_STATE    state;  // See DRIVER_STATE discussion above
MDL             mdl;    // MDL describing the GUI's view of eb
extern "C" NTSTATUS DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath  );

// Moves our cheezy state machine into the next state
inline DRIVER_STATE NextState()
{
    //_asm    lock inc state
    InterlockedIncrement( (PLONG)&state );
    return state;
}

// Moves our cheezy state machine into the previous state
inline DRIVER_STATE PreviousState()
{
    //_asm    lock inc state
    InterlockedDecrement( (PLONG)&state );
    return state;
}

// Prepares our driver to be unloaded. Can be called from anywhere
// not just unload routine. Any fatal errors will call this before
// spiriling downward to doom.
void Cleanup(PDRIVER_OBJECT DriverObject)
{
    UNICODE_STRING uniWin32NameString;
   
    DTPrint( ("Cleanup called!!" ) );
    switch ( state )
    {
        case STATE_MONITORING:
            InstallDebugServiceHook( FALSE );
        case STATE_HASLINK:
            // Delete the link from our device name to a
            // name in the Win32 namespace. 
            RtlInitUnicodeString( &uniWin32NameString,
                                   DOS_DEVICE_NAME );
            IoDeleteSymbolicLink( &uniWin32NameString );
        case STATE_HASDEVICES:
            // Finally delete our device object
            IoDeleteDevice( DriverObject->DeviceObject );
        case STATE_HASBUFFER:
            // Free up our trapper resources
            BringDownTrapper();
        case STATE_INITIAL:
            state = STATE_INITIAL;
            break;
    }
}

// generically checks basic things about potential buffer
NTSTATUS ValidateBuffer(PVOID pBuffer,          // potential buffer
        DWORD length,           // length this buffer claims to be
        DWORD requiredLength    // length this buffer *must* be
        )
{
    if ( pBuffer == NULL )
        return STATUS_INVALID_PARAMETER;
    if ( length < requiredLength )
        return STATUS_INFO_LENGTH_MISMATCH;
    return STATUS_SUCCESS;
}

// We keep a pointer to the ring 3 buffer for each open file handle 
// to our device that has been given access to our event buffer.
// This function sets that buffer value into the file object that
// originated the current IRP
void SetGuiView(IN PIRP     pIrp, IN PVOID    value)
{
    PFILE_OBJECT pFile = pIrp->Tail.Overlay.OriginalFileObject;
    pFile->FsContext = (PVOID)value;
}

// We keep a pointer to the ring 3 buffer for each open file handle
// to our device that has been given access to our event buffer.
// This function plucks that buffer value out of the file object
// indirectly, via the current IRP.
PVOID GetGuiView(IN PIRP pIrp)
{
    PFILE_OBJECT pFile = pIrp->Tail.Overlay.OriginalFileObject;
    return pFile->FsContext;
}

    PMDL        pMdl;

// We graciously share our event buffer with the GUI. It's up to
// the GUI to behave properly with the event buffer. Since our 
// device is exclusive & I am writing both the GUI & the driver,
// there is no reason to think I'd write the driver any better
// than I'd write the GUI...so there's no problem ;-)
NTSTATUS MapGuiView(IN OUT  PVOID   outputBuffer,
    IN      DWORD   outputBufferLength,  IN      PIRP    pIrp)
{
    NTSTATUS    status = STATUS_UNSUCCESSFUL;
    // Anything to do?
    if ( GetGuiView(pIrp) != NULL)
        return STATUS_SUCCESS;
    // Do we have good parameters?
    status = ValidateBuffer( outputBuffer,
                outputBufferLength, sizeof(DWORD) );
    if ( status != STATUS_SUCCESS )
        return status;
    _try
    {        
        DWORD size = MmSizeOfMdl(pHeader,bufferSize);
        pMdl = (PMDL)ExAllocatePool( NonPagedPool, size );
        pMdl = MmCreateMdl( pMdl, pHeader, bufferSize);
        if ( (pMdl->MdlFlags & (MDL_PAGES_LOCKED               |
                                MDL_SOURCE_IS_NONPAGED_POOL    |
                                MDL_MAPPED_TO_SYSTEM_VA        |
                                MDL_PARTIAL) ) == 0)
            MmBuildMdlForNonPagedPool(pMdl);
        PVOID ptr = MmMapLockedPages(pMdl, UserMode);
        if ( ptr == NULL )
            *(PDBGTRAP_HEADER*)outputBuffer = NULL;
        else
            *(PDBGTRAP_HEADER*)outputBuffer =
             (PDBGTRAP_HEADER)(ULONG(ptr)|MmGetMdlByteOffset(pMdl));
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        return STATUS_ACCESS_VIOLATION;
    }
    return status;
}

// Does nothing if there's no buffer view associated with the current
// file object. Otherwise, we get rid of the user mode view of our
// event buffer.
void UnmapGuiView(PIRP   pIrp)
{
    // Pull the pointer out from the FileObject
    PVOID   pGuiView = GetGuiView( pIrp );
    if ( pGuiView == NULL )
        return;
    // Now unmap em
    MmUnmapLockedPages((PVOID)((ULONG)pGuiView&~(PAGE_SIZE-1)),pMdl);
    // do some stuff..mmunmaplockedpages()
    SetGuiView( pIrp, NULL );
}

// Handler for all IRP_MJ_CLOSE
NTSTATUS DTClose(IN PDEVICE_OBJECT pDO, IN PIRP pIrp)
{
    // Make sure that we unmap the ring 3 view of our buffer if 
    // necessary
    UnmapGuiView( pIrp );
    // Just complete the IRP normally
    pIrp->IoStatus.Status = STATUS_SUCCESS; 
    IoCompleteRequest(pIrp, IO_NO_INCREMENT ); 
    return STATUS_SUCCESS; 
}

// Handler for IRP_MJ_DEVICE_CONTROL & IRP_MJ_CREATE
NTSTATUS DTDispatch(IN PDEVICE_OBJECT pDO,IN PIRP pIrp)
{
    PVOID           inputBuffer         = NULL;
    PVOID           outputBuffer        = NULL;
    DWORD           inputBufferLength   = 0;
    DWORD           outputBufferLength  = 0;
    NTSTATUS        status              = STATUS_NOT_IMPLEMENTED;
    PIO_STACK_LOCATION pIrpStack=IoGetCurrentIrpStackLocation(pIrp);

    // Get the pointer to the input/output buffer and it's length
    inputBuffer        = pIrpStack->Parameters.DeviceIoControl
                        .Type3InputBuffer;
    outputBuffer       = pIrp->UserBuffer;
    inputBufferLength  = pIrpStack->Parameters.DeviceIoControl
                        .InputBufferLength;
    outputBufferLength = pIrpStack->Parameters.DeviceIoControl
                        .OutputBufferLength;
    pIrp->IoStatus.Information = 0; 
    // Dispatch based on major fcn code. 
    switch (pIrpStack->MajorFunction) 
    { 
        case IRP_MJ_CREATE: 
            SetGuiView( pIrp, NULL );
            status = STATUS_SUCCESS; 
            break; 
        case IRP_MJ_DEVICE_CONTROL: 
            //  Dispatch on IOCTL 
            switch (pIrpStack->Parameters.DeviceIoControl
                    .IoControlCode)
            { 
                case IOCTL_HOOK:
                    if ( InstallDebugServiceHook( TRUE ) )
                    {
                        NextState();
                        status = MapGuiView(  outputBuffer,
                              outputBufferLength, pIrp);
                        if ( status == STATUS_SUCCESS )
                            SetGuiView( pIrp, (PVOID)*
                                (PDWORD)outputBuffer );
                    }                        
                    break;
                case IOCTL_UNHOOK:
                    UnmapGuiView( pIrp );
                    if ( InstallDebugServiceHook( FALSE ) )
                        PreviousState();
                    status = STATUS_SUCCESS;
                    break;
                case IOCTL_RESET:
                    ResetBuffer();
                    status = STATUS_SUCCESS;
                    break;
                case IOCTL_LOGUSER:
                    status = ValidateBuffer( inputBuffer, 
                             inputBufferLength, 1);
                    if ( status == STATUS_SUCCESS )
                        bLogUser = *(PBOOL)inputBuffer;
                    break;
                case IOCTL_LOGKERNEL:
                    status = ValidateBuffer( inputBuffer, 
                             inputBufferLength, 1);
                    if ( status == STATUS_SUCCESS )
                        bLogKernel = *(PBOOL)inputBuffer;
                    break;
                default:
                    // ?? Where did this come from ??
                    status = STATUS_NOT_IMPLEMENTED; 
                    break;
            }
            break; 
        default:
            // ?? Where did this come from ??
            status = STATUS_NOT_IMPLEMENTED; 
            pIrp->IoStatus.Information = 0; 
            break;
    } 

    // We're done with I/O request.  Record the status of the
    // I/O action. 
    pIrp->IoStatus.Status = status; 
    // Don't boost priority when returning since this took
    // little time. 
    IoCompleteRequest(pIrp, IO_NO_INCREMENT ); 
    return status; 
} 

VOID DTUnload(IN PDRIVER_OBJECT DriverObject)
{    
    DTPrint( ("Unloading!!" ) );
    Cleanup( DriverObject );
}

#pragma code_seg("INIT")
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath)
{
    PDEVICE_OBJECT deviceObject = NULL;
    NTSTATUS status;
    UNICODE_STRING uniNtNameString;
    UNICODE_STRING uniWin32NameString;
    
    DTPrint( ("DriverEntry called - Debug Build!") );  
    // Initialize globals
    state = STATE_INITIAL;
    // Initialize the buffer
    status = InitTrapper();
    if ( !NT_SUCCESS(status) ) 
    {
        DTPrint( ("Couldn't initialize debug trap subsystem") );
        Cleanup( DriverObject );
        return status;
    }
    NextState();
    // Create the device object
    RtlInitUnicodeString( &uniNtNameString, NT_DEVICE_NAME );
    status = IoCreateDevice(DriverObject,
                 0,                     // We don't use a
                                        // device extension
                 &uniNtNameString, FILE_DEVICE_UNKNOWN,
                 0,                     // No standard device
                                        // characteristics
                 TRUE,                  // This IS an exclusive
                                        // device
                 &deviceObject
                 );
    if ( !NT_SUCCESS(status) )
    {
        DTPrint( ("Couldn't create the device") );
        Cleanup( DriverObject );
        return status;
    }
    NextState();
    // Set up our dispatch fncs
    DriverObject->MajorFunction[IRP_MJ_CREATE]  = DTDispatch;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]   = DTClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DTDispatch;
    DriverObject->DriverUnload = DTUnload;
    // Create a symbolic link for the GUI
    RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );
    status = IoCreateSymbolicLink( 
                            &uniWin32NameString, &
                            uniNtNameString 
                            );
    if (!NT_SUCCESS(status))
    {
        DTPrint( ("Couldn't create the symbolic link") );
        Cleanup( DriverObject );
        return status;
    }
    NextState();        
    return status;
}
#pragma code_seg()
//End of File

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.