I am trying to read a sector from my physical drive using SCSI commands.
I referenced other people's code and modified some, below is the code.
#include <stddef.h>
#include <stdio.h>
#include <iostream>
#include <windows.h>
#include <winioctl.h>
#define ULONG_PTR ULONG
//#include <ntddscsi.h> // SDK
//#include <spti.h>
#define wszDrive "\\\\.\\PhysicalDrive1"
// by using CreateFileW(), we need to add a L(means wchar_t) before the wszDrive string
#define SPT_CDB_LENGTH 32
#define SPT_SENSE_LENGTH 32
#define SPTWB_DATA_LENGTH 512
#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
//
// NtDeviceIoControlFile IoControlCode values for this device.
//
// Warning: Remember that the low two bits of the code specify how the
// buffers are passed to the driver!
//
#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
//
// Define values for pass-through DataIn field.
//
#define SCSI_IOCTL_DATA_OUT 0
#define SCSI_IOCTL_DATA_IN 1
#define SCSI_IOCTL_DATA_UNSPECIFIED 2
typedef struct _SCSI_PASS_THROUGH_DIRECT {
USHORT Length;// contains the value of sizeof(SCSI_PASS_THROUGH_DIRECT)
UCHAR ScsiStatus;// reports the SCSI status that was returned by the HBA or the target device.
UCHAR PathId;// indicate the SCSI port or bus for the request
UCHAR TargetId;// indicates the target controller or device on the bus
UCHAR Lun;// indicates the logical unit number of the device
UCHAR CdbLength;//indicates the size in bytes of the SCSI command descriptor block
UCHAR SenseInfoLength;// indicates the size in bytes of the request-sense buffer
UCHAR DataIn;// indicates whether the SCSI command will read(SCSI_IOCTL_DATA_IN) or write(SCSI_IOCTL_DATA_OUT) data, or no data transferred(SCSI_IOCTL_DATA_UNSPECIFIED)
ULONG DataTransferLength;//indicates the size in bytes of the data buffer.
ULONG TimeOutValue;// indicates the interval in seconds that the request can execute before the OS-specific port driver might consider it timed out.
PVOID DataBuffer;// pointer to the data buffer
ULONG SenseInfoOffset;// contains an offset from the beginning of this structure to the request-sense buffer.
UCHAR Cdb[16];// specifies the SCSI command descriptor block to be sent to the target drive.
}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
int main()
{
HANDLE hDevice = INVALID_HANDLE_VALUE;
SCSI_PASS_THROUGH_DIRECT sptd;
ULONG length = 0;
DWORD bytesReturn;
BYTE myBuffer[512];
int iRet;
hDevice = CreateFile (wszDrive,
GENERIC_READ, // dwDesiredAccess: GENERIC_READ means allow read access
FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode: FILE_SHARE_READ | FILE_SHARE_WRITE means allow shared access
NULL, // lpSecurityAttributes: points to a SECURITY_ATTRIBUTE structure
OPEN_EXISTING, // dwCreationDisposition: OPEN_EXISTING(the opening file should be already existing)
0, // dwFlagsAndAttributes: some attributes
NULL); // hTemplateFile: if not 0, it points to a file handler. The newly created file will copy the attributes from this file.
if(hDevice == INVALID_HANDLE_VALUE)
{
printf("Get disk handle failed\n");
return 0;
}
else
{
printf("Get disk handle successfully\n");
}
int posSector = 14; //starting at sector 14
int readSectors = 1 ; // read 1 sector
ZeroMemory(&sptd, sizeof(SCSI_PASS_THROUGH_DIRECT));
sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
sptd.PathId = 0;
sptd.TargetId = 1;
sptd.Lun = 0;
sptd.CdbLength = 10;
sptd.DataIn = SCSI_IOCTL_DATA_IN;
sptd.SenseInfoLength = 24;
sptd.DataTransferLength = 512 * readSectors;
sptd.TimeOutValue = 2;
sptd.DataBuffer = myBuffer;
sptd.Cdb[0] = 0x28 ;
sptd.Cdb[2] = (posSector>>24)&0xff; // start at sector posSector
sptd.Cdb[3] = (posSector>>16)&0xff;
sptd.Cdb[4] = (posSector>>8)&0xff;
sptd.Cdb[5] = posSector&0xff;
sptd.Cdb[7] = (readSectors>>8)&0xff;
sptd.Cdb[8] = readSectors&0xff; //
length = sizeof(SCSI_PASS_THROUGH_DIRECT);
iRet = DeviceIoControl(hDevice,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
&sptd,
length,
&sptd,
length,
&bytesReturn,
NULL);
if (0 == iRet)
{
printf("Get disk data failed\n");
printf("Error message: %u\n", GetLastError());
return 0;
}
CloseHandle(hDevice);
return 0;
}
I can get the HANDLE, I want to pass a SCSI_PASS_THROUGH_DIRECT structure to the device.
I read the document of Microsoft but still can't understand how the parameters(especially the CDB) of SCSI_PASS_THROUGH_DIRECT should be set.
The error code get from GetLastError() is 5(Access is denied).
Can someone please explain or give me some reference link to read? Thanks.
Run your code under Administrator.
Accessing physical drives needs the Administrator's permission.