none
implementing a kernel timer via user mode

    Question

  • i want to implement a kernel timer (i use the function ZwCreateTimer, i know that there is other function i should use them instead) , i got a blue screen error of type 0xE8

    here is a piece of my code:

    VOID pro6(PVOID sc)
    {
    NTSTATUS s = ZwCreateTimer(&th,
    OBJECT_TYPE_ALL_ACCESS, NULL, NotificationTimer);
    PMyStruct v = (PMyStruct)sc;

    if (!NT_SUCCESS(s))
    {
    KdPrint(("createtimer failed 0x%x\n", s));
    //return STATUS_UNSUCCESSFUL;
    }
    else
    {
    LARGE_INTEGER dt = RtlConvertLongToLargeInteger((LONG)0);
    BOOLEAN b;
    LONG l = 1001;
    ZwSetTimer(th, &dt, (PTIMER_APC_ROUTINE)v->t_apc, NULL, TRUE, (LONG)1000, &b);

    }

    }

    NTSTATUS ioctl_d_in_io6_pro(PIRP Irp,
    PIO_STACK_LOCATION pIoStackIrp,
    UINT *pdwDataWritten)
    {
    PIO_STACK_LOCATION sl = IoGetCurrentIrpStackLocation(Irp);
    PMyStruct ib = (PMyStruct) Irp->AssociatedIrp.SystemBuffer;

    HANDLE th;
    PsCreateSystemThread(&th,
    THREAD_ALL_ACCESS, NULL, NULL, NULL, pro6, (PVOID)ib);


    *pdwDataWritten = 0;
    return STATUS_SUCCESS;

    }

    NTSTATUS Example_IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)

    {
    NTSTATUS NtStatus = STATUS_NOT_SUPPORTED;
    PIO_STACK_LOCATION pIoStackIrp = NULL;
    UINT  dwDataWritten = 0;

    DbgPrint("Example_IoControl Called \r\n");

    /*
    * Each time the IRP is passed down the driver stack a new stack location is added
    * specifying certain parameters for the IRP to the driver.
    */
    pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);

    if (pIoStackIrp) /* Should Never Be NULL! */
    {
    switch (pIoStackIrp->Parameters.DeviceIoControl.IoControlCode)
    {

    case ioctl_d_in_io6: // we are here
    NtStatus = ioctl_d_in_io6_pro(Irp, pIoStackIrp, &dwDataWritten);
    break;

    }}

    Irp->IoStatus.Status = NtStatus;
    Irp->IoStatus.Information = dwDataWritten;

    IoCompleteRequest(Irp, IO_NO_INCREMENT);



    return NtStatus;
    }

    user mode code:

    typedef struct MyStruct
    {
    PTIMER_APC_ROUTINE t_apc;
    } MyStruct, *PMyStruct;

    VOID
    e(
    PVOID TimerContext,
    ULONG TimerLowValue,
    LONG TimerHighValue
    )
    {
    printf("a timer thread was called\n");

    }

    MyStruct * buf2 = (MyStruct*)malloc(sizeof(MyStruct));
    buf2->t_apc = (PTIMER_APC_ROUTINE) e;

    BOOL r = DeviceIoControl(hFile,
    ioctl_d_in_io6,
    buf2,
    sizeof(MyStruct),
    NULL,
    NULL,
    &br,
    NULL);


    Wednesday, May 15, 2019 11:56 PM

Answers

  • You have several serious problems here.

    First, you spin off a thread to call ZwCreateTimer (why?), passing it a pointer to the buffer from your ioctl, but the code that created the thread is going to continue to execute, calling IoCompleteRequest, which will free that buffer's memory.  If you hit IoCompleteRequest before the thread starts, which is likely, the thread will have a pointer into empty memory.

    Secondly, your whole concept is screwed.  You can't register user-mode addresses with kernel services.  That address you passed is only valid when your thread is actually in a CPU.  When that timer fires, some other process is going to be running, and the address 0x401000 contains someone else's code.

    Further, I would hope the security implications of calling user-mode code from a kernel process would be obvious.  It's not allowed, for very good reasons.  Transitions between kernel and user mode code have to be done with special instructions.

    There are user-mode APIs to get timer callbacks.  Use them.


    Tim Roberts | Driver MVP Emeritus | Providenza & Boekelheide, Inc.

    Thursday, May 16, 2019 8:03 PM

All replies

  • So, if you know that you should be using KeInitializeTimerEx, then why aren't you using it?

    If you want help debugging your crash, then also post the debugger's output from the !analyze -v command. We aren't paid to answer questions here, so don't expect people to spend time analyzing your code

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Thursday, May 16, 2019 12:28 AM
    Moderator
  • You have several serious problems here.

    First, you spin off a thread to call ZwCreateTimer (why?), passing it a pointer to the buffer from your ioctl, but the code that created the thread is going to continue to execute, calling IoCompleteRequest, which will free that buffer's memory.  If you hit IoCompleteRequest before the thread starts, which is likely, the thread will have a pointer into empty memory.

    Secondly, your whole concept is screwed.  You can't register user-mode addresses with kernel services.  That address you passed is only valid when your thread is actually in a CPU.  When that timer fires, some other process is going to be running, and the address 0x401000 contains someone else's code.

    Further, I would hope the security implications of calling user-mode code from a kernel process would be obvious.  It's not allowed, for very good reasons.  Transitions between kernel and user mode code have to be done with special instructions.

    There are user-mode APIs to get timer callbacks.  Use them.


    Tim Roberts | Driver MVP Emeritus | Providenza & Boekelheide, Inc.

    Thursday, May 16, 2019 8:03 PM