现在的位置: 首页 > 综合 > 正文

内核模式下的文件与注册表操作

2013年08月15日 ⁄ 综合 ⁄ 共 7508字 ⁄ 字号 评论关闭

和应用程序一样,取得程序也要经常和文件和注册表打交道。只不过在Ring0下对这些的操作和在Ring3下的操作不同。这里简单介绍下内核模式下文件和注册表的操作。

    首先是在驱动中读写文件。首先是打开文件的操作。由于在内核并不能直接接受一个字符串,所以我们必须填写一个OBJECT_ATTRIBUTES 结构,这个结构必须先被InitializeObjectAttributes初始化。

    然后在内核中文件操作的函数有——打开文件:ZwCreateFile ;读文件:ZwReadFile
;写文件:ZwWriteFile ;获取文件属性:ZwQueryInformationFile
;修改文件属性:ZwSetInformationFile 。下面来看段代码说明问题:

BOOLEAN
MyCopyFile(
           IN PUNICODE_STRING    ustrDestFile,
           IN PUNICODE_STRING    ustrSrcFile
            )
{
    HANDLE hSrcFile, hDestFile;
    PVOID buffer = NULL;
    ULONG length = 0;
    LARGE_INTEGER offset = {0};
    IO_STATUS_BLOCK Io_Status_Block = {0};
    OBJECT_ATTRIBUTES obj_attrib;
    NTSTATUS status;
    BOOLEAN   bRet = FALSE;
FILE_BASIC_INFORMATION fpi;

    do
    {
        // 打开源文件
        InitializeObjectAttributes(&obj_attrib,
           ustrSrcFile,
           OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
           NULL,
           NULL);
        status = ZwCreateFile(&hSrcFile,
         GENERIC_READ,
         &obj_attrib,
         &Io_Status_Block,
         NULL,
         FILE_ATTRIBUTE_NORMAL,
         FILE_SHARE_READ,
         FILE_OPEN,
         FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
         NULL,
         0);
        if (!NT_SUCCESS(status))
        {
            bRet = FALSE;
            goto END;
        }

        // 打开目标文件
        InitializeObjectAttributes(&obj_attrib,
           ustrDestFile,
           OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
           NULL,
           NULL);
        status = ZwCreateFile(&hDestFile,
         GENERIC_WRITE,
         &obj_attrib,
         &Io_Status_Block,
         NULL,
         FILE_ATTRIBUTE_NORMAL,
         FILE_SHARE_READ,
         FILE_OPEN_IF,
         FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
         NULL,
         0);
        if (!NT_SUCCESS(status))
        {
            bRet = FALSE;
            goto END;
        }

        // 为buffer分配10KB空间
        buffer = ExAllocatePool(NonPagedPool, 1024 * 10);
        if (buffer == NULL)
        {
            bRet = FALSE;
            goto END;
        }

        // 复制文件
        while (1)
        {
            length = 10 * 1024;
            // 读取源文件
            status = ZwReadFile(hSrcFile,
                            NULL,
                            NULL,
                            NULL,
                            &Io_Status_Block,
                            buffer,
                            length,
                            &offset,
                            NULL);
            if (!NT_SUCCESS(status))
            {
                // 如果状态为STATUS_END_OF_FILE,说明文件已经读取到末尾
                if (status == STATUS_END_OF_FILE)
                {
                    bRet = TRUE;
                    goto END;
                }
            }

            // 获得实际读取的长度
            length = Io_Status_Block.Information;

            // 写入到目标文件
            status = ZwWriteFile(hDestFile,
                                NULL,
                                NULL,
                                NULL,
                                &Io_Status_Block,
                                buffer,
                                length,
                                &offset,
                                NULL);
            if (!NT_SUCCESS(status))
            {
                bRet = FALSE;
                goto END;
            }
           
            // 移动文件指针
            offset.QuadPart += length;
        }
    //读取文件长度
status = ZwQueryInformationFile(hDestFile,
          &Io_Status_Block,
          &offset,
          sizeof(FILE_STANDARD_INFORMATION),
          FileStandardInformation);

fpi.FileAttributes = FILE_ATTRIBUTE_HIDDEN; //设置文件属性为隐藏,可是实际操作中并不能成功,我还没找到问题的解决方法。
status = ZwSetInformationFile(hDestFile,
         &Io_Status_Block,
         &fpi,
         sizeof(FILE_BASIC_INFORMATION),
         FileBasicInformation);
if (NT_SUCCESS(status))
  
{
   KdPrint((”update the file successfully./n”));
   goto END;
}
    } while (0);
END:
    if (hSrcFile)
    {
        ZwClose(hSrcFile);
    }
    if (hDestFile)
    {
        ZwClose(hDestFile);
    }
    if (buffer = NULL)
    {
        ExFreePool(buffer);
    }

    return bRet;
}

    调用代码如下:

RtlInitUnicodeString(&ustrSrcFile, L”//??//C://windows//system32//cmd.exe

“);
RtlInitUnicodeString(&ustrDestFile, L”//??//C://cmd1.exe

“);
  
