Decrypt the encrypted data files of a VMware Workstation / Fusion virtual machine -
.vmem (saved RAM), .vmsn / .vmss (snapshot / suspend state) and .nvram - using
only the VM password.
VMware forces "partial" VM encryption on Windows 11 guests that have a vTPM, which
also encrypts the memory/snapshot files. That makes them unusable for memory forensics
(Volatility, etc.) until they're decrypted. This tool reproduces VMware's encobj
decryption in pure Python so you don't need ESXi or VMware's internal tooling for the
decryption step.
Scope / honesty up front: this tool fully and correctly performs the decryption. For
.vmsn/.vmss/.nvramthe decrypted output is directly usable. For.vmem, VMware compresses then encrypts, so the decrypted memory is still in VMware's proprietary compressed checkpoint layout, whichvmem_flatten.pythen expands to a flat image. See Getting a Volatility-ready image.
Tested on: VMware® Workstation Pro 26H1, guest Windows 11 25H2 (build 26100),
analysed with Volatility 3 (2.28). The encobj decryption and the block/LZ container were
reverse-engineered against this build's vmware-vmx; very different VMware versions may
use a different checkpoint format (the tools fail loudly rather than producing silent
garbage, so you'll know).
STAGE 1 (password recovery) STAGE 2 (this tool)
.vmx ──VM-Password-Extractor──▶ $vmx$ hash ──hashcat──▶ password ─┐
▼
password ─PBKDF2-HMAC-SHA1(salt,10000)─▶ KEK
KEK[:32] ─AES-256-CBC─▶ keySafe dict ─▶ config_key (64 B)
config_key[:32] ─AES-256-CBC─▶ encryption.data ─▶ dataFileKey (64 B)
dataFileKey[:32] = AES-256-CBC key for .vmem/.vmsn/.vmss/.nvram
VMware labels every key XTS-AES-256, but it actually uses the first 256 bits as an
AES-256-CBC key - it is not real XTS. (Real XTS will not decrypt these files; that
trips up most people who try.)
[0x000 .. 0x1000) 4096-byte plaintext header
u32 magic @0x00 = 0x8943dd9e
u32 version @0x04 (1 = vmsn, 2 = vmem)
u32 data_per_page @0x08 = 4064
u32 iv_size @0x0c = 16
u32 mac_size @0x10 = 16
u64 logical_size @0x18 (trim the decrypted output to this)
[0x1000 .. EOF) 4096-byte on-disk pages, each:
[ ciphertext : 4064 ][ IV : 16 ][ MAC : 16 ]
plaintext = AES-256-CBC( ciphertext, key = dataFileKey[:32], iv = the page's IV )
git clone https://github.com/heeeyaaaa/vmem-decrypt
cd vmem-decrypt
pip install -r requirements.txt # just: cryptographyThe .vmx holds a PBKDF2 verifier, not the keys. Extract it as a crackable hash and
brute/dictionary-crack it:
# extract the hash from the .vmx (https://github.com/archidote/VM-Password-Extractor)
python3 VM-Password-Extractor.py --vmx VM.vmx --vmx-password-hash-to-hashcat
# -> $vmx$0$10000$<salt>$<hash>
# crack it with hashcat (VMware VMX = mode 27400)
hashcat -m 27400 hash.txt /usr/share/wordlists/rockyou.txt(John the Ripper also works; the same $vmx$… hash is its VMware format.)
# decrypt straight from the .vmx + recovered password
python3 vmem_decrypt.py VM-Snapshot1.vmsn VM-Snapshot1.dec.vmsn --vmx VM.vmx --password 'P@ssw0rd'
python3 vmem_decrypt.py VM-Snapshot1.vmem VM-Snapshot1.dec.vmem --vmx VM.vmx --password 'P@ssw0rd'
# or recover the key once and reuse it
python3 vmem_decrypt.py --vmx VM.vmx --password 'P@ssw0rd' --print-key
python3 vmem_decrypt.py VM.vmem VM.dec.vmem --key 151bcbc1...981f85
# inspect a file's structure without decrypting
python3 vmem_inspect.py VM-Snapshot1.vmemVerify it worked: a correctly decrypted .vmsn/.vmss starts with a VMware snapshot
magic (0xbed2bed2, also 0xbed2bed0 / 0xbad1bad1 / 0xbed3bed3), followed by a u32
group count and ASCII group names (Checkpoint, ConfigParams, memory, cpu, …).
For .vmsn / .vmss / .nvram: the decrypted file is already in VMware's native format
and is directly usable.
For .vmem: VMware compresses then encrypts, so the decrypted .vmem is still VMware's
compressed checkpoint format. Expand it with vmem_flatten.py, then hand the result to
Volatility together with the decrypted .vmsn:
# expand -- IMPORTANT: name the output <base>.vmem (NOT .raw)
python3 vmem_flatten.py VM-Snapshot1.dec.vmem out.vmem
# put the decrypted .vmsn beside it with the SAME basename, then run vol on the .vmem:
cp VM-Snapshot1.dec.vmsn out.vmsn
vol -f out.vmem windows.info # vol3 auto-detects its vmware layer from the .vmem/.vmsn pair
vol -f out.vmem windows.pslistWhy
.vmem+ a paired.vmsn, not a bare.raw? The flat image is region 0 (phys 0-3 GiB) followed by region 1 (phys 4-7 GiB) - there is a 1 GiB MMIO hole at 3-4 GiB, so file offset ≠ physical address. Volatility's vmware layer uses the.vmsn'smemorygroup to remap the regions; feeding it the bare image as a raw layer fails the kernel/DTB validation. The.vmem/.vmsnnaming is what triggers that layer.
The flat image is the concatenation of the 4 MiB physical blocks. The codec is a custom
byte-oriented LZ77 reverse-engineered from vmware-vmx's checkpoint inflater - see
docs/FORMAT.md for the full container + LZ grammar.
(ESXi's crypto-util encobj decrypt does decrypt and decompress in one step, if you have
access to ESXi.)
Starting point: an encrypted VM you own - VM.vmx, VM-Snapshot1.vmem,
VM-Snapshot1.vmsn - plus the VM password (recovered with VM-Password-Extractor
- hashcat; see Stage 1).
$ python3 vmem_decrypt.py VM-Snapshot1.vmem VM-Snapshot1-dec.vmem --password 'S3cret-Pass!' --vmx VM.vmx
[*] recovered dataFileKey: 7d9f2a…c41e8b
[*] VM-Snapshot1.vmem: magic ok, version 2, 833440 pages, data/page=4064, trim->3387096127
11% (406404064 bytes)
…
95% (3251204064 bytes)
[+] wrote 3387096127 bytes -> VM-Snapshot1-dec.vmem
$ python3 vmem_decrypt.py VM-Snapshot1.vmsn VM-Snapshot1-dec.vmsn --password 'S3cret-Pass!' --vmx VM.vmx
[*] recovered dataFileKey: 7d9f2a…c41e8b
[*] VM-Snapshot1.vmsn: magic ok, version 1, 1601 pages, data/page=4064, trim->6503245
[+] wrote 6503245 bytes -> VM-Snapshot1-dec.vmsnThe .vmsn/.vmss is now directly usable. For the .vmem, flatten it and pair
it with the decrypted .vmsn (same basename) for Volatility:
$ python3 vmem_flatten.py VM-Snapshot1-dec.vmem VM-Snapshot1-flat.vmem
block 1400: in 0x9522d13f/a5506698, out 5871763456
[+] 1552 blocks -> 6509559808 bytes flat image -> VM-Snapshot1-flat.vmem
$ cp VM-Snapshot1-dec.vmsn VM-Snapshot1-flat.vmsn # same basename, beside the .vmem
$ vol -f VM-Snapshot1-flat.vmem windows.info # vol3 auto-pairs via its vmware layer
Variable Value
Kernel Base 0xf80xxxxxxxxx
DTB 0x1ae000
Symbols …/ntkrnlmp.pdb/<GUID>-1/…
Is64Bit True
NtMajorVersion 10
NtMinorVersion 0
SystemTime 2026-06-24 18:23:11
NumberOfProcessors 2| File | Decrypt | Volatility-ready |
|---|---|---|
.vmsn / .vmss |
✅ | ✅ (native format) |
.nvram |
✅ | n/a |
.vmem |
✅ | ✅ (via vmem_flatten.py, paired with the decrypted .vmsn) |
- Key-chain reference: RF3/VMwareVMX, axcheron/pyvmx-cracker
- Hash extraction: archidote/VM-Password-Extractor
encobjcontainer format + per-page AES-256-CBC layout reverse-engineered for this tool.
Licensed under the MIT License.