
usb-spy 是一款基于支持 WiFi 或以太网的微控制器构建的 USB 大容量存储流量分析工具。
该板卡向目标系统暴露一个磁盘镜像(FAT 或任意文件系统)作为伪装的 USB 大容量存储设备,而实际存储数据则由远程服务器通过 WiFi 或以太网提供。这种架构使 usb-spy 能够拦截并分析目标系统执行的每一次块访问。
除了原始块级追踪之外,usb-spy 还能理解文件系统,并将每个被访问的块映射回对应的文件和目录,使您能够立即看到正在读取或写入的是哪个文件,而不仅仅是原始扇区号。
此外,usb-spy 还可以通过 JSON 配置文件自定义设备属性(如厂商 ID、产品 ID、序列号、制造商和产品名称)来模拟任意 USB 设备。这使您能够伪装成特定 USB 设备以进行测试和分析。
该工具可通过用户编写的 Python 存根轻松扩展,使您能够实现自定义逻辑来处理 USB 读写事件和块级操作。

当检测到受支持的文件系统时,usb-spy 将:
当前支持的文件系统:
未来将添加对其他文件系统的支持。
如果文件系统不受支持,usb-spy 仍然可以使用:
这确保了 usb-spy 即使面对未知、自定义或专有文件系统时依然有用。

每个受支持板卡的固件构建说明如下:
源代码位于 src 目录中。它将加载一个 FAT 镜像,通过 TCP 端口将其暴露,并记录对镜像的每一次访问。 为了打印文件和目录信息,该工具依赖 TheSleuthKit 库。
要构建,请在根目录中运行以下命令
获取所有子模块
git submodule update --init --recursive
然后运行 waf configure 命令。
./waf configure
如果您希望在无 Python 嵌入支持的情况下构建,请使用以下命令配置:
./waf configure --disable-python
它将检查并构建所需的所有依赖项,然后实际构建项目请运行
./waf build
二进制文件将位于 wbuild 目录中
当使用 --disable-python 构建时,--py 和 --py-args 运行时选项不可用。
我们可以使用 mtools 工具包轻松完成此操作
创建一个 2 MB 的文件
dd if=/dev/zero of=disk.img bs=1M count=2
在其上放置 FAT 文件系统(使用 -F 指定 FAT32,否则将自动选择)
mformat -i disk.img ::
向其中添加一个文件
mcopy -i disk.img example.txt ::
列出文件
mdir -i disk.img ::
提取文件
mcopy -i disk.img ::/example.txt extracted.txt
使用新创建的镜像运行间谍工具
./usb-spy -v disk.img
强制使用原始模式并跳过文件系统自动检测:
./usb-spy --raw disk.img
将访问直接代理到真实块设备:
./usb-spy --proxy /dev/sda
将板卡插入目标 USB 端口。
要模拟特定 USB 设备,可以通过 JSON 配置文件覆盖参数:
以下 JSON 文件将模拟 Kingston DataTraveler USB 设备:
{
"vendor_id": 2385,
"product_id": 5734,
"bcd_device": 272,
"product_rev": "3.0",
"manufacturer": "Kingston",
"product_name": "DataTraveler",
"serial": "509C4BBFACCDE742880C026B",
"language": 1033
}
使用此配置文件运行间谍工具
./usb-spy -c config/kingston.json disk.img
该设备的 dmesg 输出:
usb 1-8: New USB device found, idVendor=0951, idProduct=1666, bcdDevice= 1.10
usb 1-8: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-8: Product: DataTraveler
usb 1-8: Manufacturer: Kingston
usb 1-8: SerialNumber: 509C4BBFACCDE742880C026B
usb-storage 1-8:1.0: USB Mass Storage device detected
scsi host6: usb-storage 1-8:1.0
scsi 6:0:0:0: Direct-Access Kingston DataTraveler 3.0 PQ: 0 ANSI: 2
如果您想为每次读写事件实现自己的逻辑,可以轻松地使用 Python 完成。
像这个 dummy 镜像一样在 Python 中实现 USBImage 类:
class USBImage:
def __init__(self, *args, **kwargs):
"""
Initialize the USBImage.
:param args: should contain:
- filename: The name of the file to manage.
:param kwargs: Arbitrary arguments passed from the c++ command line including:
readOnly: Whether the interface is read-only.
verbose: Whether to enable verbose logging.
block: Whether to enable block mode.
"""
pass
def getBlockNumber(self):
"""Get block number"""
return 100
def getBlockSize(self):
"""Get block size"""
return 512
def read(self, lba, buffer, size):
"""Read block"""
print(f"read block={lba} size={size}")
for i in range(size):
buffer[i] = (lba + i) % 256 # Simulate reading data
return size
def write(self, lba, buffer, size):
"""Write block"""
print(f"write block={lba} size={size}")
print(buffer)
return size
def flush(self):
"""Flush block"""
print("flush data")
然后使用您的 Python 模块运行间谍工具。
./usb-spy --py python/dummy.py disk.img
您还可以从命令行向 Python 类传递任意参数。 参数可在 kwargs 中获取。
./usb-spy --py python/dummy.py --py-args arg1=2 --py-args arg2=Hello disk.img
您也可以从 rawimage 示例开始,该示例提供了 usb-spy 二进制文件原生实现功能的完整实现(约 100 行代码)。
本项目按“原样”提供。不保证其正确性、安全性或对任何特定用途的适用性。
请自行承担使用这些工具和固件的风险。作者和贡献者不对因使用本软件或硬件而产生的任何损害、数据丢失或法律后果负责。
欢迎贡献!请遵循以下步骤:
本项目采用 GNU 通用公共许可证 v3.0 授权。详情请参阅 LICENSE 文件。