11#include < ntstatus.h>
2+ #include < winioctl.h>
3+ #include < ntddscsi.h>
24
35#include " hooks.h"
46#include " logging.h"
57#include " process.h"
68#include " secdrv_ioctl.h"
79
10+ template <typename T>
11+ inline T WordSwap (T w) {
12+ USHORT temp;
13+
14+ temp = ((*((USHORT*)&w) & 0xff00 ) >> 8 );
15+ temp |= ((*((USHORT*)&w) & 0x00ff ) << 8 );
16+
17+ return *((T*)&temp);
18+ }
19+
20+ template <typename T>
21+ inline T DWordSwap (T dw) {
22+ ULONG temp;
23+
24+ temp = *((ULONG*)&dw) >> 24 ;
25+ temp |= ((*((ULONG*)&dw) & 0x00FF0000 ) >> 8 );
26+ temp |= ((*((ULONG*)&dw) & 0x0000FF00 ) << 8 );
27+ temp |= ((*((ULONG*)&dw) & 0x000000FF ) << 24 );
28+
29+ return *((T*)&temp);
30+ }
31+
832NTSTATUS NTAPI hooks::NtDeviceIoControlFile_Hook (HANDLE FileHandle,
933 HANDLE Event,
1034 PIO_APC_ROUTINE ApcRoutine,
@@ -19,20 +43,70 @@ NTSTATUS NTAPI hooks::NtDeviceIoControlFile_Hook(HANDLE FileHandle,
1943
2044 /* all IOCTLs will pass through this function, but it's probably fine since
2145 * secdrv uses unique control codes */
22- if ( IoControlCode == secdrvIoctl::ioctlCodeMain ) {
23- if ( secdrvIoctl::ProcessMainIoctl (InputBuffer,
46+ if (IoControlCode == secdrvIoctl::ioctlCodeMain) {
47+ if (secdrvIoctl::ProcessMainIoctl (InputBuffer,
2448 InputBufferLength,
2549 OutputBuffer,
26- OutputBufferLength) ) {
50+ OutputBufferLength)) {
2751 IoStatusBlock->Information = OutputBufferLength;
2852 IoStatusBlock->Status = STATUS_SUCCESS;
2953 }
3054 else IoStatusBlock->Status = STATUS_UNSUCCESSFUL;
3155 }
32- else if ( IoControlCode == 0xCA002813 ) {
56+ else if (IoControlCode == 0xCA002813 ) {
3357 spdlog::error (" IOCTL 0xCA002813 unhandled (please report!)" );
3458 IoStatusBlock->Status = STATUS_UNSUCCESSFUL;
3559 }
60+ else if (IoControlCode == IOCTL_SCSI_PASS_THROUGH) {
61+ spdlog::trace (" IOCTL_SCSI_PASS_THROUGH called" , IoControlCode);
62+
63+ // Remember input data buffer size and sense info size for later
64+ SCSI_PASS_THROUGH* inStruct = (SCSI_PASS_THROUGH*)InputBuffer;
65+ UCHAR inSenseSize = inStruct->SenseInfoLength ;
66+ ULONG inDataSize = inStruct->DataTransferLength ;
67+
68+ // Execute the original function
69+ NTSTATUS result = NtDeviceIoControlFile_Orig (FileHandle, Event, ApcRoutine, ApcContext,
70+ IoStatusBlock, IoControlCode, InputBuffer,
71+ InputBufferLength, OutputBuffer,
72+ OutputBufferLength);
73+
74+ // This is a workaround for a bug in SPTD SATA controller where it doesn't return
75+ // "LBA out of range" error for out-of-range sectors (affects both Alcohol and DAEMON Tools).
76+ //
77+ // This breaks SafeDisc disc check on later versions since it tries to read track 1 pregap
78+ // (negative LBA) to see if the drive supports it. SPTD doesn't return an error for these sectors
79+ // despite not being able to output them so SafeDisc keeps happily reading pregap sectors
80+ // and then fails the disc check since SPTD doesn't actually output valid sector data.
81+ if (result == STATUS_SUCCESS && inStruct && inSenseSize && inDataSize) {
82+ UCHAR cmd = inStruct->Cdb [0x00 ];
83+
84+ if (cmd == 0x28 || cmd == 0xBE ) { // READ (10), READ CD
85+ LONG lba = DWordSwap (*(LONG*)(inStruct->Cdb + 2 ));
86+
87+ if (lba < 0 && inStruct->ScsiStatus == 0x00 && inStruct->DataTransferLength == 0x00 ) {
88+ // If no error was returned for negative LBA but output buffer is empty, this is bugged
89+ // SPTD behavior and we need to manually write the error.
90+ spdlog::info (" Incorrect output from disc drive when reading sector {}, "
91+ " manually returning LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE" , lba);
92+
93+ UCHAR* senseBuffer = (UCHAR*)inStruct + inStruct->SenseInfoOffset ;
94+
95+ inStruct->ScsiStatus = 0x02 ; // CHECK_CONDITION
96+ inStruct->SenseInfoLength = std::min (0x12ui8, inSenseSize);
97+ memset (senseBuffer, 0x00 , inStruct->SenseInfoLength );
98+
99+ senseBuffer[0x00 ] = 0xf0 ; // response code
100+ senseBuffer[0x02 ] = 0x05 ; // ILLEGAL_REQUEST
101+ senseBuffer[0x07 ] = 0x0a ; // length
102+ senseBuffer[0x0c ] = 0x21 ; // LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE
103+ senseBuffer[0x0d ] = 0x00 ;
104+ }
105+ }
106+ }
107+
108+ return result;
109+ }
36110 else {
37111 // not a secdrv request, pass to original function
38112 return NtDeviceIoControlFile_Orig (FileHandle, Event, ApcRoutine, ApcContext,
0 commit comments