public PropertyStoreDataBlock(byte[] rawBytes)
        {
            Signature = ExtraDataTypes.PropertyStoreDataBlock;

            Size = BitConverter.ToUInt32(rawBytes, 0);

            var propBytes = new byte[Size - 8];
            Buffer.BlockCopy(rawBytes, 8, propBytes, 0, (int) Size - 8);

            PropertyStore = new PropertyStore(propBytes);
        }
示例#2
0
        public Beef0021(byte[] rawBytes)
            : base(rawBytes)
        {
            if (Signature != 0xbeef0021)
            {
                throw new Exception($"Signature mismatch! Should be 0xbeef0021 but is {Signature}");
            }

            var propStore = new PropertyStore(rawBytes.Skip(8).ToArray());

            PropertyStore = propStore;

            VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
        }
示例#3
0
        public Beef0021(byte[] rawBytes)
            : base(rawBytes)
        {
            if (Signature != 0xbeef0021)
            {
                throw new Exception($"Signature mismatch! Should be 0xbeef0021 but is {Signature}");
            }

            var propStore = new PropertyStore(rawBytes.Skip(8).ToArray());


            PropertyStore = propStore;


            VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
        }
示例#4
0
        public Beef0026(byte[] rawBytes)
            : base(rawBytes)
        {
            if (Signature != 0xbeef0026)
            {
                throw new Exception($"Signature mismatch! Should be Beef0026 but is {Signature}");
            }


            if (rawBytes[8] == 0x11 || rawBytes[8] == 0x10 || rawBytes[8] == 0x12 || rawBytes[8] == 0x34 || rawBytes[8] == 0x31)
            {
                var ft1 = DateTimeOffset.FromFileTime((long)BitConverter.ToUInt64(rawBytes, 12)).ToUniversalTime();

                CreatedOn = ft1.ToUniversalTime();


                var ft2 = DateTimeOffset.FromFileTime((long)BitConverter.ToUInt64(rawBytes, 20)).ToUniversalTime();

                LastModified = ft2.ToUniversalTime();


                var ft3 = DateTimeOffset.FromFileTime((long)BitConverter.ToUInt64(rawBytes, 28)).ToUniversalTime();

                LastAccessed = ft3.ToUniversalTime();


                return;
            }

            var shellPropertySheetListSize = BitConverter.ToUInt16(rawBytes, 8);

            if (shellPropertySheetListSize > rawBytes.Length - 8)
            {
                //not enough data for there to be a property store, so bail
                return;
            }

            var propBytes = rawBytes.Skip(8).Take(shellPropertySheetListSize).ToArray();

            PropertyStore = new PropertyStore(propBytes);

            VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 4);
        }
