2014年9月11日星期四

内核中的APC

/*
文件名:KeInsertQueueApc.c

应用层有相应的公开的APC函数,如:QueueUserAPC。
但是内核中却没有公开的函数,在微软的网站上搜索下,只搜索到一篇文章:
http://www.microsoft.com/msj/0799/nerd/nerd0799.aspx
很早的了,上个世纪的。而且还有隐含的声明。
APC作为一个操作系统的基本的机制,岂能没有?除非你把应用层的也删除了等原因。
其实这些APC函数在内核中已经导出了,且在很早的版本都有了。
所以可以放心使用这些函数。
内核驱动开发的功能和性能在于开发人员的认识和胆量。
胆量从何而来,在于认识的熟练程度。

顺便说一下:
内核的DPC函数倒是公开了,如:
KeInitializeDpc
KeInsertQueueDpc
KeRemoveQueueDpc

本文的一些数据来自WRK和上面的链接。

本文只是一个简单的示例:
在内核中调用应用程序事先准备好的函数。
更多的功能请看网上:如杀进程,注入DLL等。

made by correy
made at 2014.09.11
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

#include "ntddk.h"

#define FILE_DEVICE_UNKNOWN             0x00000022
#define IOCTL_UNKNOWN_BASE              FILE_DEVICE_UNKNOWN
#define IOCTL_NOTIFY_REGISTER_APC CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0803, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)

typedef
VOID
(*PKNORMAL_ROUTINE) (
    IN PVOID NormalContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    );

typedef
VOID
(*PKKERNEL_ROUTINE) (
    IN struct _KAPC *Apc,
    IN OUT PKNORMAL_ROUTINE *NormalRoutine,
    IN OUT PVOID *NormalContext,
    IN OUT PVOID *SystemArgument1,
    IN OUT PVOID *SystemArgument2
    );

typedef
VOID
(*PKRUNDOWN_ROUTINE) (
    IN struct _KAPC *Apc
    );

typedef enum _KAPC_ENVIRONMENT {
    OriginalApcEnvironment,
    AttachedApcEnvironment,
    CurrentApcEnvironment,
    InsertApcEnvironment
} KAPC_ENVIRONMENT;

NTKERNELAPI
VOID
KeInitializeApc (
    __out PRKAPC Apc,
    __in PRKTHREAD Thread,
    __in KAPC_ENVIRONMENT Environment,
    __in PKKERNEL_ROUTINE KernelRoutine,
    __in_opt PKRUNDOWN_ROUTINE RundownRoutine,
    __in_opt PKNORMAL_ROUTINE NormalRoutine,
    __in_opt KPROCESSOR_MODE ProcessorMode,
    __in_opt PVOID NormalContext
    );

PLIST_ENTRY
KeFlushQueueApc (
    __inout PKTHREAD Thread,
    __in KPROCESSOR_MODE ProcessorMode
    );

NTKERNELAPI
BOOLEAN
KeInsertQueueApc (
    __inout PRKAPC Apc,
    __in_opt PVOID SystemArgument1,
    __in_opt PVOID SystemArgument2,
    __in KPRIORITY Increment
    );

BOOLEAN
KeRemoveQueueApc (
    __inout PKAPC Apc
    );

void     KnotifyUnloadDriver(PDRIVER_OBJECT DriverObject);
NTSTATUS KnotifyDispatchCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS KnotifyDispatchIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);


NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
    NTSTATUS        ntStatus;
    UNICODE_STRING  uszDriverString;
    UNICODE_STRING  uszDeviceString;
    UNICODE_STRING  uszNotifyEventString;

    PDEVICE_OBJECT  pDeviceObject;
         
    __debugbreak();
   
    RtlInitUnicodeString(&uszDriverString, L"\\Device\\test");// Point uszDriverString at the driver name  
    ntStatus = IoCreateDevice(DriverObject, 0, &uszDriverString, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);// Create and initialize device object
    if(ntStatus != STATUS_SUCCESS)
        return ntStatus;  
 
    RtlInitUnicodeString(&uszDeviceString, L"\\DosDevices\\test");// Point uszDeviceString at the device name  
    ntStatus = IoCreateSymbolicLink(&uszDeviceString, &uszDriverString);// Create symbolic link to the user-visible name
    if(ntStatus != STATUS_SUCCESS)
    {      
        IoDeleteDevice(pDeviceObject);// Delete device object if not successful
        return ntStatus;
    }

    // Load structure to point to IRP handlers...
    DriverObject->DriverUnload                         = KnotifyUnloadDriver;
    DriverObject->MajorFunction[IRP_MJ_CREATE]         = KnotifyDispatchCreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]          = KnotifyDispatchCreateClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KnotifyDispatchIoctl;
     
    return ntStatus;// Return success
}


NTSTATUS KnotifyDispatchCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information=0;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    return(STATUS_SUCCESS);
}


void KMApcCallback(PKAPC Apc, PKNORMAL_ROUTINE NormalRoutine, PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)
    /*
    0: kd> k
    ChildEBP RetAddr
    b1a6fcfc 8050099b KNotify!KMApcCallback [d:\temp\sources\msj\column\0799\kernel\knotify.c @ 164]
    b1a6fd4c 80542853 nt!KiDeliverApc+0x1af
    b1a6fd4c 7c92e514 nt!KiServiceExit+0x59
    0012fef8 7c92d21a ntdll!KiFastSystemCallRet
    0012fefc 7c8023f1 ntdll!ZwDelayExecution+0xc
    0012ff54 0040110b kernel32!SleepEx+0x61
    0012ff78 00401228 ConsoleApplication1!main+0xab [e:\code\consoleapplication1\consoleapplication1.cpp @ 51]
    0012ffc0 7c816037 ConsoleApplication1!__tmainCRTStartup+0xfe [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 241]
    0012fff0 00000000 kernel32!BaseProcessStart+0x23
    */
{
    ExFreePool(Apc);
    return;
}


