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().

DriverFilter.c: DriveFilterDispatchIrp()

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.

IRP_MJ_READ, IRP_MJ_WRITE

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.

Conclusion

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.