0

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.

asked Mar 22, 2021 at 11:22
2
  • I changed the second parameter to (GENERIC_READ | GENERIC_WRITE), and the error becomes 87(The parameter is incorrect) Commented Mar 26, 2021 at 1:09
  • Edit your question instead adding comments with vital information. Commented May 17, 2021 at 13:38

1 Answer 1

0

Run your code under Administrator.

Accessing physical drives needs the Administrator's permission.

answered Mar 22, 2021 at 11:33
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your response. I ran cmd as administrator and execute the code using cmd, does that mean the same thing?

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.