如何在 C 中将 IOCTL 发送到 Windows 上的所有驱动程序

Posted

技术标签:

【中文标题】如何在 C 中将 IOCTL 发送到 Windows 上的所有驱动程序【英文标题】:How to Send IOCTL's to all drivers on windows in C 【发布时间】:2015-09-25 11:05:10 【问题描述】:

有人可以提供一个示例 C 代码,列出我可以使用 Createfile() 打开的所有设备名称吗?我总是得到错误代码 3:路径不存在

不起作用的示例代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <regstr.h>
#include <devioctl.h>
#include <usb.h>
#include <usbiodef.h>
#include <usbioctl.h>
#include <usbprint.h>
#include <setupapi.h>
#include <devguid.h>
#include <wdmguid.h>

#pragma comment(lib, "Setupapi.lib")
int main(void)
    HDEVINFO deviceInfoList;
    deviceInfoList = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);

    if (deviceInfoList != INVALID_HANDLE_VALUE)
    
        SP_DEVINFO_DATA deviceInfoData;
        deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
        for (DWORD i = 0; SetupDiEnumDeviceInfo(deviceInfoList, i, &deviceInfoData); i++)
        
            LPTSTR buffer = NULL;
            DWORD buffersize = 0;
            while (!SetupDiGetDeviceInstanceIdA(deviceInfoList, &deviceInfoData, buffer, buffersize, &buffersize))
            
                if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
                
                    if (buffer) delete buffer;
                    buffer = new TCHAR[buffersize];
                
                else
                
                    printf("%ls\n", "error");
                    break;
                
            
            HANDLE hFile = CreateFileA(buffer,
                GENERIC_READ,
                0,
                NULL,
                OPEN_EXISTING,
                0,
                NULL);

            if (hFile == INVALID_HANDLE_VALUE) 
                printf("InvalidHandle, error code: %d\n", GetLastError());
            
            CloseHandle(hFile);

            printf("%s\n", buffer);
            if (buffer)  delete buffer; buffer = NULL; 
        
    
    getchar();

我的目标是打印所有有效的设备名称并尝试获取一个有效的句柄,以便以后用户发送 ioctl`s

谢谢

编辑: 好的 abhineet 所以这就是我现在得到的:

DWORD EnumerateDevices()
    DWORD dwResult = 0;

    HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);// DIGCF_ALLCLASSES
    /*HDEVINFO hdev =SetupDiGetClassDevs(NULL,
        0, // Enumerator
        0,
        DIGCF_PRESENT | DIGCF_ALLCLASSES); */
    if (INVALID_HANDLE_VALUE != hdev) 
        for (int idev = 0; idev < 100; idev++)
        
            SP_DEVICE_INTERFACE_DATA did =  0 ;
            did.cbSize = sizeof(did);

            if (SetupDiEnumDeviceInterfaces(hdev, NULL, &GUID_DEVCLASS_BATTERY, idev, &did))
            
                DWORD cbRequired = 0;

                SetupDiGetDeviceInterfaceDetail(hdev,
                    &did,
                    NULL,
                    0,
                    &cbRequired,
                    0);
                if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
                
                    PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, cbRequired);
                    if (pdidd) 
                        pdidd->cbSize = sizeof(*pdidd);
                        if (SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, 0)) 
                            wprintf(L"%s\n", pdidd->DevicePath);
                            HANDLE hBattery = CreateFile(pdidd->DevicePath,
                                GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ | FILE_SHARE_WRITE,
                                NULL,
                                OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);
                            if (INVALID_HANDLE_VALUE != hBattery)
                            
                                printf("Successfully opened Handle\n");
                                CloseHandle(hBattery);
                            
                            else
                                wprintf(L"CreateFile(%s) failed %d\n", pdidd->DevicePath, GetLastError());
                            
                        
                        else
                            printf("SetupDiGetDeviceInterfaceDetail() failed %d\n", GetLastError());
                        
                        LocalFree(pdidd);
                    
                
                else
                    printf("SetupDiGetDeviceInterfaceDetail() failed %d\n", GetLastError());
                
            
            else  if (ERROR_NO_MORE_ITEMS == GetLastError())
            
                printf("-NoMoreItems-");
                break;  // Enumeration failed - perhaps we're out of items
            
        
        SetupDiDestroyDeviceInfoList(hdev);
    
    else
        printf("SetupDiGetClassDevs() failed %d\n", GetLastError());
    
    return dwResult;

我从这里撕得最多:https://msdn.microsoft.com/en-us/library/windows/desktop/bb204769(v=vs.85).aspx

我的输出是:

\\?\acpi#pnp0c0a#1#72631e54-78a4-11d0-bcf7-00aa00b7b32a
Successfully opened Handle
-NoMoreItems-

至少我有一个有效的句柄! 所以我想在系统上所有可用的设备上执行此操作,该怎么做?

【问题讨论】:

好吧,您可以对每个设备类重复相同的过程。可能有更简单的方法;例如,尝试传递 NULL 而不是类 GUID。但真的没有任何意义;如果您(至少)不知道设备类,您怎么知道哪些 IOCTL 是有效的? @harry johnston 1. 已经这样做了,但后来我得到了 -NoMoreItems- 2. 蛮力逆向工程。我的目标只是向当前正在运行的每个 .sys Driver-Service 发送一个 ioctl。 和顺便说一句:你不能将 NULL 作为 ClassGuid 传递给 SetupDiEnumDeviceInterfaces ,你会在 0x0 处获得 AV 读数 当您用完一个设备类中的项目时,您会从下一个设备类重新开始。 我尝试了很多 ClassGuid,除了电池类之外几乎所有的都只返回 -NoMoreItems-,所以我需要对每个 classguid 函数调用进行硬编码吗?有这么多... 【参考方案1】:

恕我直言,我不认为,你可以在InstanceID 上做一个CreateFile。要执行CreateFile,您需要设备的符号名称。您可以使用以下 SetupAPI,

SetupDiEnumDeviceInterfaces SetupDiGetDeviceInterfaceDetail

两个 API 的 Remark 部分都声明,

SetupDiEnumDeviceInterfaces:: DeviceInterfaceData 指向一个标识请求的结构 设备接口。要获取有关接口的详细信息,请调用 SetupDiGetDeviceInterfaceDetail。 详细信息包括 可以传递给 Win32 函数的设备接口的名称 例如 CreateFile(在 Microsoft Windows SDK 文档中描述) 获取接口的句柄。

SetupDiGetDeviceInterfaceDetail:: 这个函数返回的接口细节包含一个可以传递给Win32的设备路径 CreateFile 等函数。 不要尝试解析设备路径 象征性名称。设备路径可以在系统启动时重复使用。

这可能对你有用,how to get DevicePath from DeviceID

【讨论】:

以上是关于如何在 C 中将 IOCTL 发送到 Windows 上的所有驱动程序的主要内容,如果未能解决你的问题,请参考以下文章

如何仅在 C 中将 SIGINT 发送到后台进程

C++ - 向 WBF 发送 IOCTL 命令以获取 Windows 上的传感器属性

如何在 ReactJS 中将数据发送到另一个页面

如何在 C# Nest 中将日期值发送到 elasticsearch 聚合查询

如何从 golang 正确地进行 IOCTL

如何在C#中将IntPtr转换为字节数组?