NTSTATUS KnotifyDispatchIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    NTSTATUS           ntStatus;
    PIO_STACK_LOCATION irpStack  = IoGetCurrentIrpStackLocation(Irp);

    switch(irpStack->Parameters.DeviceIoControl.IoControlCode)
    {
        case IOCTL_NOTIFY_REGISTER_APC:
        {
            PKAPC Apc;
            ULONG *UserRoutine = (ULONG *)Irp->AssociatedIrp.SystemBuffer;

            Apc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
            KeInitializeApc(Apc,
                            KeGetCurrentThread(),
                            OriginalApcEnvironment,
                            (PKKERNEL_ROUTINE)&KMApcCallback, // kernel-mode routine
                            0,                                // rundown routine
                            (PKNORMAL_ROUTINE)*UserRoutine,   // user-mode routine
                            UserMode, (PVOID)(ULONG)1);
            KeInsertQueueApc(Apc, (PVOID)(ULONG)2, (PVOID)(ULONG)3, 0);
            ntStatus = STATUS_SUCCESS;
            break;
        }    
        default:
            break;
    }

    Irp->IoStatus.Status = ntStatus;
   
    // Set # of bytes to copy back to user-mode...
    if(ntStatus == STATUS_SUCCESS)
        Irp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    else
        Irp->IoStatus.Information = 0;

    if(ntStatus != STATUS_PENDING)
        IoCompleteRequest(Irp, IO_NO_INCREMENT);

    return ntStatus;
}


void KnotifyUnloadDriver(PDRIVER_OBJECT DriverObject)
{
    UNICODE_STRING  uszDeviceString;

    IoDeleteDevice(DriverObject->DeviceObject);

    RtlInitUnicodeString(&uszDeviceString, L"\\DosDevices\\test");
    IoDeleteSymbolicLink(&uszDeviceString);
}
----------------------------------------------------------------------------------------------------------------------------------------------
#include "stdafx.h"

#include <Windows.h>

#define FILE_DEVICE_UNKNOWN             0x00000022
#define IOCTL_UNKNOWN_BASE              FILE_DEVICE_UNKNOWN
#define IOCTL_NOTIFY_REGISTER_APC CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0803, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)


void ApcCallback(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2)
    /*
    0: kd> k
    ChildEBP RetAddr
    0012fc1c 7c92e457 ConsoleApplication1!ApcCallback [e:\code\consoleapplication1\consoleapplication1.cpp @ 20]
    0012ff54 0040110b ntdll!KiUserApcDispatcher+0x7
    0012ff78 00401228 ConsoleApplication1!main+0xab [e:\code\consoleapplication1\consoleapplication1.cpp @ 51]
    0012ffc0 7c816037 ConsoleApplication1!__tmainCRTStartup+0xfe [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 241]
    0012fff0 00000000 kernel32!BaseProcessStart+0x23
    */
{
    wchar_t Message[80];
    wsprintf(Message,L"APC Callback!\n P1 == %lx\n P2 == %lx\n P3 == %lx", NormalContext,  SystemArgument1, SystemArgument2);
    MessageBox(NULL, Message, L"Unotify", MB_OK);
}


 int __cdecl main ()
{
    __debugbreak();

    HANDLE hDevice = CreateFile(L"\\\\.\\test", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
    if(hDevice == INVALID_HANDLE_VALUE)
    {
        MessageBox(0,L"请加载驱动!",0,0);
        return 0;
    }

    DWORD dwBytesReturned;
    DWORD pfnApc = (DWORD)&ApcCallback;    
    BOOL bReturnCode = DeviceIoControl(hDevice, IOCTL_NOTIFY_REGISTER_APC, &pfnApc, sizeof(DWORD), 0, 0, &dwBytesReturned, 0);
    if(bReturnCode == FALSE)
    {
        MessageBox(0,L"DeviceIoControl失败!",0,0);
        return 0;
    }
   
    MessageBox(NULL,L"APC Dispatched!",L"Unotify",MB_OK);//先显示这个,再显示ApcCallback的消息框。不过这也可以想办法改变的。
       
    SleepEx(INFINITE, TRUE);//这一行是所有实现的关键。

    return 0;
}

没有评论:

发表评论