zoukankan      html  css  js  c++  java
  • 《Windows内核安全与驱动开发》 5.1&5.2 内核与应用方面的编程

    《Windows内核安全与驱动开发》阅读笔记 -- 索引目录

    《Windows内核安全与驱动开发》  5.1&5.2 内核与应用方面的编程

    一、生成控制设备

    1. 如果一个驱动需要和应用程序通信,那么首先要生成一个_____。
    2. ____和____构成了整个操作系统的基本框架。
    3. ____暴露给了应用层,应用层可以像操作__一样操作它。
    4. 一般而言,用于和应用程序的设备往往用来"控制"这个内核驱动,所以往往称之为____。
    5. 作为一个控制设备,一般需要____,而普通设备可以不要。

    二、控制设备的名字和符号链接

    1. 控制设备需要一个____,这样它才会暴露出来,供其他程序打开与之通信。
    2. 应用层是无法直接通过____来打开设备对象的,为此必须要建立一个暴露给应用层的____。
    3. 设备名的前缀____,符号链接的前缀为____,在应用层符号链接的前缀为_____。

    三、分发函数与请求处理

    1. 标准分发函数的第一个参数是____,第二个参数是_____。
    2. 在分发函数中处理请求的第一步是_____,使用API函数_____。
    3. 利用____来获取主功能号。
    4. 设置____主要用于返回输出时。
    5. ____用于记录这个请求的完成状态。
    6. ____用于结束这个请求。

    四、在应用层中打开与关闭设备

    1. 打开设备使用API函数____。文件的路径就是____的路径,但是其在应用层来看,是以___开头的,注意C语言需要转义。
    2. 关闭设备使用API函数____。

    五、设备控制请求

    1. CTL_CODE是一个宏,我们要做的是直接利用这个宏来生成一个自己的____。
    2. CTL_CODE第一个参数是____,我们与任何硬件没关系,可以直接定义为未知类型(FILE_DEVICE_UNKNOWN)。
    3. CTL_CODE第二个参数是____,范围为____。
    4. CTL_CODE第三个参数METHOD_BUFFERED是____,输入/输出缓冲区会在__与__之间拷贝。
    5. CTL_CODE最后一个参数是____,因为要写入数据,因此为FILE_WRITE_DATA。
    6. 除了打开设备和关闭设备之外,中间增加了使用____发送请求的过程。

    六、内核中对应的处理

    1. 在处理设备控制请求时,还有如下任务要完成缓冲区是irp->AssicatedIrp.SystemBuffer的前提是,这是一个__方式的设备控制请求。
      1. 获得____。
      2. 如果有输入缓冲区,必须获取输入缓冲区的____和____。
      3. 如果有输出缓冲区,必须获得输出缓冲区的____和____。
    2. 缓冲区是irp->AssociatedIrp.SystemBuffer的前提是,这是一个____方式的设备控制请求。
    3. 只说缓冲区,未说输入还是输出缓冲区,是因为在控制设备中,输入和输出缓冲区是____的,是同一个___。

    答案

    一、生成控制设备

    1. 设备对象
    2. 设备对象  分发函数
    3. 设备对象  文件
    4. 控制设备对象 CDO
    5. 设备名称

    二、控制设备的名字和符号链接

    1. 名称
    2. 设备名称 符号链接
    3. device[设备名称]  ??[符号链接] \.[符号链接]

    三、分发函数与请求处理

    1. 设备对象指针 irp请求
    2. 获得请求的当前栈空间(Current Stack Location)IoGetCurrentIrpStackLocation
    3. irpsp->MajorFunction
    4. irp->IoStatus.Information
    5. irp->IoStatus.Status
    6. IoCompleteRequest

    四、在应用层中打开与关闭设备

    1. CreateFile  符号链接  \.
    2. CloseHandle

    五、控制设备请求

    1. 设备请求功能号
    2. 设备类型
    3. 生成这个功能号的核心数字 (0x7ff,0xfff]
    4. 缓冲 用户 内核
    5. 操作需要的权限
    6. DeviceIoControl

    六、内核中对应的处理

    1. 功能号 指针 长度 指针 长度
    2. 缓冲
    3. 共享 指针

    R3与R0通信实例

    一、R0层代码

    /*********
        作者:OneTrianee
        编写时间:2019/12/8
        编译环境:Win10+vs2019+"Empty WDM Driver"
        代码作用:R0与R3通讯的R0层代码,只负责接收R3层传过来的字符串
        参考资料:《Windows内核安全与驱动开发》
        注意事项:无
    ***********/
    #include <ntifs.h>
    #include <wdmsec.h> // IoCreateDeviceSecure 函数原型
    #include <ntddk.h>
    
    PDEVICE_OBJECT g_cdo = NULL; // 控制设备
    #define CWK_CDO_SYB_NAME  L"\??\sdfjkfsjdfsdfjkls" // 在R0的链接符号
    
    // 从应用层给驱动发送一个字符串。
    #define  CWK_DVC_SEND_STR 
        (ULONG)CTL_CODE( 
        FILE_DEVICE_UNKNOWN, 
        0x911,METHOD_BUFFERED, 
        FILE_WRITE_DATA)
    
    // 从驱动读取一个字符串
    #define  CWK_DVC_RECV_STR 
        (ULONG)CTL_CODE( 
        FILE_DEVICE_UNKNOWN, 
        0x912,METHOD_BUFFERED, 
        FILE_READ_DATA)
    
    // 默认的GUID,辅助粘贴即可
    const GUID  CWK_GUID_CLASS_MYCDO =
    { 0x17a0d1e0L, 0x3249, 0x12e1, {0x92,0x16, 0x45, 0x1a, 0x21, 0x30, 0x29, 0x06} };
    
    //
    //提供一个卸载函数,删除符号链接与控制设备
    //
    VOID UnDriver(PDRIVER_OBJECT driver)
    {
        UNICODE_STRING cdo_syb = RTL_CONSTANT_STRING(CWK_CDO_SYB_NAME); // 符号链接字符串
        ASSERT(g_cdo != NULL);
        IoDeleteSymbolicLink(&cdo_syb); //删除 符号链接
        IoDeleteDevice(g_cdo); // 删除 控制设备
        KdPrint(("卸载驱动成功"));
    }
    
    //
    // 分发函数
    //
    NTSTATUS cwkDispatch(IN PDEVICE_OBJECT dev, IN PIRP irp) {
    
        //
        // 获取当前irp栈空间
        //
        PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
    
        NTSTATUS status = STATUS_SUCCESS;
        ULONG ret_len = 0; // 请求长度
    
        //
        // 循环处理发送给 g_cdo 的请求
        // 如果不是发送给 g_cdo,则明显错误
        //
        while (dev == g_cdo) {
            if (irpsp->MajorFunction == IRP_MJ_CREATE || irpsp->MajorFunction == IRP_MJ_CLOSE) {
                // 生成和关闭请求,一律跳过即可
                break;
            }
            if (irpsp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
    
                // 处理 DeviceIoControl
                PVOID buffer = irp->AssociatedIrp.SystemBuffer; // 缓冲区地址
                ULONG inlen = irpsp->Parameters.DeviceIoControl.InputBufferLength; // 输入缓冲区长度
                ULONG outlen = irpsp->Parameters.DeviceIoControl.OutputBufferLength; // 输出缓冲区长度
                ULONG len;
    
                //
                // 根据前面定义好的设备请求功能号,
                // 详细判断输入还是输出.
                // 我们在这里只判断输入
                //
                switch (irpsp->Parameters.DeviceIoControl.IoControlCode) {
                case CWK_DVC_SEND_STR:
                    ASSERT(buffer != NULL);
                    ASSERT(inlen > 0);
                    ASSERT(outlen == 0);
                    DbgPrint((char*)buffer);
                    // 已经打印过,则可以认为这个请求已经处理成功,放行即可
                    break;
                case CWK_DVC_RECV_STR:
                default:
                    // 到这里的请求都是不接收的(我们没设置接收)。
                    // 未知的请求一律返回非法参数错误
                    status = STATUS_INVALID_PARAMETER;
                    break;
                }
            }
            break;
        }
    
        //
        // 不是发送给 g_cdo,明显错误
        //
        irp->IoStatus.Information = ret_len; // 填写返回信息
        irp->IoStatus.Status = status;    // 填写返回结果
        IoCompleteRequest(irp, IO_NO_INCREMENT); // 完成请求
        return status;
    }
    
    //入口函数,相当于main。
    NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
    {
        NTSTATUS status;
        UCHAR mem[256] = { 0 };
        ULONG i;
        //
        // 生成一个控制设备。
        // 然后生成符号链接。
        //
        UNICODE_STRING sddl = RTL_CONSTANT_STRING(L"D:P(A;;GA;;;WD)"); // 通用[直接复制即可]
        UNICODE_STRING cdo_name = RTL_CONSTANT_STRING(L"\Device\adjdask"); // 设备名
        UNICODE_STRING cdo_syb = RTL_CONSTANT_STRING(CWK_CDO_SYB_NAME); // 符号链接
    
    
        //
        // 生成一个设备对象。
        //
        status = IoCreateDevice(
            driver,
            0, &cdo_name,
            FILE_DEVICE_UNKNOWN,
            0,
            FALSE, 
            &g_cdo);
        if (!NT_SUCCESS(status))
            return status;
    
        //
        // 生成链接符号并与设备绑定
        //
        IoDeleteSymbolicLink(&cdo_syb); // 为防止冲突,先预先删除
        status = IoCreateSymbolicLink(&cdo_syb, &cdo_name); // 将链接符号与设备绑定
        if (!NT_SUCCESS(status)) {
            IoDeleteDevice(g_cdo); // 删除设备
            return status;
        }
    
        //
        // 将所有的分发函数设置为自定义的
        //
        for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
            driver->MajorFunction[i] = cwkDispatch;
        }
    
    
        // 支持动态删除 && 清除控制设备的初始化标记
        driver->DriverUnload = UnDriver;
        g_cdo->Flags &= ~DO_DEVICE_INITIALIZING;
    
        return STATUS_SUCCESS;
    }

     二、R3层代码

    /*********
        作者:OneTrianee
        编写时间:2019/12/8
        编译环境:WinXp+VC6.0+"console"
        代码作用:R0与R3层通信中R3层的代码,负责向R0层传递字符串。
        参考资料:《Windows内核安全与驱动开发》
        注意事项:原版很多宏在Vc6.0环境下都没有找到,在Vs2019中找到然后单独定义即可。
    ***********/
    
    #include "stdafx.h"
    
    #include <stdio.h>
    #include <tchar.h>
    
    #include <windows.h>
    #define CTL_CODE(DeviceType, Function, Method, Access) (  ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
    #define CWK_DEV_SYM L"\\.\sdfjkfsjdfsdfjkls"
    
    // 从应用层给驱动发送一个字符串。
    #define  CWK_DVC_SEND_STR 
        (ULONG)CTL_CODE( 
        0x00000022, 
        0x911,0, 
        FILE_WRITE_DATA)
    
    // 从驱动读取一个字符串
    #define  CWK_DVC_RECV_STR 
        (ULONG)CTL_CODE( 
        FILE_DEVICE_UNKNOWN, 
        0x912,METHOD_BUFFERED, 
        FILE_READ_DATA)
    
    int main(int argc, char* argv[])
    {
        HANDLE device = NULL;
        ULONG ret_len;
        int ret = 0;
        // 定义发送信息
        char* msg = { "hello dirver, this is a message form app" };
    
        // 打开设备,每次要操作驱动对象时,先以此为例子打开设备
        device = CreateFileW(CWK_DEV_SYM, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
        if (device == INVALID_HANDLE_VALUE)
        {
            printf("coworker demo: Open device failed.
    ");
            return -1;
        }
        else
            printf("coworker demo: Open device successfully.
    ");
    
        if (!DeviceIoControl(device, CWK_DVC_SEND_STR, msg, strlen(msg) + 1, NULL, 0, &ret_len, 0)) {
            printf("coworker demo: Send message failed.
    ");
            ret = -2;
        }
        else
            printf("coworker demo: Send message successfully.
    ");
    
        CloseHandle(device);
    
        return 0;
    }
  • 相关阅读:
    EF Power Tools
    ntsysv命令
    chpasswd 批量更新用户口令
    at定时执行任务命令详解
    shell
    为什么使用 shell 编程
    shell
    redis cluster 3.0
    CSS命名规则规范整理
    log4j:WARN No appenders could be found for logger
  • 原文地址:https://www.cnblogs.com/onetrainee/p/12003155.html
Copyright © 2011-2022 走看看