Some of my colleagues have worked on a mini-port driver that encrypts data when it is being written to a volume and decrypts it when it is being read. A possible issue that occurs in this for user is determine if the data is actually encrypted on the disk. To tackle this issue, I wrote a program that when given a complete file path, would print the data of the file present on the harddisk, thus displaying the encrypted version of the file data to the user. I have been successful for a volume when it belongs to a single disk, But have been facing issues when the volume is a spanned volume. After getting the logical address of the file, I convert it into physical offset and thus read data, but in case of spanned volumes, I can't deduce to which of the harddisks this physical offset belongs, since the volume now resides on multiple disks. Is there any way to deduce that or do i need to add this as a limitation of my program ?
My code till now is this.
void fetchData(string filenameWithPath) {
string driveLetter = "\\\\.\\" + filenameWithPath.substr(0, 2);
map<int, pair<unsigned long long, unsigned long long>> volStruct;
wstring wdriveLetter = wstring(driveLetter.begin(), driveLetter.end());
wstring wfilenameWithPath = wstring(filenameWithPath.begin(), filenameWithPath.end());
HANDLE volHandle = CreateFile(wdriveLetter.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (volHandle == INVALID_HANDLE_VALUE) {
cerr << "Failed to open volume. Error code: " << GetLastError() << std::endl;
return;
}
HANDLE handle = CreateFileW(wfilenameWithPath.c_str(), GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED |
FILE_FLAG_NO_BUFFERING, NULL);
if (handle == INVALID_HANDLE_VALUE) {
cerr << "Failed to open file Handle. Error code: " << GetLastError() << endl;
return;
}
VOLUME_DISK_EXTENTS* diskExtents = nullptr;
DWORD buffersize = sizeof(diskExtents)*4;
DWORD bytesReturned = 0;
while (true) {
diskExtents = (VOLUME_DISK_EXTENTS*)malloc(buffersize);
if(DeviceIoControl(volHandle,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
NULL,
0,
diskExtents,
buffersize,
&bytesReturned,
NULL)){
break;
}
if (GetLastError() != ERROR_MORE_DATA) {
cout << endl << "FAILED TO GET VOLUME DISK EXTENTS DATA. ERROR CODE [" << GetLastError() << "]";
CloseHandle(handle);
break;
}
buffersize = buffersize * 2;
free(diskExtents);
}
CloseHandle(volHandle);
CloseHandle(handle);
for (DWORD i = 0; i < diskExtents->NumberOfDiskExtents; i++) {
pair<unsigned long long, unsigned long long> temp;
temp.first = diskExtents->Extents[i].StartingOffset.QuadPart;
temp.second = diskExtents->Extents[i].ExtentLength.QuadPart;
volStruct[diskExtents->Extents[i].DiskNumber] = temp;
}
cout << endl << "Exiting";
free(diskExtents);
return;
}
Okay so I found out how to determine on which disk does a particular logical offset of a spanned volume resides. All I had to do was create a VOLUME_LOGICAL_OFFSET buffer. Then pass this buffer to the IOCTL IOCTL_VOLUME_LOGICAL_TO_PHYSICAL. This gives an output buffer of type VOLUME_PHYSICAL_OFFSET. This buffer contains, the physical offset along with the disk number to which this physical offset relates.
VOLUME_LOGICAL_OFFSET logicalOff;
logicalOff.LogicalOffset = 16049504256;
VOLUME_PHYSICAL_OFFSETS physicalOff;
DWORD bytesReturned2;
if (!DeviceIoControl(
volHandle,
IOCTL_VOLUME_LOGICAL_TO_PHYSICAL,
&logicalOff,
sizeof(VOLUME_LOGICAL_OFFSET),
&physicalOff,
sizeof(VOLUME_PHYSICAL_OFFSETS),
&bytesReturned2,
NULL)) {
cout << endl << "Error converting Logical address to physical address...";
cout << endl << "The last error is " << GetLastError();
CloseHandle(volHandle);
return;
}
CloseHandle(volHandle);
cout << endl << "The logical offset " << logicalOff.LogicalOffset
<< " belongs to disk " << physicalOff.PhysicalOffset[0].DiskNumber
<< " and the physical offset is " << physicalOff.PhysicalOffset[0].Offset;