DeviceIoControl 返回 ERROR_ACCESS_DENIED
Posted
技术标签:
【中文标题】DeviceIoControl 返回 ERROR_ACCESS_DENIED【英文标题】:DeviceIoControl returning ERROR_ACCESS_DENIED 【发布时间】:2020-05-02 16:20:18 【问题描述】:我正在尝试与用于创建 TUN 接口 (WinTun) 的驱动程序进行交互,但为了从它们发送和接收数据,我需要注册一个环形缓冲区。我使用的代码看起来像这样(我省略了使用 SetupApi 创建设备的部分,因为这似乎有效):
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#define REGISTER_RINGS_IOCTL CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
#define BUF_CAPACITY 0x20000
#define BUF_TRAILING 0x10000
typedef struct
volatile ULONG Head;
volatile ULONG Tail;
volatile LONG Alertable;
UCHAR Data[BUF_CAPACITY + BUF_TRAILING];
TUN_RING;
typedef struct
ULONG Size;
UCHAR Data;
TUN_PACKET;
typedef struct
struct
ULONG RingSize;
TUN_RING *Ring;
HANDLE TailMoved;
Send, Receive;
TUN_REGISTER_RINGS;
int main()
HANDLE device = CreateFileW(
L"\\\\?\\ROOT#NET#0006#cac88484-7515-4c03-82e6-71a87abac361",
// ^^ This comes from the omitted code ^^
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if(device == INVALID_HANDLE_VALUE)
printf("The device does not exist\n");
return -1;
TUN_RING Send, Receive = 0;
TUN_REGISTER_RINGS params =
.Send.RingSize = sizeof(TUN_RING),
.Send.Ring = &Send,
.Send.TailMoved = CreateEventW(NULL, FALSE, FALSE, NULL),
.Receive.RingSize = sizeof(TUN_RING),
.Receive.Ring = &Receive,
.Receive.TailMoved = CreateEventW(NULL, FALSE, FALSE, NULL),
;
DWORD bytes;
BOOL ret = DeviceIoControl(
device,
REGISTER_RINGS_IOCTL,
¶ms,
sizeof(TUN_REGISTER_RINGS),
NULL,
0,
&bytes,
NULL
);
if(ret == 0)
printf("Err: %d\n", GetLastError());
return -2;
return 0;
我的问题是此代码在 DeviceIoControl
处失败,错误 5 对应于 ERROR_ACCESS_DENIED。
我不知道为什么会发生这种情况,因为程序已经以管理员权限运行并且设备句柄已使用推荐的属性 (as you can see here) 打开。很抱歉缺少额外的信息,但我在 Windows 驱动程序方面没有太多经验,也不知道如何进一步调试。
我认为问题可能与 check in the source code of the driver 有关,因为它似乎在检查输入缓冲区之前停止(当我将垃圾放入输入缓冲区时它应该重新运行 INVALID_PARAMETER,但这不会发生)。
再次,如果我误解了某些内容或遗漏了一些重要的内容,我深表歉意,但我正在学习所有这些内容,提前致谢!
【问题讨论】:
从TunInitializeDispatchSecurityDescriptor 清楚可见它只允许FILE_ALL_ACCESS
用于LocalSystem 帐户。所以只有 LocalSystem 可以向设备发送一些 ioctl。如果您以管理员身份运行但不是 LocalSystem,则您必须得到 ERROR_ACCESS_DENIED
@RbMm 是的!你说的对!我尝试将可执行文件作为 LocalSystem 运行,它终于成功了,我想它是为了确保与驱动程序对话的每个应用程序都是服务?无论如何,谢谢!
@ErykSun - 如果我没弄错FILE_OPEN_FOR_BACKUP_INTENT
(win32 的FILE_FLAG_BACKUP_SEMANTICS
)仅在创建/打开文件操作中有效。但我们在 ioct 内部有问题,直接调用 SeAccessCheck
here - 所以没有帮助
在调用 SeAccessCheck
here 中根本没有使用来自 Irp 的 FileObject
,而只是调用线程的安全上下文。所以无论如何我们现在需要 LocalSystem 而 SeBackupPrivilege 和 SeRestorePrivilege 无济于事
@RbMm,抱歉打扰了,显然之前的CreateFileW
调用成功了。在 IOCTL 中进行另一次安全检查很奇怪。通常它取决于 I/O 管理器,基于授予句柄的访问权限和 IOCTL 所需的读/写访问权限。我想他们需要在IoCreateFileEx
中解决 I/O 管理器的权限检查问题,以便只允许 SYSTEM 使用 IOCTL,但是如果没有这个额外的安全描述符,有更简单的方法可以做到这一点。也许它们为代码提供了一种替换或扩展安全描述符的方法。
【参考方案1】:
找到了解决办法。正如@RbMm 所述,code that creates the security descriptor 仅允许访问 LocalSystem。这意味着它是唯一允许与司机交谈的帐户。
【讨论】:
以上是关于DeviceIoControl 返回 ERROR_ACCESS_DENIED的主要内容,如果未能解决你的问题,请参考以下文章
DeviceIoControl 完全不起作用,返回时 SystemBuffer 为空
SCSI INQUIRY 命令的 DeviceIoControl 返回错误 50
用于 DeviceIOControl 的 SetWindowsHookEx,要使用啥 hookid?