驱动学习笔记2

来源:互联网 发布:奥尼尔06总决赛数据 编辑:程序博客网 时间:2024/06/06 23:16

1.文件操作
a)OBJECT_ATTRIBUTES
b)VOID InitializeObjectAttributes(
    OUT POBJECT_ATTRIBUTES InitializedAttributes,
    IN PUNICODE_STRING ObjectName,  // 文件的路径 L”//??//C://a.dat”,//??//为设备链的路径
    IN ULONG Attributes,  // OBJ_CASE_INSENSITIVE| OBJ_KERNEL_HANDLE
    IN HANDLE RootDirectory,  // NULL
    IN PSECURITY_DESCRIPTOR SecurityDescriptor);  // 用于设置安全描述符,OBJ_KERNEL_HANDLE情况下可以不用设置此参数
c)创建文件
NTSTATUS ZwCreateFile(
    OUT PHANDLE FileHandle,  // 是一个句柄的指针                  
    IN ACCESS_MASK DesiredAccess,   // 申请的权限。          
    IN POBJECT_ATTRIBUTES ObjectAttribute,   
    OUT PIO_STATUS_BLOCK IoStatusBlock, // 返回值,status和information
    IN PLARGE_INTEGER AllocationSize OPTIONAL, // NULL
    IN ULONG FileAttributes,  // FILE_ATTRIBUTE_NORMAL
    IN ULONG ShareAccess, // 共享访问 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE
    IN ULONG CreateDisposition, // 打开意图
    IN ULONG createOptions, // FILE_ DIRECTORY_FILE,FILE_NON_DIRECTORY_FILE是否打开目录。 FILE_SYNCHRONOUS_IO_NONALERT同步操作,写文件阻塞,与SYNCHRONIZE联用。
    IN PVOID EaBuffer OPTIONAL, // FILE_NO_INTERMEDIATE_BUFFERING 按磁盘扇区大小对齐
    IN ULONG EaLength);
d)文件访问属性可用|组合
FILE_WRITE_DATA
FILE_READ_DATA
DELETE
FILE_WRITE_ATTRIBUTES
FILE_READ_ATTRIBUTES
GENERIC_READ -  常用的读权限组合
GENERIC_WRITE - 常用的写权限组合
GENERIC_ALL - 全部权限
SYNCHRONIZE - 同步打开文件
e)返回信息
FILE_CREATED:文件被成功的新建了。
FILE_OPENED:    文件被打开了。
FILE_OVERWRITTEN:文件被覆盖了。
FILE_SUPERSEDED:    文件被替代了。
FILE_EXISTS:文件已存在。(因而打开失败了)。
FILE_DOES_NOT_EXIST:文件不存在。(因而打开失败了)。
f)文件打开意图
FILE_CREATE:新建文件。如果文件已经存在,则这个请求失败。
FILE_OPEN:打开文件。如果文件不存在,则请求失败。
FILE_OPEN_IF:打开或新建。如果文件存在,则打开。如果不存在,则失败。
FILE_OVERWRITE:覆盖。如果文件存在,则打开并覆盖其内容。如果文件不存在,这个请求返回失败。
FILE_OVERWRITE_IF:新建或覆盖。如果要打开的文件已存在,则打开它,并覆盖其内存。如果不存在,则简单的新建新文件。
FILE_SUPERSEDE:新建或取代。如果要打开的文件已存在。则生成一个新文件替代之。如果不存在,则简单的生成新文件。
g)打开文件例子
    // 要返回的文件句柄
    HANDLE file_handle = NULL;
    // 返回值
    NTSTATUS status;
    // 首先初始化含有文件路径的OBJECT_ATTRIBUTES
    OBJECT_ATTRIBUTES object_attributes;
    UNICODE_STRING ufile_name = RTL_CONST_STRING(L”//??//C://a.dat”);
    InitializeObjectAttributes(
        &object_attributes,
        &ufile_name,
        OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
        NULL,
        NULL);
    // 以OPEN_IF方式打开文件。
    status = ZwCreateFile(
        &file_handle,
        GENERIC_READ | GENERIC_WRITE,
        &object_attributes,
        &io_status,
        NULL,
        FILE_ATTRIBUTE_NORMAL,
        FILE_SHARE_READ,
        FILE_OPEN_IF,
        FILE_NON_DIRECTORY_FILE |
        FILE_RANDOM_ACCESS |
        FILE_SYNCHRONOUS_IO_NONALERT,
        NULL,
        0);
h)ZwClose(file_handle);
i)读文件/写文件
    NTSTATUS ZwReadFile/ZwWriteFile(
        IN HANDLE  FileHandle,
        IN HANDLE  Event  OPTIONAL,  // 异步读写完成事件,同步读写时为NULL
        IN PIO_APC_ROUTINE  ApcRoutine  OPTIONAL, // 异步读写完成回调例程,同步读写时为NULL
        IN PVOID  ApcContext  OPTIONAL,
        OUT PIO_STATUS_BLOCK  IoStatusBlock,  // 返回结果状态
        OUT PVOID  Buffer,  // 缓冲区
        IN ULONG  Length, // 描述缓冲区的长度,这个长度也就是试图读取文件的长度。
        IN PLARGE_INTEGER  ByteOffset  OPTIONAL, // 要读取的文件的偏移量
        IN PULONG  Key  OPTIONAL); // 读取文件时用的一种附加信息,一般不使用。设置NULL。
