2013年11月23日星期六

驱动复制文件

/*
名字:驱动复制文件.

文件操作很简单.
NT*系列函数的操作在用户层也可以.

为何有今天的文章?
文件操作真的简单吗?看完本篇就知道了.
为何要做ZW*系列函数?在内核中没有权限的限制,不知是哪本书或者那个地方这样说的.
所以在内核就可以做一些应用层难做的事情,如需要特特特特权限的.

网上没有看到相关的示例代码.
只有WDK上的一些简单的介绍:Using Files In A Driver
http://msdn.microsoft.com/en-us/library/windows/hardware/ff565384(v=vs.85).aspx

前两个函数测试如下用例失败:
打开:windows\\system32\\config\\sam
会导致:C0000043 == -1073741757,解释是:另一个程序正在使用此文件,进程无法访问。
可能是独占方式打开的.

made by correy
made at 2013.11.23
homepage:http://correy.webs.com
不足之处,敬请指出.
*/

#include <ntifs.h>
#include <windef.h>

#define TAG 'tset' //本驱动在内存中的标志:test


BOOLEAN copy_file(IN PWCH DestinationFile, IN PWCH SourceFile, IN BOOLEAN bFailIfExists)
    /*
    参数的形式为:C:\WINDOWS\example.txt

    bFailIfExists == TRUE时,如果DestinationFile存在就返回失败;
    bFailIfExists == FALSE时,如果DestinationFile存在就新建或者覆盖;

    存在的缺点有:
    1.没有复制文件的属性,如:文件的所有者等信息.
    */
{
    BOOLEAN b = FALSE;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    UNICODE_STRING df = {0};
    UNICODE_STRING f  = RTL_CONSTANT_STRING(L"\\??\\");//On Microsoft Windows 2000 and later versions of the operating system, \?? is equivalent to \DosDevices.
    OBJECT_ATTRIBUTES ob;
    HANDLE FileHandle = 0;
    HANDLE DestinationFileHandle = 0;
    IO_STATUS_BLOCK  IoStatusBlock = {0};
    PVOID Buffer = 0;
    ULONG Length = 0;
    LARGE_INTEGER file_size = {0};
    LARGE_INTEGER ByteOffset = {0};
    LARGE_INTEGER i = {0};
    FILE_STANDARD_INFORMATION fsi = {0};
    LARGE_INTEGER AllocationSize = {0};
    ULONG CreateDisposition = 0;

    //如果SourceFile是文件夹,在下面打开的时候返回失败.

    __try 
    { 
        df.Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG);
        if (df.Buffer == NULL) { 
            DbgPrint("发生错误的文件为:%s, 代码行为:%d\n", __FILE__, __LINE__);
            __leave;
        }
        RtlZeroMemory(df.Buffer, MAX_PATH);
        RtlInitEmptyUnicodeString(&df,df.Buffer,MAX_PATH);
        RtlCopyUnicodeString(&df,&f);
        status = RtlAppendUnicodeToString(&df, SourceFile);
        if (!NT_SUCCESS (status)) {
            KdPrint(("RtlAppendUnicodeToString fail with 0x%x.\n", status));
            __leave;
        }
        InitializeObjectAttributes(&ob, &df, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
        status = ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
        if (!NT_SUCCESS (status)) 
        {
            KdPrint(("ZwOpenFile fail with 0x%x.\n", status));
            if ( status == STATUS_OBJECT_NAME_NOT_FOUND) {
                KdPrint(("file does not exist\n"));
            }
            if (IoStatusBlock.Information == FILE_DOES_NOT_EXIST ) {
                KdPrint(("file does not exist\n"));
            }
            __leave;
        }

        RtlZeroMemory(df.Buffer, MAX_PATH);
        RtlInitEmptyUnicodeString(&df,df.Buffer,MAX_PATH);
        RtlCopyUnicodeString(&df,&f);
        status = RtlAppendUnicodeToString(&df, DestinationFile);
        if (!NT_SUCCESS (status)) {
            KdPrint(("RtlAppendUnicodeToString fail with 0x%x.\n", status));
            __leave;
        }
        InitializeObjectAttributes(&ob, &df, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);        
        if (bFailIfExists) {
            CreateDisposition = FILE_CREATE;//新建文件.
        } else {
            CreateDisposition = FILE_SUPERSEDE;//FILE_OVERWRITE_IF
        }
        status = ZwCreateFile(&DestinationFileHandle, FILE_ALL_ACCESS | SYNCHRONIZE, &ob, &IoStatusBlock, &AllocationSize, 
            FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, CreateDisposition, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
        if (!NT_SUCCESS (status)) 
        {
            KdPrint(("ZwCreateFile fail with 0x%x.\n", status));
            __leave;
        }

        //可以考虑在这里给文件加锁,保护,不让别的操作再写入.ZwLockFile,再在适当的时候解锁:ZwUnlockFile.

        status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &fsi, sizeof (FILE_STANDARD_INFORMATION), FileStandardInformation);
        if (!NT_SUCCESS (status)) 
        {
            KdPrint(("ZwQueryInformationFile fail with 0x%x.\n", status));
            __leave;
        }

        if (fsi.EndOfFile.QuadPart == 0)
        {
            __leave;
        }

        file_size = fsi.EndOfFile;
        Length = 9;//可用ZwQuerySystemInformation SystemBasicInformation取页的大小。
        Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, TAG);
        if (Buffer == NULL) { 
            status = STATUS_UNSUCCESSFUL;
            DbgPrint("发生错误的文件为:%s, 代码行为:%d\n", __FILE__, __LINE__);
            __leave;
        }

        for ( ;i.QuadPart < file_size.QuadPart ; )
        {
            RtlZeroMemory(Buffer, Length);

            status = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, Length, &i, NULL);
            if (!NT_SUCCESS (status)) 
            {
                KdPrint(("ZwReadFile fail with 0x%x.\n", status));
                __leave;
            }             
            
            status = ZwWriteFile(DestinationFileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, IoStatusBlock.Information, &i, NULL);
            if (!NT_SUCCESS (status)) //可以检查写入的数量或者写入的总量。
            {
                KdPrint(("ZwWriteFile fail with 0x%x.\n", status));
                __leave;
            }

            i.QuadPart += IoStatusBlock.Information;//必须在这里,在ZwWriteFile的前面就会出现大小的问题。
        }
    } __finally {
        if (NT_SUCCESS( status )) //检查上面的所有情况.
        {
            b = TRUE;//有时写文件会返回0x103,即重叠 I/O 操作在进行中,也会走到这里.
        }

        //关闭句柄.        
        if (FileHandle)
        {
            status = ZwClose(FileHandle);
            if (!NT_SUCCESS (status)) 
            {
                KdPrint(("ZwClose fail with 0x%x.\n", status));
            }
        }
        if (DestinationFileHandle)
        {
            status = ZwClose(DestinationFileHandle);
            if (!NT_SUCCESS (status)) 
            {
                KdPrint(("ZwClose fail with 0x%x.\n", status));
            }
        }

        //释放内存.
        if (df.Buffer) {
            ExFreePoolWithTag(df.Buffer, TAG);
        }
        if (Buffer) {
            ExFreePoolWithTag(Buffer, TAG);
        }
    }    

    return b;//不做同步是要蓝屏的.
}


