2

我有一个循环工作的硬件。它带有一个专有软件工具,允许用户通过 USB 从 PC 控制它。用户定义每个周期有多长。在每个周期开始时,软件工具通过 USB 快速向硬件发出一系列命令,然后进入空闲模式,等待下一个周期。

第二个硬件需要与第一个同步。基本上,当向硬件#1 发出上述一系列命令时,硬件#2 也应该做它的事情。

硬件 #2 带有 API 和 SDK 等等。硬件 #1 没有——只有这个工具可以定义你的周期有多长。

鉴于这一切,我们决定实现这一目标的最简单方法是侦听硬件#1 使用的 USB 端口,以便每次检测到硬件#2 上的流量时也会发出其指令。我在硬件 #1 的 USB 端口上使用了一个监控应用程序,它的流量看起来非常简单:它是一个周期开始时快速而短暂的连续数据包,然后直到下一个周期才没有。

这个想法是编写一个基于 Windows 的小型实用程序应用程序,该应用程序将侦听硬件 #1 的 USB 端口,并在每次检测到循环时向硬件 #2 发出 API 调用。理想情况下,它应该是一个 .NET 应用程序,因为我最熟悉它,就编写 Windows 代码而言。

困难的部分是编写用于监听硬件#1 的 USB 端口的代码。此外,我始终无法访问硬件 #1,因此我使用普通的 USB 键盘和鼠标作为其替代品。此时的目标是简单地检测键盘或鼠标 USB 端口上的流量。

到目前为止,我已经尝试了我在网上找到的两个库——LibUsbDotNet 和 Usb.Net。两者中的任何一个我都无法实现目标。

我什至无法让 Usb.Net 读取数据包......

LibUsbDotNet 似乎劫持了流量 - 因此,如果我在记事本或 Word 中的键盘上键入,字母不会出现在那里,而我的应用程序成功读取了数据包。将截获的数据包写回端口没有帮助。

这是我与 LibUsbDotNet 一起使用的代码。它基本上是库的示例,稍作修改以与我的键盘一起使用。

// 1118 = Vendor Id, 1872 = Product Id
UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(1118, 1872);

ErrorCode ec = ErrorCode.None;

try
{
    // Find and open the usb device.
    MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);

    // If the device is open and ready
    if (MyUsbDevice == null) throw new Exception("Device Not Found.");

    // If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
    // it exposes an IUsbDevice interface. If not (WinUSB) the 
    // 'wholeUsbDevice' variable will be null indicating this is 
    // an interface of a device; it does not require or support 
    // configuration and interface selection.
    IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
    if (!ReferenceEquals(wholeUsbDevice, null))
    {
        // This is a "whole" USB device. Before it can be used, 
        // the desired configuration and interface must be selected.

        // Select config #1
        wholeUsbDevice.SetConfiguration(1);

        // Claim interface #0.
        wholeUsbDevice.ClaimInterface(0);
    }

    // open read endpoint 1.
    UsbEndpointReader reader = MyUsbDevice.OpenEndpointReader(ReadEndpointID.Ep01);

    // keyboard communicates in packets of size 8
    byte[] readBuffer = new byte[8];
    while (ec == ErrorCode.None)
    {
        int bytesRead;

        // If the device hasn't sent data in the last 5 seconds,
        // a timeout error (ec = IoTimedOut) will occur. 
        ec = reader.Read(readBuffer, 5000, out bytesRead);

        if (bytesRead == 0) throw new Exception(string.Format("{0}:No more bytes!", ec));
        Console.WriteLine("{0} bytes read", bytesRead);

        // Write that output to the console.
        foreach (byte b in readBuffer) Console.Write("{0} ", b);
        Console.WriteLine();
    }

    Console.WriteLine("\r\nDone!\r\n");
}
catch (Exception ex)
{
    Console.WriteLine();
    Console.WriteLine((ec != ErrorCode.None? ec + ":" : String.Empty) + ex.Message);
}
finally
{
    if (MyUsbDevice != null)
    {
        if (MyUsbDevice.IsOpen)
        {
            // If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
            // it exposes an IUsbDevice interface. If not (WinUSB) the 
            // 'wholeUsbDevice' variable will be null indicating this is 
            // an interface of a device; it does not require or support 
            // configuration and interface selection.
            IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
            if (!ReferenceEquals(wholeUsbDevice, null))
            {
                // Release interface #0.
                wholeUsbDevice.ReleaseInterface(0);
            }

            MyUsbDevice.Close();
        }
        MyUsbDevice = null;

        // Free usb resources
        UsbDevice.Exit();

    }

    // Wait for user input..
    Console.ReadKey();
}

如何修改它以使其不拦截数据包,而只是在让它们通过到预期目的地的同时检测它们?

欢迎使用 Usb.Net 或 LibUsbDotNet 提供任何建议。或者,也许,一个更适合我需要的不同图书馆?

4

2 回答 2

2

USB 流量嗅探不如实际的端到端 USB 设备控制常见,因此可用于帮助处理此类事情的库的数量实际上有点少。您可能需要对可用的选项进行一些调整。

一种直观的方法是https://desowin.org/usbpcap/:命令行版本可以实时输出到标准输出,如下面的屏幕截图所示(来自链接页面):

截屏

这种方法的一个重要问题是需要实现 Pcap 数据格式,我强烈怀疑你最终将不得不自己做,因为确实存在的所有 Pcap 解析实现(包括 .NET)都是为了(再次) 使用 Pcap 捕获网络数据的更流行的案例场景。