示例#5
0
        public override string ToString()
        {
            var sb = new StringBuilder();

            sb.AppendLine(base.ToString());
            sb.AppendLine();

            if (CreatedOn.HasValue)
            {
                sb.AppendLine(
                    $"Created: {CreatedOn.Value.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}");
            }

            if (LastModified.HasValue)
            {
                sb.AppendLine(
                    $"Last modified: {LastModified.Value.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}");
            }

            if (LastAccessed.HasValue)
            {
                sb.AppendLine(
                    $"Last accessed: {LastAccessed.Value.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}");
            }

            if (PropertyStore != null)
            {
                if (PropertyStore.Sheets.Count > 0)
                {
                    sb.AppendLine("Property Sheets");

                    sb.AppendLine(PropertyStore.ToString());
                    sb.AppendLine();
                }
            }

            return(sb.ToString());
        }
        public PropertySheet(byte[] contents)
        {
            PropertyNames = new Dictionary<string, string>();

            var sheetindex = 0;

            var serializedSize = BitConverter.ToInt32(contents, sheetindex);
            sheetindex = 4; //skip size

            Size = serializedSize;

            var serializedVersion = BitConverter.ToString(contents, sheetindex, 4);

            sheetindex += 4;

            if (serializedVersion != "31-53-50-53")
            {
                throw new Exception($"Version mismatch! {serializedVersion} != 31-53-50-53");
            }

            Version = serializedVersion;

            var rawguidshellProperty = new byte[16];

            Array.Copy(contents, sheetindex, rawguidshellProperty, 0, 16);

            var formatClassIdguid = Utils.ExtractGuidFromShellItem(rawguidshellProperty);

            sheetindex += 16;

            GUID = formatClassIdguid;

            if (formatClassIdguid == "d5cdd505-2e9c-101b-9397-08002b2cf9ae")
            {
                //all serialized property values are named properties
                PropertySheetType = PropertySheetTypeEnum.Named;

                var valueSize = 0;
                var propertyName = "";

                var propertyValues = new Dictionary<int, byte[]>();
                var propertySlotNumber = 0;

                while (sheetindex < contents.Length)
                {
                    //cut up shellPropertySheetList into byte arrays based on length, then process each one
                    valueSize = BitConverter.ToInt32(contents, sheetindex);

                    if (valueSize == 0)
                    {
                        break; // we are out of lists
                    }

                    var sheetListBytes = new byte[valueSize];
                    Array.Copy(contents, sheetindex, sheetListBytes, 0, valueSize);

                    propertyValues.Add(propertySlotNumber, sheetListBytes);
                    propertySlotNumber += 1;

                    sheetindex += valueSize;
                } //end of while in shellPropertySheetList

                foreach (var propertyValue in propertyValues)
                {
                    var propertyIndex = 0;

                    valueSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                    propertyIndex += 4;

                    var nameSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                    propertyIndex += 4;

                    propertyIndex += 1; //reserved

                    propertyName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex, nameSize - 2);

                    propertyIndex += (nameSize);

                    var namedType = BitConverter.ToUInt16(propertyValue.Value, propertyIndex);

                    propertyIndex += 2; //skip type
                    propertyIndex += 2; //skip padding?

                    //TODO Combine these with what is below. Make a function to take the type, process and return a string?
                    switch (namedType)
                    {
                        case 0x000b:
                            //VT_BOOL (0x000B)
                            var boolInt = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 8;

                            var boolval = boolInt > 0;

                            PropertyNames.Add(propertyName,
                                boolval.ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0:
                        case 0x1:
                            PropertyNames.Add(propertyName, "");
                            break;

                        case 0x0002:
                            PropertyNames.Add(propertyName,
                                BitConverter.ToInt16(propertyValue.Value, propertyIndex)
                                    .ToString(CultureInfo.InvariantCulture));
                            break;

                        case 0x0003:
                            PropertyNames.Add(propertyName,
                                BitConverter.ToInt32(propertyValue.Value, propertyIndex)
                                    .ToString(CultureInfo.InvariantCulture));
                            break;

                        case 0x0004:
                            PropertyNames.Add(propertyName,
                                BitConverter.ToSingle(propertyValue.Value, propertyIndex)
                                    .ToString(CultureInfo.InvariantCulture));
                            break;

                        case 0x0005:
                            PropertyNames.Add(propertyName,
                                BitConverter.ToDouble(propertyValue.Value, propertyIndex)
                                    .ToString(CultureInfo.InvariantCulture));
                            break;

                        case 0x0008:

                            var uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 4;

                            var unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                uniLength - 2);
                            propertyIndex += (uniLength);

                            PropertyNames.Add(propertyName, unicodeName);

                            //  PropertyNames.Add(propertyName, BitConverter.ToDouble(propertyValue.Value, propertyIndex).ToString(CultureInfo.InvariantCulture));
                            break;

                        case 0x000a:
                            PropertyNames.Add(propertyName,
                                BitConverter.ToUInt32(propertyValue.Value, propertyIndex)
                                    .ToString(CultureInfo.InvariantCulture));
                            break;

                        case 0x0014:
                            //VT_I8 (0x0014)  MUST be an 8-byte signed integer.

                            PropertyNames.Add(propertyName,
                                BitConverter.ToInt64(propertyValue.Value, propertyIndex)
                                    .ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0015:
                            //VT_I8 (0x0014)  MUST be an 8-byte unsigned integer.

                            PropertyNames.Add(propertyName,
                                BitConverter.ToUInt64(propertyValue.Value, propertyIndex)
                                    .ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0016:
                            //VT_I8 (0x0014)  MUST be an 4-byte signed integer.

                            PropertyNames.Add(propertyName,
                                BitConverter.ToInt32(propertyValue.Value, propertyIndex)
                                    .ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0013:
                        case 0x0017:
                            //VT_I8 (0x0014)  MUST be an 4-byte unsigned integer.

                            PropertyNames.Add(propertyName,
                                BitConverter.ToUInt32(propertyValue.Value, propertyIndex)
                                    .ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x001f: //unicode string

                            uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 4;

                            if (uniLength <= 0)
                            {
                                PropertyNames.Add(propertyName, string.Empty);
                                break;
                            }

                            unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                (uniLength*2) - 2);
                            propertyIndex += (uniLength*2);

                            PropertyNames.Add(propertyName, unicodeName);

                            break;

                        case 0x0040:
                            // VT_FILETIME 0x0040 Type is FILETIME, and the minimum property set version is 0.

                            var hexNumber = BitConverter.ToInt64(propertyValue.Value, propertyIndex);
                            // "01CDF407";

                            propertyIndex += 8;

                            var dd = DateTime.FromFileTimeUtc(hexNumber);

                            PropertyNames.Add(propertyName,
                                dd.ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0041:
                            //VT_BLOB 0x0041 Type is binary large object (BLOB), and the minimum property set version is 0

                            //TODO FINISH THIS

                            var blobSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 4;

                            var bytes = propertyValue.Value.Skip(0x69).ToArray();

                            var props = new PropertyStore(bytes);

                            PropertyNames.Add(propertyName,
                                $"BLOB data: {BitConverter.ToString(propertyValue.Value, propertyIndex)}");

                            foreach (var prop in props.Sheets)
                            {
                                foreach (var name in prop.PropertyNames)
                                {
                                    PropertyNames.Add($"{name.Key}", name.Value); // (From BLOB data)
                                }
                            }

                            propertyIndex += blobSize;

                            break;

                        case 0x0042:
                            //TODO FINISH THIS

                            //Type is Stream, and the minimum property set version is 0. VT_STREAM is not allowed in a simple property set.
                            PropertyNames.Add(propertyName,
                                "VT_STREAM not implemented (yet) See extension block section for contents for now");

                            break;

                        default:
                            PropertyNames.Add(propertyName,
                                $"Unknown named property type: {namedType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}. Send file to [email protected] to get support added");
                            break;
                            //throw new Exception($"Unknown named property type: {namedType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}");
                    }
                }

                var terminator = BitConverter.ToInt32(contents, sheetindex);

                if (terminator != 0)
                {
                    throw new Exception($"Expected terminator of 0, but got {terminator}");
                }
            }
            else
            {
                //treat as numeric property values

                PropertySheetType = PropertySheetTypeEnum.Numeric;

                var valueSize = 0;
                var propertyId = 0;

                var propertyValues = new Dictionary<int, byte[]>();
                var propertySlotNumber = 0;

                while (sheetindex < contents.Length)
                {
                    //cut up shellPropertySheetList into byte arrays based on length, then process each one
                    var sheetSize = BitConverter.ToInt32(contents, sheetindex);

                    if (sheetSize == 0)
                    {
                        break; // we are out of lists
                    }

                    var sheetListBytes = new byte[sheetSize];
                    Array.Copy(contents, sheetindex, sheetListBytes, 0, sheetSize);

                    propertyValues.Add(propertySlotNumber, sheetListBytes);
                    propertySlotNumber += 1;

                    sheetindex += sheetSize;
                } //end of while in shellPropertySheetList

                foreach (var propertyValue in propertyValues)
                {
                    var propertyIndex = 0;

                    valueSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                    propertyIndex += 4;

                    propertyId = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                    propertyIndex += 4;

                    propertyIndex += 1; //skip reserved

                    var numericType = BitConverter.ToUInt16(propertyValue.Value, propertyIndex);

                    propertyIndex += 2; //skip type
                    propertyIndex += 2; //skip padding?

                    //TODO Combine these with what is below. Make a function to take the type, process and return a string?
                    switch (numericType)
                    {
                        case 0x1048:
                            //MUST be a VectorHeader followed by a sequence of GUID (Packet Version) packets.

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                "VT_VECTOR data not implemented (yet)");

                            break;
                        case 0x01e:
                            var uniLength1e = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 4;

                            var unicodeName1e =
                                Encoding.Unicode.GetString(propertyValue.Value, propertyIndex, uniLength1e)
                                    .Split('\0')
                                    .First();

                           // Debug.WriteLine($"Find me: {BitConverter.ToString(propertyValue.Value)}, propertyIndex: {propertyIndex} unicodeName1e: {unicodeName1e}");

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), unicodeName1e);

                            break;
                        case 0x001f: //unicode string

                            var uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 4;

                            if (uniLength <= 0)
                            {
                                PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), string.Empty);
                                break;
                            }

                            var unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                (uniLength*2) - 2);
                            propertyIndex += (uniLength*2);

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), unicodeName);

                            break;

                        case 0x000b:
                            //VT_BOOL (0x000B) MUST be a VARIANT_BOOL as specified in [MS-OAUT] section 2.2.27, followed by zero padding to 4 bytes.

                            var boolInt = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 8;

                            var boolval = boolInt > 0;

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                boolval.ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0003:
                            //VT_I4 (0x0003) MUST be a 32-bit signed integer.

                            var signedInt = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 4;

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                signedInt.ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0015:
                            //VT_UI8 (0x0015) MUST be an 8-byte unsigned integer

                            var unsigned8int = BitConverter.ToUInt64(propertyValue.Value, propertyIndex);
                            propertyIndex += 8;

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                unsigned8int.ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0042:
                            //VT_STREAM (0x0042) MUST be an IndirectPropertyName. The storage representing the
                            //(non-simple) property set MUST have a stream element with this name

                            //defer for now

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                "VT_STREAM not implemented");

                            break;

                        case 0x0013:
                            //VT_UI4 (0x0013) MUST be a 4-byte unsigned integer

                            var unsigned4int = BitConverter.ToUInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 4;

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                unsigned4int.ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0001:
                            //VT_NULL (0x0001) MUST be zero bytes in length.

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), "Null");

                            break;

                        case 0x0002:
                            //VT_I2 (0x0002) Either the specified type, or the type of the element or contained field MUST be a 2-byte signed int

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), BitConverter.ToUInt16(propertyValue.Value, propertyIndex).ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x101f:
                            //VT_VECTOR | VT_LPWSTR 0x101F Type is Vector of UnicodeString, and the minimum property set version is 0

                            propertyIndex += 4;

                            unicodeName = string.Empty;

                            if (propertyValue.Value.Length>propertyIndex)
                            {
                                uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                                propertyIndex += 4;

                                unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                    (uniLength * 2) - 2);
                                propertyIndex += (uniLength * 2);
                            }

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), unicodeName);

                            break;

                        case 0x0048:
                            //VT_CLSID 0x0048 Type is CLSID, and the minimum property set version is 0.

                            var rawguid1 = new byte[16];

                            Array.Copy(propertyValue.Value, propertyIndex, rawguid1, 0, 16);

                            propertyIndex += 16;

                            var rawguid = Utils.ExtractGuidFromShellItem(rawguid1);

                            var foldername = Utils.GetFolderNameFromGuid(rawguid);

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), foldername);

                            break;

                        case 0x1011:
                            //VT_VECTOR | VT_UI1 0x1011 Type is Vector of 1-byte unsigned integers, and the minimum property  set version is 0.

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                "VT_VECTOR data not implemented (yet) See extension block section for contents for now");

                            //TODO i see indicators from 0x00, case 0x23febbee: ProcessPropertyViewGUID(rawBytes) in the bits for this
                            // can we pull out the property sheet and add them to the property names here?

                            break;

                        case 0x0040:
                            //VT_FILETIME 0x0040 Type is FILETIME, and the minimum property set version is 0.

                            var hexNumber = BitConverter.ToInt64(propertyValue.Value, propertyIndex);
                            // "01CDF407";

                            propertyIndex += 8;

                            var dd = DateTime.FromFileTimeUtc(hexNumber);

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                dd.ToString(CultureInfo.InvariantCulture));

                            break;

                        case 0x0008:

                            var codePageSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 4;

                            var codePageName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                codePageSize - 2);
                            propertyIndex += (codePageSize);

                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), codePageName);

                            break;

                        default:
                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                $"Unknown numeric property type: {numericType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}. Send file to [email protected] to get support added");
                            break;
                          //  throw new Exception($"Unknown numeric property type: {numericType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}");
                    }
                }

                var terminator = BitConverter.ToInt32(contents, sheetindex);

                if (terminator != 0)
                {
                    throw new Exception($"Expected terminator of 0, but got {terminator}");
                }
            }
        }
        private void ProcessPropertyViewDefault(byte[] rawBytes)
        {
            FriendlyName = "Variable: Users property view";
            var index = 10;

            var shellPropertySheetListSize = BitConverter.ToInt16(rawBytes, index);

            index += 2;

            var identifiersize = BitConverter.ToInt16(rawBytes, index);

            index += 2;

            var identifierData = new byte[identifiersize];

            Array.Copy(rawBytes, index, identifierData, 0, identifiersize);

            index += identifiersize;

            if (shellPropertySheetListSize > 0)
            {
                var propBytes = rawBytes.Skip(index).Take(shellPropertySheetListSize).ToArray();
                var propStore = new PropertyStore(propBytes);

                PropertyStore = propStore;

                var p = propStore.Sheets.Where(t => t.PropertyNames.ContainsKey("32"));

                if (p.Any())
                {
                    //we can now look thru prop bytes for extension blocks
                    //TODO this is a hack until we can process vectors natively

                    var extOffsets = new List<int>();
                    try
                    {
                        var regexObj = new Regex("([0-9A-F]{2})-00-EF-BE", RegexOptions.IgnoreCase);
                        var matchResult = regexObj.Match(BitConverter.ToString(propBytes));
                        while (matchResult.Success)
                        {
                            extOffsets.Add(matchResult.Index);
                            matchResult = matchResult.NextMatch();
                        }

                        foreach (var extOffset in extOffsets)
                        {
                            var binaryOffset = extOffset/3 - 4;
                            var exSize = BitConverter.ToInt16(propBytes, binaryOffset);

                            var exBytes = propBytes.Skip(binaryOffset).Take(exSize).ToArray();

                            var signature1 = BitConverter.ToUInt32(exBytes, 4);

                            var block1 = Utils.GetExtensionBlockFromBytes(signature1, exBytes);

                            ExtensionBlocks.Add(block1);
                        }
                    }
                    catch (ArgumentException ex)
                    {
                        throw ex;
                        // Syntax error in the regular expression
                    }
                }
            }
            else
            {
                if (rawBytes[0x28] == 0x2f ||
                    (rawBytes[0x24] == 0x4e && rawBytes[0x26] == 0x2f && rawBytes[0x28] == 0x41))
                {
                    //we have a good date

                    var zip = new ShellBagZipContents(rawBytes);
                    FriendlyName = zip.FriendlyName;
                    //   LastAccessTime = zip.LastAccessTime;

                    Value = zip.Value;

                    return;
                }
            }

            index += shellPropertySheetListSize;

            index += 2; //move past end of property sheet terminator

            var rawguid = Utils.ExtractGuidFromShellItem(rawBytes.Skip(index).Take(16).ToArray());
            index += 16;

            rawguid = Utils.ExtractGuidFromShellItem(rawBytes.Skip(index).Take(16).ToArray());
            index += 16;

            var name = Utils.GetFolderNameFromGuid(rawguid);

            Value = name;

            var extBlockSize = BitConverter.ToInt16(rawBytes, index);

            if (extBlockSize > 0)
            {
                //process extension blocks

                while (extBlockSize > 0)
                {
                    var extBytes = rawBytes.Skip(index).Take(extBlockSize).ToArray();

                    index += extBlockSize;

                    var signature1 = BitConverter.ToUInt32(extBytes, 4);

                    var block1 = Utils.GetExtensionBlockFromBytes(signature1, extBytes);

                    ExtensionBlocks.Add(block1);

                    extBlockSize = BitConverter.ToInt16(rawBytes, index);
                }
            }

            int terminator = BitConverter.ToInt16(rawBytes, index);

            if (terminator > 0)
            {
                throw new Exception($"Expected terminator of 0, but got {terminator}");
            }

            var valuestring = (from propertySheet in PropertyStore.Sheets
                from propertyName in propertySheet.PropertyNames
                where propertyName.Key == "10"
                select propertyName.Value).FirstOrDefault();

            if (valuestring == null)
            {
                var namesList =
                    (from propertySheet in PropertyStore.Sheets
                            from propertyName in propertySheet.PropertyNames
                            select propertyName.Value)
                        .ToList();

                valuestring = string.Join("::", namesList.ToArray());
            }

            if (valuestring == "")
            {
                valuestring = "No Property sheet value found";
            }

            Value = valuestring;
        }
        public ShellBag0X1F(byte[] rawBytes)
        {
            ExtensionBlocks = new List<IExtensionBlock>();

            PropertyStore = new PropertyStore();

            _sheets = new List<PropertySheet>();

            var index = 0;

            var dataSig = BitConverter.ToUInt32(rawBytes, 6);

            if (dataSig == 0xbeebee00)
            {
                ProcessPropertyViewDefault(rawBytes);
                return;
            }

            if (dataSig == 0xF5A6B710)
            {
                // this is a strange one. it contains a drive letter and other unknown items

                index = 13;

                var dl = Encoding.GetEncoding(1252).GetString(rawBytes, index, 3);

                FriendlyName = "Users property view?: Drive letter";

                Value = dl;

                return;
            }

            if (rawBytes[0] == 0x14) //This is a GUID only
            {
                ProcessGuid(rawBytes);
                return;
            }

            if (rawBytes[0] == 50 || rawBytes[0] == 58) //This is a GUID and a beefXX, usually 25
            {
                ProcessGuid(rawBytes);

                index += 20;

                var extsize = BitConverter.ToInt16(rawBytes, index);

                if (extsize > 0)
                {
                    var signature = BitConverter.ToUInt32(rawBytes, index + 4);

                    var block = Utils.GetExtensionBlockFromBytes(signature, rawBytes.Skip(index).ToArray());

                    ExtensionBlocks.Add(block);
                }

                index += extsize;

                if (index != rawBytes[0])
                {
                    Debug.WriteLine("remaining data!!!");
                }

                return;
            }

            FriendlyName = "Users property view";

            var bin = new BinaryReader(new MemoryStream(rawBytes));

            bin.ReadBytes(2); // skip size

            bin.ReadByte(); //skip indicator (0x1F)

            var sortIndicator = bin.ReadByte();

            var dataSize = bin.ReadUInt16(); // BitConverter.ToUInt16(rawBytes, index);

            var dataSignature = bin.ReadUInt32(); //  BitConverter.ToUInt32(rawBytes, index);

            var propertyStoreSize = bin.ReadUInt16(); //BitConverter.ToUInt16(rawBytes, index);

            var identifierSize = bin.ReadUInt16(); //BitConverter.ToUInt16(rawBytes, index);

            if (identifierSize > 0)
            {
                bin.ReadBytes(identifierSize);
                //index += identifierSize; // whats here?
            }

            if (propertyStoreSize > 0)
            {
                var propertysheetBytes = bin.ReadBytes(propertyStoreSize);

                var propStore = new PropertyStore(propertysheetBytes);

                var p = propStore.Sheets.Where(t => t.PropertyNames.ContainsKey("AutoList"));

                if (p.Any())
                {
                    //we can now look thry prop bytes for extension blocks
                    //TODO this is a hack until we can process vectors natively

                    var extOffsets = new List<int>();
                    try
                    {
                        var regexObj = new Regex("([0-9A-F]{2})-00-EF-BE", RegexOptions.IgnoreCase);
                        var matchResult = regexObj.Match(BitConverter.ToString(propertysheetBytes));
                        while (matchResult.Success)
                        {
                            extOffsets.Add(matchResult.Index);
                            matchResult = matchResult.NextMatch();
                        }

                        foreach (var extOffset in extOffsets)
                        {
                            var binaryOffset = extOffset/3 - 4;
                            var exSize = BitConverter.ToInt16(propertysheetBytes, binaryOffset);

                            var exBytes = propertysheetBytes.Skip(binaryOffset).Take(exSize).ToArray();

                            var signature1 = BitConverter.ToUInt32(exBytes, 4);

                            var block1 = Utils.GetExtensionBlockFromBytes(signature1, exBytes);

                            ExtensionBlocks.Add(block1);
                        }
                    }
                    catch (ArgumentException ex)
                    {
                        throw ex;
                        // Syntax error in the regular expression
                    }
                }

                PropertyStore = propStore;
            }

            bin.ReadBytes(2); //skip end of property sheet marker

            var rawguid = Utils.ExtractGuidFromShellItem(bin.ReadBytes(16));
            //    index += 16;

            rawguid = Utils.ExtractGuidFromShellItem(bin.ReadBytes(16));
            //   index += 16;

            var name = Utils.GetFolderNameFromGuid(rawguid);

            var extsize1 = bin.ReadUInt16(); // BitConverter.ToUInt16(rawBytes, index);

            if (extsize1 > 0)
            {
                //TODO is it ever bigger than one block? if so loop it

                //move position back 2 so we get the entire block of data below
                bin.BaseStream.Position -= 2;

                while (bin.BaseStream.Position != bin.BaseStream.Length)
                {
                    extsize1 = bin.ReadUInt16();

                    if (extsize1 == 0)
                    {
                        break;
                    }

                    bin.BaseStream.Position -= 2;

                    var extBytes = bin.ReadBytes(extsize1);

                    var signature1 = BitConverter.ToUInt32(extBytes, 4);

                    //Debug.WriteLine(" 0x1f bag sig: " + signature1.ToString("X8"));

                    var block1 = Utils.GetExtensionBlockFromBytes(signature1, extBytes);

                    ExtensionBlocks.Add(block1);
                }

                //Trace.Assert(bin.BaseStream.Position == bin.BaseStream.Length);
            }

            Value = name;
        }
        public ShellBagCDBurn(byte[] rawBytes)
        {
            ShortName = string.Empty;

            PropertyStore = new PropertyStore();

            ExtensionBlocks = new List<IExtensionBlock>();

            FriendlyName = "CDBurn";

            var index = 8; //reset index to after signature

            index += 4; //skip 4 unknown
            index += 4; //skip 4 unknown
            index += 4; //skip 4 unknown

            var chunks = new List<byte[]>();

            while (index < rawBytes.Length)
            {
                var subshellitemdatasize = BitConverter.ToInt16(rawBytes, index);
                index += 2;

                if (subshellitemdatasize <= 0)
                {
                    break;
                }

                if (subshellitemdatasize == 1)
                {
                    //some kind of separator
                    index += 2;
                }
                else
                {
                    chunks.Add(rawBytes.Skip(index).Take(subshellitemdatasize).ToArray());
                    index += subshellitemdatasize;
                }
            }

            var oldIndex = index;

            //if (chunks.Count != 2)
            //{
            //    Debug.WriteLine(chunks.Count);
            //}

            foreach (var bytes in chunks)
            {
                index = 0;

                var typeIndicator = bytes[index];
                index += 1;
                index += 1; //skip unknown empty value

                var filesize = BitConverter.ToInt32(rawBytes, index);
                index += 4;

                FileSize = filesize;

                var modDate =
                    Utils.ExtractDateTimeOffsetFromBytes(bytes.Skip(index).Take(4).ToArray());

                LastModificationTime = modDate;

                index += 4;

                index += 2; //skip 2 bytes for file attributes

                var len = 0;

                var shortName = string.Empty;

                //get position of beef0004

                var beefPos = BitConverter.ToString(bytes).IndexOf("04-00-EF-BE", StringComparison.InvariantCulture)/3;
                beefPos = beefPos - 4; //add header back for beef

                var strLen = beefPos - index;

                if (typeIndicator == 0x35)
                {
                    //unicode
                    var tempString = Encoding.Unicode.GetString(bytes, index, strLen - 2);

                    shortName = tempString;
                    index += strLen;
                }
                else
                {
                    //ascii

                    while (bytes[index + len] != 0x0)
                    {
                        len += 1;
                    }

                    var tempBytes = new byte[len];
                    Array.Copy(bytes, index, tempBytes, 0, len);

                    index += len;
                    shortName = Encoding.ASCII.GetString(tempBytes);
                }

                ShortName = shortName;

                while (bytes[index] == 0x0)
                {
                    index += 1;
                }

                var extsize = BitConverter.ToInt16(bytes, index);

                var signature = BitConverter.ToUInt32(bytes, index + 4);

                //TODO does this need to check if its a 0xbeef?? regex?
                var block = Utils.GetExtensionBlockFromBytes(signature, bytes.Skip(index).ToArray());

                ExtensionBlocks.Add(block);

                var beef0004 = block as Beef0004;
                if (beef0004 != null)
                {
                    CreatedOnTime = beef0004.CreatedOnTime;
                    LastAccessTime = beef0004.LastAccessTime;
                    Value = beef0004.LongName;
                }
                else
                {
                    Value = "!!! Unable to determine Value !!!";
                }
            }

            if (oldIndex + 5 < rawBytes.Length)
            {
                index = oldIndex + 2;

                _extraBag = new ShellBag0X31(rawBytes.Skip(index).ToArray());

                foreach (var ex in _extraBag.ExtensionBlocks)
                {
                    ExtensionBlocks.Add(new BeefPlaceHolder(null));
                }
            }
        }
