Page 3 of 6 FirstFirst 12345 ... LastLast
Results 31 to 45 of 81

Thread: Question about stealth methods

  1. #31
    Developer
    Join Date
    Jan 2002
    Posts
    239
    While I don't think that SoE would go to the trouble and expense of a hardware dongle, they do exist for USB.

    Google (search) for "usb dongle copy protect" and you will get many, here is the first I found:

    http://www.marx1.com/

  2. #32
    Registered User
    Join Date
    Dec 2001
    Posts
    752
    lostinspace just a question:

    I donīt want to seem greedy, but do you plan to post the source of the driver and the calling app in complete ?

    I have not a great skill in programming, i am a networking consultant and i just wanted to know before i try to make it work ... what is not guranteed that i will come to that point ...

    As said above, its just a question - if you want to keep your work its fine to me you gave great hints.

    Thank you again



    aha, and yes i never looked on the demo of MS - i am using Borland and have to get the MS-Compiler first, because my personal edition of Borland cannot compile a driver :P
    -- Lord Crush

    Greater Faydark has to be cleaned from all Elves !

    This is a HOTKEY !!!

  3. #33
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    As I already posted before, I didnt post complete driver code because only one line needs to be added in any small driver example in DDK, which will invoke my procedure for which I posted code. But if it will be easier for those who are trying to get their kernel driver working, I will post here complete code.

    I'll take as base DDK demo for portio at NTDDK\src\general\portio. There are 3 subfolders there, 2 are for sample read/write clients (ignore them), and 3rd is 'sys' - where driver source is.

    You actually need to change only 3 files:
    NTDDK\src\general\portio\gpioctl.h
    NTDDK\src\general\portio\sys\genport.h
    NTDDK\src\general\portio\sys\genport.c

    You need to do following:
    1- install VC 6
    2- install DDK. I used DDK 2000, but compiled on XP
    3- test if you are able to compile sample portio driver as it is
    4- Replace listed files with files that I will post in following post
    5- start 'Free build environment' DOS prompt from DDK
    6- cd \NTDDK\src\general\portio
    7- build -cewZ
    8- after that, new driver is portio.sys in portio\sys\objfre\i386
    9- install new driver from ControlPanel/AddNewHardware (there is explanation how to do as HTML in root of DDK CD, explaining how to do step 3, test DDK )
    10- change your existing keyreader to use driver in any way that you think is appropriate
    11- when its working, change source for driver, add / rearrange things so your driver is different, and repeat steps 5-9



    I will not post source for my keyreader program, from several reasons, like:

    - it is very large and complex now, since I'm using same program to test all my read options and to simulate program that needs to be read, to simulate VirtualProtect usage etc....

    - it is not written in C , so most people here who use C-compiler would not be able to use it

    - using of kernel driver in existing posted sniffer versions (maggotboys for example) is very simple, and I posted few lines of code that invoke ioctl call. You use function 8 from driver instead of directly reading memory. Or you go more creative and use function 9 only once to read Physical Address (PA), and later use function 10 to read from PA. I posted options that I use in my reader


    But if someone will have questions/problems about using kernel driver, post them here and I'll try to help.

  4. #34
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    gpioctl.h

    /*++

    Copyright (c) 1990-2000 Microsoft Corporation, All Rights Reserved

    Module Name:

    gpioctl.h

    Abstract: Include file for Generic Port I/O Example Driver


    Author: Robert R. Howell January 8, 1993


    Revision History:

    Robert B. Nelson (Microsoft) March 1, 1993

    --*/

    #if !defined(__GPIOCTL_H__)
    #define __GPIOCTL_H__

    //
    // Define the IOCTL codes we will use. The IOCTL code contains a command
    // identifier, plus other information about the device, the type of access
    // with which the file must have been opened, and the type of buffering.
    //

    //
    // Device type -- in the "User Defined" range."
    //

    #define GPD_TYPE 40000

    // The IOCTL function codes from 0x800 to 0xFFF are for customer use.

    #define IOCTL_GPD_READ_PORT_UCHAR \
    CTL_CODE( GPD_TYPE, 0x900, METHOD_BUFFERED, FILE_READ_ACCESS )

    #define IOCTL_GPD_READ_PORT_USHORT \
    CTL_CODE( GPD_TYPE, 0x901, METHOD_BUFFERED, FILE_READ_ACCESS )

    #define IOCTL_GPD_READ_PORT_ULONG \
    CTL_CODE( GPD_TYPE, 0x902, METHOD_BUFFERED, FILE_READ_ACCESS )

    #define IOCTL_GPD_WRITE_PORT_UCHAR \
    CTL_CODE(GPD_TYPE, 0x910, METHOD_BUFFERED, FILE_WRITE_ACCESS)

    #define IOCTL_GPD_WRITE_PORT_USHORT \
    CTL_CODE(GPD_TYPE, 0x911, METHOD_BUFFERED, FILE_WRITE_ACCESS)

    #define IOCTL_GPD_WRITE_PORT_ULONG \
    CTL_CODE(GPD_TYPE, 0x912, METHOD_BUFFERED, FILE_WRITE_ACCESS)


    #define IOCTL_GPD_READ_TST2 \
    CTL_CODE(GPD_TYPE, 0x974, METHOD_BUFFERED, FILE_READ_ACCESS)

    typedef struct _GENPORT_WRITE_INPUT {
    ULONG PortNumber; // Port # to write to
    union { // Data to be output to port
    ULONG LongData;
    USHORT ShortData;
    UCHAR CharData;
    };
    } GENPORT_WRITE_INPUT;

    #endif

  5. #35
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    genport.h

    /*++

    Copyright (c) 1990-2000 Microsoft Corporation, All Rights Reserved

    Module Name:

    genport.h

    Abstract: Include file for Generic Port I/O Example Driver


    Author: Robert R. Howell January 6, 1993


    Environment:

    Kernel mode

    Revision History:

    Eliyas Yakub Dec 29, 1998

    Converted to Windows 2000

    --*/
    #include <ntddk.h>
    #include "gpioctl.h" // Get IOCTL interface definitions

    #if !defined(__GENPORT_H__)
    #define __GENPORT_H__

    // NT device name
    #define GPD_DEVICE_NAME L"\\Device\\mtst0"

    // File system device name. When you execute a CreateFile call to open the
    // device, use "\\.\GpdDev", or, given C's conversion of \\ to \, use
    // "\\\\.\\GpdDev"

    #define DOS_DEVICE_NAME L"\\DosDevices\\mtstDev"

    #define PORTIO_TAG 'TROP'

    // driver local data structure specific to each device object
    typedef struct _LOCAL_DEVICE_INFO {
    PVOID PortBase; // base port address
    ULONG PortCount; // Count of I/O addresses used.
    ULONG PortMemoryType; // HalTranslateBusAddress MemoryType
    PDEVICE_OBJECT DeviceObject; // The Gpd device object.
    PDEVICE_OBJECT NextLowerDriver; // The top of the stack
    BOOLEAN Started;
    BOOLEAN Removed;
    BOOLEAN PortWasMapped; // If TRUE, we have to unmap on unload
    BOOLEAN Filler[1]; //bug fix
    IO_REMOVE_LOCK RemoveLock;
    } LOCAL_DEVICE_INFO, *PLOCAL_DEVICE_INFO;


    #if DBG
    #define DebugPrint(_x_) \
    DbgPrint ("PortIo:"); \
    DbgPrint _x_;

    #define TRAP() DbgBreakPoint()

    #else
    #define DebugPrint(_x_)
    #define TRAP()
    #endif


    /********************* function prototypes ***********************************/
    //

    NTSTATUS
    DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    );


    NTSTATUS
    GpdDispatch(
    IN PDEVICE_OBJECT pDO,
    IN PIRP pIrp
    );

    NTSTATUS
    GpdIoctlReadPort(
    IN PLOCAL_DEVICE_INFO pLDI,
    IN PIRP pIrp,
    IN PIO_STACK_LOCATION IrpStack,
    IN ULONG IoctlCode
    );

    NTSTATUS
    GpdIoctlReadTst(
    IN PLOCAL_DEVICE_INFO pLDI,
    IN PIRP pIrp,
    IN PIO_STACK_LOCATION IrpStack,
    IN ULONG IoctlCode
    );

    NTSTATUS
    GpdIoctlWritePort(
    IN PLOCAL_DEVICE_INFO pLDI,
    IN PIRP pIrp,
    IN PIO_STACK_LOCATION IrpStack,
    IN ULONG IoctlCode
    );

    VOID
    GpdUnload(
    IN PDRIVER_OBJECT DriverObject
    );


    NTSTATUS
    GpdAddDevice(
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT PhysicalDeviceObject
    );


    NTSTATUS
    GpdDispatchPnp (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

    NTSTATUS
    GpdStartDevice (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

    NTSTATUS
    GpdDispatchPower(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );
    NTSTATUS
    GpdDispatchSystemControl(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );
    PCHAR
    PnPMinorFunctionString (
    UCHAR MinorFunction
    );

    #endif

  6. #36
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    genport.c

    /*++

    Copyright (c) 1990-2000 Microsoft Corporation, All Rights Reserved

    Module Name:

    genport.c

    Abstract: Generic Port I/O driver for Windows 2000


    Author: Author: Robert R. Howell January 8, 1993


    Environment:

    Kernel mode

    Revision History:

    Robert B. Nelson (Microsoft) January 12, 1993
    Cleaned up comments
    Enabled and tested resource reporting
    Added code to retrieve I/O address and port count from the Registry.

    Robert B. Nelson (Microsoft) March 1, 1993
    Added support for byte, word, and long I/O.
    Added support for MIPS.
    Fixed resource reporting.

    Robert B. Nelson (Microsoft) May 1, 1993
    Fixed port number validation.

    Robert B. Nelson (Microsoft) Oct 25, 1993
    Fixed MIPS support.

    Eliyas Yakub
    Fixed AddressSpace Bug Nov 30, 1997

    Eliyas Yakub
    Converted to Windows 2000 Dec 29, 1998
    Fixed bugs Feb 17, 2000

    --*/


    #include "genport.h"

    #ifdef ALLOC_PRAGMA
    #pragma alloc_text (INIT, DriverEntry)
    #pragma alloc_text (PAGE, GpdAddDevice)
    #pragma alloc_text (PAGE, GpdDispatchPnp)
    #pragma alloc_text (PAGE, GpdDispatchSystemControl)
    #pragma alloc_text (PAGE, GpdUnload)
    #pragma alloc_text (PAGE, GpdDispatch)
    #pragma alloc_text (PAGE, GpdIoctlReadPort)
    #pragma alloc_text (PAGE, GpdIoctlReadTst)
    #pragma alloc_text (PAGE, GpdIoctlWritePort)
    #pragma alloc_text (PAGE, GpdStartDevice)
    #endif


    NTSTATUS
    DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
    /*++

    Routine Description:

    Installable driver initialization entry point.
    This entry point is called directly by the I/O system.

    Arguments:

    DriverObject - pointer to the driver object

    RegistryPath - pointer to a unicode string representing the path,
    to driver-specific key in the registry.

    Return Value:

    STATUS_SUCCESS

    --*/
    {

    UNREFERENCED_PARAMETER (RegistryPath);

    DebugPrint (("Entered Driver Entry\n"));

    //
    // Create dispatch points for the IRPs.
    //

    DriverObject->MajorFunction[IRP_MJ_CREATE] = GpdDispatch;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = GpdDispatch;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = GpdDispatch;
    DriverObject->DriverUnload = GpdUnload;
    DriverObject->MajorFunction[IRP_MJ_PNP] = GpdDispatchPnp;
    DriverObject->MajorFunction[IRP_MJ_POWER] = GpdDispatchPower;
    DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = GpdDispatchSystemControl;
    DriverObject->DriverExtension->AddDevice = GpdAddDevice;

    return STATUS_SUCCESS;
    }


    NTSTATUS
    GpdAddDevice(
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT PhysicalDeviceObject
    )
    /*++

    Routine Description:

    The Plug & Play subsystem is handing us a brand new PDO, for which we
    (by means of INF registration) have been asked to provide a driver.

    We need to determine if we need to be in the driver stack for the device.
    Create a functional device object to attach to the stack
    Initialize that device object
    Return status success.

    Remember: we can NOT actually send ANY non pnp IRPS to the given driver
    stack, UNTIL we have received an IRP_MN_START_DEVICE.

    Arguments:

    DeviceObject - pointer to a device object.

    PhysicalDeviceObject - pointer to a device object created by the
    underlying bus driver.

    Return Value:

    NT status code.

    --*/
    {
    NTSTATUS status = STATUS_SUCCESS;
    PDEVICE_OBJECT deviceObject = NULL;
    PLOCAL_DEVICE_INFO deviceInfo;
    UNICODE_STRING ntDeviceName;
    UNICODE_STRING win32DeviceName;

    PAGED_CODE();

    RtlInitUnicodeString(&ntDeviceName, GPD_DEVICE_NAME);

    //
    // Create a device object.
    //

    status = IoCreateDevice (DriverObject,
    sizeof (LOCAL_DEVICE_INFO),
    &ntDeviceName,
    GPD_TYPE,
    0,
    FALSE,
    &deviceObject);


    if (!NT_SUCCESS (status)) {
    //
    // Either not enough memory to create a deviceobject or another
    // deviceobject with the same name exits. This could happen
    // if you install another instance of this device.
    //
    return status;
    }

    RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);

    status = IoCreateSymbolicLink( &win32DeviceName, &ntDeviceName );

    if (!NT_SUCCESS(status)) // If we we couldn't create the link then
    { // abort installation.
    IoDeleteDevice(deviceObject);
    return status;
    }

    deviceInfo = (PLOCAL_DEVICE_INFO) deviceObject->DeviceExtension;

    deviceInfo->NextLowerDriver = IoAttachDeviceToDeviceStack (
    deviceObject,
    PhysicalDeviceObject);
    if(NULL == deviceInfo->NextLowerDriver) {
    IoDeleteSymbolicLink(&win32DeviceName);
    IoDeleteDevice(deviceObject);
    return STATUS_NO_SUCH_DEVICE;
    }

    IoInitializeRemoveLock (&deviceInfo->RemoveLock ,
    PORTIO_TAG,
    1, // MaxLockedMinutes
    5); // HighWatermark, this parameter is
    // used only on checked build.
    //
    // Set the flag if the device is not holding a pagefile
    // crashdump file or hibernate file.
    //

    deviceObject->Flags |= DO_POWER_PAGABLE;

    deviceInfo->DeviceObject = deviceObject;
    deviceInfo->Removed = FALSE;
    deviceInfo->Started = FALSE;

    deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

    //
    // This values is based on the hardware design.
    // Let us assume the address is in I/O space.
    //
    deviceInfo->PortMemoryType = 1;

    DebugPrint(("AddDevice: %p to %p->%p \n", deviceObject,
    deviceInfo->NextLowerDriver,
    PhysicalDeviceObject));


    return STATUS_SUCCESS;

    }

    NTSTATUS
    GpdCompletionRoutine(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    )
    /*++

    Routine Description:

    The completion routine for plug & play irps that needs to be
    processed first by the lower drivers.

    Arguments:

    DeviceObject - pointer to a device object.

    Irp - pointer to an I/O Request Packet.

    Context - pointer to an event object.

    Return Value:

    NT status code

    --*/
    {
    PKEVENT event;

    event = (PKEVENT) Context;

    UNREFERENCED_PARAMETER(DeviceObject);

    if (Irp->PendingReturned) {
    IoMarkIrpPending(Irp);
    }

    //
    // We could switch on the major and minor functions of the IRP to perform
    // different functions, but we know that Context is an event that needs
    // to be set.
    //
    KeSetEvent(event, 0, FALSE);

    //
    // Allows the caller to reuse the IRP
    //
    return STATUS_MORE_PROCESSING_REQUIRED;
    }


    NTSTATUS
    GpdDispatchPnp (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
    /*++

    Routine Description:

    The plug and play dispatch routines.

    Most of these the driver will completely ignore.
    In all cases it must pass the IRP to the next lower driver.

    Arguments:

    DeviceObject - pointer to a device object.

    Irp - pointer to an I/O Request Packet.

    Return Value:

    NT status code

    --*/
    {
    PIO_STACK_LOCATION irpStack;
    NTSTATUS status = STATUS_SUCCESS;
    KEVENT event;
    UNICODE_STRING win32DeviceName;
    PLOCAL_DEVICE_INFO deviceInfo;

    PAGED_CODE();

    deviceInfo = (PLOCAL_DEVICE_INFO) DeviceObject->DeviceExtension;
    irpStack = IoGetCurrentIrpStackLocation(Irp);

    status = IoAcquireRemoveLock (&deviceInfo->RemoveLock, Irp);
    if (!NT_SUCCESS (status)) {
    Irp->IoStatus.Status = status;
    IoCompleteRequest (Irp, IO_NO_INCREMENT);
    return status;
    }

    DebugPrint(("%s\n",PnPMinorFunctionString(irpStack->MinorFunction)));

    switch (irpStack->MinorFunction) {
    case IRP_MN_START_DEVICE:

    //
    // The device is starting.
    //
    // We cannot touch the device (send it any non pnp irps) until a
    // start device has been passed down to the lower drivers.
    //
    IoCopyCurrentIrpStackLocationToNext(Irp);
    KeInitializeEvent(&event,
    NotificationEvent,
    FALSE
    );

    IoSetCompletionRoutine(Irp,
    (PIO_COMPLETION_ROUTINE) GpdCompletionRoutine,
    &event,
    TRUE,
    TRUE,
    TRUE);

    status = IoCallDriver(deviceInfo->NextLowerDriver, Irp);

    if (STATUS_PENDING == status) {
    KeWaitForSingleObject(
    &event,
    Executive, // Waiting for reason of a driver
    KernelMode, // Must be kernelmode if event memory is in stack
    FALSE, // No allert
    NULL); // No timeout
    }

    if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) {

    status = GpdStartDevice(DeviceObject, Irp);
    if(NT_SUCCESS(status))
    {
    //
    // As we are successfully now back from our start device
    // we can do work.
    //

    deviceInfo->Started = TRUE;
    deviceInfo->Removed = FALSE;
    }
    }

    //
    // We must now complete the IRP, since we stopped it in the
    // completion routine with STATUS_MORE_PROCESSING_REQUIRED.
    //
    Irp->IoStatus.Status = status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    break;

    case IRP_MN_QUERY_STOP_DEVICE:

    //
    // Fail the query stop to prevent the system from taking away hardware
    // resources. If you do support this you must have a queue to hold
    // incoming requests between stop and subsequent start with new set of
    // resources.
    //

    Irp->IoStatus.Status = status = STATUS_UNSUCCESSFUL;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    break;

    case IRP_MN_QUERY_REMOVE_DEVICE:
    //
    // The device can be removed without disrupting the machine.
    //
    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoSkipCurrentIrpStackLocation(Irp);
    status = IoCallDriver(deviceInfo->NextLowerDriver, Irp);
    break;

    case IRP_MN_SURPRISE_REMOVAL:

    //
    // The device has been unexpectedly removed from the machine
    // and is no longer available for I/O. Stop all access to the device.
    // Release any resources associated with the device, but leave the
    // device object attached to the device stack until the PnP Manager
    // sends a subsequent IRP_MN_REMOVE_DEVICE request.
    // You should fail any outstanding I/O to the device. You will
    // not get a remove until all the handles open to the device
    // have been closed.
    //

    deviceInfo->Removed = TRUE;
    deviceInfo->Started = FALSE;

    if (deviceInfo->PortWasMapped)
    {
    MmUnmapIoSpace(deviceInfo->PortBase, deviceInfo->PortCount);
    deviceInfo->PortWasMapped = FALSE;
    }
    RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);
    IoDeleteSymbolicLink(&win32DeviceName);

    IoSkipCurrentIrpStackLocation(Irp);
    Irp->IoStatus.Status = STATUS_SUCCESS;
    status = IoCallDriver(deviceInfo->NextLowerDriver, Irp);
    break;

    case IRP_MN_REMOVE_DEVICE:

    //
    // Relinquish all resources here.
    // Detach and delete the device object so that
    // your driver can be unloaded. You get remove
    // either after query_remove or surprise_remove.
    //

    if(!deviceInfo->Removed)
    {
    deviceInfo->Removed = TRUE;
    deviceInfo->Started = FALSE;

    if (deviceInfo->PortWasMapped)
    {
    MmUnmapIoSpace(deviceInfo->PortBase, deviceInfo->PortCount);
    deviceInfo->PortWasMapped = FALSE;
    }
    RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);
    IoDeleteSymbolicLink(&win32DeviceName);
    }

    //
    // Wait for all outstanding requests to complete
    //
    DebugPrint(("Waiting for outstanding requests\n"));
    IoReleaseRemoveLockAndWait(&deviceInfo->RemoveLock, Irp);

    Irp->IoStatus.Status = STATUS_SUCCESS;
    IoSkipCurrentIrpStackLocation(Irp);
    status = IoCallDriver(deviceInfo->NextLowerDriver, Irp);

    IoDetachDevice(deviceInfo->NextLowerDriver);
    IoDeleteDevice(DeviceObject);

    return status;

    case IRP_MN_STOP_DEVICE:
    // Since you failed query stop, you will not get this request.
    case IRP_MN_CANCEL_REMOVE_DEVICE:
    // No action required in this case. Just pass it down.
    case IRP_MN_CANCEL_STOP_DEVICE:
    //No action required in this case.
    Irp->IoStatus.Status = STATUS_SUCCESS;
    default:
    //
    // Please see PnP documentation for use of these IRPs.
    //
    IoSkipCurrentIrpStackLocation (Irp);
    status = IoCallDriver(deviceInfo->NextLowerDriver, Irp);
    break;
    }
    IoReleaseRemoveLock(&deviceInfo->RemoveLock, Irp);
    return status;
    }

    NTSTATUS
    GpdStartDevice (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
    /*++

    Routine Description:

    Get the resources, map the resources if required
    and initialize the device.

    Arguments:

    DeviceObject - pointer to a device object.

    Irp - pointer to an I/O Request Packet.

    Return Value:

    NT status code


    --*/
    {
    NTSTATUS status = STATUS_SUCCESS;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceTrans;
    PCM_PARTIAL_RESOURCE_LIST partialResourceList;
    PCM_PARTIAL_RESOURCE_LIST partialResourceListTranslated;
    PIO_STACK_LOCATION stack;
    ULONG i;
    PLOCAL_DEVICE_INFO deviceInfo;

    deviceInfo = (PLOCAL_DEVICE_INFO) DeviceObject->DeviceExtension;

    stack = IoGetCurrentIrpStackLocation (Irp);

    PAGED_CODE();

    //
    // We need to check that we haven't received a surprise removal
    //

    if (deviceInfo->Removed) {
    //
    // Some kind of surprise removal arrived. We will fail the IRP
    // The dispatch routine that called us will take care of
    // completing the IRP.
    //
    return STATUS_DELETE_PENDING;
    }

    //
    // Do whatever initialization needed when starting the device:
    // gather information about it, update the registry, etc.
    //

    if ((NULL == stack->Parameters.StartDevice.AllocatedResources) &&
    (NULL == stack->Parameters.StartDevice.AllocatedResourcesTranslat ed)) {

    return STATUS_INSUFFICIENT_RESOURCES;
    }
    //
    // Parameters.StartDevice.AllocatedResources points to a
    // CM_RESOURCE_LIST describing the hardware resources that
    // the PnP Manager assigned to the device. This list contains
    // the resources in raw form. Use the raw resources to program
    // the device.
    //

    partialResourceList =
    &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;

    resource = &partialResourceList->PartialDescriptors[0];

    //
    // Parameters.StartDevice.AllocatedResourcesTranslate d points
    // to a CM_RESOURCE_LIST describing the hardware resources that
    // the PnP Manager assigned to the device. This list contains
    // the resources in translated form. Use the translated resources
    // to connect the interrupt vector, map I/O space, and map memory.
    //

    partialResourceListTranslated =
    &stack->Parameters.StartDevice.AllocatedResourcesTranslat ed->List[0].PartialResourceList;

    resourceTrans = &partialResourceListTranslated->PartialDescriptors[0];

    for (i = 0;
    i < partialResourceList->Count; i++, resource++, resourceTrans++) {

    switch (resource->Type) {
    case CmResourceTypePort:

    switch (resourceTrans->Type) {

    case CmResourceTypePort:

    deviceInfo->PortWasMapped = FALSE;
    deviceInfo->PortBase = (PVOID)resourceTrans->u.Port.Start.LowPart;
    deviceInfo->PortCount = resourceTrans->u.Port.Length;

    DebugPrint(("Resource Translated Port: (%x) Length: (%d)\n",
    resourceTrans->u.Port.Start.LowPart,
    resourceTrans->u.Port.Length));

    break;

    case CmResourceTypeMemory:

    //
    // We need to map the memory
    //

    deviceInfo->PortBase = (PVOID)
    MmMapIoSpace (resourceTrans->u.Memory.Start,
    resourceTrans->u.Memory.Length,
    MmNonCached);

    deviceInfo->PortCount = resourceTrans->u.Memory.Length;
    deviceInfo->PortWasMapped = TRUE;

    DebugPrint(("Resource Translated Memory: (%x) Length: (%d)\n",
    resourceTrans->u.Memory.Start.LowPart,
    resourceTrans->u.Memory.Length));

    break;

    default:
    DebugPrint(("Unhandled resource_type (0x%x)\n", resourceTrans->Type));
    status = STATUS_UNSUCCESSFUL;
    TRAP ();
    }
    break;

    case CmResourceTypeMemory:

    deviceInfo->PortBase = (PVOID)
    MmMapIoSpace (resourceTrans->u.Memory.Start,
    resourceTrans->u.Memory.Length,
    MmNonCached);

    deviceInfo->PortCount = resourceTrans->u.Memory.Length;
    deviceInfo->PortWasMapped = TRUE;

    DebugPrint(("Resource Translated Memory: (%x) Length: (%d)\n",
    resourceTrans->u.Memory.Start.LowPart,
    resourceTrans->u.Memory.Length));

    break;

    case CmResourceTypeInterrupt:

    default:

    DebugPrint(("Unhandled resource type (0x%x)\n", resource->Type));
    status = STATUS_UNSUCCESSFUL;
    break;

    } // end of switch
    } // end of for

    return status;

    }


    NTSTATUS
    GpdDispatchPower(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
    /*++

    Routine Description:

    This routine is the dispatch routine for power irps.
    Does nothing except forwarding the IRP to the next device
    in the stack.

    Arguments:

    DeviceObject - Pointer to the device object.

    Irp - Pointer to the request packet.

    Return Value:

    NT Status code
    --*/
    {
    PLOCAL_DEVICE_INFO deviceInfo;

    deviceInfo = (PLOCAL_DEVICE_INFO) DeviceObject->DeviceExtension;

    //
    // If the device has been removed, the driver should not pass
    // the IRP down to the next lower driver.
    //

    if (deviceInfo->Removed) {

    PoStartNextPowerIrp(Irp);
    Irp->IoStatus.Status = STATUS_DELETE_PENDING;
    IoCompleteRequest(Irp, IO_NO_INCREMENT );
    return STATUS_DELETE_PENDING;
    }

    PoStartNextPowerIrp(Irp);
    IoSkipCurrentIrpStackLocation(Irp);
    return PoCallDriver(deviceInfo->NextLowerDriver, Irp);
    }

    NTSTATUS
    GpdDispatchSystemControl(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
    /*++

    Routine Description:

    This routine is the dispatch routine for WMI irps.
    Does nothing except forwarding the IRP to the next device
    in the stack.

    Arguments:

    DeviceObject - Pointer to the device object.

    Irp - Pointer to the request packet.

    Return Value:

    NT Status code
    --*/
    {
    PLOCAL_DEVICE_INFO deviceInfo;

    PAGED_CODE();

    deviceInfo = (PLOCAL_DEVICE_INFO) DeviceObject->DeviceExtension;
    IoSkipCurrentIrpStackLocation(Irp);
    return IoCallDriver(deviceInfo->NextLowerDriver, Irp);
    }


    VOID
    GpdUnload(
    IN PDRIVER_OBJECT DriverObject
    )
    /*++

    Routine Description:

    Free all the allocated resources, etc.

    Arguments:

    DriverObject - pointer to a driver object.

    Return Value:

    VOID.

    --*/
    {
    PAGED_CODE ();

    //
    // The device object(s) should be NULL now
    // (since we unload, all the devices objects associated with this
    // driver must have been deleted.
    //
    ASSERT(DriverObject->DeviceObject == NULL);

    DebugPrint (("unload\n"));

    return;
    }

    NTSTATUS
    GpdDispatch(
    IN PDEVICE_OBJECT pDO,
    IN PIRP pIrp
    )

    /*++

    Routine Description:
    This routine is the dispatch handler for the driver. It is responsible
    for processing the IRPs.

    Arguments:

    pDO - Pointer to device object.

    pIrp - Pointer to the current IRP.

    Return Value:

    STATUS_SUCCESS if the IRP was processed successfully, otherwise an error
    indicating the reason for failure.

    --*/

    {
    PLOCAL_DEVICE_INFO pLDI;
    PIO_STACK_LOCATION pIrpStack;
    NTSTATUS Status;

    PAGED_CODE();

    pIrp->IoStatus.Information = 0;
    pLDI = (PLOCAL_DEVICE_INFO)pDO->DeviceExtension; // Get local info struct

    DebugPrint (("Entered GpdDispatch\n"));

    Status = IoAcquireRemoveLock (&pLDI->RemoveLock, pIrp);
    if (!NT_SUCCESS (Status)) {
    pIrp->IoStatus.Information = 0;
    pIrp->IoStatus.Status = Status;
    IoCompleteRequest (pIrp, IO_NO_INCREMENT);
    return Status;
    }

    if (!pLDI->Started) {
    //
    // We fail all the IRPs that arrive before the device is started.
    //
    pIrp->IoStatus.Status = Status = STATUS_DEVICE_NOT_READY;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT );
    IoReleaseRemoveLock(&pLDI->RemoveLock, pIrp);
    return Status;
    }

    pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

    // Dispatch based on major fcn code.

    switch (pIrpStack->MajorFunction)
    {
    case IRP_MJ_CREATE:
    case IRP_MJ_CLOSE:
    // We don't need any special processing on open/close so we'll
    // just return success.
    Status = STATUS_SUCCESS;
    break;

    case IRP_MJ_DEVICE_CONTROL:
    // Dispatch on IOCTL
    switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode)
    {
    case IOCTL_GPD_READ_PORT_UCHAR:
    case IOCTL_GPD_READ_PORT_USHORT:
    case IOCTL_GPD_READ_PORT_ULONG:
    Status = GpdIoctlReadPort(
    pLDI,
    pIrp,
    pIrpStack,
    pIrpStack->Parameters.DeviceIoControl.IoControlCode
    );
    break;

    case IOCTL_GPD_READ_TST2:
    Status = GpdIoctlReadTst(
    pLDI,
    pIrp,
    pIrpStack,
    pIrpStack->Parameters.DeviceIoControl.IoControlCode
    );
    break;
    case IOCTL_GPD_WRITE_PORT_UCHAR:
    case IOCTL_GPD_WRITE_PORT_USHORT:
    case IOCTL_GPD_WRITE_PORT_ULONG:
    Status = GpdIoctlWritePort(
    pLDI,
    pIrp,
    pIrpStack,
    pIrpStack->Parameters.DeviceIoControl.IoControlCode
    );
    break;
    default:
    Status = STATUS_INVALID_PARAMETER;

    }
    break;
    default:
    Status = STATUS_NOT_IMPLEMENTED;
    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 );
    IoReleaseRemoveLock(&pLDI->RemoveLock, pIrp);
    return Status;
    }


    NTSTATUS
    GpdIoctlReadPort(
    IN PLOCAL_DEVICE_INFO pLDI,
    IN PIRP pIrp,
    IN PIO_STACK_LOCATION IrpStack,
    IN ULONG IoctlCode )


    /*++

    Routine Description:
    This routine processes the IOCTLs which read from the ports.

    Arguments:

    pLDI - our local device data
    pIrp - IO request packet
    IrpStack - The current stack location
    IoctlCode - The ioctl code from the IRP

    Return Value:
    STATUS_SUCCESS -- OK

    STATUS_INVALID_PARAMETER -- The buffer sent to the driver
    was too small to contain the
    port, or the buffer which
    would be sent back to the driver
    was not a multiple of the data size.

    STATUS_ACCESS_VIOLATION -- An illegal port number was given.

    --*/

    {
    // NOTE: Use METHOD_BUFFERED ioctls.
    PULONG pIOBuffer; // Pointer to transfer buffer
    // (treated as an array of longs).
    ULONG InBufferSize; // Amount of data avail. from caller.
    ULONG OutBufferSize; // Max data that caller can accept.
    ULONG nPort; // Port number to read
    ULONG DataBufferSize;

    PAGED_CODE();

    // Size of buffer containing data from application
    InBufferSize = IrpStack->Parameters.DeviceIoControl.InputBufferLength;

    // Size of buffer for data to be sent to application
    OutBufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;

    // NT copies inbuf here before entry and copies this to outbuf after
    // return, for METHOD_BUFFERED IOCTL's.
    pIOBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer;

    // Check to ensure input buffer is big enough to hold a port number and
    // the output buffer is at least as big as the port data width.
    //
    switch (IoctlCode)
    {
    case IOCTL_GPD_READ_PORT_UCHAR:
    DataBufferSize = sizeof(UCHAR);
    break;
    case IOCTL_GPD_READ_PORT_USHORT:
    DataBufferSize = sizeof(USHORT);
    break;
    case IOCTL_GPD_READ_PORT_ULONG:
    DataBufferSize = sizeof(ULONG);
    break;
    default:
    return STATUS_INVALID_PARAMETER;

    }

    if ( InBufferSize != sizeof(ULONG) || OutBufferSize < DataBufferSize )
    {
    return STATUS_INVALID_PARAMETER;
    }

    // Buffers are big enough.

    nPort = *pIOBuffer; // Get the I/O port number from the buffer.

    if (nPort >= pLDI->PortCount ||
    (nPort + DataBufferSize) > pLDI->PortCount ||
    (((ULONG_PTR)pLDI->PortBase + nPort) & (DataBufferSize - 1)) != 0)
    {
    return STATUS_ACCESS_VIOLATION; // It was not legal.
    }

    if (pLDI->PortMemoryType == 1)
    {
    // Address is in I/O space

    switch (IoctlCode)
    {
    case IOCTL_GPD_READ_PORT_UCHAR:
    *(PUCHAR)pIOBuffer = READ_PORT_UCHAR(
    (PUCHAR)((ULONG_PTR)pLDI->PortBase + nPort) );
    break;
    case IOCTL_GPD_READ_PORT_USHORT:
    *(PUSHORT)pIOBuffer = READ_PORT_USHORT(
    (PUSHORT)((ULONG_PTR)pLDI->PortBase + nPort) );
    break;
    case IOCTL_GPD_READ_PORT_ULONG:
    *(PULONG)pIOBuffer = READ_PORT_ULONG(
    (PULONG)((ULONG_PTR)pLDI->PortBase + nPort) );
    break;
    default:
    return STATUS_INVALID_PARAMETER;


    }
    }
    else if (pLDI->PortMemoryType == 0)
    {
    // Address is in Memory space

    switch (IoctlCode)
    {
    case IOCTL_GPD_READ_PORT_UCHAR:
    *(PUCHAR)pIOBuffer = READ_REGISTER_UCHAR(
    (PUCHAR)((ULONG_PTR)pLDI->PortBase + nPort) );
    break;
    case IOCTL_GPD_READ_PORT_USHORT:
    *(PUSHORT)pIOBuffer = READ_REGISTER_USHORT(
    (PUSHORT)((ULONG_PTR)pLDI->PortBase + nPort) );
    break;
    case IOCTL_GPD_READ_PORT_ULONG:
    *(PULONG)pIOBuffer = READ_REGISTER_ULONG(
    (PULONG)((ULONG_PTR)pLDI->PortBase + nPort) );
    break;
    default:
    return STATUS_INVALID_PARAMETER;

    }
    }
    else
    {
    return STATUS_UNSUCCESSFUL;
    }

    //
    // Indicate # of bytes read
    //

    pIrp->IoStatus.Information = DataBufferSize;

    return STATUS_SUCCESS;
    }


    NTSTATUS
    GpdIoctlWritePort(
    IN PLOCAL_DEVICE_INFO pLDI,
    IN PIRP pIrp,
    IN PIO_STACK_LOCATION IrpStack,
    IN ULONG IoctlCode
    )

    /*++

    Routine Description:
    This routine processes the IOCTLs which write to the ports.

    Arguments:

    pLDI - our local device data
    pIrp - IO request packet
    IrpStack - The current stack location
    IoctlCode - The ioctl code from the IRP

    Return Value:
    STATUS_SUCCESS -- OK

    STATUS_INVALID_PARAMETER -- The buffer sent to the driver
    was too small to contain the
    port, or the buffer which
    would be sent back to the driver
    was not a multiple of the data size.

    STATUS_ACCESS_VIOLATION -- An illegal port number was given.

    --*/

    {
    // NOTE: Use METHOD_BUFFERED ioctls.
    PULONG pIOBuffer; // Pointer to transfer buffer
    // (treated as array of longs).
    ULONG InBufferSize ; // Amount of data avail. from caller.
    ULONG nPort; // Port number to read or write.
    ULONG DataBufferSize;

    PAGED_CODE();

    // Size of buffer containing data from application
    InBufferSize = IrpStack->Parameters.DeviceIoControl.InputBufferLength;

    // NT copies inbuf here before entry and copies this to outbuf after return,
    // for METHOD_BUFFERED IOCTL's.
    pIOBuffer = (PULONG) pIrp->AssociatedIrp.SystemBuffer;

    pIrp->IoStatus.Information = 0;

    // Check to ensure input buffer is big enough to hold a port number as well
    // as the data to write.
    //
    // The relative port # is a ULONG, and the data is the type appropriate to
    // the IOCTL.
    //

    switch (IoctlCode)
    {
    case IOCTL_GPD_WRITE_PORT_UCHAR:
    DataBufferSize = sizeof(UCHAR);
    break;
    case IOCTL_GPD_WRITE_PORT_USHORT:
    DataBufferSize = sizeof(USHORT);
    break;
    case IOCTL_GPD_WRITE_PORT_ULONG:
    DataBufferSize = sizeof(ULONG);
    break;
    default:
    return STATUS_INVALID_PARAMETER;
    }

    if ( InBufferSize < (sizeof(ULONG) + DataBufferSize) )
    {
    return STATUS_INVALID_PARAMETER;
    }

    nPort = *pIOBuffer++;

    if (nPort >= pLDI->PortCount ||
    (nPort + DataBufferSize) > pLDI->PortCount ||
    (((ULONG_PTR)pLDI->PortBase + nPort) & (DataBufferSize - 1)) != 0)
    {
    return STATUS_ACCESS_VIOLATION; // Illegal port number
    }

    if (pLDI->PortMemoryType == 1)
    {
    // Address is in I/O space

    switch (IoctlCode)
    {
    case IOCTL_GPD_WRITE_PORT_UCHAR:
    WRITE_PORT_UCHAR(
    (PUCHAR)((ULONG_PTR)pLDI->PortBase + nPort),
    *(PUCHAR)pIOBuffer );
    break;
    case IOCTL_GPD_WRITE_PORT_USHORT:
    WRITE_PORT_USHORT(
    (PUSHORT)((ULONG_PTR)pLDI->PortBase + nPort),
    *(PUSHORT)pIOBuffer );
    break;
    case IOCTL_GPD_WRITE_PORT_ULONG:
    WRITE_PORT_ULONG(
    (PULONG)((ULONG_PTR)pLDI->PortBase + nPort),
    *(PULONG)pIOBuffer );
    break;
    default:
    return STATUS_INVALID_PARAMETER;
    }
    }
    else if (pLDI->PortMemoryType == 0)
    {
    // Address is in Memory space

    switch (IoctlCode)
    {
    case IOCTL_GPD_WRITE_PORT_UCHAR:
    WRITE_REGISTER_UCHAR(
    (PUCHAR)((ULONG_PTR)pLDI->PortBase + nPort),
    *(PUCHAR)pIOBuffer );
    break;
    case IOCTL_GPD_WRITE_PORT_USHORT:
    WRITE_REGISTER_USHORT(
    (PUSHORT)((ULONG_PTR)pLDI->PortBase + nPort),
    *(PUSHORT)pIOBuffer );
    break;
    case IOCTL_GPD_WRITE_PORT_ULONG:
    WRITE_REGISTER_ULONG(
    (PULONG)((ULONG_PTR)pLDI->PortBase + nPort),
    *(PULONG)pIOBuffer );
    break;
    default:
    return STATUS_INVALID_PARAMETER;
    }
    }
    else
    {
    return STATUS_UNSUCCESSFUL;
    }

    //
    // Indicate # of bytes written
    //

    pIrp->IoStatus.Information = DataBufferSize;

    return STATUS_SUCCESS;
    }



    #if DBG
    PCHAR
    PnPMinorFunctionString (
    UCHAR MinorFunction
    )
    {
    switch (MinorFunction)
    {
    case IRP_MN_START_DEVICE:
    return "IRP_MN_START_DEVICE";
    case IRP_MN_QUERY_REMOVE_DEVICE:
    return "IRP_MN_QUERY_REMOVE_DEVICE";
    case IRP_MN_REMOVE_DEVICE:
    return "IRP_MN_REMOVE_DEVICE";
    case IRP_MN_CANCEL_REMOVE_DEVICE:
    return "IRP_MN_CANCEL_REMOVE_DEVICE";
    case IRP_MN_STOP_DEVICE:
    return "IRP_MN_STOP_DEVICE";
    case IRP_MN_QUERY_STOP_DEVICE:
    return "IRP_MN_QUERY_STOP_DEVICE";
    case IRP_MN_CANCEL_STOP_DEVICE:
    return "IRP_MN_CANCEL_STOP_DEVICE";
    case IRP_MN_QUERY_DEVICE_RELATIONS:
    return "IRP_MN_QUERY_DEVICE_RELATIONS";
    case IRP_MN_QUERY_INTERFACE:
    return "IRP_MN_QUERY_INTERFACE";
    case IRP_MN_QUERY_CAPABILITIES:
    return "IRP_MN_QUERY_CAPABILITIES";
    case IRP_MN_QUERY_RESOURCES:
    return "IRP_MN_QUERY_RESOURCES";
    case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
    return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
    case IRP_MN_QUERY_DEVICE_TEXT:
    return "IRP_MN_QUERY_DEVICE_TEXT";
    case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
    return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
    case IRP_MN_READ_CONFIG:
    return "IRP_MN_READ_CONFIG";
    case IRP_MN_WRITE_CONFIG:
    return "IRP_MN_WRITE_CONFIG";
    case IRP_MN_EJECT:
    return "IRP_MN_EJECT";
    case IRP_MN_SET_LOCK:
    return "IRP_MN_SET_LOCK";
    case IRP_MN_QUERY_ID:
    return "IRP_MN_QUERY_ID";
    case IRP_MN_QUERY_PNP_DEVICE_STATE:
    return "IRP_MN_QUERY_PNP_DEVICE_STATE";
    case IRP_MN_QUERY_BUS_INFORMATION:
    return "IRP_MN_QUERY_BUS_INFORMATION";
    case IRP_MN_DEVICE_USAGE_NOTIFICATION:
    return "IRP_MN_DEVICE_USAGE_NOTIFICATION";
    case IRP_MN_SURPRISE_REMOVAL:
    return "IRP_MN_SURPRISE_REMOVAL";

    default:
    return "IRP_MN_?????";
    }
    }

    #endif



    // --> TEST <--
    NTSTATUS
    GpdIoctlReadTst(
    IN PLOCAL_DEVICE_INFO pLDI,
    IN PIRP pIrp,
    IN PIO_STACK_LOCATION IrpStack,
    IN ULONG IoctlCode )



    {
    // NOTE: Use METHOD_BUFFERED ioctls.
    PULONG pIOBuffer; // Pointer to transfer buffer
    // (treated as an array of longs).
    ULONG InBufferSize; // Amount of data avail. from caller.
    ULONG OutBufferSize; // Max data that caller can accept.
    ULONG nPort; // Port number to read
    DWORD64 nOut; // return integer
    ULONG flags; // input flags
    ULONG DataBufferSize;
    VOID UNALIGNED *pSource, *pDest;
    PVOID pAddress;
    PULONG pUlong;
    ULONG dw;
    PDWORD64 p64bit, p64bit2;
    PHYSICAL_ADDRESS pa;

    PAGED_CODE();

    // Size of buffer containing data from application
    InBufferSize = IrpStack->Parameters.DeviceIoControl.InputBufferLength;

    // Size of buffer for data to be sent to application
    OutBufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;


    // NT copies inbuf here before entry and copies this to outbuf after
    // return, for METHOD_BUFFERED IOCTL's.
    pIOBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer;

    // Check to ensure input buffer is big enough to hold a port number and
    // the output buffer is at least as big as the port data width.
    // Used terms:
    // VA - virtual address = normal address used in programs
    // PA - physical address
    //
    // check input & output
    nPort = *pIOBuffer; // Get read type
    // return result
    switch (nPort){
    case 8: // Read 8 bytes from VA, using normal memory read
    if (InBufferSize<8) return STATUS_INVALID_PARAMETER;
    p64bit= (PDWORD64) *(pIOBuffer+1);
    if (InBufferSize>=12) flags=*(pIOBuffer+2); else flags=0;
    // should I check for Memory validation?
    if ((flags& 0x01)==0){
    pAddress= (PVOID) (((ULONG)p64bit & 0xFFFFF000));
    if (!MmIsAddressValid(pAddress)) return STATUS_ACCESS_VIOLATION;
    }
    nOut= *p64bit;
    pSource = (VOID UNALIGNED *)&nOut; // int64 from ptr->
    if (OutBufferSize>8) DataBufferSize=8; else DataBufferSize=OutBufferSize;
    break;

    case 9: // return 8-byte long PA based on input VA
    if (InBufferSize<8) return STATUS_INVALID_PARAMETER;
    pAddress= (PVOID) *(pIOBuffer+1);
    //pa = (PHYSICAL_ADDRESS) 1234; // test
    pa= MmGetPhysicalAddress(pAddress); // get Physical address
    pSource = (VOID UNALIGNED *)&pa;
    DataBufferSize=sizeof(pa);
    break;

    case 10: // read 8 bytes from PA
    if (InBufferSize<12) return STATUS_INVALID_PARAMETER;
    pa= * (PPHYSICAL_ADDRESS) (pIOBuffer+1);
    p64bit2= MmMapIoSpace(pa, 8, MmNonCached );
    nOut= *p64bit2; // read from Phys addr
    MmUnmapIoSpace( p64bit2, 8);
    pSource = (VOID UNALIGNED *)&nOut;
    DataBufferSize=sizeof(nOut);
    break;

    case 11: // return <>0 if input VA is valid
    if (InBufferSize<8) return STATUS_INVALID_PARAMETER;
    pAddress= (PVOID) *(pIOBuffer+1);
    nOut = 0;
    nOut = MmIsAddressValid(pAddress); // isAddressValid
    pSource = (VOID UNALIGNED *)&nOut;
    DataBufferSize=sizeof(nOut);
    break;

    case 12: // read 4 bytes from input VA
    if (InBufferSize<8) return STATUS_INVALID_PARAMETER;
    pUlong= (PULONG) *(pIOBuffer+1);;
    if (!MmIsAddressValid(pUlong)) return STATUS_ACCESS_VIOLATION;
    nOut= *pUlong;
    pSource = (VOID UNALIGNED *)&nOut; // read 4 bytes from ptr->
    DataBufferSize=4;
    break;

    case 13: // my custom GetPhysicalAddress, terurn PA based on input VA
    if (InBufferSize<8) return STATUS_INVALID_PARAMETER;
    dw= *(pIOBuffer+1); // Virtual(linear) addres for which we want PA
    if ((dw >= 0x80000000)&&(dw<0xA0000000)){
    // here is 4MB paged kernel range. I dont need it, but ...
    nOut= dw & 0x1FFFFFFF;
    } else {
    // here is part for 4kb pages, read PTE at 0xC0000000
    pUlong= (PULONG) (0xC0000000 + ((dw >> 12) * 4)) ; // calculate PTE address
    if (!MmIsAddressValid(pUlong)) return STATUS_ACCESS_VIOLATION;
    nOut= *pUlong; // read start of Phys page from PTE
    nOut= (nOut & 0xFFFFF000) | (dw & 0xFFF); // last bits are retained from virt. addr
    }
    pSource = (VOID UNALIGNED *)&nOut;
    DataBufferSize=sizeof(nOut);
    break;

    default:
    return STATUS_INVALID_PARAMETER;
    }
    // copy results
    pDest=pIOBuffer;
    if (DataBufferSize>OutBufferSize) return STATUS_INVALID_PARAMETER;
    RtlCopyMemory (pDest, pSource , DataBufferSize);


    //
    // Indicate # of bytes read
    //

    pIrp->IoStatus.Information = DataBufferSize;

    return STATUS_SUCCESS;
    }

  7. #37
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    Examples of using driver functions from user code

    NOTE: I have this functions in language that is not C, so I just wrote them here doing on-line translation to C .... therefore they are not compile-checked


    //You use memory read from USER application (like hook.dll) with:



    // *************************************************
    // function that invoke driver
    BOOL requestDrv
    ( PVOID inAdr, int inSz, PVOID outAdr, int outSz)
    {

    HANDLE hndFile; // Handle to device, obtain from CreateFile
    BOOL IoctlResult;
    DWORD ReturnedLength; // Number of bytes returned

    hndFile = CreateFile(
    "\\\\.\\mtstDev", // Open the Device "file"
    GENERIC_READ,
    FILE_SHARE_READ,
    NULL,
    OPEN_EXISTING,
    0,
    NULL
    );

    if (hndFile == INVALID_HANDLE_VALUE) // Was the device opened?
    {
    return 0;
    //"Unable to open the device.\n";
    }


    IoctlResult = DeviceIoControl(
    hndFile, // Handle to device
    IOCTL_GPD_READ_TST2, // IO Control code for Read
    inAdr, // Buffer to driver.
    inSz, // Length of buffer in bytes.
    outAdr, // return Buffer from driver.
    outSz, // Length of buffer in bytes.
    &ReturnedLength, // Bytes placed in DataBuffer.
    NULL // NULL means wait till op. completes.
    );

    if (!CloseHandle(hndFile)) ; //printf("Failed to close device.\n");

    if (IoctlResult) // Did the IOCTL succeed?
    {
    return 1;
    }else
    return 0;
    //printf("Read failed with code %ld\n", GetLastError() );
    }

    } // end of requestDrv



    // *************************************************
    // Example of function that read 8-bytes from memory

    BOOL readDrvMem8
    (PVOID ptr, PDWORD64 res)
    {

    LONG IoctlCode;
    DWORD64 resultKey

    struct TinDrv // Declare inDrv struct type
    {
    DWORD callType;
    DWORD64 inParam;
    } drvIn; // Define object to hold input data for driver

    IoctlCode = IOCTL_GPD_READ_TST2;
    drvIn.callType=8;
    drvIn.inParam= (DWORD64) ptr;

    // call driver
    return requestDrv(&drvIn,sizeof(drvIn),res,sizeof(DWORD64 ));

    }

    // *************************************************
    // Example of function that read Phys Addr (PA) into res
    // based on input VA from ptr

    BOOL readDrvPA
    (PVOID ptr, PDWORD64 res)
    {

    LONG IoctlCode;
    DWORD64 resultKey

    struct TinDrv // Declare inDrv struct type
    {
    DWORD callType;
    DWORD64 inParam;
    } drvIn; // Define object to hold input data for driver

    IoctlCode = IOCTL_GPD_READ_TST2;
    drvIn.callType=13; // could use 9 too, but my custom f-on is better
    drvIn.inParam= (DWORD64) ptr;

    // call driver
    return requestDrv(&drvIn,sizeof(drvIn),res,sizeof(DWORD64 ));

    }

    // *************************************************
    // Example of function that read memory from Phys Addr pa
    // and store in 8-bytes pointed by res

    BOOL readDrvPA
    (DWORD64 pa, PDWORD64 res)
    {

    LONG IoctlCode;
    DWORD64 resultKey

    struct TinDrv // Declare inDrv struct type
    {
    DWORD callType;
    DWORD64 inParam;
    } drvIn; // Define object to hold input data for driver

    IoctlCode = IOCTL_GPD_READ_TST2;
    drvIn.callType=10;
    drvIn.inParam= pa;

    // call driver
    return requestDrv(&drvIn,sizeof(drvIn),res,sizeof(DWORD64 ));

    }

  8. #38
    Registered User
    Join Date
    Dec 2001
    Posts
    752
    Thank you very much /bow
    -- Lord Crush

    Greater Faydark has to be cleaned from all Elves !

    This is a HOTKEY !!!

  9. #39
    Registered User
    Join Date
    Aug 2002
    Posts
    143
    Just another suggestion for the kernel mode driver:

    Do a google search for KeAttachProcess. It's part of ntifs.h which you get with the IFS kit but it switches the user mode memory to that of a specified driver so you can then play with it...

  10. #40
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    Ok, after week or so dedicated to RL issues, I returned to my kernel driver. Last version of that driver had ability to read key from any PHYSICAL memory location, thus being completely undetectable, even if that memory is VirtualProtected.

    But one slight drawback was fact that in order to find out what Physical memory corresponds to actual Offset ( = Virtual memory address), I had to call GetPhysicalAddress from context of EQGAME thread. I needed to do that only once, so I used my previously made hook.dll and if i detect EQGAME upon hooking, I call GetPhysicalAddress( Offset), and return resulting PhysAddr to my hookshell.exe. After that hooking dll detach and is not needed any more, all reads could be done from separate exe using mentioned ReadFromPhysical.

    Of course, I wanted to be able to do complete process from separate EXE - which would eliminate need for hooking dll. I found on web examples of using KeAttachProcess, but I could not at first get prototype of its only parameter - EPROCESS, which is in kernel something that resemble HANDLE of process that is result of OpenProcess. Then I managed to find some headers (from some Sven guy) with defined EPROCESS structure. But main problem was ... how to find that process handle.

    BTW, thanks Throx for mentioning that ntifs.h I managed to find it on net, and it has much better defined structures that previous headers with undocumented things that i had. But my main problem still remained - how to find EPROCESS.

    First example that i tried to implement was:

    http://www.windowsitlibrary.com/Content/356/04/7.html

    This approach use undocumented PsInitialSystemProcess, which is not included even in ntifs.h ... but could be just addes as extern in ntifs.h and it can link:

    extern PEPROCESS PsInitialSystemProcess;

    Problem that I had with this approach is that it use fixed ListEntryOffset , which is hardcoded for NT and win2k, but does not work for XP. But looking at EPROCESS for XP ( build>=2600)definition in header , I was able to find correct values for XP too:
    ListEntryOffset=0x88;
    NameOffset=0x174;

    Other problem was that PsInitialSystemProcess was NOT pointing at anything meaningfull ... and that problem I could not solve.


    Second example that i tried to implement was:

    http://www.phrack.com/phrack/59/p59-0x10.txt

    This example also used fixed ListEntry and Named offsets which were wrong for XP, but I had that problem already solved. Difference is in that second example use (again undocumented) kernel variable PsActiveProcessHead to find start of EPROCESS list. And unlike PsInitialSystemProcess , this one I could not just add as extern because it wouldnt link. So i had to hard code address, just like it was done in example. BUT , again, that address was for win2k and not for XP. I used windbg> ? PsActiveProcessHead , and resulting address was 0x80547b58. Using that value, I finally got working link to EPROCESS list, and from that I was able to find address of Eprocess for EQGAME task.


    Result is that I added in kernel driver function #16, which takes as parameter name of application (up to 8 chars), and offset ... and it does following (this is pseudo code):

    DWORD64 myReadKey(char* appName, DWORD32 Offset){
    ep= myFindEprocess(appName)
    KeAttachProcess(ep)
    pa= myGetPhysicalAddress ( Offset)
    Key= ReadFromPhysAddr( pa );
    KeDetachProcess()
    return Key;
    }


    So, I just call this function from my EXE with 'EQGAME' and 7912632 as parameters, and I get key ... unless driver can not find process or read, in which case i get zero. I call function periodically, every N seconds, and if key is different, I sent UDP or write file, as I did before.

    This approach seems to be noticeably better that hooking version - there isnt ANY interraction with target process (eqgame). And I'm not calling any API or even ntdll function that can be hooked. Only function I call with eq-related parameter is KeAttachProcess, but that function is linked directly in driver, not using gateways (meaning, not using SSDT tables) - so its impossible to hook unless someone rewrite kernel code to put his hook at start of function code. BUT even then, windows itself use KeAttachProcess, so that information wouldnt be any positive proof of keysniffer.

    I think that this approach is practically undetectable.

  11. #41
    Registered User
    Join Date
    Aug 2002
    Posts
    143
    I think that this approach is practically undetectable.
    Agreed. And you know I'm not about to say that lightly given my previous statements.

  12. #42
    Registered User
    Join Date
    Nov 2002
    Posts
    36
    Any chance of posting case #16?

  13. #43
    Registered User
    Join Date
    Dec 2001
    Posts
    752
    and "myFindEprocess()"

    thnx /duck
    -- Lord Crush

    Greater Faydark has to be cleaned from all Elves !

    This is a HOTKEY !!!

  14. #44
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    Ok, here is code.
    You also need to include ntifs.h in source.





    // myFindProcess

    void* myFindProcess(char* ProcName){

    char ProcessName[16];
    ULONG BuildNumber,ListEntryOffset,NameOffset;
    ULONG p,sz1;
    PLIST_ENTRY ProcessListPtr, PsActiveProcessHead;
    void *Peb;


    BuildNumber= (*NtBuildNumber) & 0x0000FFFF;

    if ((BuildNumber==0x421) || (BuildNumber==0x565) ) { // NT 3.51; 4.0
    PsActiveProcessHead = (PLIST_ENTRY) 0x8046A180; // not sure for this number
    ListEntryOffset=0x98;
    NameOffset=0x1DC;
    } else if (BuildNumber==0x755) {// Windows 2000
    PsActiveProcessHead = (PLIST_ENTRY) 0x8046A180;
    ListEntryOffset=0xA0;
    NameOffset=0x1FC;
    } else {// treat anything else as Windows XP, BuildNumber==0xA28
    PsActiveProcessHead = (PLIST_ENTRY) 0x80547b58;
    ListEntryOffset=0x88;
    NameOffset=0x174;
    }

    p=0;
    sz1=strlen(ProcName); // input process name length must be < 16
    ProcessListPtr=PsActiveProcessHead;
    while ((p<250)&&((ProcessListPtr!=PsActiveProcessHead)|| (p==0))) {
    // get process name
    Peb=(void *)(((char *)ProcessListPtr)-ListEntryOffset);
    memset(ProcessName, 0, sizeof(ProcessName));
    memcpy(ProcessName, ((char *)Peb)+NameOffset, 16);
    // compare names. Limit process name to length of our input parameter. Case sensitive
    ProcessName[sz1]=0;
    if (strcmp(ProcessName,ProcName)==0)){
    // process found!
    return Peb;
    }
    // next process
    p++;
    if (!MmIsAddressValid(ProcessListPtr->Flink)) {
    return 0;
    }
    ProcessListPtr=ProcessListPtr->Flink;
    }
    return 0;
    }




    // case #16 part
    case 16: // read key completely, based on app name and offset
    // first parameter (8 bytes) is still function (=16)
    // second parameter (8 bytes) is offset of key
    // third parameter (8 bytes) is process name up to 7 chars (0 at end)

    if (InBufferSize<24) return STATUS_INVALID_PARAMETER;
    DWORD32 d32;
    void* pv; // declaration of d32, pv and cs need to be done at start of function, not in case
    char* cs= (char*) (pIOBuffer+2);
    cs[7]=0;
    pv=myFindProcess(cs); // find process, name in first param
    nOut=0;
    if (pv){
    KeAttachProcess(pv); // attach to process
    d32=myGetPA((DWORD32)*(pIOBuffer +1)); // first get PA for given VA. For myGetPA see case #13
    nOut=myReadPA(d32); // then return result read from PA. For myReadPA see case #10
    KeDetachProcess();
    }
    break;

  15. #45
    Registered User
    Join Date
    Dec 2001
    Posts
    752
    Wooot thank you

    i did read the article about the PhysicalMemory access that you posted as second link (http://www.phrack.com/phrack/59/p59-0x10.txt ) while driving home from work in the metro - puh i think i got a light idea what to do but no chance to make it my own . But it is a very interesting article

    /bow and thank you again
    -- Lord Crush

    Greater Faydark has to be cleaned from all Elves !

    This is a HOTKEY !!!

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

You may post new threads
You may post replies
You may post attachments
You may edit your posts
HTML code is Off
vB code is On
Smilies are On
[IMG] code is Off