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); }
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); }
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); }
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)); } } }
// 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); }
// 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); }
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; }
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; } }
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}"); } } }