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,67 @@ 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+ // Remember input data buffer size and sense info size for later
62+ SCSI_PASS_THROUGH* inStruct = (SCSI_PASS_THROUGH*)InputBuffer;
63+ ULONG inSenseSize = inStruct->SenseInfoLength ;
64+ ULONG inDataSize = inStruct->DataTransferLength ;
65+
66+ // Execute the original function
67+ NTSTATUS result = NtDeviceIoControlFile_Orig (FileHandle, Event, ApcRoutine, ApcContext,
68+ IoStatusBlock, IoControlCode, InputBuffer,
69+ InputBufferLength, OutputBuffer,
70+ OutputBufferLength);
71+
72+ // This is a workaround for a bug in Alcohol SATA controller where it doesn't return
73+ // "LBA out of range" error for out-of-range sectors.
74+ //
75+ // This breaks SafeDisc disc check on later versions since it tries to read track 1 pregap
76+ // (negative LBA) to see if the drive supports it. Alcohol doesn't return an error for these
77+ // sectors despite not being able to output them so SafeDisc keeps happily reading pregap sectors
78+ // and then fails the disc check since Alcohol doesn't actually output valid sector data.
79+ if (result == STATUS_SUCCESS && inStruct && inSenseSize && inDataSize) {
80+ UCHAR* senseBuffer = (UCHAR*)inStruct + inStruct->SenseInfoOffset ;
81+ UCHAR cmd = inStruct->Cdb [0x00 ];
82+
83+ if (cmd == 0x28 || cmd == 0xBE ) { // READ (10), READ CD
84+ LONG lba = DWordSwap (*(LONG*)(inStruct->Cdb + 2 ));
85+
86+ if (lba < 0 && inStruct->ScsiStatus == 0x00 && inStruct->DataTransferLength == 0x00 ) {
87+ // If no error was returned for negative LBA but output buffer is empty, this is bugged
88+ // Alcohol behavior and we need to manually write the error.
89+ spdlog::info (" Incorrect output from disc drive when reading sector {}, "
90+ " manually returning LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE" , lba);
91+
92+ inStruct->ScsiStatus = 0x02 ; // CHECK_CONDITION
93+ inStruct->SenseInfoLength = std::min (0x12ul , inSenseSize);
94+ memset (senseBuffer, 0x00 , inStruct->SenseInfoLength );
95+
96+ senseBuffer[0x00 ] = 0xf0 ; // response code
97+ senseBuffer[0x02 ] = 0x05 ; // ILLEGAL_REQUEST
98+ senseBuffer[0x07 ] = 0x0a ; // length
99+ senseBuffer[0x0c ] = 0x21 ; // LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE
100+ senseBuffer[0x0d ] = 0x00 ;
101+ }
102+ }
103+ }
104+
105+ return result;
106+ }
36107 else {
37108 // not a secdrv request, pass to original function
38109 return NtDeviceIoControlFile_Orig (FileHandle, Event, ApcRoutine, ApcContext,
0 commit comments