利用 PowerShell 脚本恢复 VMware 加密密码
本文记录了我在忘记 VMware Workstation 虚拟机加密密码后,通过 PowerShell 调用 Windows 凭据管理器 API 成功恢复密码的完整过程。如果你也遇到了同样的问题,希望这篇文章能帮到你。
起因
前几天我需要迁移一台之前创建的 VMware 加密虚拟机,选择导出 OVF,结果弹出了密码输入框 —— 我完全不记得当时设置了什么密码。
说实话,这个密码根本不是我主动设置的。VMware Workstation 在某些操作(比如启用加密、克隆加密虚拟机)时会引导你设置加密密码,同时提供一个「Remember the password」(记住密码)选项。当时我随手勾选了这个选项,之后每次打开虚拟机都是自动解锁的。
直到需要迁移虚拟机时,它需要用户主动输入密码了。于是我开始研究恢复方案。
原理
经过一番搜索,我了解到以下关键信息:
- VMware Workstation 在你勾选「Remember the password」时,会将加密密码存储在 Windows 凭据管理器(Credential Manager) 中。
- 每台加密虚拟机都有一个唯一的 GUID,VMware 用这个 GUID 作为凭据的名称(Target Name)来存储密码。
- 虽然你可以在 Windows 的「凭据管理器」界面中看到这些条目,但界面上不会显示密码明文。
- 好消息是,我们可以通过 Windows 的 Win32
CredReadWAPI 直接读取凭据中存储的密码。
换句话说,密码一直都在你的电脑里,只是 VMware 没有提供一个「显示密码」的按钮而已。
恢复步骤
找到虚拟机的加密 GUID
用文本编辑器打开虚拟机的 .vmx 配置文件。这个文件通常位于虚拟机的存储目录下,例如:1
C:\Users\<用户名>\Documents\Virtual Machines\<虚拟机名>\<虚拟机名>.vmx
在文件中搜索 encryptedVM.guid,你会找到类似这样的一行:1
encryptedVM.guid = "{833AB4F5-587E-4B11-9260-4DB13742FA7F}"
记下这个 GUID(包括大括号),后面会用到。
在 PowerShell 中加载 Win32 API
打开 PowerShell,将以下代码完整复制粘贴进去并回车执行:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47Add-Type @"
using System;
using System.Runtime.InteropServices;
public class Win32Cred
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CREDENTIAL
{
public int Flags;
public int Type;
public IntPtr TargetName;
public IntPtr Comment;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
public int CredentialBlobSize;
public IntPtr CredentialBlob;
public int Persist;
public int AttributeCount;
public IntPtr Attributes;
public IntPtr TargetAlias;
public IntPtr UserName;
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CredReadW(
string target, int type, int reservedFlag, out IntPtr credentialPtr);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern void CredFree(IntPtr buffer);
public static string CredRead(string targetName, int type = 1)
{
IntPtr credPtr;
if (CredReadW(targetName, type, 0, out credPtr))
{
CREDENTIAL cred = (CREDENTIAL)Marshal.PtrToStructure(
credPtr, typeof(CREDENTIAL));
string pass = Marshal.PtrToStringAnsi(
cred.CredentialBlob, cred.CredentialBlobSize);
CredFree(credPtr);
return pass;
}
throw new System.ComponentModel.Win32Exception(
Marshal.GetLastWin32Error());
}
}
"@
这段代码通过 C# 的 P / Invoke 机制定义了对 advapi32.dll 中 CredReadW 和 CredFree 函数的调用接口,并封装了一个简洁的 CredRead 方法。
读取密码
继续在 PowerShell 中执行以下命令,将 GUID 替换为你在第一步中找到的值:1
[Win32Cred]::CredRead("{833AB4F5-587E-4B11-9260-4DB13742FA7F}")
如果一切顺利,密码会直接输出到屏幕上:1
2PS C:\Users\Andrew> [Win32Cred]::CredRead("{833AB4F5-587E-4B11-9260-4DB13742FA7F}")
MySecretPassword
就是这么简单。 拿到密码后,回到 VMware 输入即可解锁虚拟机。
总结
整个恢复过程可以概括为三步:
| 步骤 | 操作 | 关键点 |
|---|---|---|
| 1 | 打开 .vmx 文件 | 找到 encryptedVM.guid |
| 2 | 在 PowerShell 中加载 Win32 API | 复制粘贴 Add-Type 代码块 |
| 3 | 调用 CredRead 方法 | 传入 GUID,密码直接输出 |
VMware 的加密密码其实一直安静地躺在 Windows 凭据管理器里,只是没有提供直观的查看方式。通过一小段 PowerShell + C# 互操作代码,就能把它读出来。
希望这篇文章能帮助到同样被 VMware 加密密码困扰的你。
参考文章:andshrew 的 Gist