j)复制文件的例子
NTSTATUS MyCopyFile(
    PUNICODE_STRING target_path,
    PUNICODE_STRING source_path)
{
    // 源和目标的文件句柄
    HANDLE target = NULL,source = NULL;
    // 用来拷贝的缓冲区
    PVOID buffer = NULL;
    LARGE_INTEGER offset = { 0 };
    IO_STATUS_BLOCK io_status = { 0 };
    do {
        // 这里请用前一小节说到的例子打开target_path和source_path所对应的
        // 句柄target和source,并为buffer分配一个页面也就是4k的内存。
        … …
        // 然后用一个循环来读取文件。每次从源文件中读取4k内容,然后往
        // 目标文件中写入4k,直到拷贝结束为止。
         while(1) {
            length = 4*1024;        // 每次读取4k。
            // 读取旧文件。注意status。
            status = ZwReadFile (
                    source,NULL,NULL,NULL,
                    &my_io_status,buffer, length,&offset,
                    NULL);
            if(!NT_SUCCESS(status))
            {
                // 如果状态为STATUS_END_OF_FILE,则说明文件
                // 的拷贝已经成功的结束了。
                if(status == STATUS_END_OF_FILE)
                    status = STATUS_SUCCESS;
                break;
            }
            // 获得实际读取到的长度。
            length = IoStatus.Information;

            // 现在读取了内容。读出的长度为length.那么我写入
            // 的长度也应该是length。写入必须成功。如果失败,
            // 则返回错误。
            status = ZwWriteFile(
                target,NULL,NULL,NULL,
                &my_io_status,
                buffer,length,&offset,
                NULL);
            if(!NT_SUCCESS(status))
                break;
            // offset移动,然后继续。直到出现STATUS_END_OF_FILE
            // 的时候才结束。
            offset.QuadPart += length;
        }
    } while(0);

    // 在退出之前,释放资源,关闭所有的句柄。
    if(target != NULL)
        ZwClose(target);
    if(source != NULL)
        ZwClose(source);
    if(buffer != NULL)
        ExFreePool(buffer);
    return STATUS_SUCCESS;
}

2.注册表操作
a)路径

应用编程中对应的子键驱动编程中的路径写法HKEY_LOCAL_MACHINE/Registry/MachineHKEY_USERS/Registry/UserHKEY_CLASSES_ROOT没有对应的路径HKEY_CURRENT_USER没有简单的对应路径,但是可以求得

      应用程序和驱动程序很大的一个不同在于应用程序总是由某个“当前用户”启动的。因此可以直接读取HKEY_CLASSES_ROOT和HKEY_CURRENT_USER。而驱动程序和用户无关,所以直接去打开HKEY_CURRENT_USER也就不符合逻辑了
路径举例:
应用层L"//Registry//Machine//SOFTWARE//Microsoft//Windows NT//CurrentVersion"
驱动层"HKEY_LOCAL_MACHINE//SOFTWARE//Microsoft//Windows NT//CurrentVersion"
b)创建,打开注册表项
NTSTATUS ZwOpenKey/ZwCreateKey(
            OUT PHANDLE  KeyHandle,
               IN ACCESS_MASK  DesiredAccess,
            IN POBJECT_ATTRIBUTES  ObjectAttributes
        );