示例#10
0
        // public constructors...
        public Beef000e(byte[] rawBytes)
            : base(rawBytes)
        {
            if (Signature != 0xbeef000e)
            {
                throw new Exception($"Signature mismatch! Should be 0xbeef000e but is {Signature}");
            }

            ExtensionBlocks = new List<IExtensionBlock>();

            Bags = new List<IShellBag>();

            var rawguid1 = new byte[16];

            var index = 16;

            Array.Copy(rawBytes, index, rawguid1, 0, 16);

            var rawguid = ShellBagUtils.ExtractGuidFromShellItem(rawguid1);

            var foldername = ShellBagUtils.GetFolderNameFromGuid(rawguid);

            GUIDName = foldername;

            index += 16;

            index += 18;

            PropertyStores = new List<PropertyStore>();

            for (var i = 0; i < 3; i++)
            {
                var len = BitConverter.ToUInt32(rawBytes, index);

                var propStore = new PropertyStore(rawBytes.Skip(index).Take((int)len).ToArray());

                PropertyStores.Add(propStore);

                index += (int)len;
            }

            index += 11;

            var chunks = new List<string>();
            var len1 = 0;
            var s1 = string.Empty;

            var maxLoop = 0;

            while (maxLoop < 3)
            {
                len1 = 0;
                while (rawBytes[ index + len1] != 0x00)
                {
                    len1 += 1;
                }

                s1 = Encoding.ASCII.GetString(rawBytes, index, len1);

                chunks.Add(s1);
                index += len1 + 1;

                maxLoop += 1;
            }

            index += 16;

            while (rawBytes[index + len1] != 0x00)
            {
                len1 += 1;
            }

            s1 = Encoding.ASCII.GetString(rawBytes, index, len1);

            chunks.Add(s1);
            index += len1 + 1;

            index += 1;

            var extSize = 0;
            extSize = BitConverter.ToUInt16(rawBytes, index);

            var sig = BitConverter.ToUInt32(rawBytes, index + 4);

            var block = ShellBagUtils.GetExtensionBlockFromBytes(sig, rawBytes.Skip(index).Take(extSize).ToArray());

            ExtensionBlocks.Add(block);
            index += extSize;

            extSize = BitConverter.ToUInt16(rawBytes, index);

             sig = BitConverter.ToUInt32(rawBytes, index + 4);

             block = ShellBagUtils.GetExtensionBlockFromBytes(sig, rawBytes.Skip(index).Take(extSize).ToArray());

            ExtensionBlocks.Add(block);
            index += extSize;

            extSize = BitConverter.ToUInt16(rawBytes, index);

            while (extSize > 0)
            {
                var sb = new ShellBagTypes.ShellBag0X31(-1, -1, rawBytes.Skip(index).Take(extSize).ToArray(), "Inside Beef000e block");

                Bags.Add(sb);

                index += extSize; // end of the bag
                extSize = BitConverter.ToUInt16(rawBytes, index);
            }

            index += 2; //skip empty bag

            VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
        }
