Exemplo n.º 1
0
        public bool Open(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            _vmEHdr = new VMwareExtentHeader();
            _vmCHdr = new VMwareCowHeader();
            bool embedded = false;

            if (stream.Length > Marshal.SizeOf <VMwareExtentHeader>())
            {
                stream.Seek(0, SeekOrigin.Begin);
                byte[] vmEHdrB = new byte[Marshal.SizeOf <VMwareExtentHeader>()];
                stream.Read(vmEHdrB, 0, Marshal.SizeOf <VMwareExtentHeader>());
                _vmEHdr = Marshal.ByteArrayToStructureLittleEndian <VMwareExtentHeader>(vmEHdrB);
            }

            if (stream.Length > Marshal.SizeOf <VMwareCowHeader>())
            {
                stream.Seek(0, SeekOrigin.Begin);
                byte[] vmCHdrB = new byte[Marshal.SizeOf <VMwareCowHeader>()];
                stream.Read(vmCHdrB, 0, Marshal.SizeOf <VMwareCowHeader>());
                _vmCHdr = Marshal.ByteArrayToStructureLittleEndian <VMwareCowHeader>(vmCHdrB);
            }

            var  ddfStream = new MemoryStream();
            bool vmEHdrSet = false;
            bool cowD      = false;

            if (_vmEHdr.magic == VMWARE_EXTENT_MAGIC)
            {
                vmEHdrSet = true;
                _gdFilter = imageFilter;

                if (_vmEHdr.descriptorOffset == 0 ||
                    _vmEHdr.descriptorSize == 0)
                {
                    throw new Exception("Please open VMDK descriptor.");
                }

                byte[] ddfEmbed = new byte[_vmEHdr.descriptorSize * SECTOR_SIZE];

                stream.Seek((long)(_vmEHdr.descriptorOffset * SECTOR_SIZE), SeekOrigin.Begin);
                stream.Read(ddfEmbed, 0, ddfEmbed.Length);
                ddfStream.Write(ddfEmbed, 0, ddfEmbed.Length);

                embedded = true;
            }
            else if (_vmCHdr.magic == VMWARE_COW_MAGIC)
            {
                _gdFilter = imageFilter;
                cowD      = true;
            }
            else
            {
                byte[] ddfMagic = new byte[0x15];
                stream.Seek(0, SeekOrigin.Begin);
                stream.Read(ddfMagic, 0, 0x15);

                if (!_ddfMagicBytes.SequenceEqual(ddfMagic))
                {
                    throw new Exception("Not a descriptor.");
                }

                stream.Seek(0, SeekOrigin.Begin);
                byte[] ddfExternal = new byte[imageFilter.GetDataForkLength()];
                stream.Read(ddfExternal, 0, ddfExternal.Length);
                ddfStream.Write(ddfExternal, 0, ddfExternal.Length);
            }

            _extents = new Dictionary <ulong, VMwareExtent>();
            ulong currentSector = 0;

            bool matchedCyls = false, matchedHds = false, matchedSpt = false;

            if (cowD)
            {
                int    cowCount = 1;
                string basePath = Path.GetFileNameWithoutExtension(imageFilter.GetBasePath());

                while (true)
                {
                    string curPath;

                    if (cowCount == 1)
                    {
                        curPath = basePath + ".vmdk";
                    }
                    else
                    {
                        curPath = $"{basePath}-{cowCount:D2}.vmdk";
                    }

                    if (!File.Exists(curPath))
                    {
                        break;
                    }

                    IFilter extentFilter = new FiltersList().GetFilter(curPath);
                    Stream  extentStream = extentFilter.GetDataForkStream();

                    if (stream.Length > Marshal.SizeOf <VMwareCowHeader>())
                    {
                        var extHdrCow = new VMwareCowHeader();
                        extentStream.Seek(0, SeekOrigin.Begin);
                        byte[] vmCHdrB = new byte[Marshal.SizeOf <VMwareCowHeader>()];
                        extentStream.Read(vmCHdrB, 0, Marshal.SizeOf <VMwareCowHeader>());
                        extHdrCow = Marshal.ByteArrayToStructureLittleEndian <VMwareCowHeader>(vmCHdrB);

                        if (extHdrCow.magic != VMWARE_COW_MAGIC)
                        {
                            break;
                        }

                        var newExtent = new VMwareExtent
                        {
                            Access   = "RW",
                            Filter   = extentFilter,
                            Filename = extentFilter.GetFilename(),
                            Offset   = 0,
                            Sectors  = extHdrCow.sectors,
                            Type     = "SPARSE"
                        };

                        AaruConsole.DebugWriteLine("VMware plugin", "{0} {1} {2} \"{3}\" {4}", newExtent.Access,
                                                   newExtent.Sectors, newExtent.Type, newExtent.Filename,
                                                   newExtent.Offset);

                        _extents.Add(currentSector, newExtent);
                        currentSector += newExtent.Sectors;
                    }
                    else
                    {
                        break;
                    }

                    cowCount++;
                }

                _imageType = VM_TYPE_SPLIT_SPARSE;
            }
            else
            {
                ddfStream.Seek(0, SeekOrigin.Begin);

                var regexVersion   = new Regex(REGEX_VERSION);
                var regexCid       = new Regex(REGEX_CID);
                var regexParentCid = new Regex(REGEX_CID_PARENT);
                var regexType      = new Regex(REGEX_TYPE);
                var regexExtent    = new Regex(REGEX_EXTENT);
                var regexParent    = new Regex(PARENT_REGEX);
                var regexCylinders = new Regex(REGEX_DDB_CYLINDERS);
                var regexHeads     = new Regex(REGEX_DDB_HEADS);
                var regexSectors   = new Regex(REGEX_DDB_SECTORS);

                var ddfStreamRdr = new StreamReader(ddfStream);

                while (ddfStreamRdr.Peek() >= 0)
                {
                    string line = ddfStreamRdr.ReadLine();

                    Match matchVersion   = regexVersion.Match(line);
                    Match matchCid       = regexCid.Match(line);
                    Match matchParentCid = regexParentCid.Match(line);
                    Match matchType      = regexType.Match(line);
                    Match matchExtent    = regexExtent.Match(line);
                    Match matchParent    = regexParent.Match(line);
                    Match matchCylinders = regexCylinders.Match(line);
                    Match matchHeads     = regexHeads.Match(line);
                    Match matchSectors   = regexSectors.Match(line);

                    if (matchVersion.Success)
                    {
                        uint.TryParse(matchVersion.Groups["version"].Value, out _version);
                        AaruConsole.DebugWriteLine("VMware plugin", "version = {0}", _version);
                    }
                    else if (matchCid.Success)
                    {
                        _cid = Convert.ToUInt32(matchCid.Groups["cid"].Value, 16);
                        AaruConsole.DebugWriteLine("VMware plugin", "cid = {0:x8}", _cid);
                    }
                    else if (matchParentCid.Success)
                    {
                        _parentCid = Convert.ToUInt32(matchParentCid.Groups["cid"].Value, 16);
                        AaruConsole.DebugWriteLine("VMware plugin", "parentCID = {0:x8}", _parentCid);
                    }
                    else if (matchType.Success)
                    {
                        _imageType = matchType.Groups["type"].Value;
                        AaruConsole.DebugWriteLine("VMware plugin", "createType = \"{0}\"", _imageType);
                    }
                    else if (matchExtent.Success)
                    {
                        var newExtent = new VMwareExtent
                        {
                            Access = matchExtent.Groups["access"].Value
                        };

                        if (!embedded)
                        {
                            newExtent.Filter =
                                new FiltersList().
                                GetFilter(Path.Combine(Path.GetDirectoryName(imageFilter.GetBasePath()),
                                                       matchExtent.Groups["filename"].Value));
                        }
                        else
                        {
                            newExtent.Filter = imageFilter;
                        }

                        uint.TryParse(matchExtent.Groups["offset"].Value, out newExtent.Offset);
                        uint.TryParse(matchExtent.Groups["sectors"].Value, out newExtent.Sectors);
                        newExtent.Type = matchExtent.Groups["type"].Value;

                        AaruConsole.DebugWriteLine("VMware plugin", "{0} {1} {2} \"{3}\" {4}", newExtent.Access,
                                                   newExtent.Sectors, newExtent.Type, newExtent.Filename,
                                                   newExtent.Offset);

                        _extents.Add(currentSector, newExtent);
                        currentSector += newExtent.Sectors;
                    }
                    else if (matchParent.Success)
                    {
                        _parentName = matchParent.Groups["filename"].Value;
                        AaruConsole.DebugWriteLine("VMware plugin", "parentFileNameHint = \"{0}\"", _parentName);
                        _hasParent = true;
                    }
                    else if (matchCylinders.Success)
                    {
                        uint.TryParse(matchCylinders.Groups["cylinders"].Value, out _imageInfo.Cylinders);
                        matchedCyls = true;
                    }
                    else if (matchHeads.Success)
                    {
                        uint.TryParse(matchHeads.Groups["heads"].Value, out _imageInfo.Heads);
                        matchedHds = true;
                    }
                    else if (matchSectors.Success)
                    {
                        uint.TryParse(matchSectors.Groups["sectors"].Value, out _imageInfo.SectorsPerTrack);
                        matchedSpt = true;
                    }
                }
            }

            if (_extents.Count == 0)
            {
                throw new Exception("Did not find any extent");
            }

            switch (_imageType)
            {
            case VM_TYPE_MONO_SPARSE:      //"monolithicSparse";
            case VM_TYPE_MONO_FLAT:        //"monolithicFlat";
            case VM_TYPE_SPLIT_SPARSE:     //"twoGbMaxExtentSparse";
            case VM_TYPE_SPLIT_FLAT:       //"twoGbMaxExtentFlat";
            case VMFS_TYPE_FLAT:           //"vmfsPreallocated";
            case VMFS_TYPE_ZERO:           //"vmfsEagerZeroedThick";
            case VMFS_TYPE_THIN:           //"vmfsThin";
            case VMFS_TYPE_SPARSE:         //"vmfsSparse";
            case VMFS_TYPE:                //"vmfs";
            case VM_TYPE_STREAM:           //"streamOptimized";
                break;

            case VM_TYPE_FULL_DEVICE:     //"fullDevice";
            case VM_TYPE_PART_DEVICE:     //"partitionedDevice";
            case VMFS_TYPE_RDM:           //"vmfsRDM";
            case VMFS_TYPE_RDM_OLD:       //"vmfsRawDeviceMap";
            case VMFS_TYPE_RDMP:          //"vmfsRDMP";
            case VMFS_TYPE_RDMP_OLD:      //"vmfsPassthroughRawDeviceMap";
            case VMFS_TYPE_RAW:           //"vmfsRaw";
                throw new
                      ImageNotSupportedException("Raw device image files are not supported, try accessing the device directly.");

            default: throw new ImageNotSupportedException($"Dunno how to handle \"{_imageType}\" extents.");
            }

            bool oneNoFlat = cowD;

            foreach (VMwareExtent extent in _extents.Values)
            {
                if (extent.Filter == null)
                {
                    throw new Exception($"Extent file {extent.Filename} not found.");
                }

                if (extent.Access == "NOACCESS")
                {
                    throw new Exception("Cannot access NOACCESS extents ;).");
                }

                if (extent.Type == "FLAT" ||
                    extent.Type == "ZERO" ||
                    extent.Type == "VMFS" ||
                    cowD)
                {
                    continue;
                }

                Stream extentStream = extent.Filter.GetDataForkStream();
                extentStream.Seek(0, SeekOrigin.Begin);

                if (extentStream.Length < SECTOR_SIZE)
                {
                    throw new Exception($"Extent {extent.Filename} is too small.");
                }

                byte[] extentHdrB = new byte[Marshal.SizeOf <VMwareExtentHeader>()];
                extentStream.Read(extentHdrB, 0, Marshal.SizeOf <VMwareExtentHeader>());
                VMwareExtentHeader extentHdr = Marshal.ByteArrayToStructureLittleEndian <VMwareExtentHeader>(extentHdrB);

                if (extentHdr.magic != VMWARE_EXTENT_MAGIC)
                {
                    throw new Exception($"{extent.Filter} is not an VMware extent.");
                }

                if (extentHdr.capacity < extent.Sectors)
                {
                    throw new
                          Exception($"Extent contains incorrect number of sectors, {extentHdr.capacity}. {extent.Sectors} were expected");
                }

                // TODO: Support compressed extents
                if (extentHdr.compression != COMPRESSION_NONE)
                {
                    throw new ImageNotSupportedException("Compressed extents are not yet supported.");
                }

                if (!vmEHdrSet)
                {
                    _vmEHdr   = extentHdr;
                    _gdFilter = extent.Filter;
                    vmEHdrSet = true;
                }

                oneNoFlat = true;
            }

            if (oneNoFlat &&
                !vmEHdrSet &&
                !cowD)
            {
                throw new
                      Exception("There are sparse extents but there is no header to find the grain tables, cannot proceed.");
            }

            _imageInfo.Sectors = currentSector;

            uint grains    = 0;
            uint gdEntries = 0;
            long gdOffset  = 0;
            uint gtEsPerGt = 0;

            if (oneNoFlat && !cowD)
            {
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.magic = 0x{0:X8}", _vmEHdr.magic);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.version = {0}", _vmEHdr.version);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.flags = 0x{0:X8}", _vmEHdr.flags);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.capacity = {0}", _vmEHdr.capacity);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.grainSize = {0}", _vmEHdr.grainSize);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.descriptorOffset = {0}", _vmEHdr.descriptorOffset);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.descriptorSize = {0}", _vmEHdr.descriptorSize);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.GTEsPerGT = {0}", _vmEHdr.GTEsPerGT);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.rgdOffset = {0}", _vmEHdr.rgdOffset);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.gdOffset = {0}", _vmEHdr.gdOffset);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.overhead = {0}", _vmEHdr.overhead);
                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.uncleanShutdown = {0}", _vmEHdr.uncleanShutdown);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.singleEndLineChar = 0x{0:X2}",
                                           _vmEHdr.singleEndLineChar);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.nonEndLineChar = 0x{0:X2}", _vmEHdr.nonEndLineChar);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.doubleEndLineChar1 = 0x{0:X2}",
                                           _vmEHdr.doubleEndLineChar1);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.doubleEndLineChar2 = 0x{0:X2}",
                                           _vmEHdr.doubleEndLineChar2);

                AaruConsole.DebugWriteLine("VMware plugin", "vmEHdr.compression = 0x{0:X4}", _vmEHdr.compression);

                _grainSize = _vmEHdr.grainSize;
                grains     = (uint)(_imageInfo.Sectors / _vmEHdr.grainSize) + 1;
                gdEntries  = grains / _vmEHdr.GTEsPerGT;
                gtEsPerGt  = _vmEHdr.GTEsPerGT;

                if ((_vmEHdr.flags & FLAGS_USE_REDUNDANT_TABLE) == FLAGS_USE_REDUNDANT_TABLE)
                {
                    gdOffset = (long)_vmEHdr.rgdOffset;
                }
                else
                {
                    gdOffset = (long)_vmEHdr.gdOffset;
                }
            }
            else if (oneNoFlat && cowD)
            {
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.magic = 0x{0:X8}", _vmCHdr.magic);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.version = {0}", _vmCHdr.version);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.flags = 0x{0:X8}", _vmCHdr.flags);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.sectors = {0}", _vmCHdr.sectors);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.grainSize = {0}", _vmCHdr.grainSize);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.gdOffset = {0}", _vmCHdr.gdOffset);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.numGDEntries = {0}", _vmCHdr.numGDEntries);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.freeSector = {0}", _vmCHdr.freeSector);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.cylinders = {0}", _vmCHdr.cylinders);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.heads = {0}", _vmCHdr.heads);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.spt = {0}", _vmCHdr.spt);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.generation = {0}", _vmCHdr.generation);

                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.name = {0}",
                                           StringHandlers.CToString(_vmCHdr.name));

                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.description = {0}",
                                           StringHandlers.CToString(_vmCHdr.description));

                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.savedGeneration = {0}", _vmCHdr.savedGeneration);
                AaruConsole.DebugWriteLine("VMware plugin", "vmCHdr.uncleanShutdown = {0}", _vmCHdr.uncleanShutdown);

                _grainSize            = _vmCHdr.grainSize;
                grains                = (uint)(_imageInfo.Sectors / _vmCHdr.grainSize) + 1;
                gdEntries             = _vmCHdr.numGDEntries;
                gdOffset              = _vmCHdr.gdOffset;
                gtEsPerGt             = grains / gdEntries;
                _imageInfo.MediaTitle = StringHandlers.CToString(_vmCHdr.name);
                _imageInfo.Comments   = StringHandlers.CToString(_vmCHdr.description);
                _version              = _vmCHdr.version;
            }

            if (oneNoFlat)
            {
                if (grains == 0 ||
                    gdEntries == 0)
                {
                    throw new Exception("Some error ocurred setting GD sizes");
                }

                AaruConsole.DebugWriteLine("VMware plugin", "{0} sectors in {1} grains in {2} tables",
                                           _imageInfo.Sectors, grains, gdEntries);

                Stream gdStream = _gdFilter.GetDataForkStream();

                gdStream.Seek(gdOffset * SECTOR_SIZE, SeekOrigin.Begin);

                AaruConsole.DebugWriteLine("VMware plugin", "Reading grain directory");
                byte[] gdBytes = new byte[gdEntries * 4];
                gdStream.Read(gdBytes, 0, gdBytes.Length);
                Span <uint> gd = MemoryMarshal.Cast <byte, uint>(gdBytes);

                AaruConsole.DebugWriteLine("VMware plugin", "Reading grain tables");
                uint currentGrain = 0;
                _gTable = new uint[grains];

                foreach (uint gtOff in gd)
                {
                    byte[] gtBytes = new byte[gtEsPerGt * 4];
                    gdStream.Seek(gtOff * SECTOR_SIZE, SeekOrigin.Begin);
                    gdStream.Read(gtBytes, 0, gtBytes.Length);

                    uint[] currentGt = MemoryMarshal.Cast <byte, uint>(gtBytes).ToArray();
                    Array.Copy(currentGt, 0, _gTable, currentGrain, gtEsPerGt);
                    currentGrain += gtEsPerGt;

                    // TODO: Check speed here

                    /*
                     * for(int i = 0; i < gtEsPerGt; i++)
                     * {
                     *  gTable[currentGrain] = BitConverter.ToUInt32(gtBytes, i * 4);
                     *  currentGrain++;
                     * }
                     */
                }

                _maxCachedGrains = (uint)(MAX_CACHE_SIZE / (_grainSize * SECTOR_SIZE));

                _grainCache = new Dictionary <ulong, byte[]>();
            }

            if (_hasParent)
            {
                IFilter parentFilter =
                    new FiltersList().GetFilter(Path.Combine(imageFilter.GetParentFolder(), _parentName));

                if (parentFilter == null)
                {
                    throw new Exception($"Cannot find parent \"{_parentName}\".");
                }

                _parentImage = new VMware();

                if (!_parentImage.Open(parentFilter))
                {
                    throw new Exception($"Cannot open parent \"{_parentName}\".");
                }
            }

            _sectorCache = new Dictionary <ulong, byte[]>();

            _imageInfo.CreationTime         = imageFilter.GetCreationTime();
            _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            _imageInfo.MediaTitle           = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
            _imageInfo.SectorSize           = SECTOR_SIZE;
            _imageInfo.XmlMediaType         = XmlMediaType.BlockMedia;
            _imageInfo.MediaType            = MediaType.GENERIC_HDD;
            _imageInfo.ImageSize            = _imageInfo.Sectors * SECTOR_SIZE;

            // VMDK version 1 started on VMware 4, so there is a previous version, "COWD"
            _imageInfo.Version = cowD ? $"{_version}" : $"{_version + 3}";

            if (cowD)
            {
                _imageInfo.Cylinders       = _vmCHdr.cylinders;
                _imageInfo.Heads           = _vmCHdr.heads;
                _imageInfo.SectorsPerTrack = _vmCHdr.spt;
            }
            else if (!matchedCyls ||
                     !matchedHds ||
                     !matchedSpt)
            {
                _imageInfo.Cylinders       = (uint)(_imageInfo.Sectors / 16 / 63);
                _imageInfo.Heads           = 16;
                _imageInfo.SectorsPerTrack = 63;
            }

            return(true);
        }