KEY_QUERY_VALUE:读取键下的值。
KEY_SET_VALUE:设置键下的值。
KEY_CREATE_SUB_KEY:生成子键。
KEY_ENUMERATE_SUB_KEYS:枚举子键。
KEY_READ:通用读权限组合
KEY_WRITE:通用写权限组合
KEY_ALL_ACCESS:通用写权限组合
c)读
NTSTATUS ZwQueryValueKey(
    IN HANDLE  KeyHandle,
    IN PUNICODE_STRING  ValueName, // 要读取的值的名字
    IN KEY_VALUE_INFORMATION_CLASS  KeyValueInformationClass,  // KeyValuePartialInformation
    OUT PVOID  KeyValueInformation,
    IN ULONG  Length, // 用户传入的输出空间KeyValueInformation的长度
    OUT PULONG  ResultLength  // 返回实际需要的长度
    );
KeyValueInformationClass:本次查询所需要查询的信息类型。这有如下的三种可能。
     KeyValueBasicInformation:获得基础信息,包含值名和类型。
     KeyValueFullInformation:获得完整信息。包含值名、类型和值的数据。
     KeyValuePartialInformation:获得局部信息。包含类型和值数据。
KeyValueInformation
typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
    ULONG  TitleIndex;           // 请忽略这个成员
    ULONG  Type;                   // 常见数据类型 REG_BINARY:十六进制数据。REG_DWORD:四字节整数。REG_SZ:以空结束的Unicode字符串。
    ULONG  DataLength;        // 数据长度
    UCHAR  Data[1];               // 可变长度的数据
}KEY_VALUE_PARTIAL_INFORMATION,*PKEY_VALUE_PARTIAL_INFORMATIO;
读取未知长度的键值时,最好反复尝试数据长度,而不是给一个足够大的长度。
d)读取例程
     // 要读取的值的名字
    UNICODE_STRING my_key_name =
        RTL_CONSTANT_STRING(L”SystemRoot”);
    // 用来试探大小的key_infor
    KEY_VALUE_PARTIAL_INFORMATION key_infor;
    // 最后实际用到的key_infor指针。内存分配在堆中
    PKEY_VALUE_PARTIAL_INFORMATION ac_key_infor;
    ULONG ac_length;
    ……
    // 前面已经打开了句柄my_key,下面如此来读取值:
    status = ZwQueryValueKey(
        my_key,
        &my_key_name,
        KeyValuePartialInformation,
        &key_infor,
        sizeof(KEY_VALUE_PARTIAL_INFORMATION),
        &ac_length);
    if(!NT_SUCCESS(status) &&
        status != STATUS_BUFFER_OVERFLOW &&
        status != STATUS_BUFFER_TOO_SMALL)
    {
        // 错误处理
        …   
    }
    // 如果没失败,那么分配足够的空间,再次读取
    ac_key_infor = (PKEY_VALUE_PARTIAL_INFORMATION)
        ExAllocatePoolWithTag(NonpagedPool,ac_length ,MEM_TAG);
    if(ac_key_infor == NULL)
    {
        stauts = STATUS_INSUFFICIENT_RESOURCES;
        // 错误处理
        …
    }
    status = ZwQueryValueKey(
        my_key,
        &my_key_name,
        KeyValuePartialInformation,
        ac_key_infor,
        ac_length,
        &ac_length);
    // 到此为止,如果status为STATUS_SUCCESS,则要读取的数据已经
    // 在ac_key_infor->Data中。请利用前面学到的知识,转换为
    // UNICODE_STRING
    ……
d)写
    NTSTATUS ZwSetValueKey(
        IN HANDLE  KeyHandle,
        IN PUNICODE_STRING  ValueName,
        IN ULONG  TitleIndex  OPTIONAL,
        IN ULONG  Type,
        IN PVOID  Data,
        IN ULONG  DataSize
    );
如果该Value已经存在,那么其值会被这次写入覆盖。如果不存在,则会新建一个。

原创粉丝点击