首页
社区
课程
招聘
[求助]通过SRB读取U盘扇区问题
发表于: 2019-7-30 15:21 4536

[求助]通过SRB读取U盘扇区问题

2019-7-30 15:21
4536
NTSTATUS
ReadWriteDisk(
     PDEVICE_OBJECT DeviceObject,
     ULONG SectorOffset,
     ULONG IsReadOperation,    // = 0 means is a write operation otherwise is read
     PVOID Buffer,
     ULONG SectorCount,
     PIO_STATUS_BLOCK IoStatusBlock
     )
{
	SENSE_DATA SenseData; // error info - -
	SCSI_REQUEST_BLOCK ScsiRequestBlock;
	PCDB CommandDescriptorBlock;

	PIRP Irp;
	PIO_STACK_LOCATION IrpSp;
	PMDL Mdl;
	KEVENT Event;

	NTSTATUS Status = STATUS_UNSUCCESSFUL;

	if (SectorCount > 0xFFFF)
	{
	   return STATUS_INVALID_PARAMETER;
	}

	RtlZeroMemory(&SenseData, sizeof(SENSE_DATA));
	RtlZeroMemory(&ScsiRequestBlock, sizeof(SCSI_REQUEST_BLOCK));

	ScsiRequestBlock.Length = sizeof(SCSI_REQUEST_BLOCK);
	ScsiRequestBlock.Function = SRB_FUNCTION_EXECUTE_SCSI;
	ScsiRequestBlock.DataBuffer = Buffer;
	ScsiRequestBlock.SenseInfoBuffer = &SenseData;
	ScsiRequestBlock.SenseInfoBufferLength = sizeof(SENSE_DATA);
	ScsiRequestBlock.DataTransferLength = SectorCount * BytesPerSector;
	ScsiRequestBlock.QueueAction = SRB_FLAGS_DISABLE_AUTOSENSE; // Indicates that request-sense information should not be returned ???
	ScsiRequestBlock.SrbFlags = IsReadOperation ? SRB_FLAGS_DATA_IN : SRB_FLAGS_DATA_OUT;
	ScsiRequestBlock.SrbFlags |= IsReadOperation ? SRB_FLAGS_ADAPTER_CACHE_ENABLE : 0;
	ScsiRequestBlock.SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
	ScsiRequestBlock.TimeOutValue = -1; //////////////////////// second
	ScsiRequestBlock.QueueSortKey = SectorOffset; // Specifies the offset from the start of the media or zero, depending on the type of the target device.

	ScsiRequestBlock.CdbLength = 10; // sizeof(CDB.CDB10);
	CommandDescriptorBlock = (PCDB)ScsiRequestBlock.Cdb;

	CommandDescriptorBlock->CDB10.OperationCode = IsReadOperation ? SCSIOP_READ : SCSIOP_WRITE;
	CommandDescriptorBlock->CDB10.LogicalUnitNumber = 0; // ??????????? what's this?
	CommandDescriptorBlock->CDB10.Reserved1 = 0; // in fact, not needed.
	// ForceUnitAccess, RelativeAddress, DisablePageOut remains still - in fact, remains 0.
	CommandDescriptorBlock->CDB10.LogicalBlockByte0 = (UCHAR)(SectorOffset >> 0x18);
	CommandDescriptorBlock->CDB10.LogicalBlockByte1 = (UCHAR)(SectorOffset >> 0x10);
	CommandDescriptorBlock->CDB10.LogicalBlockByte2 = (UCHAR)(SectorOffset >> 0x8);
	CommandDescriptorBlock->CDB10.LogicalBlockByte3 = (UCHAR)(SectorOffset);
	CommandDescriptorBlock->CDB10.Reserved2 = 0;
	CommandDescriptorBlock->CDB10.TransferBlocksMsb = (UCHAR)(SectorCount >> 0x8);
	CommandDescriptorBlock->CDB10.TransferBlocksLsb = (UCHAR)(SectorCount);
	CommandDescriptorBlock->CDB10.Control = 0; // how to initialize this?

	KeInitializeEvent(&Event, NotificationEvent, FALSE);

	Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
	if (!Irp)
	{
	   return STATUS_INSUFFICIENT_RESOURCES;
	}
	Mdl = IoAllocateMdl(Buffer, SectorCount * BytesPerSector, FALSE, FALSE, Irp);
	if (!Mdl)
	{
	   IoFreeIrp(Irp);
	   return STATUS_INSUFFICIENT_RESOURCES;
	}
	MmProbeAndLockPages(Mdl, KernelMode, IsReadOperation ? IoReadAccess : IoWriteAccess);

	ScsiRequestBlock.OriginalRequest = Irp;

	Irp->UserIosb = IoStatusBlock;
	Irp->UserEvent = &Event;
	RtlZeroMemory(&Irp->IoStatus, sizeof(IO_STATUS_BLOCK));
	Irp->MdlAddress = Mdl;
	Irp->AssociatedIrp.SystemBuffer = NULL;
	Irp->Cancel = FALSE;
	Irp->CancelRoutine = NULL;
	Irp->Flags = IRP_NOCACHE | IRP_SYNCHRONOUS_API;
	Irp->RequestorMode = KernelMode;
	Irp->Tail.Overlay.Thread = PsGetCurrentThread();

	IrpSp = IoGetNextIrpStackLocation(Irp);
	IrpSp->DeviceObject = DeviceObject;
	IrpSp->MajorFunction = IRP_MJ_SCSI;
	IrpSp->Parameters.Scsi.Srb = &ScsiRequestBlock;

	IoSetCompletionRoutine(Irp, IoCompletionRoutine, &ScsiRequestBlock, TRUE, TRUE, TRUE);

	Status = IoCallDriver(DeviceObject, Irp);

	if (Status == STATUS_PENDING)
	{
	   (VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
	   Status = STATUS_SUCCESS;
	}

	if ((ScsiRequestBlock.SenseInfoBuffer != &SenseData) && (ScsiRequestBlock.SenseInfoBuffer))
	{
	   ExFreePool(ScsiRequestBlock.SenseInfoBuffer); // should we do this?
	   DbgPrint(" Information: Freed ScsiRequestBlock.SenseInfoBuffer.\n");
	}

	if (NT_SUCCESS(Status) && ((ScsiRequestBlock.SrbStatus == SRB_STATUS_SUCCESS) || (ScsiRequestBlock.SrbStatus == SRB_STATUS_PENDING)) && (ScsiRequestBlock.ScsiStatus == SCSISTAT_GOOD) )
	{
	   //DbgPrint(" Information: ReadWriteDisk operation succeeded.\n");
	   Status = STATUS_SUCCESS;
	}
	else
	{
	   DbgPrint("Error: ReadWriteDisk fails with NT status 0x%X, Scsi status 0x%X and Srb status 0x%X.\n", Status, ScsiRequestBlock.ScsiStatus, ScsiRequestBlock.SrbStatus);
	   Status = STATUS_UNSUCCESSFUL;
	}

	return Status;
}
以上代码是读取磁盘扇区代码(来源: https://www.cnblogs.com/fanzi2009/archive/2009/05/07/1451201.html ),正常情况下没问题,但是读取2T的移动硬盘时,会不执行回调 IoCompletionRoutine (回调中会调用KeSetEvent),一直等待在 KeWaitForSingleObjec中,这种现象暂时只出现在对2T的移动硬盘读取时,想了想没发现问题所在,请大家指点迷津,多谢!!!

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-7-30 17:19 被红猪编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 407
活跃值: (1821)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
用这个试一下:IOCTL_SCSI_PASS_THROUGH_DIRECT
2019-8-1 11:38
0
雪    币: 12
活跃值: (773)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
IRP_MJ_READ也能读扇区啊
2019-8-16 12:39
0
游客
登录 | 注册 方可回帖
返回
//