接下来是注册表的操作。和文件操作类似,在操作注册表之前需要首先打开注册表,获得一个句柄,然后通过这个句柄来实现各种操作。打开注册表使用函数
ZwOpenKey ,新建或打开用ZwCreatKey 。ZwOpenKey
函数是简化版的打开注册表操作。修改注册表是ZwSetValueKey。查询键值是ZwQueryValueKey。

    枚举注册表子项使用 ZwQueryKey和 ZwEnumerateKey配合完成,枚举子键使用 ZwQueryKey和 ZwEnumerateValueKey配合完成。

    值得注意的是在内核编程里注册表各子键的路径和在Ring3下的不一样,

    HEKY_LOCAL_MACHINE对应在内核编程里的写法是/Registery/Machine

    HEKY_USERS对应在内核编程里的写法是/Registry/User

    HEKY_CLASSES_ROOT和HEKY_CURRENT_USER在内核编程中没有对应的路径,但是可以通过其他方法得到。

    下面给出个简单的代码来实现注册表的枚举:

    NTSTATUS
RegEnumTest() //枚举注册表子项函数
{
    UNICODE_STRING ustrRegString;
    UNICODE_STRING ustrKeyName;
    HANDLE hRegister;
    ULONG ulSize, i = 0;
    OBJECT_ATTRIBUTES obj_attrib;
    NTSTATUS status;
    PKEY_FULL_INFORMATION pfi;
    PKEY_BASIC_INFORMATION pbi;

    // 初始化
RtlInitUnicodeString(&ustrRegString,L”//Registry//Machine//SOFTWARE//360Safe

“);
    InitializeObjectAttributes(&obj_attrib,
        &ustrRegString,
        OBJ_CASE_INSENSITIVE,
        NULL,
        NULL);
// 打开注册表
    status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &obj_attrib);
    if (NT_SUCCESS(status))
    {
        KdPrint((”[Test] ZwOpenKey %wZ Success!”, ustrRegString));
    }
   
    // 第一次调用是为了获取需要的长度
    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++)
    {
        // 获取第i个子项的长度
        ZwEnumerateKey(hRegister, i, KeyBasicInformation, NULL, 0, &ulSize);
        pbi = (PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);
  
        // 获取第i个子项的数据
        ZwEnumerateKey(hRegister, i, KeyBasicInformation, pbi, ulSize, &ulSize);
        ustrKeyName.Length = (USHORT)pbi->NameLength;
        ustrKeyName.Buffer = pbi->Name;
       
   KdPrint((”[Test] The %d SubItem Name : %wZ./n”, i, &ustrKeyName));
  
        // 释放内存
        ExFreePool(pbi);
    }

    ExFreePool(pfi);
    ZwClose(hRegister);

    return STATUS_SUCCESS;
}

————————————————————————————————————
NTSTATUS
RegEnumSubValueTest()   //枚举注册表子键函数
{
UNICODE_STRING RegUnicodeString;
HANDLE hRegister;
ULONG ulSize;
NTSTATUS ntStatus;
UNICODE_STRING uniKeyName;
PKEY_VALUE_BASIC_INFORMATION pvbi;
PKEY_FULL_INFORMATION pfi;
ULONG i;
OBJECT_ATTRIBUTES objectAttributes;
//初始化UNICODE_STRING字符串
RtlInitUnicodeString( &RegUnicodeString,
   L”//Registry//Machine//SOFTWARE//360Safe

“);

//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
        &RegUnicodeString,
        OBJ_CASE_INSENSITIVE,//对大小写敏感
        NULL,
        NULL );
//打开注册表
    ntStatus = ZwOpenKey( &hRegister,
        KEY_ALL_ACCESS,
        &objectAttributes);

if (NT_SUCCESS(ntStatus))
{
   KdPrint((”Open register successfully/n”));
}
ZwQueryKey(hRegister,
   KeyFullInformation,
   NULL,
   0,
   &ulSize);

pfi=(PKEY_FULL_INFORMATION)
   ExAllocatePool(PagedPool,ulSize);

ZwQueryKey(hRegister,
   KeyFullInformation,
   pfi,
   ulSize,
   &ulSize);

for ( i=0;i<pfi->Values;i++)
{
   ZwEnumerateValueKey(hRegister,
     i,
     KeyValueBasicInformation,
     NULL,
     0,
     &ulSize);

pvbi =(PKEY_VALUE_BASIC_INFORMATION)
    ExAllocatePool(PagedPool,ulSize);

   ZwEnumerateValueKey(hRegister,
     i,
     KeyValueBasicInformation,
     pvbi,
     ulSize,
     &ulSize);
   uniKeyName.Length =
   uniKeyName.MaximumLength =
   (USHORT)pvbi->NameLength;

   uniKeyName.Buffer = pvbi->Name;

   KdPrint((”The %d sub value name:%wZ/n”,i,&uniKeyName));

   if (pvbi->Type==REG_SZ)
   {
    KdPrint((”The sub value type:REG_SZ/n”));
   }else if (pvbi->Type==REG_MULTI_SZ)
   {
    KdPrint((”The sub value type:REG_MULTI_SZ/n”));

   }else if (pvbi->Type==REG_DWORD)
   {
    KdPrint((”The sub value type:REG_DWORD/n”));
   }else if (pvbi->Type==REG_BINARY)
   {
    KdPrint((”The sub value type:REG_BINARY/n”));
   }

   ExFreePool(pvbi);
}

ExFreePool(pfi);
ZwClose(hRegister);
return STATUS_SUCCESS;
}

抱歉!评论已关闭.