但是,在你吓坏之前,我建议这是一个潜在可行的解决方案,因为整个格式文档似乎适合两个小 A4 页面(我检查了打印预览:D):https:/ /desowin.org/usbpcap/captureformat.html - 此外,https ://wiki.wireshark.org/Development/LibpcapFileFormat 上的官方 Pcap 格式参考(由 USBPcap 站点链接)显然也不是特别密集。

您可以使用 USBPcap 从文件中输出测试数据,然后只需花时间迭代正确解析文件。

同样,您还可以访问设备并保存一些流量转储以供以后按照自己的节奏进行解析,我怀疑这可能非常实用。

我发现了几个(稍微有点烂:))C#链接,它们可以帮助你编写自己的 Pcap 解析器:https ://github.com/ryrychj/PcapngUtils和https://formats.kaitai.io/ pcap/csharp.html


在搜索时,我还偶然发现了其他一些线索。

第一个是https://sourceforge.net/projects/usbsnoop/,我发现它已经转移到了https://github.com/SnoopWare/usbsnoop/。这实际上非常有趣,因为它实现了自己的内核驱动程序来进行捕获。我很高兴我发现了这一点 - Server 2003 之前的 Windows 不支持 USB 嗅探,但这可以追溯到 Windows 2000 (当然,最近也是 Windows 10),即使只是琐事。(我曾经想在设备和一些旧软件之间做一些我自己的 USB 嗅探,并认为 Win2K VM 将是最轻量级的方法,直到我了解了限制。)可能对您的目的不太实用;前端 UI 似乎不支持记录到文件。

发生的另一件有趣的事情是发现https://www.codeproject.com/Questions/204396/USB-Sniffer-protocol - 帖子 3 产生了投诉“你为什么要回答这个问题,这篇帖子已经有两年了”,包括一个链接到不再解析的域。网络档案在http://web.archive.org/web/20140127164835/www.tellmeword.com/dh9ic/usb_sniffer_(source_code)上只有一份链接页面的副本- 并且下载(镜像)已存档也!哈!我不知道它们是否有用,或者它们使用的技术是否已被弃用等。

尽管我认为以上两者都在 C 中。

于 2019-08-10T14:21:28.580 回答
0

您是否考虑过充当 USB 设备的“中间人”(MitM)?

根据您的说法,您已经可以使用 USB 数据,但就是这样,您的程序“信号”“消失”了。您可能希望充当设备软件的虚拟 USB 设备,以连接到您获得的任何数据并将其传递到您设置的虚拟 USB 设备。换句话说,您的软件充当了在设备和设备的驱动程序/软件之间传递所有数据的桥梁,并且您还可以根据需要使用数据。

以下答案询问如何做到这一点。接受的答案似乎不再可行,因为该软件已被弃用,但 Yaron Shani 的答案似乎仍在 2 个月前更新。

如何模拟 USB 设备?

完整的项目设计为虚拟 PC,但答案中的链接直接指向 USB 仿真部分。

https://github.com/qemu/qemu

https://github.com/qemu/qemu/tree/master/hw/usb

USB 仿真的相关文档。

QEMU 可以模拟 PCI UHCI、OHCI、EHCI 或 XHCI USB 控制器。您可以插入虚拟 USB 设备或真实主机 USB 设备(仅适用于某些主机操作系统)。QEMU 将根据需要自动创建和连接虚拟 USB 集线器以连接多个 USB 设备。

https://qemu.weilnetz.de/doc/qemu-doc.html#pcsys_005fusb

看起来这是一个命令行实用程序,但我知道有一些方法可以从 C# 运行命令行。下面是如何从命令行运行 USB 仿真的示例。

启动 QEMU

与 x86 默认的“pc”机器不同,QEMU 没有 ARM 的默认机器类型。“通用虚拟化平台”类型的virt默认没有USB连接,所以我们需要手动添加一个。ich-usb-uhci1 支持高速,因此需要一些设备在仿真下工作。在 QEMU 中使用“虚拟 FAT”支持是无需重新编译即可将驱动程序导入 UEFI 的最简单方法。下面的例子使用了一个名为 fatdir 的子目录,QEMU 从中生成一个模拟的 FAT 文件系统。

USB_HOST_BUS=8
USB_HOST_PORT=2
AARCH64_OPTS="-pflash QEMU_EFI.fd -cpu cortex-a57 -M virt -usb -device ich9-usb-uhci1"
X86_OPTS="-pflash OVMF.fd -usb"
COMMON_OPTS="-device usb-host,bus=usb-bus.0,hostbus=$USB_HOST_BUS,hostport=$USB_HOST_PORT -nographic -net none -hda fat:fatdir/"

https://station.eciton.net/qemu-usb-host-device-pass-through.html

这是一个 SO Question,解释了如何在 C# 中使用命令行命令。

string strCmdText;
strCmdText= "/C copy /b Image1.jpg + Archive.rar Image2.jpg";
System.Diagnostics.Process.Start("CMD.exe",strCmdText);

运行命令提示符命令

这可能有一个缺点,或者实际上有几个。如果存在时间依赖性(因为它需要毫秒或更短的响应时间)或通信加密,那么您可能会不走运。时间延迟对于键盘可能无关紧要,但如果它对设备或软件的工作方式至关重要,您可能会不走运或看到难以追踪的奇怪错误。此外,某些软件旨在防止虚拟设备成为中间人,因此无法从中窃取数据。您可能还会在尝试让设备软件发现您的模拟 USB 设备而不是真实设备时遇到问题。

这可能不是您希望得到的答案,但是由于您没有任何其他建议,所以除了“祝您好运!”之外,我不知道该告诉您什么。

于 2019-08-08T21:29:14.480 回答