文章总结: 这是一篇关于使用DTrace截取USB摄像头图像数据的技术文章,介绍了如何利用WindowsETWProvider监控USB摄像头活动,通过跟踪USBVideo_FillUserBufferStop事件获取帧缓冲区地址和数据大小,再使用tracemem函数输出十六进制图像数据,最后转换为JPEG文件。文章提供了完整的DTrace脚本示例和实际操作步骤,展示了系统底层监控和数据提取的技术方法。
综合评分: 100
文章分类: 安全工具,终端安全,数据安全
使用 DTrace 截取 USB 摄像头图像数据
原创
MyStackTrace
MyStackTrace
2025年8月11日 23:22
北京
在前面的 DTrace ETW 介绍 一文中,我们介绍了如何使用 DTrace 探测 Windows 的 ETW 事件。Windows 内置了很多 ETW Provider,每个 ETW Provider 又提供了很多事件,通过这些事件我们可以知道系统中发生了哪些事情,为我们监控系统行为,诊断系统故障以及分析系统性能提供了很大的帮助。
除了 Windows 内核会提供 ETW Provider 之外,Windows 上的很多驱动程序也会提供 ETW Provider,比如 Windows USB 摄像头的驱动程序:USBVideo.sys 就提供了一个名为 Microsoft-Windows-USBVideo 的 ETW Provider,这个 Provider 提供了很多用来监控 USB 摄像头行为的事件,比如 USB 摄像头启动事件,停止事件,填充帧缓冲区开始事件,填充帧缓冲区结束事件。
下面是使用 ETW Explorer 查看 ETW Provider: Microsoft-Windows-USBVideo 的截图。我们可以看到这个 Provider 的 GUID 以及它提供的事件的数量。
在 ETW Explorer 中切到这个 Provider 的 Events 标签页,我们可以看到这些事件的详细信息,包括每个事件的 ID 和参数的具体情况。USBVideo 驱动程序提供了一个名字为:USBVideo_FillUserBufferStop 的事件,这个事件是 USBVideo 驱动程序完成一帧图像数据填充时发出的,这个事件的发生就意味着 USBVideo 驱动程序已经把一帧图像数据完整地填充到一个帧缓冲区中。
下面我们写个 DTrace 脚本来跟踪一下这个 USBVideo_FillUserBufferStop 事件,并且打出这个事件的两个参数:pBuf (帧缓冲区地址),ulBytesCopied (驱动往帧缓冲区中拷贝的字节数)。在前面DTrace ETW 介绍一文中我们已经说过 ETW 事件的数据需要通过 DTrace ETW 探针(Probe)的参数 arg0 访问,arg0 指向的那块内存中不仅仅有 ETW 事件的参数,还有一个头部结构体 (nt`_EVENT_HEADER )。根据这些信息我们就可以在 DTrace 脚本中先定义出来一个表示该事件的结构体,然后再定义这个 DTrace ETW 探针(Probe),这里需要指定 ETW Provider: Microsoft-Windows-USBVideo 的 GUID 以及 USBVideo_FillUserBufferStop 事件的 ID:209。这些信息都可以通过 ETW Explorer 来查询。最后我们定义当这个 DTrace 探针被触发时的行为:通过参数 arg0 获取帧缓冲区地址以及驱动往帧缓冲区中拷贝的字节数,并且把这些信息打印出来。
下面我们先启动一个 USB 摄像头,然后运行一下这个 DTrace 脚本,效果如下,我们成功的获取到了每一帧的帧缓冲区地址,以及帧缓冲区中的字节数。
既然我们都把帧缓冲区地址给打印出来了,那么我们能不能通过这个地址把帧缓冲区中的图像数据保存下来,这样我们不就截取到了这个 USB 摄像头的图像数据了吗?经过一番折腾,我发现 DTrace 不支持把内存中的数据直接保存到文件中,但是它提供了一个内置函数叫 tracemem,这个函数可以把内存中的数据以十六进制文本的形式打印出来。下面就是我们使用 tracemem 输出图像数据的 DTrace 脚本,这里我们就只打印一帧图像的数据,然后就使用 exit 函数停止 DTrace 脚本的执行。DTrace 内置函数 tracemem 有三个参数,第一个参数是内存地址,第二个参数是要拷贝的数据量,必须是个常量,这里我们就设置为 260000,因为从上面的 DTrace 脚本跟踪的结果看,帧缓冲区中填充的字节数没有超过 260000 的,第三个参数是拷贝的字节数的上限,这个参数可以是个变量,我们就指定获取到的 ulBytesCopied 参数,这样我们就能准确的把帧缓冲区中所有的图像数据以十六进制文本的形式给打印出来。
启动 USB 摄像头,然后运行修改好的 DTrace 脚本,由于这次要打印的数据量比较大,我们就不把 DTrace 的输出打印到屏幕上了,而是通过 -o 参数将这些数据输出到文件(image.txt)中。
当 DTrace 脚本中的探针触发过一次之后,它就会自动停止(exit),这时文件 image.txt 中存放的就是我们所截取到的 USB 摄像头的一帧图像数据的十六进制文本数据。从下面的数据中我们可以看到该 USB 摄像头当前输出的图像格式是 jpeg(因为看到了 JFIF 标记)。
我们现在得到的只是一帧 jpeg 图像的十六进制文本数据,如何将其转化成二进制格式的 jpeg 文件呢?其实很简单,我们把上面 image.txt 中的红框中的数据保留下来,把其他部分的数据都删掉,就得到了如下格式的文本:image.hex.txt。
然后使用如下 xxd 命令(需要在 Linux 系统上做)就可以把 image.hex.txt 转化为二进制的 image.jpg 文件。
xxd -r -p image.hex.txt > image.jpg
下面就是我们得到的 image.jpg 图像,是不是和 USB 摄像头输出的图像是一样的。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:MyStackTrace MyStackTrace《使用 DTrace 截取 USB 摄像头图像数据》