示例#11
0
        // public constructors...
        public Beef000e(byte[] rawBytes)
            : base(rawBytes)
        {
            if (Signature != 0xbeef000e)
            {
                throw new Exception($"Signature mismatch! Should be 0xbeef000e but is {Signature}");
            }

            ExtensionBlocks = new List <IExtensionBlock>();

            Bags = new List <IShellBag>();

            var rawguid1 = new byte[16];

            var index = 16;

            Array.Copy(rawBytes, index, rawguid1, 0, 16);

            var rawguid = Utils.ExtractGuidFromShellItem(rawguid1);

            var foldername = Utils.GetFolderNameFromGuid(rawguid);

            GUIDName = foldername;

            index += 16;

            index += 18;

            PropertyStores = new List <PropertyStore>();

            for (var i = 0; i < 3; i++)
            {
                var len = BitConverter.ToUInt32(rawBytes, index);

                var propStore = new PropertyStore(rawBytes.Skip(index).Take((int)len).ToArray());

                PropertyStores.Add(propStore);

                index += (int)len;
            }



            index += 11;



            var chunks = new List <string>();
            var len1   = 0;
            var s1     = string.Empty;

            var maxLoop = 0;

            while (maxLoop < 3)
            {
                len1 = 0;
                while (rawBytes[index + len1] != 0x00)
                {
                    len1 += 1;
                }

                s1 = Encoding.ASCII.GetString(rawBytes, index, len1);

                chunks.Add(s1);
                index += len1 + 1;

                maxLoop += 1;
            }



            index += 16;


            while (rawBytes[index + len1] != 0x00)
            {
                len1 += 1;
            }

            s1 = Encoding.ASCII.GetString(rawBytes, index, len1);

            chunks.Add(s1);
            index += len1 + 1;


            index += 1;

            var extSize = 0;

            extSize = BitConverter.ToUInt16(rawBytes, index);

            var sig = BitConverter.ToUInt32(rawBytes, index + 4);

            var block = Utils.GetExtensionBlockFromBytes(sig, rawBytes.Skip(index).Take(extSize).ToArray());

            ExtensionBlocks.Add(block);
            index += extSize;

            extSize = BitConverter.ToUInt16(rawBytes, index);

            sig = BitConverter.ToUInt32(rawBytes, index + 4);

            block = Utils.GetExtensionBlockFromBytes(sig, rawBytes.Skip(index).Take(extSize).ToArray());

            ExtensionBlocks.Add(block);
            index += extSize;

            extSize = BitConverter.ToUInt16(rawBytes, index);



            while (extSize > 0)
            {
                var sb = new ShellBag0X31(-1, -1, rawBytes.Skip(index).Take(extSize).ToArray(), "Inside Beef000e block");

                Bags.Add(sb);

                index  += extSize; // end of the bag
                extSize = BitConverter.ToUInt16(rawBytes, index);
            }

            index += 2; //skip empty bag



            VersionOffset = BitConverter.ToInt16(rawBytes, rawBytes.Length - 2);
        }
