确定已挂载的TrueCrypt卷的驱动器号

本文关键字:TrueCrypt 驱动器 | 更新日期: 2023-09-27 18:15:26

TrueCrypt容器被挂载到驱动器号后,是否有可能在批处理文件中确定驱动器号是从哪个容器挂载的,或者容器挂载到哪个驱动器号?

在批处理文件中,我想将指定的TrueCrypt容器挂载到指定的驱动器号。如果容器已经挂载或驱动器号不可用,则TrueCrypt会出错,因此我只想在指定的容器尚未挂载到指定的驱动器号时运行TrueCrypt,也就是说,只有在操作尚未完成时才运行TrueCrypt。

如有任何建议,不胜感激。

编辑

赏罚摘要简而言之,假设您将卷C:'Vol1.tcC:'Vol2.tc挂载到驱动器XY上。如何用批处理文件或c#代码告诉C:'Vol1.tc挂载到驱动X, C:'Vol2.tc挂载到驱动Y ?

确定已挂载的TrueCrypt卷的驱动器号

这样做的方法是直接要求Truecrypt驱动程序自己。这可以通过DeviceIoControl函数实现。事实上,这正是TrueCrypt GUI正在做的。

注意,在c++中更容易做到这一点。你可以在这里找到一篇好文章。

思路是调用DeviceIoControl函数,请求TC_IOCTL_GET_MOUNTED_VOLUMES您将获得一个结构,其中包含所有挂载的卷路径和驱动器号。实际上,它是一个26个元素的数组(每个可能的驱动器号一个),称为wszVolume,其中包含挂载在。

希望下面的例子能帮助你找到如何处理你的情况。

c#示例代码:

class Program
{
    static void Main(string[] args)
    {
        uint size = (uint)Marshal.SizeOf(typeof(MOUNT_LIST_STRUCT));
        IntPtr buffer = Marshal.AllocHGlobal((int)size);
        uint bytesReturned;
        IntPtr _hdev = CreateFile("''''.''TrueCrypt", FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
        bool bResult = DeviceIoControl(_hdev, TC_IOCTL_GET_MOUNTED_VOLUMES, buffer, size, buffer, size, out bytesReturned, IntPtr.Zero);
        MOUNT_LIST_STRUCT mount = new MOUNT_LIST_STRUCT();
        Marshal.PtrToStructure(buffer, mount);
        Marshal.FreeHGlobal(buffer);
        for (int i = 0; i < 26; i++)
            Console.WriteLine("{0}: => {1}", (char)('A' + i), mount.wszVolume[i]);
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    class MOUNT_LIST_STRUCT
    {
        public readonly UInt32 ulMountedDrives; /* Bitfield of all mounted drive letters */
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly MOUNT_LIST_STRUCT_VOLUME_NAME[] wszVolume;  /* Volume names of mounted volumes */
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly UInt64[] diskLength;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly int[] ea;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly int[] volumeType;   /* Volume type (e.g. PROP_VOL_TYPE_OUTER, PROP_VOL_TYPE_OUTER_VOL_WRITE_PREVENTED, etc.) */
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct MOUNT_LIST_STRUCT_VOLUME_NAME
    {
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I2, SizeConst = 260)]
        public readonly char[] wszVolume;   /* Volume names of mounted volumes */
        public override string ToString()
        {
            return (new String(wszVolume)).TrimEnd(''0');
        }
    }
    public static int CTL_CODE(int DeviceType, int Function, int Method, int Access)
    {
        return (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2)
          | (Method));
    }
    private static readonly uint TC_IOCTL_GET_MOUNTED_VOLUMES = (uint)CTL_CODE(0x00000022, 0x800 + (6), 0, 0);
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode,
    IntPtr lpInBuffer, uint nInBufferSize,
    IntPtr lpOutBuffer, uint nOutBufferSize,
    out uint lpBytesReturned, IntPtr lpOverlapped);
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CreateFile(
         [MarshalAs(UnmanagedType.LPTStr)] string filename,
         [MarshalAs(UnmanagedType.U4)] FileAccess access,
         [MarshalAs(UnmanagedType.U4)] FileShare share,
         IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
         [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
         [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
         IntPtr templateFile);
}

这是我到目前为止的内容:

我正在创建一个用c#编写的自定义应用程序,通知用户哪些卷被挂载/卸载,如果它们被挂载,我需要通知用户在哪个驱动器上。为了知道一个卷是否挂载,我有以下类:

注意我使用handle.exe程序可以从http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx或http://download.sysinternals.com/files/Handle.zip

下载

而且我相信您必须以管理员身份运行程序

class TrueCryptHelp
{
    // I have that program on the working directory
    // it can be downloaded from http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx
    const string HandleExeLocation = "handle.exe"; 
    static string systemProcessFiles;
    static DateTime dateFilesLockedInfo = new DateTime();
    static string SystemProcessFiles
    {
        get
        {
            if ((DateTime.Now - dateFilesLockedInfo).TotalSeconds > 2)
            {
                Process p = new Process();
                var psi = new ProcessStartInfo();
                psi.RedirectStandardOutput = true;
                psi.UseShellExecute = false;
                psi.FileName = HandleExeLocation;
                p.StartInfo = psi;
                p.Start();
                var output = p.StandardOutput.ReadToEnd();
                systemProcessFiles = string.Empty;
                foreach (Match m in Regex.Matches(output ?? "", @"(?sx) -{20}  [^-]  .+?  -{20}"))
                {
                    if (Regex.Match(m.Value ?? "", @"(?xi) -{10}  ['s'r'n]+  System 's pid").Success)
                    {
                        if (Regex.Match(m.Value ?? "", @"(?xi)  ') 's+ ''clfs 's* ('r|'n)").Success)
                        {
                            systemProcessFiles = m.Value.ToLower();
                            break;
                        }
                    }
                }
            }
            dateFilesLockedInfo = DateTime.Now;
            return systemProcessFiles;
        }
    }
    public static bool IsVolumeMounted(string volumeLocation)
    {
        //DriveInfo d = new System.IO.DriveInfo(volume.DriveLetter);
        //if (d == null)
        //return false;
        //if (d.DriveType != System.IO.DriveType.Fixed)
        //return false;
        //if ((d.DriveFormat ?? "").ToLower().Contains("fat") == false)
        //return false;
        if (SystemProcessFiles.Contains(volumeLocation.ToLower()))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

然后,如果我想知道位于C:'Users'Tono'Desktop'v1.tc的卷是否已挂载,我将调用该方法:

var isVolMounted = TrueCryptHelp.IsVolumeMounted(@"A:'Users'Tono'Desktop'v1.tc");

现在我错过了回答这个问题!通过我发布的课程,我能够知道位于c:' users '等的卷……是安装,但进入什么驱动器号!?

只是为了扩展VeraCrypt的答案,修改自Gerard Walace的帖子:

TrueCrypt和VeraCrypt在MSFT_Helpers.cs中的使用@ https://github.com/BananaAcid/Selfcontained-C-Sharp-WPF-compatible-utility-classes

简单的用法示例:http://github.com/BananaAcid/VeraCrypt-Cmd

public static class VcGetMounts
{
    public static async Task<Dictionary<char, string>> getMounted()
    {
        return await Task.Run<Dictionary<char, string>>(() =>
        {
            var ret = new Dictionary<char, string>();
            uint size = (uint)Marshal.SizeOf(typeof(MOUNT_LIST_STRUCT));
            IntPtr buffer = Marshal.AllocHGlobal((int)size);
            uint bytesReturned;
            IntPtr _hdev = CreateFile("''''.''VeraCrypt", FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
            bool bResult = DeviceIoControl(_hdev, TC_IOCTL_GET_MOUNTED_VOLUMES, buffer, size, buffer, size, out bytesReturned, IntPtr.Zero);
            // IMPORTANT! Otherwise, the struct fills up with random bytes from memory, if no VeraCrypt is available
            if (!bResult) return ret;
            MOUNT_LIST_STRUCT mount = new MOUNT_LIST_STRUCT();
            Marshal.PtrToStructure(buffer, mount);
            Marshal.FreeHGlobal(buffer);
            for (int i = 0; i < 26; i++)
                if (mount.wszVolume[i].ToString().Length > 0)
                    ret.Add((char)('A' + i), mount.wszVolume[i].ToString());
            return ret;
        });
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    class MOUNT_LIST_STRUCT
    {
        public readonly UInt32 ulMountedDrives; /* Bitfield of all mounted drive letters */
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly MOUNT_LIST_STRUCT_VOLUME_NAME[] wszVolume;  /* Volume names of mounted volumes */
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly MOUNT_LIST_STRUCT_VOLUME_LABEL[] wszLabel;  /* Volume labels of mounted volumes */
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly MOUNT_LIST_STRUCT_VOLUME_ID[] volumeID;  /* Volume labels of mounted volumes */
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly UInt64[] diskLength;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly int[] ea;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly int[] volumeType;   /* Volume type (e.g. PROP_VOL_TYPE_OUTER, PROP_VOL_TYPE_OUTER_VOL_WRITE_PREVENTED, etc.) */
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)]
        public readonly bool[] truecryptMode;
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct MOUNT_LIST_STRUCT_VOLUME_NAME
    {
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I2, SizeConst = 260)]
        public readonly char[] wszVolume;   /* Volume names of mounted volumes */
        public override string ToString()
        {
            return (new String(wszVolume)).TrimEnd(''0');
        }
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct MOUNT_LIST_STRUCT_VOLUME_ID
    {
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I2, SizeConst = 32)]
        public readonly char[] volumeID;   /* Volume ids of mounted volumes */
        public override string ToString()
        {
            return (new String(volumeID)).TrimEnd(''0');
        }
    }
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct MOUNT_LIST_STRUCT_VOLUME_LABEL
    {
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I2, SizeConst = 33)]
        public readonly char[] wszLabel;   /* Volume labels of mounted volumes */
        public override string ToString()
        {
            return (new String(wszLabel)).TrimEnd(''0');
        }
    }
    public static int CTL_CODE(int DeviceType, int Function, int Method, int Access)
    {
        return (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2)
          | (Method));
    }
    private static readonly uint TC_IOCTL_GET_MOUNTED_VOLUMES = (uint)CTL_CODE(0x00000022, 0x800 + (6), 0, 0);
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
    static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode,
    IntPtr lpInBuffer, uint nInBufferSize,
    IntPtr lpOutBuffer, uint nOutBufferSize,
    out uint lpBytesReturned, IntPtr lpOverlapped);
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr CreateFile(
         [MarshalAs(UnmanagedType.LPTStr)] string filename,
         [MarshalAs(UnmanagedType.U4)] FileAccess access,
         [MarshalAs(UnmanagedType.U4)] FileShare share,
         IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
         [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
         [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
         IntPtr templateFile);
}

我不确定通过查询驱动器号或反之亦然来确定卷名。根据您的需要,一个可以接受的解决方法是查询卷上的文件锁。如果卷被锁定,则很有可能已挂载。如果您愿意,还可以更花哨一些,并使用for/f

检查它是否被系统进程锁定。

我应该提到,在调用truecrypt.exe时,如果驱动器已经挂载,那么使用/quit background和/silent将默默地失败。不确定是否只是你关心的error display。不确定您是否注意到命令行参考

这是一个简单的cmd脚本挂载卷,只有当它还没有挂载,从而防止错误被触发的truecrypt.exe。它做了一些天真的假设,但应该给一个想法。

@echo off
setlocal enableextensions enabledelayedexpansion
:: Dependencies: Truecrypt obviously, and sysinternals handles.exe (live.sysinternals.com).
:: To use command line arguments instead of static assignments like these, reference %1 %2 from within script..
set driveletter=x
set yourvolume=c:'temp'your_volume.vol
set yourpassword=your_password
set truecrypt_loc=c:'program files'truecrypt'truecrypt.exe
set handle_loc=c:'temp'handle.exe
:: - check if volume already mounted
"%handle_loc%" -a "%yourvolume%" /accepteula >nul
if %errorlevel% EQU 0 echo This volume is already mounted. && goto :EOF
:: - check if drive letter is in use
if exist %driveletter% echo This drive is already mounted. && goto :EOF
:: - mount tc volume to a specified drive letter
:: silent flag suppresses errors being displayed to user
"%truecrypt_loc%" /letter %driveletter% /password "%yourpassword%" /volume "%yourvolume%" /mountoption rm /quit background /silent
:: - check if drive letter is in use
if exist %driveletter%:' echo Drive was mounted successfully as %driveletter%: && goto :EOF
echo Drive could not be mounted.

请注意,由于某些版本的TrueCrypt可能存在错误,从GUI卸载会导致驱动器号在将来的挂载中不可用。一种解决方法是使用:truecrypt.exe/q/dx(其中x是驱动器号)从命令行卸载。

我可能过于简化了,但是挂载的驱动器上的驱动器标签是唯一的吗?如果是这样,您可以使用简单的查找,如:

private string GetDriveLetter(string volumeLabel)
{
    string driveLetter = "";
    DriveInfo[] dis = DriveInfo.GetDrives();
    foreach (DriveInfo di in dis)
    {
        var dt = di.DriveType;
        if (dt == DriveType.Fixed || dt == DriveType.Removable)
        {
            if (di.VolumeLabel == volumeLabel)
            {
                driveLetter = di.Name.Substring(0, 1).ToUpper();
                break;
            }
        }
    }
    return driveLetter;
}

只是为了确保这一点是正确的:您要确保TrueCrypt通过脚本将某个卷挂载到某个驱动器号,并且如果卷已经挂载,它将不会尝试做任何事情。

Maybe Several Potential Solutions。我将在下面强调几个选项;如果有值得进一步研究的,请告诉我,我将继续研究并更新更多细节。

选项1:Favorites and Auto-Mount

TrueCrypt支持"收藏卷"。

从页面——在以下情况下使用Favorite volumes:

  • 您有一个总是需要挂载到特定驱动器号的卷。
  • 您有一个卷,它需要在其主机设备连接到计算机时自动挂载(例如,一个容器)位于USB闪存驱动器或外置USB硬盘驱动器)。
  • 您有一个卷需要在您登录操作系统时自动挂载。
  • 您有一个卷总是需要挂载为只读或可移动介质。

值得注意的地方:

  • 一个特殊的标签可以应用到每个最喜欢的音量-可能是方便的
  • 你可以运行"TrueCrypt.exe /a favorites /quit"来自动挂载你最喜欢的卷,然后退出。您可能需要对此进行测试,因为truecrypt收藏页面注意到If it is already mounted, an Explorer window is opened for it.

选项2:只检查驱动器号

如果您总是将卷挂载到某个驱动器号上,那么您可以合理地假设该驱动器号上不会有任何其他内容。

如果这是一个合理的假设,你总是可以用PowerShell检查驱动器:

$DriveLetterToCheck = "s:"
$DriveLetterMounted = Test-Path $DriveLetterToCheck #true if it exists
if(!$DriveLetterMounted)
{
  # Run your TrueCrypt mount command
}
如果我想到更好的我会更新的。