BOOLEAN copy_file_ex(IN UNICODE_STRING * FileName, IN UNICODE_STRING * newFileName) //CONST
    /*
    参数的形式是:"\Device\HarddiskVolume1\XXX等。

    存在的缺点有:
    1.没有复制文件的属性,如:文件的所有者等信息.
    */
{
    BOOLEAN b = FALSE;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    OBJECT_ATTRIBUTES ob;
    HANDLE FileHandle = 0;
    HANDLE DestinationFileHandle = 0;
    IO_STATUS_BLOCK  IoStatusBlock = {0};
    PVOID Buffer = 0;
    ULONG Length = 0;
    ULONG CreateDisposition = 0;
    FILE_STANDARD_INFORMATION fsi = {0};
    LARGE_INTEGER ByteOffset = {0};
    LARGE_INTEGER AllocationSize = {0};
    LARGE_INTEGER file_size = {0};

    InitializeObjectAttributes(&ob, FileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
    status = ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS (status)) 
    {
        //KdPrint(("ZwOpenFile fail with 0x%x.\n", status));
        if ( status == STATUS_OBJECT_NAME_NOT_FOUND)  {
            KdPrint(("file does not exist\n"));
        }
        if (IoStatusBlock.Information == FILE_DOES_NOT_EXIST ) {
            KdPrint(("file does not exist\n"));
        }
        return b;
    }

    //可以考虑在这里给文件加锁,保护,不让别的操作再写入.ZwLockFile,再在适当的时候解锁:ZwUnlockFile.

    status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &fsi, sizeof (FILE_STANDARD_INFORMATION), FileStandardInformation);
    if (!NT_SUCCESS (status)) 
    {
        KdPrint(("ZwQueryInformationFile fail with 0x%x.\n", status));
        ZwClose(FileHandle);
        return b;;
    }

    //新建文件.
    CreateDisposition = FILE_CREATE;
    InitializeObjectAttributes(&ob, newFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
    status = ZwCreateFile(&DestinationFileHandle, FILE_ALL_ACCESS | SYNCHRONIZE, &ob, &IoStatusBlock, &AllocationSize, 
        FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, CreateDisposition, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
    if (!NT_SUCCESS (status)) 
    {
        //KdPrint(("ZwCreateFile fail with 0x%x.\n", status));
        ZwClose(FileHandle);
        if (status == STATUS_OBJECT_NAME_COLLISION)   {//-1073741771 ((NTSTATUS)0xC0000035L) Object Name already exists.
            b = TRUE;
        }
        return b;
    }
    
    if (fsi.EndOfFile.QuadPart == 0)
    {
        ZwClose(FileHandle);
        ZwClose(DestinationFileHandle);
        return TRUE ;
    }

    file_size = fsi.EndOfFile;
    Length = 9;//测试专用。
    Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, TAG);//Length == 0时加驱动验证器,这里会蓝屏。
    if (Buffer == NULL) { 
        status = STATUS_UNSUCCESSFUL;
        DbgPrint("发生错误的文件为:%s, 代码行为:%d\n", __FILE__, __LINE__);
        ZwClose(FileHandle);
        ZwClose(DestinationFileHandle);
        return b;
    }

    for ( ;ByteOffset.QuadPart < file_size.QuadPart ; )
    {
        RtlZeroMemory(Buffer, Length);

        status = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, Length, &ByteOffset, NULL);
        if (!NT_SUCCESS (status)) 
        {
            KdPrint(("ZwReadFile fail with 0x%x.\n", status));
            ExFreePoolWithTag(Buffer, TAG);
            ZwClose(FileHandle);
            ZwClose(DestinationFileHandle);
            return b;
        }

        status = ZwWriteFile(DestinationFileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, IoStatusBlock.Information, &ByteOffset, NULL);
        if (!NT_SUCCESS (status)) 
        {
            KdPrint(("ZwWriteFile fail with 0x%x.\n", status));
            ExFreePoolWithTag(Buffer, TAG);
            ZwClose(FileHandle);
            ZwClose(DestinationFileHandle);
            return b;
        }

        ByteOffset.QuadPart += IoStatusBlock.Information;
    }

    ExFreePoolWithTag(Buffer, TAG);
    ZwClose(FileHandle);
    ZwClose(DestinationFileHandle);

    return TRUE ;
}


BOOLEAN copy_file_ex2(IN UNICODE_STRING * FileName, IN UNICODE_STRING * newFileName) //CONST
    /*
    参数的形式是:"\Device\HarddiskVolume1\XXX或者\\??\\c:\\WINDOWS\\system32\\config\\SAM。

    功能:由于专门复制被独占式使用的文件,如分页文件(正在使用的pagefile.sys)和各种被正在使用HIVE文件.
    扩展功能:如删除文件(打开的时候带有删除的属性:FILE_DELETE_ON_CLOSE )估计也可以的,这个不用发送IRP,至少在形式上。

    说明:IoCreateFileEx函数有IO_IGNORE_SHARE_ACCESS_CHECK功能,可是This routine is available starting with Windows Vista.

    存在的缺点有:
    1.没有复制文件的属性,如:文件的所有者等信息.

    made by correy
    made at 2014.07.28
    homepage:http://correy.webs.com
    */
{
    BOOLEAN b = FALSE;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    OBJECT_ATTRIBUTES ob;
    HANDLE FileHandle = 0;
    HANDLE DestinationFileHandle = 0;
    IO_STATUS_BLOCK  IoStatusBlock = {0};
    PVOID Buffer = 0;
    ULONG Length = 0;
    ULONG CreateDisposition = 0;
    FILE_STANDARD_INFORMATION fsi = {0};
    LARGE_INTEGER ByteOffset = {0};
    LARGE_INTEGER AllocationSize = {0};
    LARGE_INTEGER file_size = {0};
    FILE_FULL_EA_INFORMATION ffai = {0};

    InitializeObjectAttributes(&ob, FileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
    //status = ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
    //if (!NT_SUCCESS (status)) 
    //{
    //    //KdPrint(("ZwOpenFile fail with 0x%x.\n", status));
    //    if ( status == STATUS_OBJECT_NAME_NOT_FOUND)  {
    //        KdPrint(("file does not exist\n"));
    //    }
    //    if (IoStatusBlock.Information == FILE_DOES_NOT_EXIST ) {
    //        KdPrint(("file does not exist\n"));
    //    }
    //    return b;
    //}
    status = IoCreateFileSpecifyDeviceObjectHint(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, &AllocationSize, FILE_ATTRIBUTE_NORMAL, 
        /*
        Specifies the type of share access to the file that the caller would like, as zero, or one, or a combination of the following flags. 
        To request exclusive access, set this parameter to zero. 
        If the IO_IGNORE_SHARE_ACCESS_CHECK flag is specified in the Options parameter, the I/O manager ignores this parameter. 
        However, the file system might still perform access checks.
        Thus, it is important to specify the sharing mode you would like for this parameter, even when using the IO_IGNORE_SHARE_ACCESS_CHECK flag.
        For the greatest chance of avoiding sharing violation errors, specify all of the following share access flags. 
        */
        FILE_SHARE_VALID_FLAGS, 
        FILE_OPEN,
        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
        &ffai,
        sizeof (FILE_FULL_EA_INFORMATION),
        CreateFileTypeNone,//其实命名管道和邮件槽也定义了。
        NULL,
        /*
        Indicates that the I/O manager should not perform share-access checks on the file object after it is created. 
        However, the file system might still perform these checks. 
        */
        IO_IGNORE_SHARE_ACCESS_CHECK,
        /*
        A pointer to the device object to which the create request is to be sent. 
        The device object must be a filter or file system device object in the file system driver stack for the volume on which the file or directory resides. 
        This parameter is optional and can be NULL. If this parameter is NULL, the request will be sent to the device object at the top of the driver stack. 
        */
        NULL
        );
    if (!NT_SUCCESS (status)) 
    {
        //KdPrint(("ZwOpenFile fail with 0x%x.\n", status));
        if ( status == STATUS_OBJECT_NAME_NOT_FOUND)  {
            KdPrint(("file does not exist\n"));
        }
        if (IoStatusBlock.Information == FILE_DOES_NOT_EXIST ) {
            KdPrint(("file does not exist\n"));
        }
        return b;
    }

    //可以考虑在这里给文件加锁,保护,不让别的操作再写入.ZwLockFile,再在适当的时候解锁:ZwUnlockFile.
    //可是This routine is available in Windows 7 and later versions of the Windows operating system.

    status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &fsi, sizeof (FILE_STANDARD_INFORMATION), FileStandardInformation);
    if (!NT_SUCCESS (status)) 
    {
        KdPrint(("ZwQueryInformationFile fail with 0x%x.\n", status));
        ZwClose(FileHandle);
        return b;;
    }

    //新建文件.
    CreateDisposition = FILE_CREATE;
    InitializeObjectAttributes(&ob, newFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
    status = ZwCreateFile(&DestinationFileHandle, FILE_ALL_ACCESS | SYNCHRONIZE, &ob, &IoStatusBlock, &AllocationSize, 
        FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, CreateDisposition, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
    if (!NT_SUCCESS (status)) 
    {
        //KdPrint(("ZwCreateFile fail with 0x%x.\n", status));
        ZwClose(FileHandle);
        if (status == STATUS_OBJECT_NAME_COLLISION)   {//-1073741771 ((NTSTATUS)0xC0000035L) Object Name already exists.
            b = TRUE;
        }
        return b;
    }
    
    if (fsi.EndOfFile.QuadPart == 0)
    {
        ZwClose(FileHandle);
        ZwClose(DestinationFileHandle);
        return TRUE ;
    }

    file_size = fsi.EndOfFile;
    Length = 9;//测试专用。
    Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, TAG);//Length == 0时加驱动验证器,这里会蓝屏。
    if (Buffer == NULL) { 
        status = STATUS_UNSUCCESSFUL;
        DbgPrint("发生错误的文件为:%s, 代码行为:%d\n", __FILE__, __LINE__);
        ZwClose(FileHandle);
        ZwClose(DestinationFileHandle);
        return b;
    }

    for ( ;ByteOffset.QuadPart < file_size.QuadPart ; )
    {
        RtlZeroMemory(Buffer, Length);

        status = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, Length, &ByteOffset, NULL);
        if (!NT_SUCCESS (status)) 
        {
            KdPrint(("ZwReadFile fail with 0x%x.\n", status));
            ExFreePoolWithTag(Buffer, TAG);
            ZwClose(FileHandle);
            ZwClose(DestinationFileHandle);
            return b;
        }

        status = ZwWriteFile(DestinationFileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, IoStatusBlock.Information, &ByteOffset, NULL);
        if (!NT_SUCCESS (status)) 
        {
            KdPrint(("ZwWriteFile fail with 0x%x.\n", status));
            ExFreePoolWithTag(Buffer, TAG);
            ZwClose(FileHandle);
            ZwClose(DestinationFileHandle);
            return b;
        }

        ByteOffset.QuadPart += IoStatusBlock.Information;
    }

    ExFreePoolWithTag(Buffer, TAG);
    ZwClose(FileHandle);
    ZwClose(DestinationFileHandle);

    return TRUE ;
}


