登录  | 立即注册

游客您好!登录后享受更多精彩

查看: 222|回复: 0

WindowsX86内核02.驱动程序

[复制链接]

71

主题

1

回帖

146

积分

管理员

积分
146
发表于 2024-12-4 07:01:21 | 显示全部楼层 |阅读模式
把昨天的程序改用 c++ 编译,改成 .cpp ,发现编译报错
1662551722467-f1994678-00e2-44b0-abb9-95218842ac75.png
原因是名称粉碎,因此可以直接 extern “C”声明一下这个函数 或者用 头文件(推荐)
因为 在头文件中 可以把 头文件一起包含进去
  1. #pragma once
  2. extern "C" {
  3. #include <Ntddk.h>

  4. /*驱动入口函数*/
  5. NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT* DriverObject,
  6.         __in PUNICODE_STRING  RegistryPath);

  7. /*驱动卸载函数*/
  8. VOID Unload(__in struct _DRIVER_OBJECT* DriverObject);

  9. }
复制代码
api
在驱动编程里面也可以面向对象编程,可以用class ,但是有很多功能是禁止的 ,例如 try catch 这是3环的机制,内核处理的方法不一样, malloc , printf ,scanf,new 等 基本的库函数 和 3环 的 api都不行 因为 内核有一套独立的内核空间,必须用微软提供的独立的内核api去申请 .操作系统会提供一套独立的 内核专用的 内核 api
Reference 里面就是所有的api
1662552543552-82f68918-3faa-40c1-8b74-a0c4fdff22e7.png
1662552874506-6f88c0d4-33d4-4b7a-90a9-c6c43e6981fd.png
WDM(NT)驱动框架
我们前面写的算一个一个驱动程序 (有打印功能),但不具备交互性,即不能跟驱动沟通
那么怎么让驱动具备交互性呢(跟3环程序作交互)
内核驱动一般不做界面功能,有3环程序来做,因为内核不能中出bug
因此 内核驱动开发有一个原则,驱动里面3环能解决的问题就在3环解决,驱动里面只做内核才能做的事
  • 想要跟3环做交互,那就要按操作系统的设计来做这个框架
  • 如果不需要跟3环程序交互,可能不需要 按 操作系统的设计来
  • 卸载函数必须有,不然装上了就无法卸载 (因为有些驱动可能是系统一定要用的,防止被误卸载了)如果是开机启动,重启也无法卸载,除非进安全模式
1662555178641-9da34895-6ac9-40c8-abf0-969280635c36.png
步骤
  • 实现驱动入口函数 DriverEntry
  • 创建设备
  • 注册派函数
  • 注册卸载函数 Unload
系统 =》 驱动接口 =》 硬件
因为将来的硬件我们也知道有什么,所以驱动接口必须支持现在的硬件,还要支持将来的硬件,因此驱动接口的设计就十分重要,必须抽象
驱动接口 => 抽象 =》 硬件共同的特点 => 文件
应用程序 =》 文件API => 系统 => 驱动操作接口(open read write close) Dispatch Routines =》 硬件
写驱动就是想操作系统提供 open read write close 的接口,就是文件指针,这些函数就是派遣函数
设备对象 DEVICE_OBJECT 存放 open read write close 的接口
绑定
驱动对象 DRIVER_OBJECT 虚拟出来的,当操作系统加载驱动的时候,就会创建一个驱动对象来描述加载的驱动的所有信息 DriverObject
3环程序只需要 操作设备对象 ,设备对象自然会跟驱动对象绑定
1662560238648-9116f4e8-afa8-436d-b9e4-26cf4fdb9e50.png
实现实现驱动入口函数 DriverEntry
  1. /*驱动入口函数*/
  2. NTSTATUS DriverEntry(
  3.     __in struct _DRIVER_OBJECT* DriverObject,
  4.     __in PUNICODE_STRING  RegistryPath)
  5. {

  6.     return STATUS_SUCCESS;
  7. }
复制代码
添加设备
操作系统会提供内核API 实现王操作系统添加一个设备
ms-help://MS.WDK.v10.7600.091201/Kernel_r/hh/Kernel_r/k104_1e38a631-7e65-4b4b-8d51-3150a8073511.xml.htm
1662557871081-50c81ee9-6440-469f-9a00-6629418c53af.png
最常用的就是 IoCreateDevice
1662557925130-d6d0d100-3b41-422c-ba3f-5e9e184b0641.png
参数:
  • 驱动对象 (一个驱动可以创建多个设备对象,他就会挂链表)
  • 设备口拓展大小 (驱动对象结构体有一个空指针成员,可以用来存放用户申请的地址,对结构体进行拓展,用来取代全局变量),一般定义一个结构体,也可以不用
  • 设备名字 (在内核中基本不用 3环的字符串格式char* 即不是'\0'结尾的字符串,而是用 UNICODE_STRING 结构体),名字有要求 前面必须要有 \Device\ 。而且必须唯一,不可以与其他设备相同
  • 设备种类,不能为NULL
  • 是否独占 一般是false true表示独占:该软件使用时,其他软件无法使用
  • 返回的设备对象
