vsstudio2019,windows平台,使用DeviceIOControl向大容量存储设备发起SCSI通信,读写其扇区,绕过文件系统的排查;

源码:

电脑插入U盘,为物理驱动器3

如下使用DeviceIOControl发送MSC类规定的SCSI通信指令中

读指令(0x28)

指定读0扇区,读1长度的扇区,一共长度为512字节

#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <ntddscsi.h>

// 定义 SCSI 直通控制码,用于与 SCSI 设备进行通信
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)

int main() {
	try {
		// 尝试打开指定的物理设备(这里假设是 U 盘)
		HANDLE hDevice = CreateFile(
			L"\\\\.\\PhysicalDrive2",
			GENERIC_READ | GENERIC_WRITE,
			FILE_SHARE_READ | FILE_SHARE_WRITE,
			NULL,
			OPEN_EXISTING,
			0,
			NULL
		);

		// 如果打开失败,输出错误信息并返回错误码
		if (hDevice == INVALID_HANDLE_VALUE) {
			std::cerr << "无法打开 U 盘设备。错误代码: " << GetLastError() << std::endl;
			return 1;
		}

		// 定义 SCSI 直通结构,用于发送 SCSI 命令和接收结果
		SCSI_PASS_THROUGH_DIRECT sptd = { 0 };
		sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
		sptd.CdbLength = 10; // SCSI Read(6) 命令的命令描述块(CDB)长度为 10 字节
		sptd.DataIn = SCSI_IOCTL_DATA_IN; // 表示从设备读取数据
		sptd.DataTransferLength = 512; // 假设扇区大小为 512 字节
		sptd.TimeOutValue = 2; // 设置超时时间为 2 秒
		sptd.DataBuffer = malloc(512); // 分配 512 字节的数据缓冲区

		// 设置 SCSI Read(6) 命令的具体参数
		sptd.Cdb[0] = 0x28; // SCSI Read(6) 命令码
		sptd.Cdb[1] = 0x00;    // 逻辑块地址高字节
		sptd.Cdb[2] = 0x00;    // 逻辑块地址中高字节
		sptd.Cdb[3] = 0x00;    // 逻辑块地址中低字节
		sptd.Cdb[4] = 0x00;    // 逻辑块地址低字节(扇区 1)
		sptd.Cdb[5] = 0x00;    // 传输长度高字节
		sptd.Cdb[6] = 0x00;    // 传输长度中高字节
		sptd.Cdb[7] = 0x00;    // 传输长度中低字节
		sptd.Cdb[8] = 0x01;    // 传输长度低字节(1 个块)
		sptd.Cdb[9] = 0x00;    // 控制字节

		DWORD bytesReturned = 0;
		// 调用 DeviceIoControl 函数发送 SCSI 命令并接收结果
		BOOL result = DeviceIoControl(
			hDevice,
			IOCTL_SCSI_PASS_THROUGH_DIRECT,
			&sptd,
			sizeof(SCSI_PASS_THROUGH_DIRECT),
			&sptd,
			sizeof(SCSI_PASS_THROUGH_DIRECT),
			&bytesReturned,
			NULL
		);

		// 如果命令发送成功
		if (result) {
			// 输出成功信息和返回的字节数
			std::cout << "SCSI 命令发送成功。" << bytesReturned << std::endl;
			// 将返回的数据以十六进制形式打印出来
			unsigned char* data = reinterpret_cast<unsigned char*>(sptd.DataBuffer);
			// 遍历数据缓冲区,每 16 个字节换行输出
			for (DWORD i = 0; i < 512; ++i) {
				if (0 == i % 16) std::cout << "\n" << std::endl;
				std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]) << " ";
			}
			std::cout << std::endl;
		}
		else {
			// 如果命令发送失败,输出错误信息和错误码
			std::cerr << "SCSI 命令发送失败。错误代码: " << GetLastError() << std::endl;
		}

		// 关闭设备句柄并释放数据缓冲区
		CloseHandle(hDevice);
		free(sptd.DataBuffer);
	}
	catch (const std::exception& e) {
		// 如果发生异常,输出异常信息并返回错误码
		std::cerr << "发生异常: " << e.what() << std::endl;
		return 1;
	}

	return 0;
}

运行结果

遇到的问题:返回的可用长度一直是44,但是我强制输出512的长度时发现缓冲区的数据都是正确的;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值