DRIVER_UNLOAD DriverUnload;
VOID DriverUnload(__in PDRIVER_OBJECT DriverObject)
{   

}


#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    UNICODE_STRING FileName  = RTL_CONSTANT_STRING(L"\\??\\c:\\1.exe");
    UNICODE_STRING newFileName  = RTL_CONSTANT_STRING(L"\\??\\c:\\3.exe");
    UNICODE_STRING FileName2  = RTL_CONSTANT_STRING(L"\\??\\c:\\WINDOWS\\system32\\config\\SAM");
    UNICODE_STRING newFileName2  = RTL_CONSTANT_STRING(L"\\??\\c:\\WINDOWS\\system32\\config\\SAM2");
    UNICODE_STRING FileName3  = RTL_CONSTANT_STRING(L"\\Device\\HarddiskVolume1\\WINDOWS\\system32\\config\\SAM");//
    UNICODE_STRING newFileName3  = RTL_CONSTANT_STRING(L"\\Device\\HarddiskVolume1\\WINDOWS\\system32\\config\\SAM3");

    KdBreakPoint();

    DriverObject->DriverUnload = DriverUnload;

    if (!copy_file(L"c:\\1.exe", L"c:\\2.exe", FALSE))
    {
        KdPrint(("copy_file fail!\n"));
    }

    if (!copy_file_ex(&FileName, &newFileName))
    {
        KdPrint(("copy_file_ex fail!\n"));
    }

    if (!copy_file_ex2(&FileName2, &newFileName2))
    {
        KdPrint(("copy_file_ex2 fail!\n"));
    }

    if (!copy_file_ex2(&FileName3, &newFileName3))
    {
        KdPrint(("copy_file_ex2 fail!\n"));
    }

    return STATUS_SUCCESS;
} 

2013年11月19日星期二

BUGCHECK:0xc4_e3的通解

BUGCHECK:0xc4_e3的通解.

原因:是在和函数访问了用户的数据,解决办法吗?最简单的就是copy.

关键是看:访问了用户的哪个地址和内核的哪个函数的哪个参数用到了那个用户的地址.

1: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

DRIVER_VERIFIER_DETECTED_VIOLATION (c4)
A device driver attempting to corrupt the system has been caught.  This is
because the driver was specified in the registry as being suspect (by the
administrator) and the kernel has enabled substantial checking of this driver.
If the driver attempts to corrupt the system, bugchecks 0xC4, 0xC1 and 0xA will
be among the most commonly seen crashes.
Arguments:
Arg1: 00000000000000e3, Kernel Zw API called with user-mode address as parameter.
Arg2: fffff880060cacab, Address inside the driver making the incorrect API call.
Arg3: 000007fefbdccb40, User-mode address used as API parameter.
Arg4: 0000000000000000

Debugging Details:
------------------


BUGCHECK_STR:  0xc4_e3

FAULTING_IP:
rdrct64!Process_CreateKey+18b [e:\securedesktop\dpdesk\rdrct\regeditvista.c @ 311]
fffff880`060cacab 89442444        mov     dword ptr [rsp+44h],eax

FOLLOWUP_IP:
rdrct64!Process_CreateKey+18b [e:\securedesktop\dpdesk\rdrct\regeditvista.c @ 311]
fffff880`060cacab 89442444        mov     dword ptr [rsp+44h],eax

DEFAULT_BUCKET_ID:  WIN7_DRIVER_FAULT

PROCESS_NAME:  explorer.exe

CURRENT_IRQL:  2

LAST_CONTROL_TRANSFER:  from fffff800019b9a02 to fffff800018c09b0