不用char* 是因容易字符串一处造成漏洞
内核中有些库函数还是可以用的 如: strlen strcpy但不推荐,因为不是 "\0" 结尾
windows整个操作系统是由C语言 + 汇编写的,但他整个设计用的是面向对象的思想的
内核里面基本返回值统一,这样调 api 可以统一检查 ,通过宏 NT_SUCCESS 检查
驱动卸载下次在安装将创建不了,因为名称被占用了,因此需要在upload 中 删除对象设备
  1. #define DEVICE_NAME  L"\\Device\\CR42"

  2. UNICODE_STRING ustrDevName;
  3.   //ustrDevName.Length = 8;
  4.   //ustrDevName.MaximumLength = 10;
  5.   //ustrDevName.Buffer = L"CR42";
  6.   RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);  //该函数就是实现上面3 行代码

  7.   PDEVICE_OBJECT pDevObj = NULL;
  8.   NTSTATUS Status = IoCreateDevice(DriverObject,
  9.                                    sizeof(MyDeviceExt),
  10.                                   &ustrDevName,
  11.                                   FILE_DEVICE_UNKNOWN,  //不知道的设备类型
  12.                                   FILE_DEVICE_SECURE_OPEN,
  13.                                   FALSE, //独占
  14.                                   &pDevObj);
  15.   if (!NT_SUCCESS(Status)) {    //检查错误
  16.     DbgPrint("[51asm] IoCreateDevice Status:%p\n", Status);
  17.     return Status;     //失败返回 状态码
  18.   }
