With the release of Volatility 2.3, we've adapted and ported Nir's code into the core framework, giving you even more flexibility with the types of memory dumps you can analyze. Unlike other memory dump file formats that simply store basic metadata, the .vmss and .vmsn files contain a fairly complex structure layout which the physical memory runs, the VM configuration data, CPU registers, and even PNG thumbnails of the VM's screen.
File Format
At offset 0 of the .vmss/.vmsn file, there's a _VMWARE_HEADER structure, which looks like this:
>>> dt("_VMWARE_HEADER") '_VMWARE_HEADER' (12 bytes) 0x0 : Magic ['unsigned int'] 0x8 : GroupCount ['unsigned int'] 0xc : Groups ['array', <function <lambda> at 0x1046b7320>, ['_VMWARE_GROUP']]
As you can see there's a magic value, which must be 0xbed2bed0, 0xbad1bad1, 0xbed2bed2, or 0xbed3bed3 for the file to be considered valid. Following the magic value, there is an array of _VMWARE_GROUP structures (of count GroupCount), each of which look like this:
>>> dt("_VMWARE_GROUP") '_VMWARE_GROUP' (80 bytes) 0x0 : Name ['String', {'length': 64, 'encoding': 'utf8'}] 0x40 : TagsOffset ['unsigned long long']
The Name field is a string that identifies the type of data contained in the group. Here are a few of the groups just to give you an idea of what's inside:
- Checkpoint: VMware product that produced the memory dump, along with version and build numbers, platform, memory size, and FSB size.
- cpu: values for all of the cpu's 32-bit registers (EIP, EAX, EBX, etc), 64-bit registers if applicable (RAX, RCX, RDX, etc), EFLAGS, IDT, control registers, debug registers, MSRs (sysEnterCS, sysEnterESP, sysenterEIP), and floating point registers.
- memory: information on the physical memory runs, including page number, size of each region, and contents of the region.
- Snapshot: contents of the .vmx configuration file at the time of the snapshot, including the nvram file and extended configuration file.
- scsiX, ideX: details on the connected SCSI and IDE devices (X is the 0-indexed device number)
- PCIBridgeX: details on the connected PCI devices (X is the 0-indexed device number)
- VGA, SVGA: colormaps describing the current state of the video adaptor
- EthernetX: ethernet adaptor state, including eeprom, flash, IP, and other data
That's just the tip of the iceberg. There are also groups named DMA, CMOS, FlashRam, Keyboard, serial, MemoryHotplug, vmDebugControl - all of which can be very interesting sources of information in forensic investigations.
Now, how exactly is data organized within these groups? The TagsOffset member is an offset in the .vmss/.vmsn file where an array of _VMWARE_TAG structures can be found. An example of the structure is shown below:
>>> dt("_VMWARE_TAG") '_VMWARE_TAG' (None bytes) 0x0 : Flags ['unsigned char'] 0x1 : NameLength ['unsigned char'] 0x2 : Name ['String', {'length': <function <lambda> at 0x1046b7398>, 'encoding': 'utf8'}]
The tag structures are a bit more complex than others. They have a Name field and a Flags field which devotes some bits to the length of the data associated with the tag, and a set of indices (not shown) which allow you to distinguish between multiple tags with the same name within a group.
The data for a tag follows the _VMWARE_TAG structure, however there are a few intricacies that Nir researched and are better understood by reading the source code of the address space. If the system has less than 4 GB of RAM, there will be a single physical memory run stored in a group named "memory" and a tag named "Memory" using indices [0][0]. For systems with greater than 4 GB of RAM, there will be multiple runs, also in a group named "memory" but including tags named "Memory", "regionPPN", "regionPageNum", and "regionSize."
Metadata
You can dump meta-data from .vmss/.vmsn files using the vmwareinfo plugin. If the data in a tag is 1, 2, 4, or 8 bytes, it's formatted as a number. If its more than 8 bytes and you supply --verbose to the plugin, you'll get a hexdump.
The example below shows a VMware saved state file from ESX 4.1.0. The group and tag names are combined in the Name column, but separated with a forward slash. You can see the values of the volatile CPU registers and the beginning of the .vmx file contents for the snapshot.
$ python vol.py -f Win7SP1x64-d8737a34.vmss vmwareinfo --verbose
Magic: 0xbad1bad1 (Version 1)
Group count: 0x5c
File Offset PhysMem Offset Size
----------- -------------- ----------
0x000010000 0x000000000000 0xc0000000
0x0c0010000 0x000100000000 0xc0000000
DataOffset DataSize Name Value
---------- ---------- ------------------------------------------------- -----
0x00001cd9 0x4 Checkpoint/fileversion 0xa
0x00001cfc 0x100 Checkpoint/ProductName
0x00001cfc 56 4d 77 61 72 65 20 45 53 58 00 00 00 00 00 00 VMware.ESX......
0x00001d0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[snip]
0x00001e1d 0x100 Checkpoint/VersionNumber
0x00001e1d 34 2e 31 2e 30 00 00 00 00 00 00 00 00 00 00 00 4.1.0...........
0x00001e2d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[snip]
0x00002046 0x4 Checkpoint/Platform 0x1
0x00002055 0x4 Checkpoint/usageMode 0x1
0x00002062 0x4 Checkpoint/memSize 0x1800
0x00002071 0x4 Checkpoint/maxFBSize 0x800000
0x00002085 0x4 cpu/cpu:numVCPUs 0x1
0x00002095 0x4 cpu/eflags[0] 0x86
0x000020a2 0x8 cpu/rip[0] 0xfffff80002c1c0ba
0x000020b3 0x4 cpu/eip[0] 0x2c1c0ba
0x000020c3 0x1 cpu/halted[0] 0
[snip]
0x00005eea 0x4 cpu/CR[0][0] 0x80050031
0x00005efa 0x4 cpu/CR[0][1] 0x0
0x00005f0a 0x4 cpu/CR[0][2] 0x865eb08
0x00005f1a 0x4 cpu/CR[0][3] 0x187000
0x00005f2a 0x4 cpu/CR[0][4] 0x6f8
0x00005f3c 0x8 cpu/DR64[0][0] 0x0
[snip]
0x00006020 0x8 cpu/DR64[0][6] 0xffff0ff0
0x00006034 0x4 cpu/DR[0][6] 0xffff0ff0
0x00006046 0x8 cpu/DR64[0][7] 0x400
0x0000605a 0x4 cpu/DR[0][7] 0x400
0x0000606c 0x2 cpu/GDTR[0][0] 127
0x0000607c 0x4 cpu/GDTR[0][1] 0x3cd5000
0x0000608e 0x4 cpu/GDTR[0][2] 0xfffff800
0x000060a0 0x2 cpu/IDTR[0][0] 4095
0x000060b0 0x4 cpu/IDTR[0][1] 0x3cd5080
0x000060c2 0x4 cpu/IDTR[0][2] 0xfffff800
[snip]
0x180011963 0x2c29 Snapshot/cfgFile
0x180011953 2e 65 6e 63 6f 64 69 6e 67 20 3d 20 22 55 54 46 .encoding.=."UTF
0x180011963 2d 38 22 0a 63 6f 6e 66 69 67 2e 76 65 72 73 69 -8".config.versi
0x180011973 6f 6e 20 3d 20 22 38 22 0a 76 69 72 74 75 61 6c on.=."8".virtual
0x180011983 48 57 2e 76 65 72 73 69 6f 6e 20 3d 20 22 37 22 HW.version.=."7"
0x180011993 0a 70 63 69 42 72 69 64 67 65 30 2e 70 72 65 73 .pciBridge0.pres
0x1800119a3 65 6e 74 20 3d 20 22 74 72 75 65 22 0a 70 63 69 ent.=."true".pci
0x1800119b3 42 72 69 64 67 65 34 2e 70 72 65 73 65 6e 74 20 Bridge4.present.
0x1800119c3 3d 20 22 74 72 75 65 22 0a 70 63 69 42 72 69 64 =."true".pciBrid
0x1800119d3 67 65 34 2e 76 69 72 74 75 61 6c 44 65 76 20 3d ge4.virtualDev.=
0x1800119e3 20 22 70 63 69 65 52 6f 6f 74 50 6f 72 74 22 0a ."pcieRootPort".
Even More Metadata
We previously introduced you to the ability of taking screenshots from memory dumps using data structures found in GUI memory. These were primitive, wire-frame diagrams, with labels for window titles. If you have a VMware .vmss/.vmsn file, there is another way to extract a full color screenshot of the guest VM at the time the snapshot was taken or the VM's state was saved. In a group named MKSVMX and a tag named imageData, there is an embedded PNG file. All you have to do is pass the --dump-dir parameter to Volatility and the screenshot will be extracted to your desired output directory.
For example:
$ mkdir screenshot $ python vol.py -f Win7SP1x64-d8737a34.vmss vmwareinfo --verbose --dump-dir=screenshot/
Now check what you've got in your screenshot directory:
Conclusion
We must extend a huge thanks to Nir Izraeli for creating the vmsnparser project and providing the foundation for Volatility's VMware address space. VMware snapshot and saved state files are full of valuable information even beyond the contents of the VM's physical memory. The only downside is that some VMware products have been reported to create both a .vmss and .vmem file, where the .vmss only contains metadata describing the contents of the .vmem file. In these cases, especially for larger memory dumps (from VMs with more than 4GB RAM), there can be issues parsing the .vmem files. Until further notice, Volatility does not fully support (as in YMMV) these types of memory dumps that are split across multiple files, however in our experience the conditions are seemingly rare.
No comments:
Post a Comment