STACK_TEXT:
fffff880`06670a88 fffff800`019b9a02 : 00000000`000000e3 fffffa80`05ee0720 00000000`00000065 fffff800`01903898 : nt!RtlpBreakWithStatusInstruction
fffff880`06670a90 fffff800`019ba7ee : 000007fe`00000003 00000000`00000000 fffff800`019040f0 00000000`000000c4 : nt!KiBugCheckDebugBreak+0x12
fffff880`06670af0 fffff800`018c8c84 : fffff980`08deac00 fffff800`01d5e012 00000000`00000400 fffff800`01d5832e : nt!KeBugCheck2+0x71e
fffff880`066711c0 fffff800`01d564ec : 00000000`000000c4 00000000`000000e3 fffff880`060cacab 000007fe`fbdccb40 : nt!KeBugCheckEx+0x104
fffff880`06671200 fffff800`01d56fd5 : 00000000`00000000 fffff800`01d584ae 00000000`00000000 fffff800`01893081 : nt!VerifierBugCheckIfAppropriate+0x3c
fffff880`06671240 fffff800`01d584ae : fffff880`060cacab fffff800`01d5854e fffff880`06671390 fffff880`060cacab : nt!ViZwCheckAddress+0x35
fffff880`06671280 fffff800`01d5cc28 : fffff880`06671390 fffff880`060cacab 00000000`00ee00ec fffff980`04186c00 : nt!ViZwCheckUnicodeString+0x2e
fffff880`066712c0 fffff880`060cacab : 00000000`00000000 fffff880`06671a50 00000000`00000000 fffff880`06671380 : nt!VfZwCreateKey+0x68
fffff880`06671320 fffff880`060cb451 : fffff880`06671680 fffff880`06671680 fffff8a0`04217570 fffff800`01c741d1 : rdrct64!Process_CreateKey+0x18b [e:\securedesktop\dpdesk\rdrct\regeditvista.c @ 311]
fffff880`066713d0 fffff800`01c74460 : 00000000`00000000 00000000`0000001a fffff880`06671680 00000000`000007ff : rdrct64!RegistryCallback+0x91 [e:\securedesktop\dpdesk\rdrct\regeditvista.c @ 1179]
fffff880`06671420 fffff800`01b2bedd : fffffa80`0000001a fffff880`06671680 fffffa80`05ee0701 fffff880`0000001b : nt!CmpCallCallBacks+0x1c0
fffff880`066714f0 fffff800`01bc56d8 : fffffa80`0590acc8 fffffa80`00000000 fffffa80`0590ab10 fffff8a0`00000001 : nt! ?? ::NNGAKEGL::`string'+0x2ad6d
fffff880`066717f0 fffff800`01bc68f6 : 00000000`000000d4 fffffa80`0590ab10 16a00000`01b7d860 fffffa80`03d36f30 : nt!ObpLookupObjectName+0x588
fffff880`066718e0 fffff800`01b7d024 : fffff880`06671b88 00000000`00000000 fffff880`06671a01 fffff800`018c6dbd : nt!ObOpenObjectByName+0x306
fffff880`066719b0 fffff800`01b7d8c2 : 00000000`053fe3b8 fffff880`0002001f 00000000`053fe3d8 fffff800`01b7d894 : nt!CmCreateKey+0x2e1
fffff880`06671b20 fffff800`018c7e13 : fffffa80`05ee0720 0000007f`00000007 00000000`053fe318 00000980`00000000 : nt!NtCreateKey+0x2e
fffff880`06671b70 00000000`775f148a : 00000000`7738d4d8 00000000`053fe7a8 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13
00000000`053fe368 00000000`7738d4d8 : 00000000`053fe7a8 00000000`00000000 00000000`00000000 000007fe`fbe6626a : ntdll!NtCreateKey+0xa
00000000`053fe370 00000000`7738d7c8 : 00000000`053fe7a8 00000000`053fe780 00000000`00000000 00000000`053fe8d8 : kernel32!Wow64NtCreateKey+0xe8
00000000`053fe440 00000000`7738d343 : 000007fe`fe9053c0 00000000`00000170 00000000`053fe8d8 00000000`053fe788 : kernel32!LocalBaseRegCreateKey+0x282
00000000`053fe720 00000000`7738d3e0 : 00000000`000000d4 00000000`00000000 00000000`0399c020 00000000`00000000 : kernel32!RegCreateKeyExInternalW+0x15c
00000000`053fe800 000007fe`fbddfe97 : 00000000`0399c020 00000000`0001035a 00000000`00000190 00000000`00000000 : kernel32!RegCreateKeyExW+0x50
00000000`053fe860 000007fe`fe5ad3fc : 00000000`053fe990 00000000`00030352 00000000`053fe978 00000000`053fe970 : comctl32!CreateMRUListLazyW+0x8f
00000000`053fe940 000007fe`fe55b5b2 : 00000000`00000004 00000000`774ba85d 00000000`0001035a 00000000`00000141 : SHELL32!CreateMRUListW+0x38
00000000`053fe970 000007fe`fe55a0ae : 00000000`00000000 00000000`0399c020 00000000`0399c020 00000000`0399c020 : SHELL32!OpenRunDlgMRU+0x5e
00000000`053fe9d0 000007fe`fe559f63 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000087 : SHELL32!CRunDlg::InitRunDlg+0x185
00000000`053fec70 00000000`774ae53b : 00000000`038b4830 00000000`00000000 00000000`00000001 ffffffff`fc74b7cf : SHELL32!RunDlgProc+0x279
00000000`053fed20 00000000`774ae2f2 : 00000000`00000110 000007fe`fe55af1c 00000000`00700c80 00000000`0001035a : USER32!GetCapture+0x40b
00000000`053fede0 00000000`774d4843 : 00000000`00000000 00000000`00700c80 00000000`00000000 00000000`00030352 : USER32!GetCapture+0x1c2
00000000`053fee60 00000000`00000000 : 00000000`00700c80 00000000`00000000 00000000`00030352 00000000`00000000 : USER32!UserHandleGrantAccess+0x8d73


STACK_COMMAND:  kb

FAULTING_SOURCE_LINE:  e:\securedesktop\dpdesk\rdrct\regeditvista.c

FAULTING_SOURCE_FILE:  e:\securedesktop\dpdesk\rdrct\regeditvista.c

FAULTING_SOURCE_LINE_NUMBER:  311

SYMBOL_STACK_INDEX:  8

SYMBOL_NAME:  rdrct64!Process_CreateKey+18b

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: rdrct64

IMAGE_NAME:  rdrct64.sys

DEBUG_FLR_IMAGE_TIMESTAMP:  5285ddfd

FAILURE_BUCKET_ID:  X64_0xc4_e3_VRF_rdrct64!Process_CreateKey+18b

BUCKET_ID:  X64_0xc4_e3_VRF_rdrct64!Process_CreateKey+18b

Followup: MachineOwner
---------

关键的问题在这里:
nt!ViZwCheckAddress:
                           fffff800`01d0efa0 4883ec38        sub     rsp,38h
                           fffff800`01d0efa4 4885c9          test    rcx,rcx
                           fffff800`01d0efa7 742c            je      nt!ViZwCheckAddress+0x35 (fffff800`01d0efd5)
                           fffff800`01d0efa9 483b0d6090daff  cmp     rcx,qword ptr [nt!MmHighestUserAddress (fffff800`01ab8010)]
                           fffff800`01d0efb0 7323            jae     nt!ViZwCheckAddress+0x35 (fffff800`01d0efd5)
                           fffff800`01d0efb2 8b0528f10400    mov     eax,dword ptr [nt!ViZwBreakForIssues (fffff800`01d5e0e0)]
                           fffff800`01d0efb8 85c0            test    eax,eax
                           fffff800`01d0efba 7419            je      nt!ViZwCheckAddress+0x35 (fffff800`01d0efd5)
                           fffff800`01d0efbc 488364242000    and     qword ptr [rsp+20h],0
                           fffff800`01d0efc2 4c8bc2          mov     r8,rdx
                           fffff800`01d0efc5 bae3000000      mov     edx,0E3h
                           fffff800`01d0efca 4c8bc9          mov     r9,rcx
                           fffff800`01d0efcd 8d4ae1          lea     ecx,[rdx-1Fh]
                           fffff800`01d0efd0 e8dbf4ffff      call    nt!VerifierBugCheckIfAppropriate (fffff800`01d0e4b0)
                           fffff800`01d0efd5 4883c438        add     rsp,38h
                           fffff800`01d0efd9 c3              ret

这是用异常处理也处理不了的.

made by correy
made at 2013.11.19

2013年11月18日星期一

枚举桌面的内容

/*
文件名:IShellFolder.Cpp
功能:列出桌面的所以的(子)文件和(子)文件夹.

至今方知目录和文件夹的区别.
Windows Shell一直是一个知道但不熟悉的名字.

Windows Shell搞懂了,再搞COM等.

参考示例:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb776885(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/bb776889(v=vs.85).aspx

made by correy
made at 2013.11.18
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
不足之处,敬请指出.
*/

#include <shlobj.h>
#pragma comment(lib, "shlwapi.lib")

int main()
{  
    IShellFolder *psfDeskTop = NULL;
    HRESULT hr = SHGetDesktopFolder(&psfDeskTop);//获取对象的地址.

    LPENUMIDLIST ppenum = NULL;    
    hr = psfDeskTop->EnumObjects(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &ppenum);//获取对象的地址.
   
    ULONG celtFetched;
    LPITEMIDLIST pidlItems = NULL;
    while( hr = ppenum->Next(1,&pidlItems, &celtFetched) == S_OK && (celtFetched) == 1) //获取pidlItems
    {
        STRRET strDispName;
        psfDeskTop->GetDisplayNameOf(pidlItems, SHGDN_INFOLDER, &strDispName);//获取strDispName

        MessageBox(0,strDispName.pOleStr,0,0);

        CoTaskMemFree(pidlItems);
    }

    ppenum->Release();

    return 0;
}

2013年11月15日星期五

官方的驱动中获取内核模块列表的办法

/*
文件名:AuxKlibQueryModuleInformation.C
功能:retrieves information about the image modules that the operating system has loaded.

SOURCE文件内容如下:
TARGETNAME=test

TARGETTYPE=DRIVER

TARGETLIBS=$(DDK_LIB_PATH)\Aux_klib.lib

SOURCES=AuxKlibQueryModuleInformation.C

TARGETPATH=obj

made by correy
made at 2013.11.15
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
不足之处,敬请指出.
*/

#include <ntifs.h>
#include <Aux_klib.h>

#define TAG  'tset' //test

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{  

}

#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    NTSTATUS status = 0;
    ULONG  modulesSize;
    AUX_MODULE_EXTENDED_INFO * modules;
    ULONG  numberOfModules;
    ULONG i;
    PIMAGE_EXPORT_DIRECTORY pied = 0;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;

    status = AuxKlibInitialize();
    if (!NT_SUCCESS( status ))
    {
        KdPrint(( "AuxKlibInitialize fail %d\n", status));
        return status;
    }  
 
    status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), NULL);// Get the required array size.
    if (!NT_SUCCESS(status) || modulesSize == 0) {
        return status;
    }
 
    numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO);// Calculate the number of modules.
     
    modules = (AUX_MODULE_EXTENDED_INFO*) ExAllocatePoolWithTag(PagedPool, modulesSize, TAG);// Allocate memory to receive data.
    if (modules == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        return status;
    }
    RtlZeroMemory(modules, modulesSize);
 
    status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), modules);// Obtain the module information.
    if (!NT_SUCCESS(status)) {
        ExFreePoolWithTag(modules,TAG);
        return status;
    }

    for (i = 0;i<numberOfModules;i++)
    {
        KdPrint(("加载顺序:%d\n",i));
        KdPrint(("FileName:%s\n",modules[i].FullPathName + modules[i].FileNameOffset));
        KdPrint(("ImageBase:%p\n",modules[i].BasicInfo.ImageBase));
        KdPrint(("ImageSize:0x%08x\n",modules[i].ImageSize));
        KdPrint(("FullPathName:%s\n",modules[i].FullPathName));
        KdPrint(("\n\n"));

        //注意传递的地址不要错,要可以访问的,并且是一个文件内存的地址.
        //PVOID ImageBase = modules[i].BasicInfo.ImageBase;
        //pied = AuxKlibGetImageExportDirectory(ImageBase);
        //这里可以打印每个驱动的更多的信息.
    }

    ExFreePoolWithTag(modules,TAG);
    return status;
}

在驱动中获取进程的用户名及SID

/*
文件名:GetSecurityUserInfo.C

功能:获取当前操作注册表的进程的用户.

SOURCE文件内容如下:
TARGETNAME=test

TARGETTYPE=DRIVER

TARGETLIBS=$(DDK_LIB_PATH)\ksecdd.lib 

SOURCES=GetSecurityUserInfo.C 

TARGETPATH=obj

made by correy
made at 2013.11.15
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
不足之处,敬请指出.
*/

#include <ntifs.h>

LARGE_INTEGER  Cookie;

NTSTATUS print_current_user()
    /*
    打印当前操作的当前进程的用户名等.
    */
{
    NTSTATUS status = 0;
    PACCESS_TOKEN pat = 0;    
    UNICODE_STRING  SidString = {0};
    PTOKEN_STATISTICS pts;
    PSecurityUserData  PUserInformation;

    pat = PsReferencePrimaryToken(PsGetCurrentProcess());    

    status = SeQueryInformationToken(pat, TokenStatistics,(PVOID *) & pts);
    if( !NT_SUCCESS( status ) )
    {
        PsDereferencePrimaryToken(pat);
        return status;
    }

    //还有一种情况也会发生如下情况,就是在Windows server 2008 X64上,具体的有待检查和添加.
    if (pts->AuthenticationId.HighPart == 0 && pts->AuthenticationId.LowPart == 999)//为何是这两个数,不得而知.
    {
        //获取到了系统帐户,就是system,本地系统帐户.
        //打印的消息一般如下:
        //UserName :KOUDAQIANG-2008$
        //LogonServer :
        //LogonDomainName :WORKGROUP
        //SID :S-1-5-18

        KdPrint(("UserName:system\n"));

        PsDereferencePrimaryToken(pat);
        return status;
    }

    //可以考虑把下面的代码写成工作线程.

    //下面的函数需要连接Ksecdd.lib,如:TARGETLIBS=$(DDK_LIB_PATH)\ksecdd.lib
    status = GetSecurityUserInfo(&pts->AuthenticationId, 0, &PUserInformation);
    if( !NT_SUCCESS( status ) )
    {
        return status;
    }

    //status = RtlConvertSidToUnicodeString(&SidString, PUserInformation->pSid,TRUE);
    //if( !NT_SUCCESS( status ) )//成功.#define STATUS_INVALID_SID               ((NTSTATUS)0xC0000078L)   -1073741704
    //{
    //    return status;
    //}        

    KdPrint(("UserName:%wZ\n",&PUserInformation->UserName));
    //KdPrint(("LogonServer :%wZ\n",&PUserInformation->LogonServer));
    //KdPrint(("LogonDomainName :%wZ\n",&PUserInformation->LogonDomainName));
    //KdPrint(("SID :%wZ\n",&SidString));

    //RtlFreeUnicodeString(&SidString); 
    LsaFreeReturnBuffer(PUserInformation);

    PsDereferencePrimaryToken(pat);

    return status;
}

EX_CALLBACK_FUNCTION RegistryCallback;
NTSTATUS RegistryCallback(__in PVOID  CallbackContext, __in_opt PVOID  Argument1, __in_opt PVOID  Argument2)
{
    print_current_user();

    return STATUS_SUCCESS;
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{   
    CmUnRegisterCallback(Cookie);
}

#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    KdBreakPoint();

    DriverObject->DriverUnload = Unload; 

    return CmRegisterCallback(RegistryCallback, NULL, &Cookie);
} 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*
文件名:RtlFormatCurrentUserKeyPath.C

功能:获取当前操作注册表的进程的用户的SID.

made by correy
made at 2014.06.14
homepage:http://correy.webs.com
不足之处,敬请指出.
*/

#include <ntifs.h>
#include <windef.h>

//#pragma comment (lib,"ksecdd.lib")

LARGE_INTEGER  Cookie;


//http://msdn.microsoft.com/en-us/library/ff899322(v=vs.85).aspx 
//Initializes the supplied buffer with a string representation of the SID for the current user.
//extern NTSTATUS /*WINAPI*/ RtlFormatCurrentUserKeyPath(/*_Out_*/  UNICODE_STRING CurrentUserKeyPath);  //此函数在XP就已经导出,但直接引用会出现链接错误。
typedef NTSTATUS (WINAPI * RtlFormatCurrentUserKeyPath)(/*_Out_*/  UNICODE_STRING * CurrentUserKeyPath); //那咱就动态获取吧!
//CurrentUserKeyPath [out]
//String that represents the current user's root key in the Registry. Caller must call RtlFreeUnicodeString to free the buffer when done with it.
/*
注意:微软的官方的链接里面是错误的。
开始我还以为这是我第一个发现参数传递结构,而不是指针的。
*/

RtlFormatCurrentUserKeyPath g_p_RtlFormatCurrentUserKeyPath;


PVOID ExpAllocateStringRoutine (IN SIZE_T NumberOfBytes)
{
    return ExAllocatePoolWithTag (PagedPool,NumberOfBytes,'grtS');
}
//上下的定义摘自:\wrk\WindowsResearchKernel-WRK\WRK-v1.2\base\ntos\ex\pool.c
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg("PAGECONST")
#endif
const PRTL_ALLOCATE_STRING_ROUTINE RtlAllocateStringRoutine = ExpAllocateStringRoutine;
const PRTL_FREE_STRING_ROUTINE RtlFreeStringRoutine = (PRTL_FREE_STRING_ROUTINE)ExFreePool;
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg()
#endif


// Maximum size of TOKEN_USER information.
#define SIZE_OF_TOKEN_INFORMATION                   \
    sizeof( TOKEN_USER )                            \
    + sizeof( SID )                                 \
    + sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
//这个函数及上面的定义摘自WRK-v1.2/base/ntos/rtl/regutil.c,但是有修改,可以在驱动中使用或者利用。
NTSTATUS RtlFormatCurrentUserKeyPath0(OUT PUNICODE_STRING CurrentUserKeyPath)
/*++
Routine Description:
    Initialize the supplied buffer with a string representation of the current user's SID.
    这个函数还是有必要说明几点:
    1.要获取当前用户的SID,首先的不是判断SID而是当前用户,再获取SID这很容易。
      一台计算机同时登陆几个不同的用户是正常的。
      通常一个普通的用户一个会话,包括远程登录的。
      所以另一个捷径是判断会话,这有公开/导出的函数。如某个进程或者线程属于哪个会话。
    2.此函数有发掘利用的价值,看你怎么用了。
    3.此函数获取的不是当前登录用户的SID,而是当前的操作的进程的用户的SID,如系统帐户,网络帐户,服务帐户等。

Arguments:
    CurrentUserKeyPath - Returns a string that represents the current user's root key in the Registry.  
    Caller must call RtlFreeUnicodeString to free the buffer when done with it.

Return Value:
    NTSTATUS - Returns STATUS_SUCCESS if the user string was succesfully initialized.
--*/
{
    HANDLE TokenHandle = 0;
    UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ];
    ULONG ReturnLength;
    ULONG SidStringLength = 0 ;//添加初始化为0.
    UNICODE_STRING SidString ;
    NTSTATUS Status;

    // Inside the kernel we can tell rapidly if we are impersonating.
    Status = STATUS_NO_TOKEN;
    if (PsIsThreadTerminating (PsGetCurrentThread ())) {//原来是PS_IS_THREAD_IMPERSONATING。
        Status = ZwOpenThreadTokenEx (NtCurrentThread(), TOKEN_READ, TRUE, OBJ_KERNEL_HANDLE, &TokenHandle);
        if ( !NT_SUCCESS( Status ) && ( Status != STATUS_NO_TOKEN ) ) {
            return Status;
        }
    }

    if ( !NT_SUCCESS( Status ) ) {
        Status = ZwOpenProcessTokenEx (NtCurrentProcess(), TOKEN_READ, OBJ_KERNEL_HANDLE, &TokenHandle);
        if ( !NT_SUCCESS( Status )) {
            return Status;
        }
    }

    Status = ZwQueryInformationToken( TokenHandle, TokenUser, TokenInformation, sizeof( TokenInformation ), &ReturnLength);
    ZwClose( TokenHandle );
    if ( !NT_SUCCESS( Status )) {
        return Status;
    }

    //Status = RtlLengthSidAsUnicodeString(((PTOKEN_USER)TokenInformation)->User.Sid, &SidStringLength);
    //if ( !NT_SUCCESS( Status ) ) {
    //    return Status ;
    //}
    //因为RtlLengthSidAsUnicodeString在XP上没有导出,所以用下面的两个函数替换。
    if (!RtlValidSid(((PTOKEN_USER)TokenInformation)->User.Sid)) {
        return Status ;
    }
    SidStringLength = RtlLengthSid(((PTOKEN_USER)TokenInformation)->User.Sid);
    if (!SidStringLength) {
        return Status ;
    }

    CurrentUserKeyPath->Length = 0;
    CurrentUserKeyPath->MaximumLength = (USHORT)(SidStringLength + sizeof( L"\\REGISTRY\\USER\\" ) + sizeof( UNICODE_NULL ));
    CurrentUserKeyPath->Buffer = (RtlAllocateStringRoutine)( CurrentUserKeyPath->MaximumLength );
    if (CurrentUserKeyPath->Buffer == NULL) {
        return STATUS_NO_MEMORY;
    }
        
    RtlAppendUnicodeToString( CurrentUserKeyPath, L"\\REGISTRY\\USER\\" );// Copy "\REGISTRY\USER" to the current user string.

    SidString.MaximumLength = CurrentUserKeyPath->MaximumLength;//(USHORT)SidStringLength ;这里有修改 原数乘以2应该也可以的,不然RtlConvertSidToUnicodeString失败。
    SidString.Length = 0 ;
    SidString.Buffer = CurrentUserKeyPath->Buffer + (CurrentUserKeyPath->Length / sizeof(WCHAR) );

    Status = RtlConvertSidToUnicodeString( &SidString, ((PTOKEN_USER)TokenInformation)->User.Sid, FALSE);
    if ( !NT_SUCCESS( Status )) {//#define STATUS_BUFFER_OVERFLOW           ((NTSTATUS)0x80000005L)
        RtlFreeUnicodeString( CurrentUserKeyPath );
    } else {
        CurrentUserKeyPath->Length += SidString.Length ;
    }

    return Status;
}


NTSTATUS print_current_user()
    /*
    打印当前操作的当前进程的用户名等.
    */
{
    NTSTATUS status = 0;
    UNICODE_STRING CurrentUserKeyPath = {0};

    status = g_p_RtlFormatCurrentUserKeyPath(&CurrentUserKeyPath);
    if( !NT_SUCCESS( status ) )
    {
        return status;
    }
    KdPrint(("CurrentUserKeyPath:%wZ\n",&CurrentUserKeyPath));//"\REGISTRY\USER\S-1-5-18"
    RtlFreeUnicodeString(&CurrentUserKeyPath);


    status = RtlFormatCurrentUserKeyPath0(&CurrentUserKeyPath);
    if( !NT_SUCCESS( status ) )
    {
        return status;
    }
    KdPrint(("CurrentUserKeyPath:%wZ\n",&CurrentUserKeyPath));//"\REGISTRY\USER\S-1-5-18"
    RtlFreeUnicodeString(&CurrentUserKeyPath);

    return status;
}

EX_CALLBACK_FUNCTION RegistryCallback;
NTSTATUS RegistryCallback(__in PVOID  CallbackContext, __in_opt PVOID  Argument1, __in_opt PVOID  Argument2)
{
    print_current_user();
    return STATUS_SUCCESS;
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{   
    CmUnRegisterCallback(Cookie);
}

#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    UNICODE_STRING us_RtlFormatCurrentUserKeyPath;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload; 

    RtlInitUnicodeString( &us_RtlFormatCurrentUserKeyPath, L"RtlFormatCurrentUserKeyPath" );
    g_p_RtlFormatCurrentUserKeyPath = MmGetSystemRoutineAddress(&us_RtlFormatCurrentUserKeyPath);
    if (g_p_RtlFormatCurrentUserKeyPath == NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }

    return CmRegisterCallback(RegistryCallback, NULL, &Cookie);
} 

2013年11月13日星期三

创建注册表的根键

/*
功能:创建注册表的根键.

尽管:《深入解析windows操作系统》的第四章有如下说明:
There are six root keys (and you can't add new root keys or delete existing ones) that store information

RegLoadKey函数有如下说明:
Creates a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE and loads the data from the specified registry hive into that subkey.

而且:http://msdn.microsoft.com/en-us/library/windows/hardware/ff546907(v=vs.85).aspx
的补充说明里面说不建议使用如下函数.
NtRestoreKey
NtSaveKey
NtSaveKeyEx
NtLoadKeyEx
NtUnloadKey2
NtUnloadKeyEx
NtReplaceKey
NtRenameKey
NtSetInformationKey

这些函数没有公开的调用接口,但是导出了,而且很早的版本就导出了,所以可以安心的使用.

注册表根键创建的成功与失败可以通过代码的返回值查看.
                          也可以通过注册表路径HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\hivelist查看.

不足之处,敬请指出.
made by correy
made at 2013.11.13
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com                        
*/

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
用户层创建注册表根键的代码.

#include <windows.h>

typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
#ifdef MIDL_PASS
    [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
    _Field_size_bytes_part_(MaximumLength, Length) PWCH   Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR
    PVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;

#ifdef __cplusplus
extern "C++"
{
char _RTL_CONSTANT_STRING_type_check(const char *s);
char _RTL_CONSTANT_STRING_type_check(const WCHAR *s);
// __typeof would be desirable here instead of sizeof.
template <size_t N> class _RTL_CONSTANT_STRING_remove_const_template_class;
template <> class _RTL_CONSTANT_STRING_remove_const_template_class<sizeof(char)>  {public: typedef  char T; };
template <> class _RTL_CONSTANT_STRING_remove_const_template_class<sizeof(WCHAR)> {public: typedef WCHAR T; };
#define _RTL_CONSTANT_STRING_remove_const_macro(s) \
    (const_cast<_RTL_CONSTANT_STRING_remove_const_template_class<sizeof((s)[0])>::T*>(s))
}
#else
char _RTL_CONSTANT_STRING_type_check(const void *s);
#define _RTL_CONSTANT_STRING_remove_const_macro(s) (s)
#endif
#define RTL_CONSTANT_STRING(s) \
{ \
    sizeof( s ) - sizeof( (s)[0] ), \
    sizeof( s ) / sizeof(_RTL_CONSTANT_STRING_type_check(s)), \
    _RTL_CONSTANT_STRING_remove_const_macro(s) \
}

#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );          \
    (p)->RootDirectory = r;                             \
    (p)->Attributes = a;                                \
    (p)->ObjectName = n;                                \
    (p)->SecurityDescriptor = s;                        \
    (p)->SecurityQualityOfService = NULL;               \
    }

#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

#define OBJ_INHERIT             0x00000002L
#define OBJ_PERMANENT           0x00000010L
#define OBJ_EXCLUSIVE           0x00000020L
#define OBJ_CASE_INSENSITIVE    0x00000040L
#define OBJ_OPENIF              0x00000080L
#define OBJ_OPENLINK            0x00000100L
#define OBJ_KERNEL_HANDLE       0x00000200L
#define OBJ_FORCE_ACCESS_CHECK  0x00000400L
#define OBJ_VALID_ATTRIBUTES    0x000007F2L

//NTSTATUS ZwUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes);
//NTSTATUS ZwLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes, IN POBJECT_ATTRIBUTES FileObjectAttributes);

//函数指针.
typedef NTSTATUS (WINAPI  * ZWLOADKEY) (IN POBJECT_ATTRIBUTES KeyObjectAttributes, IN POBJECT_ATTRIBUTES FileObjectAttributes);//__stdcall
typedef NTSTATUS (WINAPI * ZWUNLOADKEY) (IN POBJECT_ATTRIBUTES KeyObjectAttributes);//__stdcall

//全局变量
UNICODE_STRING uRegistryPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\correy");
UNICODE_STRING uRegDatPath = RTL_CONSTANT_STRING(L"\\DosDevices\\c:\\correy.DAT");
OBJECT_ATTRIBUTES obj;
OBJECT_ATTRIBUTES HiveFile;
ZWUNLOADKEY ZwUnloadKey;
ZWLOADKEY ZwLoadKey;


BOOL SetPrivilege(
    //HANDLE hToken,          // access token handle
    LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
    BOOL bEnablePrivilege   // to enable or disable privilege
    )
{
    TOKEN_PRIVILEGES tp;
    LUID luid;

    HANDLE hToken; // Get a token for this process.
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        return( FALSE );
    }

    if ( !LookupPrivilegeValue(
        NULL,            // lookup privilege on local system
        lpszPrivilege,   // privilege to lookup
        &luid ) )        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError() );
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.
    if ( !AdjustTokenPrivileges(
        hToken,
        FALSE,
        &tp,
        sizeof(TOKEN_PRIVILEGES),
        (PTOKEN_PRIVILEGES) NULL,
        (PDWORD) NULL) )
    {
        printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
        return FALSE;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
        printf("The token does not have the specified privilege. \n");
        return FALSE;
    }

    return TRUE;
}


void main( )
{
    BOOL B;

    B = SetPrivilege(SE_BACKUP_NAME, TRUE);
    B = SetPrivilege(SE_RESTORE_NAME, TRUE);//必须加上这个RegSaveKey才成功.

    int r;

    LONG l = RegSaveKey(HKEY_CURRENT_USER, L"c:\\correy.dat", NULL);//如果已经存在,即使不在使用中,这个会失败.
    if (l != ERROR_SUCCESS)
    {
        r = GetLastError();
    }

    InitializeObjectAttributes(&obj,&uRegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL );//|OBJ_KERNEL_HANDLE
    InitializeObjectAttributes(&HiveFile,&uRegDatPath,OBJ_CASE_INSENSITIVE, NULL, NULL );//|OBJ_KERNEL_HANDLE

    HINSTANCE hinstLib = LoadLibrary(TEXT("ntdll.dll")); // Get a handle to the DLL module.    
    if (hinstLib != NULL) // If the handle is valid, try to get the function address.
    {
        ZwLoadKey = (ZWLOADKEY) GetProcAddress(hinstLib, "NtLoadKey");
        if (NULL != ZwLoadKey) // If the function address is valid, call the function.
        {
            NTSTATUS status = ZwLoadKey(&obj,&HiveFile);//只一行运行会出错.
            if(!NT_SUCCESS(status))
            {
                MessageBox(0,0,0,0);
                //return;
            }
        }  

        MessageBox(0,L"下面开始卸载",0,0);

        ZwUnloadKey = (ZWUNLOADKEY) GetProcAddress(hinstLib, "NtUnloadKey");
        if (NULL != ZwUnloadKey) // If the function address is valid, call the function.
        {
            NTSTATUS status = ZwUnloadKey(&obj);//只一行运行会出错.
            if(!NT_SUCCESS(status))
            {
                MessageBox(0,0,0,0);
                //return;
            }
        }

        FreeLibrary(hinstLib); // Free the DLL module.
    }

    //BOOL b = CopyFile(L"C:\\Users\\Administrator\\NTUSER.DAT", L"c:\\hkcu_copy.dat",false);
    //if (!b)
    //{
    //    r = GetLastError();//0x00000020,另一个程序(system)正在使用此文件,进程无法访问。
    //}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
驱动层创建注册表根键的代码如下:

#include <ntifs.h>

NTSTATUS ZwUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes);
NTSTATUS ZwLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes, IN POBJECT_ATTRIBUTES FileObjectAttributes);

UNICODE_STRING uRegistryPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\correy");
UNICODE_STRING uRegDatPath = RTL_CONSTANT_STRING(L"\\DosDevices\\c:\\correy.DAT");//此文件必须是本计算机的,系统的或者自己生成的.
OBJECT_ATTRIBUTES obj;
OBJECT_ATTRIBUTES HiveFile;

VOID RegisterLoad()
{
    NTSTATUS status;
    HANDLE hRegister;
    ULONG i=0,ulSize=0;
    UNICODE_STRING us;

    status = ZwLoadKey(&obj,&HiveFile);
    if(!NT_SUCCESS(status))
    {
        DbgPrint("LoadKey failed Error: [%x] \n", status);
        return;
    }

    //一下是列举其子键的,也就是验证下.
    status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &obj);
    if (NT_SUCCESS(status))
    {        
        PKEY_FULL_INFORMATION pfi;

        ZwQueryKey(hRegister, KeyFullInformation, NULL, 0, &ulSize);
        pfi = (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);// 第一次调用是为了获取需要的长度

        ZwQueryKey(hRegister, KeyFullInformation, pfi, ulSize, &ulSize);// 第二次调用是为了获取数据
        for (i = 0; i < pfi->SubKeys; i++)
        {    
            PKEY_BASIC_INFORMATION pbi;

            ZwEnumerateKey(hRegister, i, KeyBasicInformation, NULL, 0, &ulSize);// 获取第i个子项的长度
            pbi = (PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);        

            ZwEnumerateKey(hRegister, i, KeyBasicInformation, pbi, ulSize, &ulSize);// 获取第i个子项的数据

            us.Buffer = pbi->Name;
            us.Length = (USHORT)pbi->NameLength;
            us.MaximumLength = pbi->NameLength + sizeof(wchar_t);

            DbgPrint("The %d SubItem Name : %wZ\n", i, &us);

            ExFreePool(pbi);// 释放内存
        }

        ExFreePool(pfi);
        ZwClose(hRegister);
    } else {
        DbgPrint("ZwOpenKey failed unknown cause. Error: [%x] \n", status);
    }
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{  
    NTSTATUS status;  

    status = ZwUnloadKey(&obj);
    if(!NT_SUCCESS(status))
    {
        DbgPrint("ZwUnloadKey fail!\n");
    }
}

#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    NTSTATUS Status = 0;

    KdBreakPoint();// == DbgBreakPoint()

    DriverObject->DriverUnload = Unload;  

    InitializeObjectAttributes(&obj,&uRegistryPath, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL );
    InitializeObjectAttributes(&HiveFile,&uRegDatPath,OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL );

    RegisterLoad();  

    return Status;
}

minifilter通讯之简单示例

应用层的代码如下:

/*
名字:minifilter通讯之简单示例.之所以说简单是因为没有列举异步,多线程等全面和安全的用法.

个人感觉FilterSendMessage就像DeviceIoControl,可以发送和接受信息.
        但是要自定义格式结构,驱动收到了再解析.

FilterGetMessage和FilterReplyMessage可能需要多线程或者异步等措施,这里不列举了,只是简单列举一下调用:

//FILTER_MESSAGE_HEADER  MessageBuffer;
//hResult = FilterGetMessage(port, &MessageBuffer, sizeof (FILTER_MESSAGE_HEADER), 0);
//if (IS_ERROR( hResult )) {
//    OutputDebugString(L"FilterGetMessage fail!\n");
//} else {
//    OutputDebugString(L"FilterGetMessage ok!\n");
//}

//FILTER_REPLY_HEADER  ReplyBuffer;
//hResult = FilterReplyMessage(port, &ReplyBuffer,sizeof(FILTER_REPLY_HEADER));
//if (IS_ERROR( hResult )) {
//    OutputDebugString(L"FilterReplyMessage fail!\n");
//} else {
//    OutputDebugString(L"FilterReplyMessage ok!\n");
//}

不足之处,敬请指出.
made by correy
made at 2013.11.13
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com

效果如下(包括驱动打印的消息):
用户发来的信息是:test
[1124] FilterSendMessage ok!
[1124] 从内核发来的信息是:
[1124] to user client
[1124]

*/

#include <windows.h>

//这两个文件在VS中没有,在WDK中有.
//如果要用VS编译要拷贝相应的文件到相应的目录或者改变目录的设置等.
#include <fltuser.h>
#pragma comment(lib, "fltLib.lib")

int _tmain(int argc, _TCHAR* argv[])
{
    MessageBox(0,L"请附加调试器",L"调试专用",0);//如果是远程调试的话,这行特别有用.

    HANDLE port = INVALID_HANDLE_VALUE;
    HRESULT hResult = S_OK;

    hResult = FilterConnectCommunicationPort( L"\\CommunicationPort", 0, NULL, 0, NULL, &port );
    if (IS_ERROR( hResult )) {
        OutputDebugString(L"FilterConnectCommunicationPort fail!\n");
        return hResult;
    }

    wchar_t InBuffer[] = L"test";
    wchar_t OutBuffer[MAX_PATH] = {0};
    DWORD bytesReturned = 0;
    hResult = FilterSendMessage(port, InBuffer, lstrlen(InBuffer), OutBuffer, sizeof(OutBuffer), &bytesReturned);
    if (IS_ERROR( hResult )) {
        OutputDebugString(L"FilterSendMessage fail!\n");
        CloseHandle( port );
        return hResult;
    } else {
        OutputDebugString(L"FilterSendMessage ok!\n");
    }

    OutputDebugString(L"从内核发来的信息是:");
    OutputDebugString(OutBuffer);
    OutputDebugString(L"\n");

    CloseHandle( port );

 return 0;
}

驱动的代码如下:

/*
内核中没有:FltGetMessage,FltReplyMessage函数.
个人认为:MessageNotifyCallback有FltGetMessage,FltReplyMessage,FltSendMessage这三个函数的功能.
所以在MessageNotifyCallback里面调用这些函数是不对的,得到一些意想不到的效果.建议不要这样做.

FltGetMessage除了在MessageNotifyCallback里面,大多的地方都可以调用,但是用户层最好开启线程处理函数.

FltGetMessage函数调用示例代码如下:
//{
//    wchar_t SenderBuffer[] = L"SenderBuffer";
//    wchar_t ReplyBuffer[] = L"ReplyBuffer";
//    ULONG replyLength = sizeof(ReplyBuffer);
//
//    status = FltSendMessage( gFilterHandle, &g_ClientPort, SenderBuffer, sizeof(SenderBuffer), ReplyBuffer, &replyLength, NULL);
//    if (STATUS_SUCCESS == status) {
//        DbgPrint( "send message to user-mode\n");       
//    } else {
//        DbgPrint( "couldn't send message to user-mode to scan file, status 0x%X\n", status );
//    }
//}
*/

#include <fltKernel.h>

PFLT_FILTER gFilterHandle;
PFLT_PORT g_ServerPort;
PFLT_PORT g_ClientPort;

NTSTATUS MessageNotifyCallback (
    IN PVOID PortCookie,
    IN PVOID InputBuffer OPTIONAL,
    IN ULONG InputBufferLength,
    OUT PVOID OutputBuffer OPTIONAL,
    IN ULONG OutputBufferLength,//用户可以接受的数据的最大长度.
    OUT PULONG ReturnOutputBufferLength)
    /*
    这里要注意:1.数据地址的对齐.
               2.文档建议使用:try/except处理.
               3.如果是64位的驱动要考虑32位的EXE发来的请求.
    */
{
    NTSTATUS status = 0;
    wchar_t buffer[] = L"to user client";//
    
    PAGED_CODE();

    UNREFERENCED_PARAMETER(PortCookie);

    //打印用户发来的信息
    KdPrint(("用户发来的信息是:%ls\n",InputBuffer));

    //返回用户一些信息.
    *ReturnOutputBufferLength = sizeof(buffer);
    RtlCopyMemory(OutputBuffer,buffer,* ReturnOutputBufferLength);

    /*
    minispy在这里用FilterSendMessage获取信息的,对就是FilterSendMessage.
    这里某个类型里面获取信息,这些信息是在各种操作时(IRP的MJ_)加入链表的.
    注意链表的操作一定要同步,支持多线程.
    然后用户的一个线程在不停的获取这些信息.
    */

    return status;
}

VOID DisconnectNotifyCallback (_In_opt_ PVOID ConnectionCookie)
{
    PAGED_CODE();

    UNREFERENCED_PARAMETER(ConnectionCookie);

    FltCloseClientPort(gFilterHandle, &g_ClientPort);//应该加判断,如果ConnectionCookie == 我们的值就执行这行.
}

NTSTATUS ConnectNotifyCallback (IN PFLT_PORT ClientPort, IN PVOID ServerPortCookie, IN PVOID ConnectionContext, IN ULONG SizeOfContext, OUT PVOID * ConnectionPortCookie)
{
    PAGED_CODE();

    UNREFERENCED_PARAMETER( ServerPortCookie );
    UNREFERENCED_PARAMETER( ConnectionContext );
    UNREFERENCED_PARAMETER( SizeOfContext);
    UNREFERENCED_PARAMETER( ConnectionPortCookie);

    //可以加以判断,禁止非法的连接,从而给予保护.
    g_ClientPort = ClientPort;//保存以供以后使用.

    return STATUS_SUCCESS;
}

#pragma PAGEDCODE
NTSTATUS PtInstanceQueryTeardown (__in PCFLT_RELATED_OBJECTS FltObjects,__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
{
    return STATUS_SUCCESS;
}

#pragma PAGEDCODE//#pragma alloc_text(PAGE, PtUnload)
NTSTATUS PtUnload (__in FLT_FILTER_UNLOAD_FLAGS Flags)
{
    FltCloseCommunicationPort(g_ServerPort);//没有这一行是停止不了驱动的,查询也是永远等待中.
    FltUnregisterFilter( gFilterHandle );
    return STATUS_SUCCESS;
}

CONST FLT_REGISTRATION FilterRegistration = {
    sizeof( FLT_REGISTRATION ),         //  Size
    FLT_REGISTRATION_VERSION,           //  Version
    0,                                  //  Flags
    NULL,                               //  Context
    NULL,                               //  Operation callbacks
    PtUnload,                           //  MiniFilterUnload
    NULL,                               //  InstanceSetup
    PtInstanceQueryTeardown,            //  InstanceQueryTeardown
    NULL,                               //  InstanceTeardownStart
    NULL,                               //  InstanceTeardownComplete
    NULL,                               //  GenerateFileName
    NULL,                               //  GenerateDestinationFileName
    NULL                                //  NormalizeNameComponent
};

DRIVER_INITIALIZE DriverEntry;
#pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE
NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS status;
    PSECURITY_DESCRIPTOR sd;
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING uniString;

    UNREFERENCED_PARAMETER(RegistryPath);

    KdBreakPoint();

    __try
    {
        status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle); 
        if (!NT_SUCCESS(status)) //;
        {       
            __leave;
        }

        status  = FltBuildDefaultSecurityDescriptor(&sd, FLT_PORT_ALL_ACCESS);
        if (!NT_SUCCESS( status )) {
            __leave;
        }

        RtlInitUnicodeString(&uniString, L"\\CommunicationPort");
        InitializeObjectAttributes( &oa, &uniString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, sd);
        status = FltCreateCommunicationPort(gFilterHandle, &g_ServerPort, &oa, NULL, ConnectNotifyCallback, DisconnectNotifyCallback, MessageNotifyCallback, 1);
        FltFreeSecurityDescriptor( sd );
        if (!NT_SUCCESS( status )) {
            __leave;
        }

        status = FltStartFiltering(gFilterHandle);//这个结果在下面判断.
    } __finally {
        if (!NT_SUCCESS( status ) )
        {
            if (NULL != g_ServerPort) {
                FltCloseCommunicationPort(g_ServerPort);
            }

            if (NULL != gFilterHandle) {
                FltUnregisterFilter(gFilterHandle);
            }
        }       
    }

    return status;
}