Abusing the TrueCrypt driver
Of course you can also use the running TrueCrypt driver (like the GUI program of TrueCrypt). You need administrator rights to open a handle to the TrueCrypt driver, which is the first step. Using CreateFile() you open a handle to the driver, and later you can use DeviceIoControl() to communicate with it. If you only use IOCTLs and not ReadFile/WriteFile, specify only the FILE_READ_ATTRIBUTES flag for the desired access. I have mentioned that flag earlier in the pagefile attack article.
HANDLE TrueCryptDriver = CreateFile(WIN32_ROOT_PREFIX, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); LONG DriverVersion; DWORD dwResult; if (!DeviceIoControl(TrueCryptDriver, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &DriverVersion, sizeof (DriverVersion), &dwResult, NULL) || !DeviceIoControl(TrueCryptDriver, TC_IOCTL_LEGACY_GET_DRIVER_VERSION, NULL, 0, &DriverVersion, sizeof (DriverVersion), &dwResult, NULL)) return 0;
Here are all devices names defined (we are using the Win32 name to open a handle to the driver):
#define NT_MOUNT_PREFIX DRIVER_STR("\\Device\\TrueCryptVolume") #define NT_ROOT_PREFIX DRIVER_STR("\\Device\\TrueCrypt") #define DOS_MOUNT_PREFIX DRIVER_STR("\\DosDevices\\") #define DOS_ROOT_PREFIX DRIVER_STR("\\DosDevices\\TrueCrypt") #define WIN32_ROOT_PREFIX DRIVER_STR("\\\\.\\TrueCrypt")
The most interesting defines are in the file Apidrvr.h. All possible IOCTLs from the TrueCrypt driver:
#define TC_IOCTL(CODE) (CTL_CODE (FILE_DEVICE_UNKNOWN, 0x800 + (CODE), METHOD_BUFFERED, FILE_ANY_ACCESS)) #define TC_IOCTL_GET_DRIVER_VERSION TC_IOCTL (1) #define TC_IOCTL_GET_BOOT_LOADER_VERSION TC_IOCTL (2) #define TC_IOCTL_MOUNT_VOLUME TC_IOCTL (3) #define TC_IOCTL_DISMOUNT_VOLUME TC_IOCTL (4) #define TC_IOCTL_DISMOUNT_ALL_VOLUMES TC_IOCTL (5) #define TC_IOCTL_GET_MOUNTED_VOLUMES TC_IOCTL (6) #define TC_IOCTL_GET_VOLUME_PROPERTIES TC_IOCTL (7) #define TC_IOCTL_GET_DEVICE_REFCOUNT TC_IOCTL (8) #define TC_IOCTL_WAS_REFERENCED_DEVICE_DELETED TC_IOCTL (9) #define TC_IOCTL_IS_ANY_VOLUME_MOUNTED TC_IOCTL (10) #define TC_IOCTL_GET_PASSWORD_CACHE_STATUS TC_IOCTL (11) #define TC_IOCTL_WIPE_PASSWORD_CACHE TC_IOCTL (12) #define TC_IOCTL_OPEN_TEST TC_IOCTL (13) #define TC_IOCTL_GET_DRIVE_PARTITION_INFO TC_IOCTL (14) #define TC_IOCTL_GET_DRIVE_GEOMETRY TC_IOCTL (15) #define TC_IOCTL_PROBE_REAL_DRIVE_SIZE TC_IOCTL (16) #define TC_IOCTL_GET_RESOLVED_SYMLINK TC_IOCTL (17) #define TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS TC_IOCTL (18) #define TC_IOCTL_BOOT_ENCRYPTION_SETUP TC_IOCTL (19) #define TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP TC_IOCTL (20) #define TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT TC_IOCTL (21) #define TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES TC_IOCTL (22) #define TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER TC_IOCTL (23) #define TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME TC_IOCTL (24) #define TC_IOCTL_GET_PORTABLE_MODE_STATUS TC_IOCTL (25) #define TC_IOCTL_SET_PORTABLE_MODE_STATUS TC_IOCTL (26) #define TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING TC_IOCTL (27) #define TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG TC_IOCTL (28) #define TC_IOCTL_DISK_IS_WRITABLE TC_IOCTL (29) #define TC_IOCTL_START_DECOY_SYSTEM_WIPE TC_IOCTL (30) #define TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE TC_IOCTL (31) #define TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS TC_IOCTL (32) #define TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT TC_IOCTL (33) #define TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR TC_IOCTL (34) #define TC_IOCTL_IS_SYSTEM_FAVORITE_VOLUME_DIRTY TC_IOCTL (35) #define TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY TC_IOCTL (36)
IOCTLs immediately handled
Some IOCTLs of TrueCrypt are immediately handled by TCDispatchQueueIRP, the major function of the TrueCrypt driver, located in Ntdriver.c. Those IOCTLs are handled immediately:
TC_IOCTL_GET_MOUNTED_VOLUMES TC_IOCTL_GET_PASSWORD_CACHE_STATUS TC_IOCTL_GET_PORTABLE_MODE_STATUS TC_IOCTL_SET_PORTABLE_MODE_STATUS TC_IOCTL_OPEN_TEST TC_IOCTL_GET_RESOLVED_SYMLINK TC_IOCTL_GET_DRIVE_PARTITION_INFO TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING IOCTL_DISK_CHECK_VERIFY
These IOCTLs are only available in _DEBUG build. If the requested devices is not a "root device", then the request will be passed to the driver filter DriveFilterDispatchIrp() or volume filter VolumeFilterDispatchIrp(). Otherwise, it will handle following I/O requests:
IRP_MJ_CLOSE IRP_MJ_CREATE IRP_MJ_CLEANUP IRP_MJ_SHUTDOWN IRP_MJ_FLUSH_BUFFERS IRP_MJ_READ IRP_MJ_WRITE IRP_MJ_DEVICE_CONTROL
All TC_IOCTL_ control codes are handled in ProcessMainDeviceControlIrp().
When doing normal ReadFile/WriteFile operations on a device, Windows will send IRP_MJ_READ and IRP_MJ_WRITE control codes to the driver. In TrueCrypt, the function DriveFilterDispatchIrp handles these requests and passes the request further to EncryptedIoQueueAddIrp(). Interestingly also the control codes IRP_MJ_PNP and IRP_MJ_POWER appear there.
If there is an unknown IOCTL, it is passed to the lower device object Extension->LowerDeviceObject.
These two I/O request packets (IRPs) are of our particular interest. If they are executed on a root device or volume (e.g. partition), then TrueCrypt will call EncryptedIoQueueAddIrp() to do the encryption.
Everything above was based on the open source of TrueCrypt 6.3a, but it will be valid for future versions too. You can use the above information (the IOCTLs) to get some information from TrueCrypt and play around with it. When you have raw sector access in your program, you should be aware of a running TrueCrypt with full volume encryption. A problem raises up if you want to write raw sectors under a running Windows (with encryption) and read it on boot time where you read raw data. For this, you will need to develop your own filter boot driver.