复制代码
注册派遣函数
驱动对象最后一项是一个函数指针数组,我们驱动有什么功能就填什么功能,而且通过宏说明了每个下标分别放什么功能
1662560586571-fc405b9b-7446-439b-b41a-80514077cc1f.png
一般对一内核驱动来说 必须提供 打开 关闭 控制 3个功能
这些函数就是派遣函数,也可以称回调函数
  1. NTSTATUS DispatchCreate(
  2.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  3.   _Inout_ struct _IRP* Irp
  4. );

  5. NTSTATUS DispatchClose(
  6.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  7.   _Inout_ struct _IRP* Irp
  8. );

  9. NTSTATUS DispatchRead(
  10.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  11.   _Inout_ struct _IRP* Irp
  12. );

  13. NTSTATUS DispatchWrite(
  14.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  15.   _Inout_ struct _IRP* Irp
  16. );

  17. NTSTATUS DispatchControl(
  18.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  19.   _Inout_ struct _IRP* Irp
  20. );



  21. /*
  22. IRP  I/O Request Packet
  23. */
  24. NTSTATUS DispatchCreate(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  25. {
  26.   //表示参数暂时不用,不说明一下的话参数没用没报错  
  27.   UNREFERENCED_PARAMETER(DeviceObject);
  28.   UNREFERENCED_PARAMETER(Irp);

  29.   DbgPrint("[51asm] %s\n", __FUNCTION__);

  30.   return STATUS_SUCCESS;
  31. }

  32. NTSTATUS DispatchClose(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  33. {
  34.   //表示参数暂时不用,不说明一下的话参数没用没报错  
  35.   UNREFERENCED_PARAMETER(DeviceObject);
  36.   UNREFERENCED_PARAMETER(Irp);
  37.    
  38.   DbgPrint("[51asm] %s\n", __FUNCTION__);

  39.   return STATUS_SUCCESS;
  40. }

  41. NTSTATUS DispatchRead(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  42. {
  43.   //表示参数暂时不用,不说明一下的话参数没用没报错   
  44.   UNREFERENCED_PARAMETER(DeviceObject);
  45.   UNREFERENCED_PARAMETER(Irp);
  46.    
  47.   DbgPrint("[51asm] %s\n", __FUNCTION__);

  48.   return STATUS_SUCCESS;
  49. }


  50. NTSTATUS DispatchWrite(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  51. {
  52.   //表示参数暂时不用,不说明一下的话参数没用没报错   
  53.   UNREFERENCED_PARAMETER(DeviceObject);
  54.   UNREFERENCED_PARAMETER(Irp);
  55.    
  56.   DbgPrint("[51asm] %s\n", __FUNCTION__);

  57.   return STATUS_SUCCESS;
  58. }

  59. NTSTATUS DispatchControl(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  60. {
  61.   //表示参数暂时不用,不说明一下的话参数没用没报错   
  62.   UNREFERENCED_PARAMETER(DeviceObject);
  63.   UNREFERENCED_PARAMETER(Irp);
  64.    
  65.   DbgPrint("[51asm] %s\n", __FUNCTION__);

  66.   return STATUS_SUCCESS;
  67. }


  68. //3.注册派遣函数
  69. DriverObject->MajorFunction[IRP_MJ_CREATE] = &DispatchCreate;     //打开
  70. DriverObject->MajorFunction[IRP_MJ_CLOSE] = &DispatchClose;       //关闭
  71. DriverObject->MajorFunction[IRP_MJ_READ] = &DispatchRead;         //读
  72. DriverObject->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite;       //写
  73. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &DispatchControl;  //控制
复制代码
注册卸载函数VOID Unload(__in struct _DRIVER_OBJECT* DriverObject){  DbgPrint("[51asm] Unload! DriverObject:%p\n", DriverObject);  //删除设备  if (DriverObject->DeviceObject != NULL)    IoDeleteDevice(DriverObject->DeviceObject);}

简单框架完成
Hello.h
  1. #pragma once

  2. extern "C" {

  3. #include <Ntddk.h>

  4. struct MyDeviceExt {
  5.   int nVirtualReg;
  6. };

  7. #define DEVICE_NAME  L"\\Device\\CR42"
  8. #define SYMBOL_NAME L"\\DosDevices\\CR42Virtual"

  9.   /*驱动入口函数*/
  10. NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT* DriverObject,
  11.   __in PUNICODE_STRING  RegistryPath);


  12. VOID Unload(__in struct _DRIVER_OBJECT* DriverObject);

  13. NTSTATUS DispatchCreate(
  14.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  15.   _Inout_ struct _IRP* Irp
  16. );

  17. NTSTATUS DispatchClose(
  18.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  19.   _Inout_ struct _IRP* Irp
  20. );

  21. NTSTATUS DispatchRead(
  22.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  23.   _Inout_ struct _IRP* Irp
  24. );

  25. NTSTATUS DispatchWrite(
  26.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  27.   _Inout_ struct _IRP* Irp
  28. );

  29. NTSTATUS DispatchControl(
  30.   _In_ struct _DEVICE_OBJECT* DeviceObject,
  31.   _Inout_ struct _IRP* Irp
  32. );

  33. }
复制代码
Hello.cpp
  1. #include "Hello.h"



  2. /*驱动卸载函数 clean_up*/
  3. VOID Unload(__in struct _DRIVER_OBJECT* DriverObject)
  4. {
  5.   DbgPrint("[51asm] Unload! DriverObject:%p\n", DriverObject);

  6.   //删除设备
  7.   if (DriverObject->DeviceObject != NULL)
  8.     IoDeleteDevice(DriverObject->DeviceObject);
  9. }

  10. /*1.驱动入口函数*/
  11. NTSTATUS DriverEntry(
  12.   __in struct _DRIVER_OBJECT* DriverObject,
  13.   __in PUNICODE_STRING  RegistryPath)
  14. {
  15.   DbgPrint("[51asm] Hello WDK! DriverObject:%p RegistryPath:%wZ\n",
  16.             DriverObject, RegistryPath);

  17.   //2.创建设备
  18.   UNICODE_STRING ustrDevName;
  19.   //ustrDevName.Length = 8;
  20.   //ustrDevName.MaximumLength = 10;
  21.   //ustrDevName.Buffer = L"CR42";
  22.   RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);

  23.   PDEVICE_OBJECT pDevObj = NULL;
  24.   NTSTATUS Status = IoCreateDevice(DriverObject,
  25.                                    sizeof(MyDeviceExt),
  26.                                   &ustrDevName,
  27.                                   FILE_DEVICE_UNKNOWN,  //不知道的设备类型
  28.                                   FILE_DEVICE_SECURE_OPEN,
  29.                                   FALSE, //独占
  30.                                   &pDevObj);
  31.   if (!NT_SUCCESS(Status)) {
  32.     DbgPrint("[51asm] IoCreateDevice Status:%p\n", Status);
  33.     return Status;
  34.   }

  35.   //3.注册派遣函数
  36.   DriverObject->MajorFunction[IRP_MJ_CREATE] = &DispatchCreate;
  37.   DriverObject->MajorFunction[IRP_MJ_CLOSE] = &DispatchClose;
  38.   DriverObject->MajorFunction[IRP_MJ_READ] = &DispatchRead;
  39.   DriverObject->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite;
  40.   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &DispatchControl;


  41.   //4.注册卸载函数
  42.   DriverObject->DriverUnload = Unload;

  43.   return STATUS_SUCCESS;
  44. }

  45. /*
  46. IRP  I/O Request Packet
  47. */
  48. NTSTATUS DispatchCreate(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  49. {
  50.   UNREFERENCED_PARAMETER(DeviceObject);
  51.   UNREFERENCED_PARAMETER(Irp);

  52.   DbgPrint("[51asm] %s\n", __FUNCTION__);


  53.   return STATUS_SUCCESS;
  54. }

  55. NTSTATUS DispatchClose(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  56. {
  57.   UNREFERENCED_PARAMETER(DeviceObject);
  58.   UNREFERENCED_PARAMETER(Irp);
  59.   DbgPrint("[51asm] %s\n", __FUNCTION__);

  60.   return STATUS_SUCCESS;
  61. }

  62. NTSTATUS DispatchRead(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  63. {
  64.   UNREFERENCED_PARAMETER(DeviceObject);
  65.   UNREFERENCED_PARAMETER(Irp);
  66.   DbgPrint("[51asm] %s\n", __FUNCTION__);

  67.   return STATUS_SUCCESS;
  68. }


  69. NTSTATUS DispatchWrite(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  70. {
  71.   UNREFERENCED_PARAMETER(DeviceObject);
  72.   UNREFERENCED_PARAMETER(Irp);
  73.   DbgPrint("[51asm] %s\n", __FUNCTION__);


  74.   return STATUS_SUCCESS;
  75. }

  76. NTSTATUS DispatchControl(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  77. {
  78.   UNREFERENCED_PARAMETER(DeviceObject);
  79.   UNREFERENCED_PARAMETER(Irp);
  80.   DbgPrint("[51asm] %s\n", __FUNCTION__);


  81.   return STATUS_SUCCESS;
  82. }
复制代码
当设备被打开时,就会找到 DispatchCreate 函数并进行调用 里面一般都是通过 内联汇编代码 跟硬件进行交互
3环程序跟驱动进行通讯
CreateFile() ReadFile() WriteFile() CloseHandle() DeviceIoControl()
分别会对应调到上面的四个函数
DispatchCreate() DispatchRead() DispatchWrite() DispatchClose() DispatchControl()
实现虚拟硬件
因为要在要xp上运行,所以编译成静态库 ,
1662564443231-43335dd8-d02d-47f5-beb1-f506853b78f6.png
然后再 PE中 把 MajorSubsystemVersion 项 改成 4 就可以了
1662575504163-c4154899-80ab-4637-8a91-a9ba3c54ed26.png
  1. #include <stdio.h>
  2. #include <Windows.h>
  3. #include <stdlib.h>

  4. struct MyDeviceExt {
  5.     int nVirtualReg;
  6. };

  7. //显示错误信息  FormatMessage
  8. void DisplayErrorText()
  9. {
  10.     LPVOID lpMsgBuf;
  11.     FormatMessage(
  12.         FORMAT_MESSAGE_ALLOCATE_BUFFER |
  13.         FORMAT_MESSAGE_FROM_SYSTEM |
  14.         FORMAT_MESSAGE_IGNORE_INSERTS,
  15.         NULL,
  16.         GetLastError(),
  17.         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  18.         (LPTSTR)&lpMsgBuf,
  19.         0,
  20.         NULL
  21.     );
  22.     printf((LPCTSTR)lpMsgBuf);
  23.     // Free the buffer.
  24.     LocalFree(lpMsgBuf);
  25. }

  26. int main()
  27. {
  28.     HANDLE hFile = CreateFile("\\Device\\CR42",     
  29.         GENERIC_ALL,
  30.         0,
  31.         NULL,
  32.         OPEN_EXISTING,  //驱动只能打开已存在
  33.         FILE_ATTRIBUTE_NORMAL,
  34.         NULL);
  35.     if (hFile == INVALID_HANDLE_VALUE)
  36.     {
  37.         DisplayErrorText();
  38.     }
  39.     else {
  40.         printf("hFile = %p\n", hFile);
  41.     }

  42.     CloseHandle(hFile);
  43.     system("pause");
  44.     return 0;
  45. }
复制代码
1662565691052-92c9aa5a-ed7d-48d4-9e34-c568c621976c.png
运行可以看到找不到路径 ,这是权限问题
每个设备有2个 名字,其中一个名字叫 NT Device Names 还有一个叫 MS-DOS Device Names
NT Device Names 只能在内核中打开 ,3环中无法打开
MS-DOS Device Names(符号链接) , 如果要想设被3环访问,必须创建一个 符号链接,就相当于路径的一个别名。如果不想被3环访问,可以没有,而且 符号名和设备名也是唯一的,卸载的时候也要删除
#define SYMBOL_NAME L"\\DosDevices\\CR42Virtual"//MS-DOS Device Names  创建符号链接UNICODE_STRING ustrSymbolName;RtlInitUnicodeString(&ustrSymbolName, SYMBOL_NAME);Status = IoCreateSymbolicLink(&ustrSymbolName, &ustrDevName);if (!NT_SUCCESS(Status)) {   DbgPrint("[51asm] IoCreateSymbolicLink Status:%p\n", Status);if (pDevObj != NULL)  IoDeleteDevice(pDevObj);  return Status;}DbgPrint("[51asm] IoCreateSymbolicLink %wZ OK\n", &ustrSymbolName);//删除符号链接UNICODE_STRING ustrSymbolName;RtlInitUnicodeString(&ustrSymbolName, SYMBOL_NAME);IoDeleteSymbolicLink(&ustrSymbolName);

#include <stdio.h>#include <Windows.h>#include <stdlib.h>struct MyDeviceExt {    int nVirtualReg;};//显示错误信息  FormatMessagevoid DisplayErrorText(){    LPVOID lpMsgBuf;    FormatMessage(        FORMAT_MESSAGE_ALLOCATE_BUFFER |        FORMAT_MESSAGE_FROM_SYSTEM |        FORMAT_MESSAGE_IGNORE_INSERTS,        NULL,        GetLastError(),        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language        (LPTSTR)&lpMsgBuf,        0,        NULL    );    printf((LPCTSTR)lpMsgBuf);    // Free the buffer.    LocalFree(lpMsgBuf);}int main(){    HANDLE hFile = CreateFile("\\\\?\\CR42VirtualRegister",   // ?= DosDevices        GENERIC_ALL,        0,        NULL,        OPEN_EXISTING,  //驱动只能打开已存在        FILE_ATTRIBUTE_NORMAL,        NULL);    if (hFile == INVALID_HANDLE_VALUE)    {        DisplayErrorText();    }    else {        printf("hFile = %p\n", hFile);    }    CloseHandle(hFile);    system("pause");    return 0;}

测试
1662566664412-913c08ca-ddc1-41d8-9926-9ae6faa977ae.png
这样3环程序可以指挥驱动程序干活了
完善
调用四个函数

  1. #include <stdio.h>
  2. #include <Windows.h>
  3. #include <stdlib.h>

  4. struct MyDeviceExt {
  5.     int nVirtualReg;
  6. };

  7. void DisplayErrorText()
  8. {
  9.     LPVOID lpMsgBuf;
  10.     FormatMessage(
  11.         FORMAT_MESSAGE_ALLOCATE_BUFFER |
  12.         FORMAT_MESSAGE_FROM_SYSTEM |
  13.         FORMAT_MESSAGE_IGNORE_INSERTS,
  14.         NULL,
  15.         GetLastError(),
  16.         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  17.         (LPTSTR)&lpMsgBuf,
  18.         0,
  19.         NULL
  20.     );

  21.     printf((LPCTSTR)lpMsgBuf);
  22.     LocalFree(lpMsgBuf);
  23. }

  24. int main()
  25. {
  26.     HANDLE hFile = CreateFile("\\\\?\\CR42Virtual",
  27.         GENERIC_ALL,
  28.         0,
  29.         NULL,
  30.         OPEN_EXISTING,
  31.         FILE_ATTRIBUTE_NORMAL,
  32.         NULL);
  33.     if (hFile == INVALID_HANDLE_VALUE)
  34.     {
  35.         DisplayErrorText();
  36.     }
  37.     else {
  38.         printf("hFile = %p\n", hFile);
  39.     }


  40.     char szBuf[100] = {0};
  41.     DWORD dwBytes = 0;
  42.     ReadFile(hFile, szBuf, sizeof(szBuf), &dwBytes, NULL);
  43.     printf("ReadFile dwBytes = %d  szBuf:%s\n", dwBytes, szBuf);


  44.     WriteFile(hFile, szBuf, sizeof(szBuf), &dwBytes, NULL);
  45.     printf("WriteFile dwBytes = %d szBuf:%s\n", dwBytes, szBuf);

  46.      //控制
  47.     //DeviceIoControl(hFile, 100, szBuf, sizeof(szBuf), szBuf, sizeof(szBuf), &dwBytes, NULL);
  48.    
  49.     CloseHandle(hFile);

  50.     system("pause");
  51.     return 0;
  52. }
复制代码
1662567835577-aa715677-753f-40be-ac70-4f3ceb7dc3d8.png
实现驱动模拟寄存器驱动程序
用一个变量来当作寄存器保存值 ,如果要读寄存器的值,把返变量的值 ,如果要写寄存器的值,就修改变量的值
实现的难点就是参数的传递 , 内核如何收到3环的数据
3环如果调用WriteFile函数 和 ReadFile 函数时 ,就会把对应的信息打包成一个 Irp 结构体传递给 内核
IRP I/O Request Packet 读写请求包
我们必须完成这个请求,如果不完成请求,函数可能会卡死在那
例如网卡驱动。假如有人发起读请求,读取从别的电脑发送过来的网络数据,这时候给不了,因为没数据发过来,那这个时候要把请求挂起来,也要把线程挂起来,直到收到数据包为止
  1. #pragma once

  2. extern "C" {

  3. #include <Ntddk.h>

  4.     struct MyDeviceExt {
  5.         int nVirtualReg;   //用来当作寄存器的值
  6.     };

  7. #define DEVICE_NAME  L"\\Device\\CR42"
  8. #define SYMBOL_NAME L"\\DosDevices\\CR42VirtualRegister"

  9.     /*驱动入口函数*/
  10.     NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT* DriverObject,
  11.         __in PUNICODE_STRING  RegistryPath);


  12.     VOID Unload(__in struct _DRIVER_OBJECT* DriverObject);

  13.     NTSTATUS DispatchCreate(
  14.         _In_ struct _DEVICE_OBJECT* DeviceObject,
  15.         _Inout_ struct _IRP* Irp
  16.     );

  17.     NTSTATUS DispatchClose(
  18.         _In_ struct _DEVICE_OBJECT* DeviceObject,
  19.         _Inout_ struct _IRP* Irp
  20.     );

  21.     NTSTATUS DispatchRead(
  22.         _In_ struct _DEVICE_OBJECT* DeviceObject,
  23.         _Inout_ struct _IRP* Irp
  24.     );

  25.     NTSTATUS DispatchWrite(
  26.         _In_ struct _DEVICE_OBJECT* DeviceObject,
  27.         _Inout_ struct _IRP* Irp
  28.     );

  29.     NTSTATUS DispatchControl(
  30.         _In_ struct _DEVICE_OBJECT* DeviceObject,
  31.         _Inout_ struct _IRP* Irp
  32.     );

  33. }
复制代码
  1. #include "Hello.h"


  2. /*驱动卸载函数 clean_up*/
  3. VOID Unload(__in struct _DRIVER_OBJECT* DriverObject)
  4. {
  5.     DbgPrint("[51asm] Unload! DriverObject:%p\n", DriverObject);

  6.     //删除符号链接
  7.     UNICODE_STRING ustrSymbolName;
  8.     RtlInitUnicodeString(&ustrSymbolName, SYMBOL_NAME);
  9.     IoDeleteSymbolicLink(&ustrSymbolName);

  10.     //删除设备
  11.     if (DriverObject->DeviceObject != NULL)
  12.         IoDeleteDevice(DriverObject->DeviceObject);
  13. }

  14. /*1.驱动入口函数*/
  15. NTSTATUS DriverEntry(
  16.     __in struct _DRIVER_OBJECT* DriverObject,
  17.     __in PUNICODE_STRING  RegistryPath)
  18. {
  19.     DbgPrint("[51asm] Hello WDK! DriverObject:%p RegistryPath:%wZ\n",
  20.         DriverObject, RegistryPath);

  21.     //2.创建设备
  22.     UNICODE_STRING ustrDevName;
  23.     //ustrDevName.Length = 8;
  24.     //ustrDevName.MaximumLength = 10;
  25.     //ustrDevName.Buffer = L"CR42";
  26.     RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);  //等于上面的3行代码



  27.     PDEVICE_OBJECT pDevObj = NULL;
  28.     NTSTATUS Status = IoCreateDevice(DriverObject,
  29.         sizeof(MyDeviceExt),
  30.         &ustrDevName,
  31.         FILE_DEVICE_UNKNOWN,  //不知道的设备类型
  32.         FILE_DEVICE_SECURE_OPEN,
  33.         FALSE, //独占
  34.         &pDevObj);
  35.     if (!NT_SUCCESS(Status)) {
  36.         DbgPrint("[51asm] IoCreateDevice Status:%p\n", Status);
  37.         return Status;
  38.     }

  39.     //初始化寄存器变量
  40.     RtlZeroMemory(pDevObj->DeviceExtension, sizeof(MyDeviceExt));
  41.     MyDeviceExt* pDevExt = (MyDeviceExt*)pDevObj->DeviceExtension;
  42.     pDevExt->nVirtualReg = 0;

  43.     //MS-DOS Device Names  创建符号链接
  44.     UNICODE_STRING ustrSymbolName;
  45.     RtlInitUnicodeString(&ustrSymbolName, SYMBOL_NAME);
  46.     Status = IoCreateSymbolicLink(&ustrSymbolName, &ustrDevName);
  47.     if (!NT_SUCCESS(Status)) {
  48.         DbgPrint("[51asm] IoCreateSymbolicLink Status:%p\n", Status);

  49.         if (pDevObj != NULL)
  50.             IoDeleteDevice(pDevObj);

  51.         return Status;
  52.     }
  53.     DbgPrint("[51asm] IoCreateSymbolicLink %wZ OK\n", &ustrSymbolName);



  54.     //3.注册派遣函数
  55.     DriverObject->MajorFunction[IRP_MJ_CREATE] = &DispatchCreate;
  56.     DriverObject->MajorFunction[IRP_MJ_CLOSE] = &DispatchClose;
  57.     DriverObject->MajorFunction[IRP_MJ_READ] = &DispatchRead;
  58.     DriverObject->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite;
  59.     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &DispatchControl;


  60.     //4.注册卸载函数
  61.     DriverObject->DriverUnload = Unload;

  62.     return STATUS_SUCCESS;
  63. }


  64. NTSTATUS DispatchCreate(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  65. {
  66.     UNREFERENCED_PARAMETER(DeviceObject);
  67.     UNREFERENCED_PARAMETER(Irp);
  68.     DbgPrint("[51asm] %s\n", __FUNCTION__);

  69.     //完成请求  如果没完成 3环的程序就会挂起
  70.     Irp->IoStatus.Status = STATUS_SUCCESS;   //状态,成功
  71.     Irp->IoStatus.Information = 0; //成功操作的字节数,非读写一般是0 就算是读写文件 dwBytes的返回值

  72.     //第二个参数线程的优先级,内核一般时 IO_NO_INCREMENT 不提升优先级
  73.     IoCompleteRequest(Irp, IO_NO_INCREMENT);  

  74.     return STATUS_SUCCESS;
  75. }

  76. NTSTATUS DispatchClose(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  77. {
  78.     UNREFERENCED_PARAMETER(DeviceObject);
  79.     UNREFERENCED_PARAMETER(Irp);
  80.     DbgPrint("[51asm] %s\n", __FUNCTION__);


  81.     //完成请求  如果没完成 3环的程序就会挂起
  82.     Irp->IoStatus.Status = STATUS_SUCCESS;   //状态,成功
  83.     Irp->IoStatus.Information = 0; //成功操作的字节数,非读写一般是0 就算是读写文件 dwBytes的返回值

  84.     //第二个参数线程的优先级,内核一般时 IO_NO_INCREMENT 不提升优先级
  85.     IoCompleteRequest(Irp, IO_NO_INCREMENT);

  86.     return STATUS_SUCCESS;
  87. }

  88. NTSTATUS DispatchRead(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  89. {
  90.     UNREFERENCED_PARAMETER(DeviceObject);
  91.     UNREFERENCED_PARAMETER(Irp);
  92.     DbgPrint("[51asm] %s\n", __FUNCTION__);

  93.    

  94.     //获取用户的缓冲区
  95.     PVOID pBuffer = Irp->UserBuffer;   //就是用户参数的 缓冲地址

  96.      //获取当前IRP堆栈
  97.     PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
  98.     ULONG nLength = pIrpStack->Parameters.Read.Length;    //就是用户参数的 缓冲大小  read表示读操作
  99.     DbgPrint("[51asm] %s pBuffer:%p nLength:%d\n", __FUNCTION__, pBuffer, nLength);


  100.     MyDeviceExt* pDevExt = (MyDeviceExt*)DeviceObject->DeviceExtension;
  101.     if (nLength > sizeof(pDevExt->nVirtualReg)) {  //检查缓冲区大小,防溢出
  102.         nLength = sizeof(pDevExt->nVirtualReg);
  103.     }
  104.         
  105.     //拷贝信息  就等于  memcoy
  106.     RtlCopyMemory(pBuffer, &pDevExt->nVirtualReg, nLength);  //把寄存器数据数据传入用缓冲区


  107.     //完成请求  如果没完成 3环的程序就会挂起
  108.     Irp->IoStatus.Status = STATUS_SUCCESS;   //状态,成功
  109.     Irp->IoStatus.Information = nLength; //成功操作的字节数,非读写一般是0 就算是读写文件 dwBytes的返回值

  110.     //第二个参数线程的优先级,内核一般时 IO_NO_INCREMENT 不提升优先级
  111.     IoCompleteRequest(Irp, IO_NO_INCREMENT);

  112.     return STATUS_SUCCESS;
  113. }


  114. NTSTATUS DispatchWrite(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  115. {
  116.     UNREFERENCED_PARAMETER(DeviceObject);
  117.     UNREFERENCED_PARAMETER(Irp);
  118.     DbgPrint("[51asm] %s\n", __FUNCTION__);

  119.      //获取用户的缓冲区
  120.     PVOID pBuffer = Irp->UserBuffer;   //就是用户参数的 缓冲地址

  121.     //获取当前IRP堆栈
  122.     PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
  123.     ULONG nLength = pIrpStack->Parameters.Write.Length;    //就是用户参数的 缓冲大小  Write表示写操作
  124.    
  125.     DbgPrint("[51asm] %s pBuffer:%p nLength:%d\n", __FUNCTION__, pBuffer, nLength);


  126.     MyDeviceExt* pDevExt = (MyDeviceExt*)DeviceObject->DeviceExtension;
  127.     if (nLength > sizeof(pDevExt->nVirtualReg)) {     //检查缓冲区大小,防溢出
  128.         nLength = sizeof(pDevExt->nVirtualReg);  
  129.     }
  130.       
  131.     RtlCopyMemory(&pDevExt->nVirtualReg, pBuffer, nLength);  //将用户数据拷贝进内核的缓冲区


  132.     //完成请求  如果没完成 3环的程序就会挂起
  133.     Irp->IoStatus.Status = STATUS_SUCCESS;   //状态,成功
  134.     Irp->IoStatus.Information = nLength; //成功操作的字节数,非读写一般是0 就算是读写文件 dwBytes的返回值

  135.     //第二个参数线程的优先级,内核一般时 IO_NO_INCREMENT 不提升优先级
  136.     IoCompleteRequest(Irp, IO_NO_INCREMENT);

  137.     return STATUS_SUCCESS;
  138. }

  139. NTSTATUS DispatchControl(_DEVICE_OBJECT* DeviceObject, _IRP* Irp)
  140. {
  141.     UNREFERENCED_PARAMETER(DeviceObject);
  142.     UNREFERENCED_PARAMETER(Irp);
  143.     DbgPrint("[51asm] %s\n", __FUNCTION__);

  144.     //完成请求  如果没完成 3环的程序就会挂起
  145.     Irp->IoStatus.Status = STATUS_SUCCESS;   //状态,成功
  146.     Irp->IoStatus.Information = 0; //成功操作的字节数,非读写一般是0 就算是读写文件 dwBytes的返回值

  147.     //第二个参数线程的优先级,内核一般时 IO_NO_INCREMENT 不提升优先级
  148.     IoCompleteRequest(Irp, IO_NO_INCREMENT);

  149.     return STATUS_SUCCESS;
  150. }
复制代码
测试程序
  1. #include <stdio.h>
  2. #include <Windows.h>
  3. #include <stdlib.h>

  4. struct MyDeviceExt {
  5.     int nVirtualReg;
  6. };

  7. void DisplayErrorText()
  8. {
  9.     LPVOID lpMsgBuf;
  10.     FormatMessage(
  11.         FORMAT_MESSAGE_ALLOCATE_BUFFER |
  12.         FORMAT_MESSAGE_FROM_SYSTEM |
  13.         FORMAT_MESSAGE_IGNORE_INSERTS,
  14.         NULL,
  15.         GetLastError(),
  16.         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  17.         (LPTSTR)&lpMsgBuf,
  18.         0,
  19.         NULL
  20.     );

  21.     printf((LPCTSTR)lpMsgBuf);
  22.     LocalFree(lpMsgBuf);
  23. }

  24. int main()
  25. {
  26.     HANDLE hFile = CreateFile("\\\\?\\CR42VirtualRegister",
  27.         GENERIC_ALL,
  28.         0,
  29.         NULL,
  30.         OPEN_EXISTING,
  31.         FILE_ATTRIBUTE_NORMAL,
  32.         NULL);
  33.     if (hFile == INVALID_HANDLE_VALUE)
  34.     {
  35.         DisplayErrorText();
  36.     }
  37.     else {
  38.         printf("hFile = %p\n", hFile);
  39.     }


  40.     MyDeviceExt DevExt = { 0 };
  41.     DWORD dwBytes = 0;
  42.     DevExt.nVirtualReg = 100;
  43.     if (!WriteFile(hFile, &DevExt, 100, &dwBytes, NULL))  //往寄存器里面写值
  44.     {
  45.         DisplayErrorText();
  46.     }
  47.     else
  48.     {
  49.         printf("WriteFile dwBytes = %d  VirtualReg:%d\n", dwBytes, DevExt.nVirtualReg);
  50.     }

  51.     DevExt.nVirtualReg = -1;
  52.     if (!ReadFile(hFile, &DevExt, sizeof(DevExt), &dwBytes, NULL))  //从寄存器里面读值
  53.     {
  54.         DisplayErrorText();
  55.     }
  56.     else
  57.     {
  58.         printf("ReadFile dwBytes = %d  VirtualReg:%d\n", dwBytes, DevExt.nVirtualReg);
  59.     }

  60.     //控制
  61.     //DeviceIoControl(hFile, 100, szBuf, sizeof(szBuf), szBuf, sizeof(szBuf), &dwBytes, NULL);

  62.     CloseHandle(hFile);

  63.     system("pause");
  64.     return 0;
  65. }
复制代码
测试
1662575670323-f357ede8-9ea4-4b36-a4b6-87369ceeacc9.png
因为不是独占,所以多个函数可以同时调用,注意,多函数同时访问存在同步问题
漏洞
例如:
    MyDeviceExt DevExt = { 0 };    DWORD dwBytes = 0;    DevExt.nVirtualReg = 100;    if (!WriteFile(hFile, &DevExt, 10000, &dwBytes, NULL))  //往寄存器里面写值    {        DisplayErrorText();    }    else    {        printf("WriteFile dwBytes = %d  VirtualReg:%d\n", dwBytes, DevExt.nVirtualReg);    }

NTSTATUS DispatchWrite(_DEVICE_OBJECT* DeviceObject, _IRP* Irp){    UNREFERENCED_PARAMETER(DeviceObject);    UNREFERENCED_PARAMETER(Irp);    DbgPrint("[51asm] %s\n", __FUNCTION__);    //获取用户的缓冲区    PVOID pBuffer = Irp->UserBuffer;   //就是用户参数的 缓冲地址    //获取当前IRP堆栈    PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);    ULONG nLength = pIrpStack->Parameters.Write.Length;    //就是用户参数的 缓冲大小  Write表示写操作        DbgPrint("[51asm] %s pBuffer:%p nLength:%d\n", __FUNCTION__, pBuffer, nLength);    MyDeviceExt* pDevExt = (MyDeviceExt*)DeviceObject->DeviceExtension;           RtlCopyMemory(&pDevExt->nVirtualReg, pBuffer, nLength);  //将用户数据拷贝进内核的缓冲区    //完成请求  如果没完成 3环的程序就会挂起    Irp->IoStatus.Status = STATUS_SUCCESS;   //状态,成功     Irp->IoStatus.Information = nLength; //成功操作的字节数,非读写一般是0 就算是读写文件 dwBytes的返回值    //第二个参数线程的优先级,内核一般时 IO_NO_INCREMENT 不提升优先级    IoCompleteRequest(Irp, IO_NO_INCREMENT);    return STATUS_SUCCESS;}

上面的代码会导致系统蓝屏 因为上面 3成程序 给驱动的缓冲区只有4字节 ,但是大小却指定了 10000,由于没有长度检查 ,这样 驱动去访问那 10000 个字节 就会 c005 ,
RtlCopyMemory(&pDevExt->nVirtualReg, pBuffer, nLength); 中 nLength 大小由3环程序控制
由于是往内核写数据,因为长度出错,导致代码溢出了,因此需要对长度检查
WinObj
可以找遍历电脑上已经安装的所有设备




您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|断点社区 |网站地图

GMT+8, 2024-12-24 03:53 , Processed in 0.076676 second(s), 32 queries .

Powered by XiunoBBS

Copyright © 2001-2025, 断点社区.

快速回复 返回顶部 返回列表