示例#12
0
        private void ProcessPropertyViewDefault(byte[] rawBytes)
        {
            FriendlyName = "Variable: Users property view";
            var index = 10;

            var shellPropertySheetListSize = BitConverter.ToInt16(rawBytes, index);

            index += 2;

            var identifiersize = BitConverter.ToInt16(rawBytes, index);

            index += 2;

            var identifierData = new byte[identifiersize];

            Array.Copy(rawBytes, index, identifierData, 0, identifiersize);

            index += identifiersize;

            if (shellPropertySheetListSize > 0)
            {
                var propBytes = rawBytes.Skip(index).Take(shellPropertySheetListSize).ToArray();
                var propStore = new PropertyStore(propBytes);

                PropertyStore = propStore;

                var p = propStore.Sheets.Where(t => t.PropertyNames.ContainsKey("32"));

                if (p.Any())
                {
                    //we can now look thry prop bytes for extension blocks
                    //TODO this is a hack until we can process vectors natively

                    var extOffsets = new List<int>();
                    try
                    {
                        var regexObj = new Regex("([0-9A-F]{2})-00-EF-BE", RegexOptions.IgnoreCase);
                        var matchResult = regexObj.Match(BitConverter.ToString(propBytes));
                        while (matchResult.Success)
                        {
                            extOffsets.Add(matchResult.Index);
                            matchResult = matchResult.NextMatch();
                        }

                        foreach (var extOffset in extOffsets)
                        {
                            var binaryOffset = extOffset/3 - 4;
                            var exSize = BitConverter.ToInt16(propBytes, binaryOffset);

                            var exBytes = propBytes.Skip(binaryOffset).Take(exSize).ToArray();

                            var signature1 = BitConverter.ToUInt32(exBytes, 4);

                            //Debug.WriteLine(" 0x1f bag sig: " + signature1.ToString("X8"));

                            var block1 = Utils.GetExtensionBlockFromBytes(signature1, exBytes);

                            ExtensionBlocks.Add(block1);
                        }
                    }
                    catch (ArgumentException ex)
                    {
                        throw ex;
                        // Syntax error in the regular expression
                    }

                    //     Debug.WriteLine("Found 32 key");
                }
            }
            else
            {
                //   Debug.Write("Oh no! No property sheets!");
                // SiAuto.Main.LogWarning("Oh no! No property sheets!");

                if (rawBytes[0x28] == 0x2f ||
                    (rawBytes[0x24] == 0x4e && rawBytes[0x26] == 0x2f && rawBytes[0x28] == 0x41))
                {
                    //we have a good date

                    var zip = new ShellBagZipContents(rawBytes);
                    FriendlyName = zip.FriendlyName;
                    LastAccessTime = zip.LastAccessTime;

                    Value = zip.Value;

                    return;
                }

                //41-75-67-4D is AugM

                if (rawBytes[4] == 0x41 && rawBytes[5] == 0x75 && rawBytes[6] == 0x67 && rawBytes[7] == 0x4D)
                {
                    var cdb = new ShellBagCDBurn(rawBytes);

                    Value = cdb.Value;
                    FriendlyName = cdb.FriendlyName;
                    CreatedOnTime = cdb.CreatedOnTime;
                    LastModificationTime = cdb.LastModificationTime;
                    LastAccessTime = cdb.LastAccessTime;
                    

                    return;
                }

                

                Debug.Write("Oh no! No property sheets!");

                Value = "!!! Unable to determine Value !!!";
            }

            index += shellPropertySheetListSize;

            index += 2; //move past end of property sheet terminator

            if (shellPropertySheetListSize > 0 && index < rawBytes.Length)
            {
                var extBlockSize = BitConverter.ToInt16(rawBytes, index);

                if (extBlockSize > 0)
                {
                    //process extension blocks

                    while (extBlockSize > 0)
                    {
                        var extBytes = rawBytes.Skip(index).Take(extBlockSize).ToArray();

                        index += extBlockSize;

                        var signature1 = BitConverter.ToUInt32(extBytes, 4);


                        var block1 = Utils.GetExtensionBlockFromBytes(signature1, extBytes);

                        ExtensionBlocks.Add(block1);

                        if (index >= rawBytes.Length)
                        {
                            break;
                        }

                        extBlockSize = BitConverter.ToInt16(rawBytes, index);
                    }
                }

//                int terminator = BitConverter.ToInt16(rawBytes, index);
//
//                if (terminator > 0)
//                {
//                    throw new Exception($"Expected terminator of 0, but got {terminator}");
//                }
            }

            var valuestring = (from propertySheet in PropertyStore.Sheets
                from propertyName in propertySheet.PropertyNames
                where propertyName.Key == "10"
                select propertyName.Value).FirstOrDefault();

            if (valuestring == null)
            {
                var namesList =
                    (from propertySheet in PropertyStore.Sheets
                        from propertyName in propertySheet.PropertyNames
                        select propertyName.Value)
                        .ToList();

                valuestring = string.Join("::", namesList.ToArray());
            }

            if (valuestring == "")
            {
                valuestring = "No Property sheet value found";
            }

            Value = valuestring;
        }
