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

            stream.Seek(0, SeekOrigin.Begin);

            if (stream.Length < 512)
            {
                return(false);
            }

            byte[] vhdxIdB = new byte[Marshal.SizeOf(vhdxId)];
            stream.Read(vhdxIdB, 0, Marshal.SizeOf(vhdxId));
            vhdxId = new VhdxIdentifier();
            IntPtr idPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vhdxId));

            Marshal.Copy(vhdxIdB, 0, idPtr, Marshal.SizeOf(vhdxId));
            vhdxId = (VhdxIdentifier)Marshal.PtrToStructure(idPtr, typeof(VhdxIdentifier));
            Marshal.FreeHGlobal(idPtr);

            return(vhdxId.signature == VHDX_SIGNATURE);
        }
Ejemplo n.º 2
0
        public bool Open(IFilter imageFilter)
        {
            Stream stream = imageFilter.GetDataForkStream();

            stream.Seek(0, SeekOrigin.Begin);

            if (stream.Length < 512)
            {
                return(false);
            }

            byte[] vhdxIdB = new byte[Marshal.SizeOf(vhdxId)];
            stream.Read(vhdxIdB, 0, Marshal.SizeOf(vhdxId));
            vhdxId = new VhdxIdentifier();
            IntPtr idPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vhdxId));

            Marshal.Copy(vhdxIdB, 0, idPtr, Marshal.SizeOf(vhdxId));
            vhdxId = (VhdxIdentifier)Marshal.PtrToStructure(idPtr, typeof(VhdxIdentifier));
            Marshal.FreeHGlobal(idPtr);

            if (vhdxId.signature != VHDX_SIGNATURE)
            {
                return(false);
            }

            imageInfo.Application = Encoding.Unicode.GetString(vhdxId.creator);

            stream.Seek(64 * 1024, SeekOrigin.Begin);
            byte[] vHdrB = new byte[Marshal.SizeOf(vHdr)];
            stream.Read(vHdrB, 0, Marshal.SizeOf(vHdr));
            vHdr = new VhdxHeader();
            IntPtr headerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vHdr));

            Marshal.Copy(vHdrB, 0, headerPtr, Marshal.SizeOf(vHdr));
            vHdr = (VhdxHeader)Marshal.PtrToStructure(headerPtr, typeof(VhdxHeader));
            Marshal.FreeHGlobal(headerPtr);

            if (vHdr.Signature != VHDX_HEADER_SIG)
            {
                stream.Seek(128 * 1024, SeekOrigin.Begin);
                vHdrB = new byte[Marshal.SizeOf(vHdr)];
                stream.Read(vHdrB, 0, Marshal.SizeOf(vHdr));
                vHdr      = new VhdxHeader();
                headerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vHdr));
                Marshal.Copy(vHdrB, 0, headerPtr, Marshal.SizeOf(vHdr));
                vHdr = (VhdxHeader)Marshal.PtrToStructure(headerPtr, typeof(VhdxHeader));
                Marshal.FreeHGlobal(headerPtr);

                if (vHdr.Signature != VHDX_HEADER_SIG)
                {
                    throw new ImageNotSupportedException("VHDX header not found");
                }
            }

            stream.Seek(192 * 1024, SeekOrigin.Begin);
            byte[] vRegTableB = new byte[Marshal.SizeOf(vRegHdr)];
            stream.Read(vRegTableB, 0, Marshal.SizeOf(vRegHdr));
            vRegHdr = new VhdxRegionTableHeader();
            IntPtr vRegTabPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vRegHdr));

            Marshal.Copy(vRegTableB, 0, vRegTabPtr, Marshal.SizeOf(vRegHdr));
            vRegHdr = (VhdxRegionTableHeader)Marshal.PtrToStructure(vRegTabPtr, typeof(VhdxRegionTableHeader));
            Marshal.FreeHGlobal(vRegTabPtr);

            if (vRegHdr.signature != VHDX_REGION_SIG)
            {
                stream.Seek(256 * 1024, SeekOrigin.Begin);
                vRegTableB = new byte[Marshal.SizeOf(vRegHdr)];
                stream.Read(vRegTableB, 0, Marshal.SizeOf(vRegHdr));
                vRegHdr    = new VhdxRegionTableHeader();
                vRegTabPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vRegHdr));
                Marshal.Copy(vRegTableB, 0, vRegTabPtr, Marshal.SizeOf(vRegHdr));
                vRegHdr = (VhdxRegionTableHeader)Marshal.PtrToStructure(vRegTabPtr, typeof(VhdxRegionTableHeader));
                Marshal.FreeHGlobal(vRegTabPtr);

                if (vRegHdr.signature != VHDX_REGION_SIG)
                {
                    throw new ImageNotSupportedException("VHDX region table not found");
                }
            }

            vRegs = new VhdxRegionTableEntry[vRegHdr.entries];
            for (int i = 0; i < vRegs.Length; i++)
            {
                byte[] vRegB = new byte[Marshal.SizeOf(vRegs[i])];
                stream.Read(vRegB, 0, Marshal.SizeOf(vRegs[i]));
                vRegs[i] = new VhdxRegionTableEntry();
                IntPtr vRegPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vRegs[i]));
                Marshal.Copy(vRegB, 0, vRegPtr, Marshal.SizeOf(vRegs[i]));
                vRegs[i] = (VhdxRegionTableEntry)Marshal.PtrToStructure(vRegPtr, typeof(VhdxRegionTableEntry));
                Marshal.FreeHGlobal(vRegPtr);

                if (vRegs[i].guid == batGuid)
                {
                    batOffset = (long)vRegs[i].offset;
                }
                else if (vRegs[i].guid == metadataGuid)
                {
                    metadataOffset = (long)vRegs[i].offset;
                }
                else if ((vRegs[i].flags & REGION_FLAGS_REQUIRED) == REGION_FLAGS_REQUIRED)
                {
                    throw new
                          ImageNotSupportedException($"Found unsupported and required region Guid {vRegs[i].guid}, not proceeding with image.");
                }
            }

            if (batOffset == 0)
            {
                throw new Exception("BAT not found, cannot continue.");
            }

            if (metadataOffset == 0)
            {
                throw new Exception("Metadata not found, cannot continue.");
            }

            uint fileParamsOff = 0, vdSizeOff = 0, p83Off = 0, logOff = 0, physOff = 0, parentOff = 0;

            stream.Seek(metadataOffset, SeekOrigin.Begin);
            byte[] metTableB = new byte[Marshal.SizeOf(vMetHdr)];
            stream.Read(metTableB, 0, Marshal.SizeOf(vMetHdr));
            vMetHdr = new VhdxMetadataTableHeader();
            IntPtr metTablePtr = Marshal.AllocHGlobal(Marshal.SizeOf(vMetHdr));

            Marshal.Copy(metTableB, 0, metTablePtr, Marshal.SizeOf(vMetHdr));
            vMetHdr = (VhdxMetadataTableHeader)Marshal.PtrToStructure(metTablePtr, typeof(VhdxMetadataTableHeader));
            Marshal.FreeHGlobal(metTablePtr);

            vMets = new VhdxMetadataTableEntry[vMetHdr.entries];
            for (int i = 0; i < vMets.Length; i++)
            {
                byte[] vMetB = new byte[Marshal.SizeOf(vMets[i])];
                stream.Read(vMetB, 0, Marshal.SizeOf(vMets[i]));
                vMets[i] = new VhdxMetadataTableEntry();
                IntPtr vMetPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vMets[i]));
                Marshal.Copy(vMetB, 0, vMetPtr, Marshal.SizeOf(vMets[i]));
                vMets[i] = (VhdxMetadataTableEntry)Marshal.PtrToStructure(vMetPtr, typeof(VhdxMetadataTableEntry));
                Marshal.FreeHGlobal(vMetPtr);

                if (vMets[i].itemId == fileParametersGuid)
                {
                    fileParamsOff = vMets[i].offset;
                }
                else if (vMets[i].itemId == virtualDiskSizeGuid)
                {
                    vdSizeOff = vMets[i].offset;
                }
                else if (vMets[i].itemId == page83DataGuid)
                {
                    p83Off = vMets[i].offset;
                }
                else if (vMets[i].itemId == logicalSectorSizeGuid)
                {
                    logOff = vMets[i].offset;
                }
                else if (vMets[i].itemId == physicalSectorSizeGuid)
                {
                    physOff = vMets[i].offset;
                }
                else if (vMets[i].itemId == parentLocatorGuid)
                {
                    parentOff = vMets[i].offset;
                }
                else if ((vMets[i].flags & METADATA_FLAGS_REQUIRED) == METADATA_FLAGS_REQUIRED)
                {
                    throw new
                          ImageNotSupportedException($"Found unsupported and required metadata Guid {vMets[i].itemId}, not proceeding with image.");
                }
            }

            byte[] tmp;

            if (fileParamsOff != 0)
            {
                stream.Seek(fileParamsOff + metadataOffset, SeekOrigin.Begin);
                tmp = new byte[8];
                stream.Read(tmp, 0, 8);
                vFileParms = new VhdxFileParameters
                {
                    blockSize = BitConverter.ToUInt32(tmp, 0),
                    flags     = BitConverter.ToUInt32(tmp, 4)
                };
            }
            else
            {
                throw new Exception("File parameters not found.");
            }

            if (vdSizeOff != 0)
            {
                stream.Seek(vdSizeOff + metadataOffset, SeekOrigin.Begin);
                tmp = new byte[8];
                stream.Read(tmp, 0, 8);
                virtualDiskSize = BitConverter.ToUInt64(tmp, 0);
            }
            else
            {
                throw new Exception("Virtual disk size not found.");
            }

            if (p83Off != 0)
            {
                stream.Seek(p83Off + metadataOffset, SeekOrigin.Begin);
                tmp = new byte[16];
                stream.Read(tmp, 0, 16);
                page83Data = new Guid(tmp);
            }

            if (logOff != 0)
            {
                stream.Seek(logOff + metadataOffset, SeekOrigin.Begin);
                tmp = new byte[4];
                stream.Read(tmp, 0, 4);
                logicalSectorSize = BitConverter.ToUInt32(tmp, 0);
            }
            else
            {
                throw new Exception("Logical sector size not found.");
            }

            if (physOff != 0)
            {
                stream.Seek(physOff + metadataOffset, SeekOrigin.Begin);
                tmp = new byte[4];
                stream.Read(tmp, 0, 4);
                physicalSectorSize = BitConverter.ToUInt32(tmp, 0);
            }
            else
            {
                throw new Exception("Physical sector size not found.");
            }

            if (parentOff != 0 && (vFileParms.flags & FILE_FLAGS_HAS_PARENT) == FILE_FLAGS_HAS_PARENT)
            {
                stream.Seek(parentOff + metadataOffset, SeekOrigin.Begin);
                byte[] vParHdrB = new byte[Marshal.SizeOf(vMetHdr)];
                stream.Read(vParHdrB, 0, Marshal.SizeOf(vMetHdr));
                vParHdr = new VhdxParentLocatorHeader();
                IntPtr vParHdrPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vMetHdr));
                Marshal.Copy(vParHdrB, 0, vParHdrPtr, Marshal.SizeOf(vMetHdr));
                vParHdr = (VhdxParentLocatorHeader)Marshal.PtrToStructure(vParHdrPtr, typeof(VhdxParentLocatorHeader));
                Marshal.FreeHGlobal(vParHdrPtr);

                if (vParHdr.locatorType != parentTypeVhdxGuid)
                {
                    throw new
                          ImageNotSupportedException($"Found unsupported and required parent locator type {vParHdr.locatorType}, not proceeding with image.");
                }

                vPars = new VhdxParentLocatorEntry[vParHdr.keyValueCount];
                for (int i = 0; i < vPars.Length; i++)
                {
                    byte[] vParB = new byte[Marshal.SizeOf(vPars[i])];
                    stream.Read(vParB, 0, Marshal.SizeOf(vPars[i]));
                    vPars[i] = new VhdxParentLocatorEntry();
                    IntPtr vParPtr = Marshal.AllocHGlobal(Marshal.SizeOf(vPars[i]));
                    Marshal.Copy(vParB, 0, vParPtr, Marshal.SizeOf(vPars[i]));
                    vPars[i] = (VhdxParentLocatorEntry)Marshal.PtrToStructure(vParPtr, typeof(VhdxParentLocatorEntry));
                    Marshal.FreeHGlobal(vParPtr);
                }
            }
            else if ((vFileParms.flags & FILE_FLAGS_HAS_PARENT) == FILE_FLAGS_HAS_PARENT)
            {
                throw new Exception("Parent locator not found.");
            }

            if ((vFileParms.flags & FILE_FLAGS_HAS_PARENT) == FILE_FLAGS_HAS_PARENT &&
                vParHdr.locatorType == parentTypeVhdxGuid)
            {
                parentImage = new Vhdx();
                bool parentWorks = false;

                foreach (VhdxParentLocatorEntry parentEntry in vPars)
                {
                    stream.Seek(parentEntry.keyOffset + metadataOffset, SeekOrigin.Begin);
                    byte[] tmpKey = new byte[parentEntry.keyLength];
                    stream.Read(tmpKey, 0, tmpKey.Length);
                    string entryType = Encoding.Unicode.GetString(tmpKey);

                    IFilter parentFilter;
                    if (string.Compare(entryType, RELATIVE_PATH_KEY, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        stream.Seek(parentEntry.valueOffset + metadataOffset, SeekOrigin.Begin);
                        byte[] tmpVal = new byte[parentEntry.valueLength];
                        stream.Read(tmpVal, 0, tmpVal.Length);
                        string entryValue = Encoding.Unicode.GetString(tmpVal);

                        try
                        {
                            parentFilter =
                                new FiltersList().GetFilter(Path.Combine(imageFilter.GetParentFolder(), entryValue));
                            if (parentFilter != null && parentImage.Open(parentFilter))
                            {
                                parentWorks = true;
                                break;
                            }
                        }
                        catch { parentWorks = false; }

                        string relEntry = Path.Combine(Path.GetDirectoryName(imageFilter.GetPath()), entryValue);

                        try
                        {
                            parentFilter =
                                new FiltersList().GetFilter(Path.Combine(imageFilter.GetParentFolder(), relEntry));
                            if (parentFilter == null || !parentImage.Open(parentFilter))
                            {
                                continue;
                            }

                            parentWorks = true;
                            break;
                        }
                        catch
                        {
                            // ignored
                        }
                    }
                    else if (string.Compare(entryType, VOLUME_PATH_KEY, StringComparison.OrdinalIgnoreCase) ==
                             0 ||
                             string.Compare(entryType, ABSOLUTE_WIN32_PATH_KEY, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        stream.Seek(parentEntry.valueOffset + metadataOffset, SeekOrigin.Begin);
                        byte[] tmpVal = new byte[parentEntry.valueLength];
                        stream.Read(tmpVal, 0, tmpVal.Length);
                        string entryValue = Encoding.Unicode.GetString(tmpVal);

                        try
                        {
                            parentFilter =
                                new FiltersList().GetFilter(Path.Combine(imageFilter.GetParentFolder(), entryValue));
                            if (parentFilter == null || !parentImage.Open(parentFilter))
                            {
                                continue;
                            }

                            parentWorks = true;
                            break;
                        }
                        catch
                        {
                            // ignored
                        }
                    }
                }

                if (!parentWorks)
                {
                    throw new Exception("Image is differential but parent cannot be opened.");
                }

                hasParent = true;
            }

            chunkRatio = (long)(Math.Pow(2, 23) * logicalSectorSize / vFileParms.blockSize);
            dataBlocks = virtualDiskSize / vFileParms.blockSize;
            if (virtualDiskSize % vFileParms.blockSize > 0)
            {
                dataBlocks++;
            }

            long batEntries;

            if (hasParent)
            {
                long sectorBitmapBlocks = (long)dataBlocks / chunkRatio;
                if (dataBlocks % (ulong)chunkRatio > 0)
                {
                    sectorBitmapBlocks++;
                }
                sectorBitmapPointers = new ulong[sectorBitmapBlocks];

                batEntries = sectorBitmapBlocks * (chunkRatio - 1);
            }
            else
            {
                batEntries = (long)(dataBlocks + (dataBlocks - 1) / (ulong)chunkRatio);
            }

            DicConsole.DebugWriteLine("VHDX plugin", "Reading BAT");

            long readChunks = 0;

            blockAllocationTable = new ulong[dataBlocks];
            byte[] batB = new byte[batEntries * 8];
            stream.Seek(batOffset, SeekOrigin.Begin);
            stream.Read(batB, 0, batB.Length);

            ulong skipSize = 0;

            for (ulong i = 0; i < dataBlocks; i++)
            {
                if (readChunks == chunkRatio)
                {
                    if (hasParent)
                    {
                        sectorBitmapPointers[skipSize / 8] = BitConverter.ToUInt64(batB, (int)(i * 8 + skipSize));
                    }

                    readChunks = 0;
                    skipSize  += 8;
                }
                else
                {
                    blockAllocationTable[i] = BitConverter.ToUInt64(batB, (int)(i * 8 + skipSize));
                    readChunks++;
                }
            }

            if (hasParent)
            {
                DicConsole.DebugWriteLine("VHDX plugin", "Reading Sector Bitmap");

                MemoryStream sectorBmpMs = new MemoryStream();
                foreach (ulong pt in sectorBitmapPointers)
                {
                    switch (pt & BAT_FLAGS_MASK)
                    {
                    case SECTOR_BITMAP_NOT_PRESENT:
                        sectorBmpMs.Write(new byte[1048576], 0, 1048576);
                        break;

                    case SECTOR_BITMAP_PRESENT:
                        stream.Seek((long)((pt & BAT_FILE_OFFSET_MASK) * 1048576), SeekOrigin.Begin);
                        byte[] bmp = new byte[1048576];
                        stream.Read(bmp, 0, bmp.Length);
                        sectorBmpMs.Write(bmp, 0, bmp.Length);
                        break;

                    default:
                        if ((pt & BAT_FLAGS_MASK) != 0)
                        {
                            throw new
                                  ImageNotSupportedException($"Unsupported sector bitmap block flags (0x{pt & BAT_FLAGS_MASK:X16}) found, not proceeding.");
                        }

                        break;
                    }
                }

                sectorBitmap = sectorBmpMs.ToArray();
                sectorBmpMs.Close();
            }

            maxBlockCache  = (int)(MAX_CACHE_SIZE / vFileParms.blockSize);
            maxSectorCache = (int)(MAX_CACHE_SIZE / logicalSectorSize);

            imageStream = stream;

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

            imageInfo.CreationTime         = imageFilter.GetCreationTime();
            imageInfo.LastModificationTime = imageFilter.GetLastWriteTime();
            imageInfo.MediaTitle           = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
            imageInfo.SectorSize           = logicalSectorSize;
            imageInfo.XmlMediaType         = XmlMediaType.BlockMedia;
            imageInfo.MediaType            = MediaType.GENERIC_HDD;
            imageInfo.ImageSize            = virtualDiskSize;
            imageInfo.Sectors           = imageInfo.ImageSize / imageInfo.SectorSize;
            imageInfo.DriveSerialNumber = page83Data.ToString();

            // TODO: Separate image application from version, need several samples.

            imageInfo.Cylinders       = (uint)(imageInfo.Sectors / 16 / 63);
            imageInfo.Heads           = 16;
            imageInfo.SectorsPerTrack = 63;

            return(true);
        }