示例#13
0
        public ShellBag0X00(byte[] rawBytes)
        {
            _guids = new List<string>();

            ShortName = string.Empty;

            FriendlyName = "Variable";

            PropertyStore = new PropertyStore();

            ExtensionBlocks = new List<IExtensionBlock>();

            // There are a few special cases for 0x00 items, so pull a special sig and see if we have one of those
            var specialDataSig = BitConverter.ToUInt32(rawBytes, 4);

            switch (specialDataSig)
            {
                case 0xc001b000: //00-B0-01-C0-
                    ProcessUrlContainer(rawBytes);

                    return;

                case 0x49534647: // this is a game folder shell item “GFSI”
                    ProcessGameFolderShellItem(rawBytes);

                    return;


                case 0xffffff38: // Control panel CPL file shell item

                    throw new Exception("Send this hive to [email protected] so support can be added!");

                //  return;
            }

            //if we are here this should be a users property view

            var index = 0;

            var shellItemSize = BitConverter.ToUInt16(rawBytes, index);
            index += 2;

            index += 1; // move past signature
            index += 1; // move past unknown

            var dataSize = BitConverter.ToUInt16(rawBytes, index);
            index += 2;
            //   SiAuto.Main.LogMessage("dataSize: {0}", dataSize);

            var dataSig = BitConverter.ToUInt32(rawBytes, index);
            index += 4;
            //   SiAuto.Main.LogMessage("dataSig: {0:X}", dataSig);

            var identifierSize = BitConverter.ToUInt16(rawBytes, index);
            index += 2;
            //    SiAuto.Main.LogMessage("identifierSize: {0}", identifierSize);

            switch (dataSig)
            {
                case 0x00030005:
                case 0x00000005:

                    ProcessFtpSubItem(rawBytes);

                    break;
                case 0x23febbee:
                    ProcessPropertyViewGuid(rawBytes);

                    return;

                case 0x10312005:

                    ProcessMtpType2(rawBytes);

                    return;

                case 0x00:
                    //this is the contents of a zip file?

                    ProcessZipFileContents(rawBytes);

                    return;

                case 0x7192006:

                    ProcessMtpType1(rawBytes);

                    return;

                default: // includes known 0xbeebee00
                    if (rawBytes.Length <= 0x64)
                    {
                        FriendlyName = "Server name";
                        Value = Encoding.Unicode.GetString(rawBytes, 6, rawBytes.Length - 6).Replace("\0", string.Empty);
                    }
                    else
                    {
                        ProcessPropertyViewDefault(rawBytes);
                    }

                    break;
            }
        }
示例#14
0
        public PropertySheet(byte[] contents)
        {
            PropertyNames = new Dictionary <string, string>();

            var sheetindex = 0;

            var serializedSize = BitConverter.ToInt32(contents, sheetindex);

            sheetindex = 4; //skip size

            Size = serializedSize;

            var serializedVersion = BitConverter.ToString(contents, sheetindex, 4);

            sheetindex += 4;

            if (serializedVersion != "31-53-50-53")
            {
                throw new Exception($"Version mismatch! {serializedVersion} != 31-53-50-53");
            }

            Version = serializedVersion;

            var rawguidshellProperty = new byte[16];

            Array.Copy(contents, sheetindex, rawguidshellProperty, 0, 16);

            var formatClassIdguid = Utils.ExtractGuidFromShellItem(rawguidshellProperty);

            sheetindex += 16;

            GUID = formatClassIdguid;

            if (formatClassIdguid == "d5cdd505-2e9c-101b-9397-08002b2cf9ae")
            {
                //all serialized property values are named properties
                PropertySheetType = PropertySheetTypeEnum.Named;

                var valueSize    = 0;
                var propertyName = "";

                var propertyValues     = new Dictionary <int, byte[]>();
                var propertySlotNumber = 0;

                while (sheetindex < contents.Length)
                {
                    //cut up shellPropertySheetList into byte arrays based on length, then process each one
                    valueSize = BitConverter.ToInt32(contents, sheetindex);

                    if (valueSize == 0)
                    {
                        break; // we are out of lists
                    }

                    var sheetListBytes = new byte[valueSize];
                    Array.Copy(contents, sheetindex, sheetListBytes, 0, valueSize);

                    propertyValues.Add(propertySlotNumber, sheetListBytes);
                    propertySlotNumber += 1;

                    sheetindex += valueSize;
                } //end of while in shellPropertySheetList

                foreach (var propertyValue in propertyValues)
                {
                    var propertyIndex = 0;

                    valueSize      = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                    propertyIndex += 4;

                    var nameSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                    propertyIndex += 4;

                    propertyIndex += 1; //reserved

                    propertyName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex, nameSize - 2);

                    propertyIndex += (nameSize);

                    var namedType = BitConverter.ToUInt16(propertyValue.Value, propertyIndex);

                    propertyIndex += 2; //skip type
                    propertyIndex += 2; //skip padding?

                    //TODO Combine these with what is below. Make a function to take the type, process and return a string?
                    switch (namedType)
                    {
                    case 0x000b:
                        //VT_BOOL (0x000B)
                        var boolInt = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 8;

                        var boolval = boolInt > 0;

                        PropertyNames.Add(propertyName,
                                          boolval.ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0:
                    case 0x1:
                        PropertyNames.Add(propertyName, "");
                        break;

                    case 0x0002:
                        PropertyNames.Add(propertyName,
                                          BitConverter.ToInt16(propertyValue.Value, propertyIndex)
                                          .ToString(CultureInfo.InvariantCulture));
                        break;

                    case 0x0003:
                        PropertyNames.Add(propertyName,
                                          BitConverter.ToInt32(propertyValue.Value, propertyIndex)
                                          .ToString(CultureInfo.InvariantCulture));
                        break;

                    case 0x0004:
                        PropertyNames.Add(propertyName,
                                          BitConverter.ToSingle(propertyValue.Value, propertyIndex)
                                          .ToString(CultureInfo.InvariantCulture));
                        break;

                    case 0x0005:
                        PropertyNames.Add(propertyName,
                                          BitConverter.ToDouble(propertyValue.Value, propertyIndex)
                                          .ToString(CultureInfo.InvariantCulture));
                        break;

                    case 0x0008:

                        var uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 4;

                        var unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                                                     uniLength - 2);
                        propertyIndex += (uniLength);

                        PropertyNames.Add(propertyName, unicodeName);

                        //  PropertyNames.Add(propertyName, BitConverter.ToDouble(propertyValue.Value, propertyIndex).ToString(CultureInfo.InvariantCulture));
                        break;


                    case 0x000a:
                        PropertyNames.Add(propertyName,
                                          BitConverter.ToUInt32(propertyValue.Value, propertyIndex)
                                          .ToString(CultureInfo.InvariantCulture));
                        break;

                    case 0x0014:
                        //VT_I8 (0x0014)  MUST be an 8-byte signed integer.

                        PropertyNames.Add(propertyName,
                                          BitConverter.ToInt64(propertyValue.Value, propertyIndex)
                                          .ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0015:
                        //VT_I8 (0x0014)  MUST be an 8-byte unsigned integer.

                        PropertyNames.Add(propertyName,
                                          BitConverter.ToUInt64(propertyValue.Value, propertyIndex)
                                          .ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0016:
                        //VT_I8 (0x0014)  MUST be an 4-byte signed integer.

                        PropertyNames.Add(propertyName,
                                          BitConverter.ToInt32(propertyValue.Value, propertyIndex)
                                          .ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0013:
                    case 0x0017:
                        //VT_I8 (0x0014)  MUST be an 4-byte unsigned integer.

                        PropertyNames.Add(propertyName,
                                          BitConverter.ToUInt32(propertyValue.Value, propertyIndex)
                                          .ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x001f:     //unicode string

                        uniLength      = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 4;

                        if (uniLength <= 0)
                        {
                            PropertyNames.Add(propertyName, string.Empty);
                            break;
                        }

                        unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                                                 (uniLength * 2) - 2);
                        propertyIndex += (uniLength * 2);

                        PropertyNames.Add(propertyName, unicodeName);

                        break;

                    case 0x0040:
                        // VT_FILETIME 0x0040 Type is FILETIME, and the minimum property set version is 0.

                        var hexNumber = BitConverter.ToInt64(propertyValue.Value, propertyIndex);
                        // "01CDF407";

                        propertyIndex += 8;

                        var dd = DateTime.FromFileTimeUtc(hexNumber);

                        PropertyNames.Add(propertyName,
                                          dd.ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0041:
                        //VT_BLOB 0x0041 Type is binary large object (BLOB), and the minimum property set version is 0

                        //TODO FINISH THIS

                        var blobSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 4;

                        var bytes = propertyValue.Value.Skip(0x69).ToArray();

                        var props = new PropertyStore(bytes);

                        PropertyNames.Add(propertyName,
                                          $"BLOB data: {BitConverter.ToString(propertyValue.Value, propertyIndex)}");

                        foreach (var prop in props.Sheets)
                        {
                            foreach (var name in prop.PropertyNames)
                            {
                                PropertyNames.Add($"{name.Key}", name.Value);     // (From BLOB data)
                            }
                        }

                        propertyIndex += blobSize;

                        break;

                    case 0x0042:
                        //TODO FINISH THIS

                        //Type is Stream, and the minimum property set version is 0. VT_STREAM is not allowed in a simple property set.
                        PropertyNames.Add(propertyName,
                                          "VT_STREAM not implemented (yet) See extension block section for contents for now");

                        break;

                    default:
                        PropertyNames.Add(propertyName,
                                          $"Unknown named property type: {namedType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}. Send file to [email protected] to get support added");
                        break;
                        //throw new Exception($"Unknown named property type: {namedType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}");
                    }
                }

                var terminator = BitConverter.ToInt32(contents, sheetindex);

                if (terminator != 0)
                {
                    throw new Exception($"Expected terminator of 0, but got {terminator}");
                }
            }
            else
            {
                //treat as numeric property values

                PropertySheetType = PropertySheetTypeEnum.Numeric;

                var valueSize  = 0;
                var propertyId = 0;

                var propertyValues     = new Dictionary <int, byte[]>();
                var propertySlotNumber = 0;

                while (sheetindex < contents.Length)
                {
                    //cut up shellPropertySheetList into byte arrays based on length, then process each one
                    var sheetSize = BitConverter.ToInt32(contents, sheetindex);

                    if (sheetSize == 0)
                    {
                        break; // we are out of lists
                    }

                    var sheetListBytes = new byte[sheetSize];
                    Array.Copy(contents, sheetindex, sheetListBytes, 0, sheetSize);

                    propertyValues.Add(propertySlotNumber, sheetListBytes);
                    propertySlotNumber += 1;

                    sheetindex += sheetSize;
                } //end of while in shellPropertySheetList

                foreach (var propertyValue in propertyValues)
                {
                    var propertyIndex = 0;

                    valueSize      = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                    propertyIndex += 4;

                    propertyId     = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                    propertyIndex += 4;

                    propertyIndex += 1; //skip reserved

                    var numericType = BitConverter.ToUInt16(propertyValue.Value, propertyIndex);

                    propertyIndex += 2; //skip type
                    propertyIndex += 2; //skip padding?

                    //TODO Combine these with what is below. Make a function to take the type, process and return a string?
                    switch (numericType)
                    {
                    case 0x1048:
                        //MUST be a VectorHeader followed by a sequence of GUID (Packet Version) packets.

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                          "VT_VECTOR data not implemented (yet)");

                        break;

                    case 0x01e:
                        var uniLength1e = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 4;

                        var unicodeName1e =
                            Encoding.Unicode.GetString(propertyValue.Value, propertyIndex, uniLength1e)
                            .Split('\0')
                            .First();

                        // Debug.WriteLine($"Find me: {BitConverter.ToString(propertyValue.Value)}, propertyIndex: {propertyIndex} unicodeName1e: {unicodeName1e}");

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), unicodeName1e);

                        break;

                    case 0x001f:     //unicode string

                        var uniLength = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 4;


                        if (uniLength <= 0)
                        {
                            PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), string.Empty);
                            break;
                        }

                        var unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                                                     (uniLength * 2) - 2);
                        propertyIndex += (uniLength * 2);

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), unicodeName);

                        break;

                    case 0x000b:
                        //VT_BOOL (0x000B) MUST be a VARIANT_BOOL as specified in [MS-OAUT] section 2.2.27, followed by zero padding to 4 bytes.

                        var boolInt = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 8;

                        var boolval = boolInt > 0;

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                          boolval.ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0003:
                        //VT_I4 (0x0003) MUST be a 32-bit signed integer.

                        var signedInt = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 4;

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                          signedInt.ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0015:
                        //VT_UI8 (0x0015) MUST be an 8-byte unsigned integer

                        var unsigned8int = BitConverter.ToUInt64(propertyValue.Value, propertyIndex);
                        propertyIndex += 8;

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                          unsigned8int.ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0042:
                        //VT_STREAM (0x0042) MUST be an IndirectPropertyName. The storage representing the
                        //(non-simple) property set MUST have a stream element with this name

                        //defer for now

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                          "VT_STREAM not implemented");

                        break;

                    case 0x0013:
                        //VT_UI4 (0x0013) MUST be a 4-byte unsigned integer

                        var unsigned4int = BitConverter.ToUInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 4;

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                          unsigned4int.ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0001:
                        //VT_NULL (0x0001) MUST be zero bytes in length.

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), "Null");

                        break;

                    case 0x0002:
                        //VT_I2 (0x0002) Either the specified type, or the type of the element or contained field MUST be a 2-byte signed int

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), BitConverter.ToUInt16(propertyValue.Value, propertyIndex).ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x101f:
                        //VT_VECTOR | VT_LPWSTR 0x101F Type is Vector of UnicodeString, and the minimum property set version is 0

                        propertyIndex += 4;

                        unicodeName = string.Empty;

                        if (propertyValue.Value.Length > propertyIndex)
                        {
                            uniLength      = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                            propertyIndex += 4;

                            unicodeName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                                                     (uniLength * 2) - 2);
                            propertyIndex += (uniLength * 2);
                        }



                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), unicodeName);

                        break;

                    case 0x0048:
                        //VT_CLSID 0x0048 Type is CLSID, and the minimum property set version is 0.

                        var rawguid1 = new byte[16];

                        Array.Copy(propertyValue.Value, propertyIndex, rawguid1, 0, 16);

                        propertyIndex += 16;

                        var rawguid = Utils.ExtractGuidFromShellItem(rawguid1);

                        var foldername = Utils.GetFolderNameFromGuid(rawguid);

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), foldername);

                        break;

                    case 0x1011:
                        //VT_VECTOR | VT_UI1 0x1011 Type is Vector of 1-byte unsigned integers, and the minimum property  set version is 0.

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                          "VT_VECTOR data not implemented (yet) See extension block section for contents for now");

                        //TODO i see indicators from 0x00, case 0x23febbee: ProcessPropertyViewGUID(rawBytes) in the bits for this
                        // can we pull out the property sheet and add them to the property names here?

                        break;

                    case 0x0040:
                        //VT_FILETIME 0x0040 Type is FILETIME, and the minimum property set version is 0.

                        var hexNumber = BitConverter.ToInt64(propertyValue.Value, propertyIndex);
                        // "01CDF407";

                        propertyIndex += 8;

                        var dd = DateTime.FromFileTimeUtc(hexNumber);

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                          dd.ToString(CultureInfo.InvariantCulture));

                        break;

                    case 0x0008:

                        var codePageSize = BitConverter.ToInt32(propertyValue.Value, propertyIndex);
                        propertyIndex += 4;

                        var codePageName = Encoding.Unicode.GetString(propertyValue.Value, propertyIndex,
                                                                      codePageSize - 2);
                        propertyIndex += (codePageSize);

                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture), codePageName);

                        break;

                    default:
                        PropertyNames.Add(propertyId.ToString(CultureInfo.InvariantCulture),
                                          $"Unknown numeric property type: {numericType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}. Send file to [email protected] to get support added");
                        break;
                        //  throw new Exception($"Unknown numeric property type: {numericType.ToString("X")}, Hex data (after property type): {BitConverter.ToString(propertyValue.Value, propertyIndex)}");
                    }
                }

                var terminator = BitConverter.ToInt32(contents, sheetindex);

                if (terminator != 0)
                {
                    throw new Exception($"Expected terminator of 0, but got {terminator}");
                }
            }
        }